audio: Initial bring up of QCOM added audio feature(jb_cho).

- Update alsa_sound and libalsa-intf to JB mainline
- Use audio channel, format, and mode definitions
  from system/core instead of libhardware_legacy
- Enable AudioPolicyManagerALSA as QCOM's customized
  audio policy manager
- Enable QCOM audio features including: proxy, USB
  audio, and  ANC.
- Disable compress audio because it's not supported
  by jb_cho kernel

Change-Id: Ia9f0a8024a3f3e1d28210687aecfc72e6b784941
diff --git a/alsa_sound/ALSAControl.cpp b/alsa_sound/ALSAControl.cpp
deleted file mode 100644
index 2d610a1..0000000
--- a/alsa_sound/ALSAControl.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/* ALSAControl.cpp
- **
- ** Copyright 2008-2009 Wind River Systems
- ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#include <errno.h>
-#include <stdarg.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <dlfcn.h>
-
-#define LOG_TAG "ALSAControl"
-//#define LOG_NDEBUG 0
-#define LOG_NDDEBUG 0
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-#include <cutils/properties.h>
-#include <media/AudioRecord.h>
-#include <hardware_legacy/power.h>
-
-#include "AudioHardwareALSA.h"
-
-namespace android_audio_legacy
-{
-
-ALSAControl::ALSAControl(const char *device)
-{
-    ALOGD("ALSAControl: ctor device %s", device);
-    mHandle = mixer_open(device);
-    ALOGV("ALSAControl: ctor mixer %p", mHandle);
-}
-
-ALSAControl::~ALSAControl()
-{
-    if (mHandle) mixer_close(mHandle);
-}
-
-status_t ALSAControl::get(const char *name, unsigned int &value, int index)
-{
-    struct mixer_ctl *ctl;
-
-    if (!mHandle) {
-        ALOGE("Control not initialized");
-        return NO_INIT;
-    }
-
-    ctl =  mixer_get_control(mHandle, name, index);
-    if (!ctl)
-        return BAD_VALUE;
-
-    mixer_ctl_get(ctl, &value);
-    return NO_ERROR;
-}
-
-status_t ALSAControl::set(const char *name, unsigned int value, int index)
-{
-    struct mixer_ctl *ctl;
-    int ret = 0;
-    ALOGD("set:: name %s value %d index %d", name, value, index);
-    if (!mHandle) {
-        ALOGE("Control not initialized");
-        return NO_INIT;
-    }
-
-    // ToDo: Do we need to send index here? Right now it works with 0
-    ctl = mixer_get_control(mHandle, name, 0);
-    if(ctl == NULL) {
-        ALOGE("Could not get the mixer control");
-        return BAD_VALUE;
-    }
-    ret = mixer_ctl_set(ctl, value);
-    return (ret < 0) ? BAD_VALUE : NO_ERROR;
-}
-
-status_t ALSAControl::set(const char *name, const char *value)
-{
-    struct mixer_ctl *ctl;
-    int ret = 0;
-    ALOGD("set:: name %s value %s", name, value);
-
-    if (!mHandle) {
-        ALOGE("Control not initialized");
-        return NO_INIT;
-    }
-
-    ctl = mixer_get_control(mHandle, name, 0);
-    if(ctl == NULL) {
-        ALOGE("Could not get the mixer control");
-        return BAD_VALUE;
-    }
-    ret = mixer_ctl_select(ctl, value);
-    return (ret < 0) ? BAD_VALUE : NO_ERROR;
-}
-
-status_t ALSAControl::setext(const char *name, int count, char **setValues)
-{
-    struct mixer_ctl *ctl;
-    int ret = 0;
-    ALOGD("setext:: name %s count %d", name, count);
-    if (!mHandle) {
-        ALOGE("Control not initialized");
-        return NO_INIT;
-    }
-
-    // ToDo: Do we need to send index here? Right now it works with 0
-    ctl = mixer_get_control(mHandle, name, 0);
-    if(ctl == NULL) {
-        ALOGE("Could not get the mixer control");
-        return BAD_VALUE;
-    }
-    ret = mixer_ctl_set_value(ctl, count, setValues);
-    return (ret < 0) ? BAD_VALUE : NO_ERROR;
-}
-
-};        // namespace android
diff --git a/alsa_sound/ALSADevice.cpp b/alsa_sound/ALSADevice.cpp
new file mode 100644
index 0000000..cd5b92d
--- /dev/null
+++ b/alsa_sound/ALSADevice.cpp
@@ -0,0 +1,2408 @@
+/* ALSADevice.cpp
+ **
+ ** Copyright 2009 Wind River Systems
+ ** Copyright (c) 2011-2012, 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 "ALSADevice"
+#define LOG_NDEBUG 0
+#define LOG_NDDEBUG 0
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <linux/ioctl.h>
+#include "AudioUtil.h"
+#include "AudioHardwareALSA.h"
+#include <media/AudioRecord.h>
+#include <dlfcn.h>
+#ifdef QCOM_CSDCLIENT_ENABLED
+extern "C" {
+static int (*csd_disable_device)();
+static int (*csd_enable_device)(int, int, uint32_t);
+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)();
+static int (*csd_client_volume)(int);
+static int (*csd_client_mic_mute)(int);
+}
+#endif
+
+#define SAMPLE_RATE_8KHZ 8000
+
+
+#define BTSCO_RATE_16KHZ 16000
+#define USECASE_TYPE_RX 1
+#define USECASE_TYPE_TX 2
+#define MAX_HDMI_CHANNEL_CNT 6
+
+#define AFE_PROXY_PERIOD_SIZE 3072
+#define KILL_A2DP_THREAD 1
+#define SIGNAL_A2DP_THREAD 2
+#define PROXY_CAPTURE_DEVICE_NAME (const char *)("hw:0,8")
+namespace sys_close {
+    ssize_t lib_close(int fd) {
+        return close(fd);
+    }
+};
+
+namespace android_audio_legacy
+{
+
+ALSADevice::ALSADevice() {
+#ifdef USES_FLUENCE_INCALL
+    mDevSettingsFlag = TTY_OFF | DMIC_FLAG;
+#else
+    mDevSettingsFlag = TTY_OFF;
+#endif
+    mBtscoSamplerate = 8000;
+    mCallMode = AUDIO_MODE_NORMAL;
+    mInChannels = 0;
+    char value[128], platform[128], baseband[128];
+
+    property_get("persist.audio.handset.mic",value,"0");
+    strlcpy(mMicType, value, sizeof(mMicType));
+    property_get("persist.audio.fluence.mode",value,"0");
+    if (!strcmp("broadside", value)) {
+        mFluenceMode = FLUENCE_MODE_BROADSIDE;
+    } else {
+        mFluenceMode = FLUENCE_MODE_ENDFIRE;
+    }
+    property_get("ro.board.platform", platform, "");
+    property_get("ro.baseband", baseband, "");
+    if (!strcmp("msm8960", platform) && !strcmp("sglte", baseband)) {
+        mIsSglte = true;
+    }
+    else {
+        mIsSglte = false;
+    }
+    strlcpy(mCurRxUCMDevice, "None", sizeof(mCurRxUCMDevice));
+    strlcpy(mCurTxUCMDevice, "None", sizeof(mCurTxUCMDevice));
+
+    mMixer = mixer_open("/dev/snd/controlC0");
+
+    mProxyParams.mExitRead = false;
+    resetProxyVariables();
+    mProxyParams.mCaptureBufferSize = AFE_PROXY_PERIOD_SIZE;
+    mProxyParams.mCaptureBuffer = NULL;
+    mProxyParams.mProxyState = proxy_params::EProxyClosed;
+    mProxyParams.mProxyPcmHandle = NULL;
+
+    ALOGD("ALSA module opened");
+}
+
+//static int s_device_close(hw_device_t* device)
+ALSADevice::~ALSADevice()
+{
+    if (mMixer) mixer_close(mMixer);
+    if(mProxyParams.mCaptureBuffer != NULL) {
+        free(mProxyParams.mCaptureBuffer);
+        mProxyParams.mCaptureBuffer = NULL;
+    }
+    mProxyParams.mProxyState = proxy_params::EProxyClosed;
+
+}
+
+bool ALSADevice::platform_is_Fusion3()
+{
+    char platform[128], baseband[128];
+    property_get("ro.board.platform", platform, "");
+    property_get("ro.baseband", baseband, "");
+    if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband))
+        return true;
+    else
+        return false;
+}
+
+int ALSADevice::deviceName(alsa_handle_t *handle, unsigned flags, char **value)
+{
+    int ret = 0;
+    char ident[70];
+
+    if (flags & PCM_IN) {
+        strlcpy(ident, "CapturePCM/", sizeof(ident));
+    } else {
+        strlcpy(ident, "PlaybackPCM/", sizeof(ident));
+    }
+    strlcat(ident, handle->useCase, sizeof(ident));
+    ret = snd_use_case_get(handle->ucMgr, ident, (const char **)value);
+    ALOGD("Device value returned is %s", (*value));
+    return ret;
+}
+
+status_t ALSADevice::setHDMIChannelCount()
+{
+    status_t err = NO_ERROR;
+    int channel_count = 0;
+    const char *channel_cnt_str = NULL;
+    EDID_AUDIO_INFO info = { 0 };
+
+    if (AudioUtil::getHDMIAudioSinkCaps(&info)) {
+        for (int i = 0; i < info.nAudioBlocks && i < MAX_EDID_BLOCKS; i++) {
+            if (info.AudioBlocksArray[i].nChannels > channel_count &&
+                  info.AudioBlocksArray[i].nChannels <= MAX_HDMI_CHANNEL_CNT) {
+                channel_count = info.AudioBlocksArray[i].nChannels;
+            }
+        }
+    }
+
+    switch (channel_count) {
+    case 6: channel_cnt_str = "Six"; break;
+    case 5: channel_cnt_str = "Five"; break;
+    case 4: channel_cnt_str = "Four"; break;
+    case 3: channel_cnt_str = "Three"; break;
+    default: channel_cnt_str = "Two"; break;
+    }
+    ALOGD("HDMI channel count: %s", channel_cnt_str);
+    setMixerControl("HDMI_RX Channels", channel_cnt_str);
+
+    return err;
+}
+
+status_t ALSADevice::setHardwareParams(alsa_handle_t *handle)
+{
+    struct snd_pcm_hw_params *params;
+    unsigned long bufferSize, reqBuffSize;
+    unsigned int periodTime, bufferTime;
+    unsigned int requestedRate = handle->sampleRate;
+    int status = 0;
+    int channels = handle->channels;
+    status_t err;
+    snd_pcm_format_t format = SNDRV_PCM_FORMAT_S16_LE;
+    struct snd_compr_caps compr_cap;
+    struct snd_compr_params compr_params;
+    uint32_t codec_id = 0;
+
+    ALOGD("handle->format: 0x%x", handle->format);
+    if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL))) {
+        ALOGV("Tunnel mode detected...");
+        //get the list of codec supported by hardware
+        if (ioctl(handle->handle->fd, SNDRV_COMPRESS_GET_CAPS, &compr_cap)) {
+            ALOGE("SNDRV_COMPRESS_GET_CAPS, failed Error no %d \n", errno);
+            err = -errno;
+            return err;
+        }
+        if( handle->format == AUDIO_FORMAT_AAC ) {
+          codec_id = get_compressed_format("AAC");
+          ALOGV("### AAC CODEC codec_id %d",codec_id);
+        }
+        else if (handle->format == AUDIO_FORMAT_AMR_WB) {
+          codec_id = get_compressed_format("AMR_WB");
+          if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) ||
+              (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED)) ||
+              (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL)) ||
+              (!strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL)) ||
+              (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL)) ||
+              (!strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL))) {
+              compr_params.codec.options.generic.reserved[0] = 8; /*band mode - 23.85 kbps*/
+              compr_params.codec.options.generic.reserved[1] = 0; /*dtx mode - disable*/
+          }
+          ALOGV("### AMR WB CODEC codec_id %d",codec_id);
+        }
+#ifdef QCOM_AUDIO_FORMAT_ENABLED
+        else if (handle->format == AUDIO_FORMAT_AMR_WB_PLUS) {
+          codec_id = get_compressed_format("AMR_WB_PLUS");
+          ALOGV("### AMR WB+ CODEC codec_id %d",codec_id);
+        }
+#endif
+        else if (handle->format == AUDIO_FORMAT_MP3) {
+          codec_id = get_compressed_format("MP3");
+          ALOGV("### MP3 CODEC codec_id %d",codec_id);
+        }
+        else {
+            return UNKNOWN_ERROR;
+        }
+        //find if codec_id matches with any of h/w supported codecs.
+        for (int i = 0; i < compr_cap.num_codecs; i++) {
+          if (compr_cap.codecs[i] == codec_id) {
+            ALOGV("### MatchedFcodec_id %u", codec_id);
+            compr_params.codec.id = codec_id;
+            break;
+          }
+        }
+        if (!compr_params.codec.id) {
+          ALOGE("### Codec %u not supported",codec_id);
+          return UNKNOWN_ERROR;
+        }
+
+        if (ioctl(handle->handle->fd, SNDRV_COMPRESS_SET_PARAMS, &compr_params)) {
+            ALOGE("SNDRV_COMPRESS_SET_PARAMS,failed Error no %d \n", errno);
+            err = -errno;
+            return err;
+        }
+    }
+
+    params = (snd_pcm_hw_params*) calloc(1, sizeof(struct snd_pcm_hw_params));
+    if (!params) {
+        ALOGE("Failed to allocate ALSA hardware parameters!");
+        return NO_INIT;
+    }
+
+    reqBuffSize = handle->bufferSize;
+    ALOGD("setHardwareParams: reqBuffSize %d channels %d sampleRate %d",
+         (int) reqBuffSize, handle->channels, handle->sampleRate);
+
+#ifdef QCOM_SSR_ENABLED
+    if (channels == 6) {
+        if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
+            || !strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, strlen(SND_USE_CASE_VERB_HIFI_REC_COMPRESSED))
+            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))
+            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) {
+            ALOGV("HWParams: Use 4 channels in kernel for 5.1(%s) recording ", handle->useCase);
+            channels = 4;
+        }
+    }
+#endif
+
+    param_init(params);
+    if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
+        param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS,
+                       SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
+    }
+    else {
+        param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS,
+                       SNDRV_PCM_ACCESS_RW_INTERLEAVED);
+    }
+
+    if (handle->format != SNDRV_PCM_FORMAT_S16_LE) {
+        if (handle->format == AUDIO_FORMAT_AMR_NB
+            || handle->format == AUDIO_FORMAT_AMR_WB
+#ifdef QCOM_AUDIO_FORMAT_ENABLED
+            || handle->format == AUDIO_FORMAT_EVRC
+            || handle->format == AUDIO_FORMAT_EVRCB
+            || handle->format == AUDIO_FORMAT_EVRCWB
+#endif
+            ) {
+            if ((strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) &&
+                (strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL)) &&
+                (strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) &&
+                (strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL)) &&
+                (strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL)) &&
+                (strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL)) &&
+                (strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL)) &&
+                (strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) {
+              format = SNDRV_PCM_FORMAT_SPECIAL;
+              ALOGW("setting format to SNDRV_PCM_FORMAT_SPECIAL");
+            }
+        }
+    }
+    //TODO: Add format setting for tunnel mode using the usecase.
+    param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+                   format);
+    param_set_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
+                   SNDRV_PCM_SUBFORMAT_STD);
+    param_set_int(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, reqBuffSize);
+    param_set_int(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
+    param_set_int(params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
+                   channels * 16);
+    param_set_int(params, SNDRV_PCM_HW_PARAM_CHANNELS,
+                  channels);
+    param_set_int(params, SNDRV_PCM_HW_PARAM_RATE, handle->sampleRate);
+    param_set_hw_refine(handle->handle, params);
+
+    if (param_set_hw_params(handle->handle, params)) {
+        ALOGE("cannot set hw params");
+        return NO_INIT;
+    }
+    param_dump(params);
+
+    handle->handle->buffer_size = pcm_buffer_size(params);
+    handle->handle->period_size = pcm_period_size(params);
+    handle->handle->period_cnt = handle->handle->buffer_size/handle->handle->period_size;
+    ALOGD("setHardwareParams: buffer_size %d, period_size %d, period_cnt %d",
+        handle->handle->buffer_size, handle->handle->period_size,
+        handle->handle->period_cnt);
+    handle->handle->rate = handle->sampleRate;
+    handle->handle->channels = handle->channels;
+    handle->periodSize = handle->handle->period_size;
+    if (strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC) &&
+        strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED) &&
+        strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC) &&
+        strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED) &&
+        (6 != handle->channels)) {
+        //Do not update buffersize for 5.1 recording
+        if (handle->format == AUDIO_FORMAT_AMR_WB &&
+            format != SNDRV_PCM_FORMAT_SPECIAL) {
+            ALOGV("### format AMWB, set bufsize to 61");
+            handle->bufferSize = 61;
+        } else {
+            handle->bufferSize = handle->handle->period_size;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+status_t ALSADevice::setSoftwareParams(alsa_handle_t *handle)
+{
+    struct snd_pcm_sw_params* params;
+    struct pcm* pcm = handle->handle;
+
+    unsigned long periodSize = pcm->period_size;
+    int channels = handle->channels;
+
+    params = (snd_pcm_sw_params*) calloc(1, sizeof(struct snd_pcm_sw_params));
+    if (!params) {
+        LOG_ALWAYS_FATAL("Failed to allocate ALSA software parameters!");
+        return NO_INIT;
+    }
+
+#ifdef QCOM_SSR_ENABLED
+    if (channels == 6) {
+        if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
+            || !strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, strlen(SND_USE_CASE_VERB_HIFI_REC_COMPRESSED))
+            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))
+            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) {
+            ALOGV("SWParams: Use 4 channels in kernel for 5.1(%s) recording ", handle->useCase);
+            channels = 4;
+        }
+    }
+#endif
+
+    // Get the current software parameters
+    params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
+    params->period_step = 1;
+    if(((!strcmp(handle->useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
+        (!strcmp(handle->useCase,SND_USE_CASE_VERB_IP_VOICECALL)))){
+          ALOGV("setparam:  start & stop threshold for Voip ");
+          params->avail_min = handle->channels - 1 ? periodSize/4 : periodSize/2;
+          params->start_threshold = periodSize/2;
+          params->stop_threshold = INT_MAX;
+     } else {
+         params->avail_min = periodSize/(channels * 2);
+         params->start_threshold = periodSize/(channels * 2);
+         params->stop_threshold = INT_MAX;
+     }
+    params->silence_threshold = 0;
+    params->silence_size = 0;
+
+    if (param_set_sw_params(handle->handle, params)) {
+        ALOGE("cannot set sw params");
+        return NO_INIT;
+    }
+    return NO_ERROR;
+}
+
+void ALSADevice::switchDevice(alsa_handle_t *handle, uint32_t devices, uint32_t mode)
+{
+    const char **mods_list;
+    use_case_t useCaseNode;
+    unsigned usecase_type = 0;
+    bool inCallDevSwitch = false;
+    char *rxDevice, *txDevice, ident[70], *use_case = NULL;
+    int err = 0, index, mods_size;
+    int rx_dev_id, tx_dev_id;
+    ALOGV("%s: device %#x mode:%d", __FUNCTION__, devices, mode);
+
+    if ((mode == AUDIO_MODE_IN_CALL)  || (mode == AUDIO_MODE_IN_COMMUNICATION)) {
+        if ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
+            (devices & AudioSystem::DEVICE_IN_WIRED_HEADSET)) {
+            devices = devices | (AudioSystem::DEVICE_OUT_WIRED_HEADSET |
+                      AudioSystem::DEVICE_IN_WIRED_HEADSET);
+        } else if (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) {
+            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 = devices | (AudioSystem::DEVICE_IN_BUILTIN_MIC |
+                      AudioSystem::DEVICE_OUT_EARPIECE);
+        } else if (devices & AudioSystem::DEVICE_OUT_SPEAKER) {
+            devices = devices | (AudioSystem::DEVICE_IN_BUILTIN_MIC |
+                       AudioSystem::DEVICE_OUT_SPEAKER);
+        } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO) ||
+                   (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET) ||
+                   (devices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {
+            devices = devices | (AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET |
+                      AudioSystem::DEVICE_OUT_BLUETOOTH_SCO);
+#ifdef QCOM_ANC_HEADSET_ENABLED
+        } else if ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
+                   (devices & AudioSystem::DEVICE_IN_ANC_HEADSET)) {
+            devices = devices | (AudioSystem::DEVICE_OUT_ANC_HEADSET |
+                      AudioSystem::DEVICE_IN_ANC_HEADSET);
+        } else if (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE) {
+            devices = devices | (AudioSystem::DEVICE_OUT_ANC_HEADPHONE |
+                      AudioSystem::DEVICE_IN_BUILTIN_MIC);
+#endif
+#ifdef QCOM_USBAUDIO_ENABLED
+        } else if ((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET ) ||
+                  (devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET )) {
+            devices = devices | (AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET |
+                      AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET);
+#endif
+        } else if (devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
+            devices = devices | (AudioSystem::DEVICE_OUT_AUX_DIGITAL |
+                      AudioSystem::DEVICE_IN_AUX_DIGITAL);
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+        } else if ((devices & AudioSystem::DEVICE_OUT_PROXY) ||
+                  (devices & AudioSystem::DEVICE_IN_PROXY)) {
+            devices = devices | (AudioSystem::DEVICE_OUT_PROXY |
+                      AudioSystem::DEVICE_IN_PROXY);
+        } else if (devices & AudioSystem::DEVICE_OUT_ALL_A2DP) {
+            devices = devices | (AudioSystem::DEVICE_IN_PROXY);
+#endif
+        }
+    }
+#ifdef QCOM_SSR_ENABLED
+    if ((devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) && ( 6 == handle->channels)) {
+        if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
+            || !strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, strlen(SND_USE_CASE_VERB_HIFI_REC_COMPRESSED))
+            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))
+            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) {
+            ALOGV(" switchDevice , use ssr devices for channels:%d usecase:%s",handle->channels,handle->useCase);
+            setFlags(SSRQMIC_FLAG);
+        }
+    }
+#endif
+
+    rxDevice = getUCMDevice(devices & AudioSystem::DEVICE_OUT_ALL, 0, NULL);
+    ALOGV("%s: rxDevice %s devices:0x%x", __FUNCTION__, rxDevice,devices);
+    txDevice = getUCMDevice(devices & AudioSystem::DEVICE_IN_ALL, 1, rxDevice);
+    ALOGV("%s: txDevice:%s devices:0x%x", __FUNCTION__, txDevice,devices);
+
+    if ((rxDevice != NULL) && (txDevice != NULL)) {
+        if (((strncmp(rxDevice, mCurRxUCMDevice, MAX_STR_LEN)) ||
+             (strncmp(txDevice, mCurTxUCMDevice, MAX_STR_LEN))) &&
+             ((mode == AUDIO_MODE_IN_CALL) ||
+             (mode == AUDIO_MODE_IN_COMMUNICATION)))
+            inCallDevSwitch = true;
+    }
+
+#ifdef QCOM_CSDCLIENT_ENABLED
+    if (platform_is_Fusion3() && (inCallDevSwitch == true)) {
+        if (csd_disable_device == NULL) {
+            ALOGE("dlsym:Error:%s Loading csd_client_disable_device", dlerror());
+        } else {
+            err = csd_disable_device();
+            if (err < 0)
+            {
+                ALOGE("csd_client_disable_device, failed, error %d", err);
+            }
+        }
+    }
+#endif
+
+    snd_use_case_get(handle->ucMgr, "_verb", (const char **)&use_case);
+    mods_size = snd_use_case_get_list(handle->ucMgr, "_enamods", &mods_list);
+    if (rxDevice != NULL) {
+        if ((strncmp(mCurRxUCMDevice, "None", 4)) &&
+            ((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);
+                if (usecase_type & USECASE_TYPE_RX) {
+                    ALOGD("Deroute use case %s type is %d\n", use_case, usecase_type);
+                    strlcpy(useCaseNode.useCase, use_case, MAX_STR_LEN);
+                    snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE);
+                    mUseCaseList.push_front(useCaseNode);
+                }
+            }
+            if (mods_size) {
+                for(index = 0; index < mods_size; index++) {
+                    usecase_type = getUseCaseType(mods_list[index]);
+                    if (usecase_type & USECASE_TYPE_RX) {
+                        ALOGD("Deroute use case %s type is %d\n", mods_list[index], usecase_type);
+                        strlcpy(useCaseNode.useCase, mods_list[index], MAX_STR_LEN);
+                        snd_use_case_set(handle->ucMgr, "_dismod", mods_list[index]);
+                        mUseCaseList.push_back(useCaseNode);
+                    }
+                }
+            }
+            snd_use_case_set(handle->ucMgr, "_disdev", mCurRxUCMDevice);
+        }
+    }
+    if (txDevice != NULL) {
+        if ((strncmp(mCurTxUCMDevice, "None", 4)) &&
+            ((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);
+                if ((usecase_type & USECASE_TYPE_TX) && (!(usecase_type & USECASE_TYPE_RX))) {
+                    ALOGD("Deroute use case %s type is %d\n", use_case, usecase_type);
+                    strlcpy(useCaseNode.useCase, use_case, MAX_STR_LEN);
+                    snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE);
+                    mUseCaseList.push_front(useCaseNode);
+                }
+            }
+            if (mods_size) {
+                for(index = 0; index < mods_size; index++) {
+                    usecase_type = getUseCaseType(mods_list[index]);
+                    if ((usecase_type & USECASE_TYPE_TX) && (!(usecase_type & USECASE_TYPE_RX))) {
+                        ALOGD("Deroute use case %s type is %d\n", mods_list[index], usecase_type);
+                        strlcpy(useCaseNode.useCase, mods_list[index], MAX_STR_LEN);
+                        snd_use_case_set(handle->ucMgr, "_dismod", mods_list[index]);
+                        mUseCaseList.push_back(useCaseNode);
+                    }
+                }
+            }
+            snd_use_case_set(handle->ucMgr, "_disdev", mCurTxUCMDevice);
+       }
+    }
+
+    ALOGV("%s,rxDev:%s, txDev:%s, curRxDev:%s, curTxDev:%s\n", __FUNCTION__, rxDevice, txDevice, mCurRxUCMDevice, mCurTxUCMDevice);
+
+    if (rxDevice != NULL) {
+        snd_use_case_set(handle->ucMgr, "_enadev", rxDevice);
+        strlcpy(mCurRxUCMDevice, rxDevice, sizeof(mCurRxUCMDevice));
+    }
+    if (txDevice != NULL) {
+       snd_use_case_set(handle->ucMgr, "_enadev", txDevice);
+       strlcpy(mCurTxUCMDevice, txDevice, sizeof(mCurTxUCMDevice));
+    }
+    for(ALSAUseCaseList::iterator it = mUseCaseList.begin(); it != mUseCaseList.end(); ++it) {
+        ALOGD("Route use case %s\n", it->useCase);
+        if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
+            strlen(SND_USE_CASE_VERB_INACTIVE))) && (!strncmp(use_case, it->useCase, MAX_UC_LEN))) {
+            snd_use_case_set(handle->ucMgr, "_verb", it->useCase);
+        } else {
+            snd_use_case_set(handle->ucMgr, "_enamod", it->useCase);
+        }
+    }
+    if (!mUseCaseList.empty())
+        mUseCaseList.clear();
+    if (use_case != NULL) {
+        free(use_case);
+        use_case = NULL;
+    }
+#ifdef QCOM_FM_ENABLED
+    if (rxDevice != NULL) {
+        if (devices & AudioSystem::DEVICE_OUT_FM)
+            setFmVolume(mFmVolume);
+    }
+#endif
+    ALOGD("switchDevice: mCurTxUCMDevivce %s mCurRxDevDevice %s", mCurTxUCMDevice, mCurRxUCMDevice);
+    if (platform_is_Fusion3() && (inCallDevSwitch == true)) {
+
+        /* 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);
+
+        if (rx_dev_id == DEVICE_SPEAKER_RX_ACDB_ID && tx_dev_id == DEVICE_HANDSET_TX_ACDB_ID) {
+            tx_dev_id = DEVICE_SPEAKER_TX_ACDB_ID;
+        }
+
+#ifdef QCOM_CSDCLIENT_ENABLED
+        ALOGV("rx_dev_id=%d, tx_dev_id=%d\n", rx_dev_id, tx_dev_id);
+        if (csd_enable_device == NULL) {
+            ALOGE("dlsym:Error:%s Loading csd_client_enable_device", dlerror());
+        } else {
+            err = csd_enable_device(rx_dev_id, tx_dev_id, mDevSettingsFlag);
+            if (err < 0)
+            {
+                ALOGE("csd_client_disable_device failed, error %d", err);
+            }
+        }
+#endif
+    }
+
+    if (rxDevice != NULL) {
+        free(rxDevice);
+        rxDevice = NULL;
+    }
+    if (txDevice != NULL) {
+        free(txDevice);
+        txDevice = NULL;
+    }
+}
+
+// ----------------------------------------------------------------------------
+/*
+status_t ALSADevice::init(alsa_device_t *module, ALSAHandleList &list)
+{
+    ALOGD("s_init: Initializing devices for ALSA module");
+
+    list.clear();
+
+    return NO_ERROR;
+}
+*/
+status_t ALSADevice::open(alsa_handle_t *handle)
+{
+    char *devName = NULL;
+    unsigned flags = 0;
+    int err = NO_ERROR;
+
+    if(handle->devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
+        err = setHDMIChannelCount();
+        if(err != OK) {
+            ALOGE("setHDMIChannelCount err = %d", err);
+            return err;
+        }
+    }
+    close(handle);
+
+    ALOGD("open: handle %p, format 0x%x", handle, handle->format);
+
+    // ASoC multicomponent requires a valid path (frontend/backend) for
+    // the device to be opened
+
+    // The PCM stream is opened in blocking mode, per ALSA defaults.  The
+    // AudioFlinger seems to assume blocking mode too, so asynchronous mode
+    // should not be used.
+    if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
+        ALOGV("LPA/tunnel use case");
+        flags |= PCM_MMAP;
+        flags |= DEBUG_ON;
+    } else if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI2)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
+        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC))) {
+        ALOGV("Music case");
+        flags = PCM_OUT;
+    } else {
+        flags = PCM_IN;
+    }
+
+    if (handle->channels == 1) {
+        flags |= PCM_MONO;
+    }
+#ifdef QCOM_SSR_ENABLED
+    else if (handle->channels == 4 ) {
+        flags |= PCM_QUAD;
+    } else if (handle->channels == 6 ) {
+        if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
+            || !strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, strlen(SND_USE_CASE_VERB_HIFI_REC_COMPRESSED))
+            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))
+            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) {
+            flags |= PCM_QUAD;
+        } else {
+            flags |= PCM_5POINT1;
+        }
+    }
+#endif
+    else {
+        flags |= PCM_STEREO;
+    }
+
+    if (deviceName(handle, flags, &devName) < 0) {
+        ALOGE("Failed to get pcm device node: %s", devName);
+        return NO_INIT;
+    }
+    if (devName != NULL) {
+        ALOGV("flags %x, devName %s",flags,devName);
+        handle->handle = pcm_open(flags, (char*)devName);
+    } else {
+        ALOGE("Failed to get pcm device node");
+        return NO_INIT;
+    }
+    ALOGV("pcm_open returned fd %d", handle->handle->fd);
+
+    if (!handle->handle || (handle->handle->fd < 0)) {
+        ALOGE("open: Failed to initialize ALSA device '%s'", devName);
+        if (devName) {
+            free(devName);
+            devName = NULL;
+        }
+        return NO_INIT;
+    }
+
+    handle->handle->flags = flags;
+    err = setHardwareParams(handle);
+
+    if (err == NO_ERROR) {
+        err = setSoftwareParams(handle);
+    }
+
+    if(err != NO_ERROR) {
+        ALOGE("Set HW/SW params failed: Closing the pcm stream");
+        standby(handle);
+        free(devName);
+        devName = NULL;
+        return err;
+    }
+
+    if (devName) {
+        free(devName);
+        devName = NULL;
+    }
+    return NO_ERROR;
+}
+
+status_t ALSADevice::startVoipCall(alsa_handle_t *handle)
+{
+
+    char* devName = NULL;
+    unsigned flags = 0;
+    int err = NO_ERROR;
+    uint8_t voc_pkt[VOIP_BUFFER_MAX_SIZE];
+
+    close(handle);
+    flags = PCM_OUT;
+    flags |= PCM_MONO;
+    ALOGV("startVoipCall  handle %p", handle);
+
+    if (deviceName(handle, flags, &devName) < 0) {
+         ALOGE("Failed to get pcm device node");
+         return NO_INIT;
+    }
+
+    if (devName != NULL) {
+        handle->handle = pcm_open(flags, (char*)devName);
+    } else {
+         ALOGE("Failed to get pcm device node");
+         return NO_INIT;
+    }
+
+     if (!handle->handle || (handle->handle->fd < 0)) {
+          if (devName) {
+              free(devName);
+              devName = NULL;
+          }
+          ALOGE("s_open: Failed to initialize ALSA device '%s'", devName);
+          return NO_INIT;
+     }
+
+     if (!pcm_ready(handle->handle)) {
+         ALOGE(" pcm ready failed");
+     }
+
+     handle->handle->flags = flags;
+     err = setHardwareParams(handle);
+
+     if (err == NO_ERROR) {
+         err = setSoftwareParams(handle);
+     }
+
+     err = pcm_prepare(handle->handle);
+     if(err != NO_ERROR) {
+         ALOGE("startVoipCall: pcm_prepare failed");
+     }
+
+     /* first write required start dsp */
+     memset(&voc_pkt,0,sizeof(voc_pkt));
+     pcm_write(handle->handle,&voc_pkt,handle->handle->period_size);
+     handle->rxHandle = handle->handle;
+     if (devName) {
+         free(devName);
+         devName = NULL;
+     }
+     ALOGV("s_open: DEVICE_IN_COMMUNICATION ");
+     flags = PCM_IN;
+     flags |= PCM_MONO;
+     handle->handle = 0;
+
+     if (deviceName(handle, flags, &devName) < 0) {
+        ALOGE("Failed to get pcm device node");
+        return NO_INIT;
+     }
+    if (devName != NULL) {
+        handle->handle = pcm_open(flags, (char*)devName);
+    } else {
+         ALOGE("Failed to get pcm device node");
+         return NO_INIT;
+    }
+
+     if (!handle->handle) {
+         if (devName) {
+             free(devName);
+             devName = NULL;
+         }
+         ALOGE("s_open: Failed to initialize ALSA device '%s'", devName);
+         return NO_INIT;
+     }
+
+     if (!pcm_ready(handle->handle)) {
+        ALOGE(" pcm ready in failed");
+     }
+
+     handle->handle->flags = flags;
+
+     err = setHardwareParams(handle);
+
+     if (err == NO_ERROR) {
+         err = setSoftwareParams(handle);
+     }
+
+
+     err = pcm_prepare(handle->handle);
+     if(err != NO_ERROR) {
+         ALOGE("DEVICE_IN_COMMUNICATION: pcm_prepare failed");
+     }
+
+     /* first read required start dsp */
+     memset(&voc_pkt,0,sizeof(voc_pkt));
+     pcm_read(handle->handle,&voc_pkt,handle->handle->period_size);
+     if (devName) {
+         free(devName);
+         devName = NULL;
+     }
+     return NO_ERROR;
+}
+
+status_t ALSADevice::startVoiceCall(alsa_handle_t *handle)
+{
+    char* devName = NULL;
+    unsigned flags = 0;
+    int err = NO_ERROR;
+
+    ALOGD("startVoiceCall: handle %p", handle);
+    // ASoC multicomponent requires a valid path (frontend/backend) for
+    // the device to be opened
+
+    flags = PCM_OUT | PCM_MONO;
+    if (deviceName(handle, flags, &devName) < 0) {
+        ALOGE("Failed to get pcm device node");
+        return NO_INIT;
+    }
+    if (devName != NULL) {
+        handle->handle = pcm_open(flags, (char*)devName);
+    } else {
+         ALOGE("Failed to get pcm device node");
+         return NO_INIT;
+    }
+
+    if (!handle->handle || (handle->handle->fd < 0)) {
+        ALOGE("startVoiceCall: could not open PCM device");
+        goto Error;
+    }
+
+    handle->handle->flags = flags;
+    err = setHardwareParams(handle);
+    if(err != NO_ERROR) {
+        ALOGE("startVoiceCall: setHardwareParams failed");
+        goto Error;
+    }
+
+    err = setSoftwareParams(handle);
+    if(err != NO_ERROR) {
+        ALOGE("startVoiceCall: setSoftwareParams failed");
+        goto Error;
+    }
+
+    err = pcm_prepare(handle->handle);
+    if(err != NO_ERROR) {
+        ALOGE("startVoiceCall: pcm_prepare failed");
+        goto Error;
+    }
+
+    if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
+        ALOGE("startVoiceCall:SNDRV_PCM_IOCTL_START failed\n");
+        goto Error;
+    }
+
+    // Store the PCM playback device pointer in rxHandle
+    handle->rxHandle = handle->handle;
+    if (devName) {
+        free(devName);
+        devName = NULL;
+    }
+
+    // Open PCM capture device
+    flags = PCM_IN | PCM_MONO;
+    if (deviceName(handle, flags, &devName) < 0) {
+        ALOGE("Failed to get pcm device node");
+        goto Error;
+    }
+    if (devName != NULL) {
+        handle->handle = pcm_open(flags, (char*)devName);
+    } else {
+         ALOGE("Failed to get pcm device node");
+         return NO_INIT;
+    }
+    if (!handle->handle || (handle->handle->fd < 0)) {
+        free(devName);
+        goto Error;
+    }
+
+    handle->handle->flags = flags;
+    err = setHardwareParams(handle);
+    if(err != NO_ERROR) {
+        ALOGE("startVoiceCall: setHardwareParams failed");
+        goto Error;
+    }
+
+    err = setSoftwareParams(handle);
+    if(err != NO_ERROR) {
+        ALOGE("startVoiceCall: setSoftwareParams failed");
+        goto Error;
+    }
+
+    err = pcm_prepare(handle->handle);
+    if(err != NO_ERROR) {
+        ALOGE("startVoiceCall: pcm_prepare failed");
+        goto Error;
+    }
+
+    if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
+        ALOGE("startVoiceCall:SNDRV_PCM_IOCTL_START failed\n");
+        goto Error;
+    }
+
+    if (platform_is_Fusion3()) {
+#ifdef QCOM_CSDCLIENT_ENABLED
+        if (csd_start_voice == NULL) {
+            ALOGE("dlsym:Error:%s Loading csd_client_start_voice", dlerror());
+        } else {
+            err = csd_start_voice();
+            if (err < 0){
+                ALOGE("s_start_voice_call: csd_client error %d\n", err);
+                goto Error;
+            }
+        }
+#endif
+    }
+
+    if (devName) {
+        free(devName);
+        devName = NULL;
+    }
+    return NO_ERROR;
+
+Error:
+    ALOGE("startVoiceCall: Failed to initialize ALSA device '%s'", devName);
+    if (devName) {
+        free(devName);
+        devName = NULL;
+    }
+    close(handle);
+    return NO_INIT;
+}
+
+status_t ALSADevice::startFm(alsa_handle_t *handle)
+{
+    char *devName = NULL;
+    unsigned flags = 0;
+    int err = NO_ERROR;
+
+    ALOGV("startFm: handle %p", handle);
+
+    // ASoC multicomponent requires a valid path (frontend/backend) for
+    // the device to be opened
+
+    flags = PCM_OUT | PCM_STEREO;
+    if (deviceName(handle, flags, &devName) < 0) {
+        ALOGE("Failed to get pcm device node");
+        goto Error;
+    }
+    if (devName != NULL) {
+        handle->handle = pcm_open(flags, (char*)devName);
+    } else {
+         ALOGE("Failed to get pcm device node");
+         return NO_INIT;
+    }
+    if (!handle->handle || (handle->handle->fd < 0)) {
+        ALOGE("startFm: could not open PCM device");
+        goto Error;
+    }
+
+    handle->handle->flags = flags;
+    err = setHardwareParams(handle);
+    if(err != NO_ERROR) {
+        ALOGE("startFm: setHardwareParams failed");
+        goto Error;
+    }
+
+    err = setSoftwareParams(handle);
+    if(err != NO_ERROR) {
+        ALOGE("startFm: setSoftwareParams failed");
+        goto Error;
+    }
+
+    err = pcm_prepare(handle->handle);
+    if(err != NO_ERROR) {
+        ALOGE("startFm: setSoftwareParams failed");
+        goto Error;
+    }
+
+    if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
+        ALOGE("startFm: SNDRV_PCM_IOCTL_START failed\n");
+        goto Error;
+    }
+
+    // Store the PCM playback device pointer in rxHandle
+    handle->rxHandle = handle->handle;
+    if (devName) {
+        free(devName);
+        devName = NULL;
+    }
+
+    // Open PCM capture device
+    flags = PCM_IN | PCM_STEREO;
+    if (deviceName(handle, flags, &devName) < 0) {
+        ALOGE("Failed to get pcm device node");
+        goto Error;
+    }
+    if (devName != NULL) {
+        handle->handle = pcm_open(flags, (char*)devName);
+    } else {
+         ALOGE("Failed to get pcm device node");
+         return NO_INIT;
+    }
+    if (!handle->handle) {
+        goto Error;
+    }
+
+    handle->handle->flags = flags;
+    err = setHardwareParams(handle);
+    if(err != NO_ERROR) {
+        ALOGE("startFm: setHardwareParams failed");
+        goto Error;
+    }
+
+    err = setSoftwareParams(handle);
+    if(err != NO_ERROR) {
+        ALOGE("startFm: setSoftwareParams failed");
+        goto Error;
+    }
+
+    err = pcm_prepare(handle->handle);
+    if(err != NO_ERROR) {
+        ALOGE("startFm: pcm_prepare failed");
+        goto Error;
+    }
+
+    if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
+        ALOGE("startFm: SNDRV_PCM_IOCTL_START failed\n");
+        goto Error;
+    }
+
+
+    setFmVolume(mFmVolume);
+    if (devName) {
+        free(devName);
+        devName = NULL;
+    }
+    return NO_ERROR;
+
+Error:
+    if (devName) {
+        free(devName);
+        devName = NULL;
+    }
+    close(handle);
+    return NO_INIT;
+}
+
+status_t ALSADevice::setFmVolume(int value)
+{
+    status_t err = NO_ERROR;
+
+    setMixerControl("Internal FM RX Volume",value,0);
+    mFmVolume = value;
+
+    return err;
+}
+
+status_t ALSADevice::setLpaVolume(int value)
+{
+    status_t err = NO_ERROR;
+
+    setMixerControl("LPA RX Volume",value,0);
+
+    return err;
+}
+
+status_t ALSADevice::start(alsa_handle_t *handle)
+{
+    status_t err = NO_ERROR;
+
+    if(!handle->handle) {
+        ALOGE("No active PCM driver to start");
+        return err;
+    }
+
+    err = pcm_prepare(handle->handle);
+
+    return err;
+}
+
+status_t ALSADevice::close(alsa_handle_t *handle)
+{
+    int ret;
+    status_t err = NO_ERROR;
+     struct pcm *h = handle->rxHandle;
+
+    handle->rxHandle = 0;
+    ALOGD("close: handle %p h %p", handle, h);
+    if (h) {
+        if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_VOICECALL) ||
+             !strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_VOICE)) &&
+            platform_is_Fusion3()) {
+#ifdef QCOM_CSDCLIENT_ENABLED
+            if (csd_stop_voice == NULL) {
+                ALOGE("dlsym:Error:%s Loading csd_client_disable_device", dlerror());
+            } else {
+                err = csd_stop_voice();
+                if (err < 0) {
+                    ALOGE("s_close: csd_client error %d\n", err);
+                }
+            }
+#endif
+        }
+        ALOGV("close rxHandle\n");
+        err = pcm_close(h);
+        if(err != NO_ERROR) {
+            ALOGE("close: pcm_close failed for rxHandle with err %d", err);
+        }
+    }
+
+    h = handle->handle;
+    handle->handle = 0;
+
+    if (h) {
+          ALOGV("close handle h %p\n", h);
+        err = pcm_close(h);
+        if(err != NO_ERROR) {
+            ALOGE("close: pcm_close failed for handle with err %d", err);
+        }
+        disableDevice(handle);
+    }
+
+    return err;
+}
+
+/*
+    this is same as s_close, but don't discard
+    the device/mode info. This way we can still
+    close the device, hit idle and power-save, reopen the pcm
+    for the same device/mode after resuming
+*/
+status_t ALSADevice::standby(alsa_handle_t *handle)
+{
+    int ret;
+    status_t err = NO_ERROR;
+    struct pcm *h = handle->rxHandle;
+    handle->rxHandle = 0;
+    ALOGD("standby: handle %p h %p", handle, h);
+    if (h) {
+        ALOGV("standby  rxHandle\n");
+        err = pcm_close(h);
+        if(err != NO_ERROR) {
+            ALOGE("standby: pcm_close failed for rxHandle with err %d", err);
+        }
+    }
+
+    h = handle->handle;
+    handle->handle = 0;
+
+    if (h) {
+        ALOGV("standby handle h %p\n", h);
+        err = pcm_close(h);
+        if(err != NO_ERROR) {
+            ALOGE("standby: pcm_close failed for handle with err %d", err);
+        }
+        disableDevice(handle);
+    }
+
+    return err;
+}
+
+status_t ALSADevice::route(alsa_handle_t *handle, uint32_t devices, int mode)
+{
+    status_t status = NO_ERROR;
+
+    ALOGD("route: devices 0x%x in mode %d", devices, mode);
+    mCallMode = mode;
+    switchDevice(handle, devices, mode);
+    return status;
+}
+
+int ALSADevice::getUseCaseType(const char *useCase)
+{
+    ALOGV("use case is %s\n", useCase);
+    if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
+            MAX_LEN(useCase, SND_USE_CASE_VERB_HIFI2)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI2)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_DIGITAL_RADIO,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
+            MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LPA,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LPA)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_FM,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))) {
+        return USECASE_TYPE_RX;
+    } else if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED,
+            MAX_LEN(useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_FM_REC,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_FM_REC)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_FM_A2DP_REC,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_FM_A2DP_REC)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_FM,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_FM)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM,
+            MAX_LEN(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED,
+            MAX_LEN(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) {
+        return USECASE_TYPE_TX;
+    } else if (!strncmp(useCase, SND_USE_CASE_VERB_VOICECALL,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_VOICECALL)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_IP_VOICECALL,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_IP_VOICECALL)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_DL_REC,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_DL_REC)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_UL_DL_REC,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_UL_DL_REC)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_INCALL_REC,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_INCALL_REC)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOIP,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
+            MAX_LEN(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_SGLTECALL,
+            MAX_LEN(useCase, SND_USE_CASE_VERB_SGLTECALL)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_SGLTE,
+            MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_SGLTE)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_VOLTE,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_VOLTE)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
+            MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_VOLTE))) {
+        return (USECASE_TYPE_RX | USECASE_TYPE_TX);
+    } else {
+        ALOGV("unknown use case %s\n", useCase);
+        return 0;
+    }
+}
+
+void ALSADevice::disableDevice(alsa_handle_t *handle)
+{
+    unsigned usecase_type = 0;
+    int i, mods_size;
+    char *useCase;
+    const char **mods_list;
+
+    snd_use_case_get(handle->ucMgr, "_verb", (const char **)&useCase);
+    if (useCase != NULL) {
+        if (!strncmp(useCase, handle->useCase, MAX_UC_LEN)) {
+            snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE);
+        } else {
+            snd_use_case_set(handle->ucMgr, "_dismod", handle->useCase);
+        }
+        free(useCase);
+        snd_use_case_get(handle->ucMgr, "_verb", (const char **)&useCase);
+        if (strncmp(useCase, SND_USE_CASE_VERB_INACTIVE,
+               strlen(SND_USE_CASE_VERB_INACTIVE)))
+            usecase_type |= getUseCaseType(useCase);
+        mods_size = snd_use_case_get_list(handle->ucMgr, "_enamods", &mods_list);
+        ALOGV("Number of modifiers %d\n", mods_size);
+        if (mods_size) {
+            for(i = 0; i < mods_size; i++) {
+                ALOGV("index %d modifier %s\n", i, mods_list[i]);
+                usecase_type |= getUseCaseType(mods_list[i]);
+            }
+        }
+        ALOGV("usecase_type is %d\n", usecase_type);
+        if (!(usecase_type & USECASE_TYPE_TX) && (strncmp(mCurTxUCMDevice, "None", 4)))
+            snd_use_case_set(handle->ucMgr, "_disdev", mCurTxUCMDevice);
+        if (!(usecase_type & USECASE_TYPE_RX) && (strncmp(mCurRxUCMDevice, "None", 4)))
+            snd_use_case_set(handle->ucMgr, "_disdev", mCurRxUCMDevice);
+    } else {
+        ALOGE("Invalid state, no valid use case found to disable");
+    }
+    free(useCase);
+}
+
+char *ALSADevice::getUCMDeviceFromAcdbId(int acdb_id)
+{
+     switch(acdb_id) {
+        case DEVICE_HANDSET_RX_ACDB_ID:
+             return strdup(SND_USE_CASE_DEV_HANDSET);
+        case DEVICE_SPEAKER_RX_ACDB_ID:
+             return strdup(SND_USE_CASE_DEV_SPEAKER);
+        case DEVICE_HEADSET_RX_ACDB_ID:
+             return strdup(SND_USE_CASE_DEV_HEADPHONES);
+        case DEVICE_TTY_HEADSET_MONO_RX_ACDB_ID:
+             return strdup(SND_USE_CASE_DEV_TTY_HEADSET_RX);
+        case DEVICE_ANC_HEADSET_STEREO_RX_ACDB_ID:
+             return strdup(SND_USE_CASE_DEV_ANC_HEADSET);
+        default:
+             return NULL;
+     }
+}
+
+char* ALSADevice::getUCMDevice(uint32_t devices, int input, char *rxDevice)
+{
+    if (!input) {
+        ALOGV("getUCMDevice for output device: devices:%x is input device:%d",devices,input);
+        if (!(mDevSettingsFlag & TTY_OFF) &&
+            (mCallMode == AUDIO_MODE_IN_CALL) &&
+            ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET)
+             || (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)
+#ifdef QCOM_ANC_HEADSET_ENABLED
+             || (devices & AudioSystem::DEVICE_OUT_ANC_HEADSET)
+             || (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE)
+#endif
+             )) {
+             if (mDevSettingsFlag & TTY_VCO) {
+                 return strdup(SND_USE_CASE_DEV_TTY_HEADSET_RX);
+             } else if (mDevSettingsFlag & TTY_FULL) {
+                 return strdup(SND_USE_CASE_DEV_TTY_FULL_RX);
+             } else if (mDevSettingsFlag & TTY_HCO) {
+                 return strdup(SND_USE_CASE_DEV_TTY_HANDSET_RX); /* HANDSET RX */
+             }
+        } else if (devices & AudioSystem::DEVICE_OUT_ALL_A2DP &&
+                   devices & AudioSystem::DEVICE_OUT_SPEAKER) {
+            return strdup(SND_USE_CASE_DEV_PROXY_RX_SPEAKER);
+        } else if (devices & AudioSystem::DEVICE_OUT_ALL_A2DP) {
+            return strdup(SND_USE_CASE_DEV_PROXY_RX);
+        } else if ((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET ||
+                    devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) &&
+                    devices & AudioSystem::DEVICE_OUT_SPEAKER) {
+             return strdup(SND_USE_CASE_DEV_PROXY_RX_SPEAKER); /* PROXY RX */
+        } 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 QCOM_PROXY_DEVICE_ENABLED
+        } else if( (devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
+                   (devices & AudioSystem::DEVICE_OUT_PROXY) &&
+                   ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
+                    (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) ) ) {
+            if (mDevSettingsFlag & ANC_FLAG) {
+                return strdup(SND_USE_CASE_DEV_PROXY_RX_SPEAKER_ANC_HEADSET);
+            } else {
+                return strdup(SND_USE_CASE_DEV_PROXY_RX_SPEAKER_HEADSET);
+            }
+#endif
+        } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
+            ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
+            (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) {
+            if (mDevSettingsFlag & ANC_FLAG) {
+                return strdup(SND_USE_CASE_DEV_SPEAKER_ANC_HEADSET); /* COMBO SPEAKER+ANC HEADSET RX */
+            } else {
+                return strdup(SND_USE_CASE_DEV_SPEAKER_HEADSET); /* COMBO SPEAKER+HEADSET RX */
+            }
+        } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
+            ((devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL))) {
+            return strdup(SND_USE_CASE_DEV_HDMI_SPEAKER);
+#ifdef QCOM_ANC_HEADSET_ENABLED
+        } else if ((devices & AudioSystem::DEVICE_OUT_PROXY) &&
+                   ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET)||
+                    (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE)) ) {
+            return strdup(SND_USE_CASE_DEV_PROXY_RX_ANC_HEADSET);
+        } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
+            ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
+            (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
+        } 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 */
+#endif
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+        } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
+                 (devices & AudioSystem::DEVICE_OUT_PROXY)) {
+            return strdup(SND_USE_CASE_DEV_PROXY_RX_SPEAKER); /* COMBO SPEAKER + PROXY RX */
+        } else if ((devices & AudioSystem::DEVICE_OUT_EARPIECE) &&
+                 (devices & AudioSystem::DEVICE_OUT_PROXY)) {
+            return strdup(SND_USE_CASE_DEV_PROXY_RX_HANDSET); /* COMBO EARPIECE + PROXY RX */
+#endif
+        } else if (devices & AudioSystem::DEVICE_OUT_EARPIECE) {
+            if (mCallMode == AUDIO_MODE_IN_CALL ||
+                mCallMode == AUDIO_MODE_IN_COMMUNICATION) {
+                return strdup(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) {
+            return strdup(SND_USE_CASE_DEV_SPEAKER); /* SPEAKER RX */
+        } else if ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
+                   (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) {
+            if (mDevSettingsFlag & ANC_FLAG) {
+                if (mCallMode == AUDIO_MODE_IN_CALL ||
+                    mCallMode == AUDIO_MODE_IN_COMMUNICATION) {
+                    return strdup(SND_USE_CASE_DEV_VOC_ANC_HEADSET); /* Voice ANC HEADSET RX */
+                } else {
+                    return strdup(SND_USE_CASE_DEV_ANC_HEADSET); /* ANC HEADSET RX */
+                }
+            } else {
+                if (mCallMode == AUDIO_MODE_IN_CALL ||
+                    mCallMode == AUDIO_MODE_IN_COMMUNICATION) {
+                    return strdup(SND_USE_CASE_DEV_VOC_HEADPHONE); /* Voice HEADSET RX */
+                } else {
+                    return strdup(SND_USE_CASE_DEV_HEADPHONES); /* HEADSET RX */
+                }
+            }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+        } else if ((devices & AudioSystem::DEVICE_OUT_PROXY) &&
+                   ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
+                    (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) {
+            if (mDevSettingsFlag & ANC_FLAG) {
+                return strdup(SND_USE_CASE_DEV_PROXY_RX_ANC_HEADSET);
+            } else {
+                return strdup(SND_USE_CASE_DEV_PROXY_RX_HEADSET);
+            }
+        } else if ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
+                   (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE)) {
+            if (mCallMode == AUDIO_MODE_IN_CALL ||
+                mCallMode == AUDIO_MODE_IN_COMMUNICATION) {
+                return strdup(SND_USE_CASE_DEV_VOC_ANC_HEADSET); /* Voice ANC HEADSET RX */
+            } else {
+                return strdup(SND_USE_CASE_DEV_ANC_HEADSET); /* ANC HEADSET RX */
+            }
+#endif
+        } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO) ||
+                  (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET) ||
+                  (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT)) {
+            if (mBtscoSamplerate == BTSCO_RATE_16KHZ)
+                return strdup(SND_USE_CASE_DEV_BTSCO_WB_RX); /* BTSCO RX*/
+            else
+                return strdup(SND_USE_CASE_DEV_BTSCO_NB_RX); /* BTSCO RX*/
+        } else if (devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
+            return strdup(SND_USE_CASE_DEV_HDMI); /* HDMI RX */
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+        } else if (devices & AudioSystem::DEVICE_OUT_PROXY) {
+            return strdup(SND_USE_CASE_DEV_PROXY_RX); /* PROXY RX */
+#endif
+#ifdef QCOM_FM_TX_ENABLED
+        } else if (devices & AudioSystem::DEVICE_OUT_FM_TX) {
+            return strdup(SND_USE_CASE_DEV_FM_TX); /* FM Tx */
+#endif
+        } else if (devices & AudioSystem::DEVICE_OUT_DEFAULT) {
+            return strdup(SND_USE_CASE_DEV_SPEAKER); /* SPEAKER RX */
+        } else {
+            ALOGD("No valid output device: %u", devices);
+        }
+    } else {
+        ALOGV("getUCMDevice for input device: devices:%x is input device:%d",devices,input);
+        if (!(mDevSettingsFlag & TTY_OFF) &&
+            (mCallMode == AUDIO_MODE_IN_CALL) &&
+            ((devices & AudioSystem::DEVICE_IN_WIRED_HEADSET)
+#ifdef QCOM_ANC_HEADSET_ENABLED
+             || (devices & AudioSystem::DEVICE_IN_ANC_HEADSET)
+#endif
+             )) {
+             if (mDevSettingsFlag & TTY_HCO) {
+                 return strdup(SND_USE_CASE_DEV_TTY_HEADSET_TX);
+             } else if (mDevSettingsFlag & TTY_FULL) {
+                 return strdup(SND_USE_CASE_DEV_TTY_FULL_TX);
+             } else if (mDevSettingsFlag & TTY_VCO) {
+                 if (!strncmp(mMicType, "analog", 6)) {
+                     return strdup(SND_USE_CASE_DEV_TTY_HANDSET_ANALOG_TX);
+                 } else {
+                     return strdup(SND_USE_CASE_DEV_TTY_HANDSET_TX);
+                 }
+             }
+        } else if (devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) {
+            if (!strncmp(mMicType, "analog", 6)) {
+                return strdup(SND_USE_CASE_DEV_HANDSET); /* HANDSET TX */
+            } 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 (((rxDevice != NULL) &&
+                        !strncmp(rxDevice, SND_USE_CASE_DEV_SPEAKER,
+                        (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) ||
+                        ((rxDevice == NULL) &&
+                        !strncmp(mCurRxUCMDevice, SND_USE_CASE_DEV_SPEAKER,
+                        (strlen(SND_USE_CASE_DEV_SPEAKER)+1)))) {
+                        if (mFluenceMode == FLUENCE_MODE_ENDFIRE) {
+                            if (mIsSglte == false) {
+                                return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */
+                            }
+                            else {
+                                return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE_SGLTE); /* DUALMIC EF TX */
+                            }
+                        } else if (mFluenceMode == FLUENCE_MODE_BROADSIDE) {
+                            return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */
+                        }
+                    } else {
+                        if (mFluenceMode == FLUENCE_MODE_ENDFIRE) {
+                            if (mIsSglte == false) {
+                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */
+                            }
+                            else {
+                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_SGLTE); /* DUALMIC EF TX */
+                            }
+                        } else if (mFluenceMode == FLUENCE_MODE_BROADSIDE) {
+                            return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */
+                        }
+                    }
+#endif
+                } else if ((mDevSettingsFlag & DMIC_FLAG) && (mInChannels > 1)) {
+                    if (((rxDevice != NULL) &&
+                        !strncmp(rxDevice, SND_USE_CASE_DEV_SPEAKER,
+                        (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) ||
+                        ((rxDevice == NULL) &&
+                        !strncmp(mCurRxUCMDevice, SND_USE_CASE_DEV_SPEAKER,
+                        (strlen(SND_USE_CASE_DEV_SPEAKER)+1)))) {
+                            if (mIsSglte == false) {
+                                return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_STEREO); /* DUALMIC EF TX */
+                            }
+                            else {
+                                return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_STEREO_SGLTE); /* DUALMIC EF TX */
+                            }
+                    } else {
+                            if (mIsSglte == false) {
+                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_HANDSET_STEREO); /* DUALMIC EF TX */
+                            }
+                            else {
+                                return strdup(SND_USE_CASE_DEV_DUAL_MIC_HANDSET_STEREO_SGLTE); /* DUALMIC EF TX */
+                            }
+                    }
+                } else if ((mDevSettingsFlag & QMIC_FLAG) && (mInChannels == 1)) {
+                    if (((rxDevice != NULL) &&
+                        !strncmp(rxDevice, SND_USE_CASE_DEV_SPEAKER,
+                        (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) ||
+                        ((rxDevice == NULL) &&
+                        !strncmp(mCurRxUCMDevice, SND_USE_CASE_DEV_SPEAKER,
+                        (strlen(SND_USE_CASE_DEV_SPEAKER)+1)))) {
+                            return strdup(SND_USE_CASE_DEV_QUAD_MIC); /* QUADMIC TX */
+                    } else {
+                        return strdup(SND_USE_CASE_DEV_LINE);
+                    }
+                }
+#ifdef QCOM_SSR_ENABLED
+                else if ((mDevSettingsFlag & QMIC_FLAG) && (mInChannels > 1)) {
+                    return strdup(SND_USE_CASE_DEV_SSR_QUAD_MIC);
+                } else if ((mDevSettingsFlag & SSRQMIC_FLAG) && (mInChannels > 1)){
+                    ALOGV("return SSRQMIC_FLAG: 0x%x devices:0x%x",mDevSettingsFlag,devices);
+                    // Mapping for quad mic input device.
+                    return strdup(SND_USE_CASE_DEV_SSR_QUAD_MIC); /* SSR Quad MIC */
+                }
+#endif
+#ifdef SEPERATED_AUDIO_INPUT
+                if(mInput_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
+                    return strdup(SND_USE_CASE_DEV_VOICE_RECOGNITION ); /* VOICE RECOGNITION TX */
+                }
+#endif
+                else {
+                    return strdup(SND_USE_CASE_DEV_LINE); /* BUILTIN-MIC TX */
+                }
+            }
+        } 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)) {
+            return strdup(SND_USE_CASE_DEV_HEADSET); /* HEADSET TX */
+#ifdef QCOM_ANC_HEADSET_ENABLED
+        } else if (devices & AudioSystem::DEVICE_IN_ANC_HEADSET) {
+            return strdup(SND_USE_CASE_DEV_HEADSET); /* HEADSET TX */
+#endif
+        } else if (devices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+             if (mBtscoSamplerate == BTSCO_RATE_16KHZ)
+                 return strdup(SND_USE_CASE_DEV_BTSCO_WB_TX); /* BTSCO TX*/
+             else
+                 return strdup(SND_USE_CASE_DEV_BTSCO_NB_TX); /* BTSCO TX*/
+#ifdef QCOM_USBAUDIO_ENABLED
+        } else if (devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) {
+            if ((mCallMode == AUDIO_MODE_IN_CALL) ||
+                (mCallMode == AUDIO_MODE_IN_COMMUNICATION)) {
+                if ((rxDevice != NULL) &&
+                   (!strncmp(rxDevice, SND_USE_CASE_DEV_USB_PROXY_RX,
+                    (strlen(SND_USE_CASE_DEV_USB_PROXY_RX)+1)))) {
+                    return strdup(SND_USE_CASE_DEV_USB_PROXY_TX); /* USB PROXY TX */
+                } else if ((rxDevice != NULL) &&
+                   (!strncmp(rxDevice, SND_USE_CASE_DEV_PROXY_RX,
+                    (strlen(SND_USE_CASE_DEV_PROXY_RX)+1)))) {
+                    return strdup(SND_USE_CASE_DEV_PROXY_TX); /* PROXY TX */
+                } else {
+                    return strdup(SND_USE_CASE_DEV_USB_PROXY_TX); /* USB PROXY TX */
+                }
+            } else {
+                return strdup(SND_USE_CASE_DEV_USB_PROXY_TX); /* USB PROXY TX */
+            }
+#endif
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+        } else if (devices & AudioSystem::DEVICE_IN_PROXY) {
+            return strdup(SND_USE_CASE_DEV_PROXY_TX); /* PROXY TX */
+#endif
+        } else if ((devices & AudioSystem::DEVICE_IN_COMMUNICATION) ||
+                   (devices & AudioSystem::DEVICE_IN_VOICE_CALL)) {
+            /* Nothing to be done, use current active device */
+            if (strncmp(mCurTxUCMDevice, "None", 4)) {
+                return strdup(mCurTxUCMDevice);
+            }
+#ifdef QCOM_FM_ENABLED
+        } 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 */
+            if (strncmp(mCurTxUCMDevice, "None", 4)) {
+                return strdup(mCurTxUCMDevice);
+            } else {
+                return strdup(SND_USE_CASE_DEV_DUMMY_TX);
+            }
+#endif
+        } else if ((devices & AudioSystem::DEVICE_IN_AMBIENT) ||
+                   (devices & AudioSystem::DEVICE_IN_BACK_MIC)) {
+            ALOGI("No proper mapping found with UCM device list, setting default");
+            if (!strncmp(mMicType, "analog", 6)) {
+                return strdup(SND_USE_CASE_DEV_HANDSET); /* HANDSET TX */
+            } else {
+#ifdef SEPERATED_AUDIO_INPUT
+                if (callMode == 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 */
+            }
+        } else {
+            ALOGD("No valid input device: %u", devices);
+        }
+    }
+    return NULL;
+}
+
+void ALSADevice::setVoiceVolume(int vol)
+{
+    int err = 0;
+    ALOGD("setVoiceVolume: volume %d", vol);
+    setMixerControl("Voice Rx Volume", vol, 0);
+
+    if (platform_is_Fusion3()) {
+#ifdef QCOM_CSDCLIENT_ENABLED
+        if (csd_volume == NULL) {
+            ALOGE("dlsym:Error:%s Loading csd_client_volume", dlerror());
+        } else {
+            err = csd_volume(vol);
+            if (err < 0) {
+                ALOGE("s_set_voice_volume: csd_client error %d", err);
+            }
+        }
+#endif
+    }
+}
+
+void ALSADevice::setSGLTEVolume(int vol)
+{
+    int err = 0;
+    ALOGD("setSGLTEVolume: volume %d", vol);
+    setMixerControl("SGLTE Rx Volume", vol, 0);
+
+    if (platform_is_Fusion3()) {
+        err = csd_client_volume(vol);
+        if (err < 0) {
+            ALOGE("setSGLTEVolume: csd_client error %d", err);
+        }
+    }
+}
+
+void ALSADevice::setVoLTEVolume(int vol)
+{
+    ALOGD("setVoLTEVolume: volume %d", vol);
+    setMixerControl("VoLTE Rx Volume", vol, 0);
+}
+
+
+void ALSADevice::setVoipVolume(int vol)
+{
+    ALOGD("setVoipVolume: volume %d", vol);
+    setMixerControl("Voip Rx Volume", vol, 0);
+}
+
+void ALSADevice::setMicMute(int state)
+{
+    int err = 0;
+    ALOGD("setMicMute: state %d", state);
+    setMixerControl("Voice Tx Mute", state, 0);
+
+    if (platform_is_Fusion3()) {
+#ifdef QCOM_CSDCLIENT_ENABLED
+        if (csd_mic_mute == NULL) {
+            ALOGE("dlsym:Error:%s Loading csd_mic_mute", dlerror());
+        } else {
+            err=csd_mic_mute(state);
+            if (err < 0) {
+                ALOGE("s_set_mic_mute: csd_client error %d", err);
+            }
+        }
+#endif
+    }
+}
+
+void ALSADevice::setSGLTEMicMute(int state)
+{
+    int err = 0;
+    ALOGD("setSGLTEMicMute: state %d", state);
+    setMixerControl("SGLTE Tx Mute", state, 0);
+
+    if (platform_is_Fusion3()) {
+        err = csd_client_mic_mute(state);
+        if (err < 0) {
+            ALOGE("setSGLTEMicMute: csd_client error %d", err);
+        }
+    }
+}
+
+void ALSADevice::setVoLTEMicMute(int state)
+{
+    ALOGD("setVolteMicMute: state %d", state);
+    setMixerControl("VoLTE Tx Mute", state, 0);
+}
+
+void ALSADevice::setVoipMicMute(int state)
+{
+    ALOGD("setVoipMicMute: state %d", state);
+    setMixerControl("Voip Tx Mute", state, 0);
+}
+
+void ALSADevice::setVoipConfig(int mode, int rate)
+{
+    ALOGD("setVoipConfig: mode %d,rate %d", mode, rate);
+    char** setValues;
+    setValues = (char**)malloc(2*sizeof(char*));
+    if (setValues == NULL) {
+          return;
+    }
+    setValues[0] = (char*)malloc(4*sizeof(char));
+    if (setValues[0] == NULL) {
+          free(setValues);
+          return;
+    }
+
+    setValues[1] = (char*)malloc(8*sizeof(char));
+    if (setValues[1] == NULL) {
+          free(setValues);
+          free(setValues[0]);
+          return;
+    }
+
+    sprintf(setValues[0], "%d",mode);
+    sprintf(setValues[1], "%d",rate);
+
+    setMixerControlExt("Voip Mode Rate Config", 2, setValues);
+    free(setValues[1]);
+    free(setValues[0]);
+    free(setValues);
+    return;
+}
+
+void ALSADevice::setBtscoRate(int rate)
+{
+    mBtscoSamplerate = rate;
+}
+
+void ALSADevice::enableWideVoice(bool flag)
+{
+    int err = 0;
+
+    ALOGD("enableWideVoice: flag %d", flag);
+    if(flag == true) {
+        setMixerControl("Widevoice Enable", 1, 0);
+    } else {
+        setMixerControl("Widevoice Enable", 0, 0);
+    }
+
+    if (platform_is_Fusion3()) {
+#ifdef QCOM_CSDCLIENT_ENABLED
+        if (csd_wide_voice == NULL) {
+            ALOGE("dlsym:Error:%s Loading csd_wide_voice", dlerror());
+        } else {
+            err = csd_wide_voice(flag);
+            if (err < 0) {
+                ALOGE("enableWideVoice: csd_client_wide_voice error %d", err);
+            }
+        }
+#endif
+    }
+}
+
+void ALSADevice::setVocRecMode(uint8_t mode)
+{
+    ALOGD("setVocRecMode: mode %d", mode);
+    setMixerControl("Incall Rec Mode", mode, 0);
+}
+
+void ALSADevice::enableFENS(bool flag)
+{
+    int err = 0;
+
+    ALOGD("enableFENS: flag %d", flag);
+    if(flag == true) {
+        setMixerControl("FENS Enable", 1, 0);
+    } else {
+        setMixerControl("FENS Enable", 0, 0);
+    }
+
+    if (platform_is_Fusion3()) {
+#ifdef QCOM_CSDCLIENT_ENABLED
+        if (csd_fens == NULL) {
+            ALOGE("dlsym:Error:%s Loading csd_fens", dlerror());
+        } else {
+            err = csd_fens(flag);
+            if (err < 0) {
+                ALOGE("s_enable_fens: csd_client error %d", err);
+            }
+        }
+#endif
+    }
+}
+
+void ALSADevice::enableSlowTalk(bool flag)
+{
+    int err = 0;
+
+    ALOGD("enableSlowTalk: flag %d", flag);
+    if(flag == true) {
+        setMixerControl("Slowtalk Enable", 1, 0);
+    } else {
+        setMixerControl("Slowtalk Enable", 0, 0);
+    }
+
+    if (platform_is_Fusion3()) {
+#ifdef QCOM_CSDCLIENT_ENABLED
+        if (csd_slow_talk == NULL) {
+            ALOGE("dlsym:Error:%s Loading csd_slow_talk", dlerror());
+        } else {
+            err = csd_slow_talk(flag);
+            if (err < 0) {
+                ALOGE("s_enable_slow_talk: csd_client error %d", err);
+            }
+        }
+#endif
+    }
+}
+
+void ALSADevice::setFlags(uint32_t flags)
+{
+    ALOGV("setFlags: flags %d", flags);
+    mDevSettingsFlag = flags;
+}
+
+status_t ALSADevice::setCompressedVolume(int value)
+{
+    status_t err = NO_ERROR;
+
+    setMixerControl("COMPRESSED RX Volume",value,0);
+
+    return err;
+}
+
+status_t ALSADevice::getMixerControl(const char *name, unsigned int &value, int index)
+{
+    struct mixer_ctl *ctl;
+
+    if (!mMixer) {
+        ALOGE("Control not initialized");
+        return NO_INIT;
+    }
+
+    ctl =  mixer_get_control(mMixer, name, index);
+    if (!ctl)
+        return BAD_VALUE;
+
+    mixer_ctl_get(ctl, &value);
+    return NO_ERROR;
+}
+
+status_t ALSADevice::setMixerControl(const char *name, unsigned int value, int index)
+{
+    struct mixer_ctl *ctl;
+    int ret = 0;
+    ALOGD("setMixerControl:: name %s value %d index %d", name, value, index);
+    if (!mMixer) {
+        ALOGE("Control not initialized");
+        return NO_INIT;
+    }
+
+    // ToDo: Do we need to send index here? Right now it works with 0
+    ctl = mixer_get_control(mMixer, name, 0);
+    if(ctl == NULL) {
+        ALOGE("Could not get the mixer control");
+        return BAD_VALUE;
+    }
+    ret = mixer_ctl_set(ctl, value);
+    return (ret < 0) ? BAD_VALUE : NO_ERROR;
+}
+
+status_t ALSADevice::setMixerControl(const char *name, const char *value)
+{
+    struct mixer_ctl *ctl;
+    int ret = 0;
+    ALOGD("setMixerControl:: name %s value %s", name, value);
+
+    if (!mMixer) {
+        ALOGE("Control not initialized");
+        return NO_INIT;
+    }
+
+    ctl = mixer_get_control(mMixer, name, 0);
+    if(ctl == NULL) {
+        ALOGE("Could not get the mixer control");
+        return BAD_VALUE;
+    }
+    ret = mixer_ctl_select(ctl, value);
+    return (ret < 0) ? BAD_VALUE : NO_ERROR;
+}
+
+status_t ALSADevice::setMixerControlExt(const char *name, int count, char **setValues)
+{
+    struct mixer_ctl *ctl;
+    int ret = 0;
+    ALOGD("setMixerControl:: name %s count %d", name, count);
+    if (!mMixer) {
+        ALOGE("Control not initialized");
+        return NO_INIT;
+    }
+
+    // ToDo: Do we need to send index here? Right now it works with 0
+    ctl = mixer_get_control(mMixer, name, 0);
+    if(ctl == NULL) {
+        ALOGE("Could not get the mixer control");
+        return BAD_VALUE;
+    }
+    ret = mixer_ctl_set_value(ctl, count, setValues);
+    return (ret < 0) ? BAD_VALUE : NO_ERROR;
+}
+
+status_t ALSADevice::setEcrxDevice(char *device)
+{
+    status_t err = NO_ERROR;
+    setMixerControl("EC_REF_RX", device);
+    return err;
+}
+
+void ALSADevice::setInChannels(int channels)
+{
+    mInChannels = channels;
+    ALOGV("mInChannels:%d", mInChannels);
+}
+
+status_t ALSADevice::exitReadFromProxy()
+{
+    ALOGV("exitReadFromProxy");
+    mProxyParams.mExitRead = true;
+    if(mProxyParams.mPfdProxy[1].fd != -1) {
+        uint64_t writeValue = KILL_A2DP_THREAD;
+        ALOGD("Writing to mPfdProxy[1].fd %d",mProxyParams.mPfdProxy[1].fd);
+        write(mProxyParams.mPfdProxy[1].fd, &writeValue, sizeof(uint64_t));
+    }
+    return NO_ERROR;
+}
+
+void ALSADevice::resetProxyVariables() {
+
+    mProxyParams.mAvail = 0;
+    mProxyParams.mFrames = 0;
+    mProxyParams.mX.frames = 0;
+    if(mProxyParams.mPfdProxy[1].fd != -1) {
+        sys_close::lib_close(mProxyParams.mPfdProxy[1].fd);
+        mProxyParams.mPfdProxy[1].fd = -1;
+    }
+}
+
+ssize_t  ALSADevice::readFromProxy(void **captureBuffer , ssize_t *bufferSize) {
+
+    status_t err = NO_ERROR;
+    int err_poll = 0;
+    initProxyParams();
+    err = startProxy();
+    if(err) {
+        ALOGE("ReadFromProxy-startProxy returned err = %d", err);
+        *captureBuffer = NULL;
+        *bufferSize = 0;
+        return err;
+    }
+    struct pcm * capture_handle = (struct pcm *)mProxyParams.mProxyPcmHandle;
+
+    while(!mProxyParams.mExitRead) {
+        ALOGV("Calling sync_ptr(proxy");
+        err = sync_ptr(capture_handle);
+        if(err == EPIPE) {
+               ALOGE("Failed in sync_ptr \n");
+               /* we failed to make our window -- try to restart */
+               capture_handle->underruns++;
+               capture_handle->running = 0;
+               capture_handle->start = 0;
+               continue;
+        } else if (err != NO_ERROR) {
+                ALOGE("Error: Sync ptr returned %d", err);
+                break;
+        }
+
+        mProxyParams.mAvail = pcm_avail(capture_handle);
+        ALOGV("avail is = %d frames = %ld, avai_min = %d\n",\
+                      mProxyParams.mAvail,  mProxyParams.mFrames,(int)capture_handle->sw_p->avail_min);
+        if (mProxyParams.mAvail < capture_handle->sw_p->avail_min) {
+            err_poll = poll(mProxyParams.mPfdProxy, NUM_FDS, TIMEOUT_INFINITE);
+            if (mProxyParams.mPfdProxy[1].revents & POLLIN) {
+                ALOGV("Event on userspace fd");
+            }
+            if ((mProxyParams.mPfdProxy[1].revents & POLLERR) ||
+                    (mProxyParams.mPfdProxy[1].revents & POLLNVAL)) {
+                ALOGV("POLLERR or INVALID POLL");
+                err = BAD_VALUE;
+                break;
+            }
+            if((mProxyParams.mPfdProxy[0].revents & POLLERR) ||
+                    (mProxyParams.mPfdProxy[0].revents & POLLNVAL)) {
+                ALOGV("POLLERR or INVALID POLL on zero");
+                err = BAD_VALUE;
+                break;
+            }
+            if (mProxyParams.mPfdProxy[0].revents & POLLIN) {
+                ALOGV("POLLIN on zero");
+            }
+            ALOGV("err_poll = %d",err_poll);
+            continue;
+        }
+        break;
+    }
+    if(err != NO_ERROR) {
+        ALOGE("Reading from proxy failed = err = %d", err);
+        *captureBuffer = NULL;
+        *bufferSize = 0;
+        return err;
+    }
+    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 != NO_ERROR ) {
+        ALOGE("Error: Sync ptr end returned %d", err);
+        *captureBuffer = NULL;
+        *bufferSize = 0;
+        return err;
+    }
+    *captureBuffer = mProxyParams.mCaptureBuffer;
+    *bufferSize = mProxyParams.mCaptureBufferSize;
+    return err;
+}
+
+void ALSADevice::initProxyParams() {
+    if(mProxyParams.mPfdProxy[1].fd == -1) {
+        ALOGV("Allocating A2Dp poll fd");
+        mProxyParams.mPfdProxy[0].fd = mProxyParams.mProxyPcmHandle->fd;
+        mProxyParams.mPfdProxy[0].events = (POLLIN | POLLERR | POLLNVAL);
+        ALOGV("Allocated A2DP poll fd");
+        mProxyParams.mPfdProxy[1].fd = eventfd(0,0);
+        mProxyParams.mPfdProxy[1].events = (POLLIN | POLLERR | POLLNVAL);
+        mProxyParams.mFrames = (mProxyParams.mProxyPcmHandle->flags & PCM_MONO) ?
+            (mProxyParams.mProxyPcmHandle->period_size / 2) :
+            (mProxyParams.mProxyPcmHandle->period_size / 4);
+        mProxyParams.mX.frames = (mProxyParams.mProxyPcmHandle->flags & PCM_MONO) ?
+            (mProxyParams.mProxyPcmHandle->period_size / 2) :
+            (mProxyParams.mProxyPcmHandle->period_size / 4);
+    }
+}
+
+status_t ALSADevice::startProxy() {
+
+    status_t err = NO_ERROR;
+    struct pcm * capture_handle = (struct pcm *)mProxyParams.mProxyPcmHandle;
+    while(1) {
+        if (!capture_handle->start) {
+            if(ioctl(capture_handle->fd, SNDRV_PCM_IOCTL_START)) {
+                err = -errno;
+                if (errno == EPIPE) {
+                   ALOGV("Failed in SNDRV_PCM_IOCTL_START\n");
+                   /* we failed to make our window -- try to restart */
+                   capture_handle->underruns++;
+                   capture_handle->running = 0;
+                   capture_handle->start = 0;
+                   continue;
+                } else {
+                   ALOGE("IGNORE - IOCTL_START failed for proxy err: %d \n", errno);
+                   err = NO_ERROR;
+                   break;
+                }
+           } else {
+               ALOGD(" Proxy Driver started(IOCTL_START Success)\n");
+               break;
+           }
+       }
+       else {
+           ALOGV("Proxy Already started break out of condition");
+           break;
+       }
+   }
+   ALOGV("startProxy - Proxy started");
+   capture_handle->start = 1;
+   capture_handle->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL |
+               SNDRV_PCM_SYNC_PTR_AVAIL_MIN;
+   return err;
+}
+
+status_t ALSADevice::openProxyDevice()
+{
+    struct snd_pcm_hw_params *params = NULL;
+    struct snd_pcm_sw_params *sparams = NULL;
+    int flags = (DEBUG_ON | PCM_MMAP| PCM_STEREO | PCM_IN);
+
+    ALOGV("openProxyDevice");
+    mProxyParams.mProxyPcmHandle = pcm_open(flags, PROXY_CAPTURE_DEVICE_NAME);
+    if (!pcm_ready(mProxyParams.mProxyPcmHandle)) {
+        ALOGE("Opening proxy device failed");
+        goto bail;
+    }
+    ALOGV("Proxy device opened successfully: mProxyPcmHandle %p", mProxyParams.mProxyPcmHandle);
+    mProxyParams.mProxyPcmHandle->channels = AFE_PROXY_CHANNEL_COUNT;
+    mProxyParams.mProxyPcmHandle->rate     = AFE_PROXY_SAMPLE_RATE;
+    mProxyParams.mProxyPcmHandle->flags    = flags;
+    mProxyParams.mProxyPcmHandle->period_size = AFE_PROXY_PERIOD_SIZE;
+
+    params = (struct snd_pcm_hw_params*) calloc(1,sizeof(struct snd_pcm_hw_params));
+    if (!params) {
+         goto bail;
+    }
+
+    param_init(params);
+
+    param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS,
+            (mProxyParams.mProxyPcmHandle->flags & PCM_MMAP)?
+            SNDRV_PCM_ACCESS_MMAP_INTERLEAVED
+            : SNDRV_PCM_ACCESS_RW_INTERLEAVED);
+    param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+            SNDRV_PCM_FORMAT_S16_LE);
+    param_set_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
+            SNDRV_PCM_SUBFORMAT_STD);
+    param_set_min(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+            mProxyParams.mProxyPcmHandle->period_size);
+    param_set_int(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
+    param_set_int(params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
+            mProxyParams.mProxyPcmHandle->channels - 1 ? 32 : 16);
+    param_set_int(params, SNDRV_PCM_HW_PARAM_CHANNELS,
+            mProxyParams.mProxyPcmHandle->channels);
+    param_set_int(params, SNDRV_PCM_HW_PARAM_RATE,
+            mProxyParams.mProxyPcmHandle->rate);
+
+    param_set_hw_refine(mProxyParams.mProxyPcmHandle, params);
+
+    if (param_set_hw_params(mProxyParams.mProxyPcmHandle, params)) {
+        ALOGE("Failed to set hardware params on Proxy device");
+        goto bail;
+    }
+
+    mProxyParams.mProxyPcmHandle->buffer_size = pcm_buffer_size(params);
+    mProxyParams.mProxyPcmHandle->period_size = pcm_period_size(params);
+    mProxyParams.mProxyPcmHandle->period_cnt  =
+            mProxyParams.mProxyPcmHandle->buffer_size /
+            mProxyParams.mProxyPcmHandle->period_size;
+    ALOGV("Capture - period_size (%d)",\
+            mProxyParams.mProxyPcmHandle->period_size);
+    ALOGV("Capture - buffer_size (%d)",\
+            mProxyParams.mProxyPcmHandle->buffer_size);
+    ALOGV("Capture - period_cnt  (%d)\n",\
+            mProxyParams.mProxyPcmHandle->period_cnt);
+    sparams = (struct snd_pcm_sw_params*) calloc(1,sizeof(struct snd_pcm_sw_params));
+    if (!sparams) {
+        ALOGE("Failed to allocated software params for Proxy device");
+        goto bail;
+    }
+
+   sparams->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
+   sparams->period_step = 1;
+   sparams->avail_min = (mProxyParams.mProxyPcmHandle->flags & PCM_MONO) ?
+           mProxyParams.mProxyPcmHandle->period_size/2
+           : mProxyParams.mProxyPcmHandle->period_size/4;
+   sparams->start_threshold = 1;
+   sparams->stop_threshold = mProxyParams.mProxyPcmHandle->buffer_size;
+   sparams->xfer_align = (mProxyParams.mProxyPcmHandle->flags & PCM_MONO) ?
+           mProxyParams.mProxyPcmHandle->period_size/2
+           : mProxyParams.mProxyPcmHandle->period_size/4; /* needed for old kernels */
+   sparams->silence_size = 0;
+   sparams->silence_threshold = 0;
+
+   if (param_set_sw_params(mProxyParams.mProxyPcmHandle, sparams)) {
+        ALOGE("Failed to set software params on Proxy device");
+        goto bail;
+   }
+   mmap_buffer(mProxyParams.mProxyPcmHandle);
+
+   if (pcm_prepare(mProxyParams.mProxyPcmHandle)) {
+       ALOGE("Failed to pcm_prepare on Proxy device");
+       goto bail;
+   }
+   mProxyParams.mProxyState = proxy_params::EProxySuspended;
+   return NO_ERROR;
+
+bail:
+   if(mProxyParams.mProxyPcmHandle)  {
+       pcm_close(mProxyParams.mProxyPcmHandle);
+       mProxyParams.mProxyPcmHandle = NULL;
+   }
+   mProxyParams.mProxyState = proxy_params::EProxyClosed;
+   return NO_INIT;
+}
+
+status_t ALSADevice::closeProxyDevice() {
+    status_t err = NO_ERROR;
+    if(mProxyParams.mProxyPcmHandle) {
+        pcm_close(mProxyParams.mProxyPcmHandle);
+        mProxyParams.mProxyPcmHandle = NULL;
+    }
+    resetProxyVariables();
+    mProxyParams.mProxyState = proxy_params::EProxyClosed;
+    mProxyParams.mExitRead = false;
+    return err;
+}
+
+bool ALSADevice::isProxyDeviceOpened() {
+
+   //TODO : Add some intelligence to return appropriate value
+   if(mProxyParams.mProxyState == proxy_params::EProxyOpened ||
+           mProxyParams.mProxyState == proxy_params::EProxyCapture ||
+           mProxyParams.mProxyState == proxy_params::EProxySuspended)
+       return true;
+   return false;
+}
+
+bool ALSADevice::isProxyDeviceSuspended() {
+
+   if(mProxyParams.mProxyState == proxy_params::EProxySuspended)
+        return true;
+   return false;
+}
+
+bool ALSADevice::suspendProxy() {
+
+   status_t err = NO_ERROR;
+   if(mProxyParams.mProxyState == proxy_params::EProxyOpened ||
+           mProxyParams.mProxyState == proxy_params::EProxyCapture) {
+       mProxyParams.mProxyState = proxy_params::EProxySuspended;
+   }
+   else {
+       ALOGE("Proxy already suspend or closed, in state = %d",\
+                mProxyParams.mProxyState);
+   }
+   return err;
+}
+
+bool ALSADevice::resumeProxy() {
+
+   status_t err = NO_ERROR;
+   struct pcm *capture_handle= mProxyParams.mProxyPcmHandle;
+   ALOGD("resumeProxy mProxyParams.mProxyState = %d, capture_handle =%p",\
+           mProxyParams.mProxyState, capture_handle);
+   if((mProxyParams.mProxyState == proxy_params::EProxyOpened ||
+           mProxyParams.mProxyState == proxy_params::EProxySuspended) &&
+           capture_handle != NULL) {
+       ALOGV("pcm_prepare from Resume");
+       capture_handle->start = 0;
+       err = pcm_prepare(capture_handle);
+       if(err != OK) {
+           ALOGE("IGNORE: PCM Prepare - capture failed err = %d", err);
+       }
+       err = startProxy();
+       if(err) {
+           ALOGE("IGNORE:startProxy returned error = %d", err);
+       }
+       mProxyParams.mProxyState = proxy_params::EProxyCapture;
+       err = sync_ptr(capture_handle);
+       if (err) {
+           ALOGE("IGNORE: sync ptr from resumeProxy returned error = %d", err);
+       }
+       ALOGV("appl_ptr= %d", (int)capture_handle->sync_ptr->c.control.appl_ptr);
+   }
+   else {
+        ALOGV("resume Proxy ignored in invalid state - ignore");
+        if(mProxyParams.mProxyState == proxy_params::EProxyClosed ||
+                capture_handle == NULL) {
+            ALOGE("resumeProxy = BAD_VALUE");
+            err = BAD_VALUE;
+            return err;
+        }
+   }
+   return NO_ERROR;
+}
+
+#ifdef SEPERATED_AUDIO_INPUT
+void s_setInput(int input)
+{
+    mInput_source = input;
+    ALOGD("s_setInput() : input_source = %d",input_source);
+}
+#endif
+
+#ifdef QCOM_CSDCLIENT_ENABLED
+void  ALSADevice::setCsdHandle(void* handle)
+{
+    mcsd_handle = static_cast<void*>(handle);
+    ALOGI("%s csd_handle: %p", __func__, mcsd_handle);
+
+    csd_disable_device = (int (*)())::dlsym(mcsd_handle,"csd_client_disable_device");
+    csd_enable_device = (int (*)(int,int,uint32_t))::dlsym(mcsd_handle,"csd_client_enable_device");
+    csd_start_voice = (int (*)())::dlsym(mcsd_handle,"csd_client_start_voice");
+    csd_stop_voice = (int (*)())::dlsym(mcsd_handle,"csd_client_stop_voice");
+    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");
+    csd_client_volume = (int (*)(int))::dlsym(mcsd_handle,"csd_client_volume");
+    csd_client_mic_mute = (int (*)(int))::dlsym(mcsd_handle,"csd_client_mic_mute");
+}
+#endif
+
+}
diff --git a/alsa_sound/ALSAMixer.cpp b/alsa_sound/ALSAMixer.cpp
index d1383cf..0875a57 100644
--- a/alsa_sound/ALSAMixer.cpp
+++ b/alsa_sound/ALSAMixer.cpp
@@ -1,6 +1,7 @@
 /* ALSAMixer.cpp
  **
  ** Copyright 2008-2010 Wind River Systems
+ ** Copyright (c) 2012, 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.
diff --git a/alsa_sound/ALSAStreamOps.cpp b/alsa_sound/ALSAStreamOps.cpp
index 4e534fd..a8c5bad 100644
--- a/alsa_sound/ALSAStreamOps.cpp
+++ b/alsa_sound/ALSAStreamOps.cpp
@@ -1,7 +1,7 @@
 /* ALSAStreamOps.cpp
  **
  ** Copyright 2008-2009 Wind River Systems
- ** Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ ** Copyright (c) 2012, 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.
@@ -65,6 +65,7 @@
             }
        }
        mParent->mVoipStreamCount = 0;
+       mParent->mVoipMicMute = 0;
        mParent->mVoipBitRate = 0;
     }
     close();
@@ -110,15 +111,15 @@
                     break;
                     // Do not fall through
                 case 4:
-                    *channels |= AudioSystem::CHANNEL_OUT_BACK_LEFT;
-                    *channels |= AudioSystem::CHANNEL_OUT_BACK_RIGHT;
+                    *channels |= AUDIO_CHANNEL_OUT_BACK_LEFT;
+                    *channels |= AUDIO_CHANNEL_OUT_BACK_RIGHT;
                     // Fall through...
                 default:
                 case 2:
-                    *channels |= AudioSystem::CHANNEL_OUT_FRONT_RIGHT;
+                    *channels |= AUDIO_CHANNEL_OUT_FRONT_RIGHT;
                     // Fall through...
                 case 1:
-                    *channels |= AudioSystem::CHANNEL_OUT_FRONT_LEFT;
+                    *channels |= AUDIO_CHANNEL_OUT_FRONT_LEFT;
                     break;
             }
         } else {
@@ -126,16 +127,16 @@
 #ifdef QCOM_SSR_ENABLED
                 // For 5.1 recording
                 case 6 :
-                    *channels |= AudioSystem::CHANNEL_IN_5POINT1;
+                    *channels |= AUDIO_CHANNEL_IN_5POINT1;
                     break;
 #endif
                     // Do not fall through...
                 default:
                 case 2:
-                    *channels |= AudioSystem::CHANNEL_IN_RIGHT;
+                    *channels |= AUDIO_CHANNEL_IN_RIGHT;
                     // Fall through...
                 case 1:
-                    *channels |= AudioSystem::CHANNEL_IN_LEFT;
+                    *channels |= AUDIO_CHANNEL_IN_LEFT;
                     break;
             }
         }
@@ -152,23 +153,23 @@
 
     if (format) {
         switch(*format) {
-            case AudioSystem::FORMAT_DEFAULT:
+            case AUDIO_FORMAT_DEFAULT:
                 break;
 
-            case AudioSystem::PCM_16_BIT:
+            case AUDIO_FORMAT_PCM_16_BIT:
                 iformat = SNDRV_PCM_FORMAT_S16_LE;
                 break;
-            case AudioSystem::AMR_NB:
-            case AudioSystem::AMR_WB:
-#ifdef QCOM_QCHAT_ENABLED
-            case AudioSystem::EVRC:
-            case AudioSystem::EVRCB:
-            case AudioSystem::EVRCWB:
+            case AUDIO_FORMAT_AMR_NB:
+            case AUDIO_FORMAT_AMR_WB:
+#ifdef QCOM_AUDIO_FORMAT_ENABLED
+            case AUDIO_FORMAT_EVRC:
+            case AUDIO_FORMAT_EVRCB:
+            case AUDIO_FORMAT_EVRCWB:
 #endif
                 iformat = *format;
                 break;
 
-            case AudioSystem::PCM_8_BIT:
+            case AUDIO_FORMAT_PCM_8_BIT:
                 iformat = SNDRV_PCM_FORMAT_S8;
                 break;
 
@@ -182,10 +183,10 @@
 
         switch(iformat) {
             case SNDRV_PCM_FORMAT_S16_LE:
-                *format = AudioSystem::PCM_16_BIT;
+                *format = AUDIO_FORMAT_PCM_16_BIT;
                 break;
             case SNDRV_PCM_FORMAT_S8:
-                *format = AudioSystem::PCM_8_BIT;
+                *format = AUDIO_FORMAT_PCM_8_BIT;
                 break;
             default:
                 break;
@@ -198,8 +199,9 @@
 status_t ALSAStreamOps::setParameters(const String8& keyValuePairs)
 {
     AudioParameter param = AudioParameter(keyValuePairs);
-    String8 key = String8(AudioParameter::keyRouting);
+    String8 key = String8(AudioParameter::keyRouting),value;
     int device;
+    status_t err = NO_ERROR;
 
 #ifdef SEPERATED_AUDIO_INPUT
     String8 key_input = String8(AudioParameter::keyInputSource);
@@ -219,13 +221,21 @@
         if ((device == 0) && (mDevices == AudioSystem::DEVICE_OUT_AUX_DIGITAL)) {
             device = AudioSystem::DEVICE_OUT_SPEAKER;
         }
-        if (device)
-            mDevices = device;
-        else
-            ALOGV("must not change mDevices to 0");
-
         if(device) {
-            mParent->doRouting(device);
+            ALOGD("setParameters(): keyRouting with device %#x", device);
+            if(device & AudioSystem::DEVICE_OUT_ALL_A2DP) {
+                mParent->mRouteAudioToA2dp = true;
+                ALOGD("setParameters(): A2DP device %#x", device);
+            }
+            err = mParent->doRouting(device);
+            if(err) {
+                ALOGE("doRouting failed = %d",err);
+            }
+            else {
+                mDevices = device;
+            }
+        } else {
+            ALOGE("must not change mDevices to 0");
         }
         param.remove(key);
     }
@@ -233,9 +243,9 @@
     else {
         key = String8(AudioParameter::keyHandleFm);
         if (param.getInt(key, device) == NO_ERROR) {
-        ALOGD("setParameters(): handleFm with device %d", device);
-        mDevices = device;
+            ALOGD("setParameters(): handleFm with device %d", device);
             if(device) {
+                mDevices = device;
                 mParent->handleFm(device);
             }
             param.remove(key);
@@ -243,7 +253,7 @@
     }
 #endif
 
-    return NO_ERROR;
+    return err;
 }
 
 String8 ALSAStreamOps::getParameters(const String8& keys)
@@ -257,7 +267,7 @@
     }
     else {
 #ifdef QCOM_VOIP_ENABLED
-        key = String8(AudioParameter::keyVoipCheck);
+        key = String8(VOIPCHECK_KEY);
         if (param.get(key, value) == NO_ERROR) {
             if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) ||
                (!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP))))
@@ -324,25 +334,25 @@
 
     switch(ALSAFormat) {
         case SNDRV_PCM_FORMAT_S8:
-             audioSystemFormat = AudioSystem::PCM_8_BIT;
+             audioSystemFormat = AUDIO_FORMAT_PCM_8_BIT;
              break;
 
-        case AudioSystem::AMR_NB:
-        case AudioSystem::AMR_WB:
-#ifdef QCOM_QCHAT_ENABLED
-        case AudioSystem::EVRC:
-        case AudioSystem::EVRCB:
-        case AudioSystem::EVRCWB:
+        case AUDIO_FORMAT_AMR_NB:
+        case AUDIO_FORMAT_AMR_WB:
+#ifdef QCOM_AUDIO_FORMAT_ENABLED
+        case AUDIO_FORMAT_EVRC:
+        case AUDIO_FORMAT_EVRCB:
+        case AUDIO_FORMAT_EVRCWB:
 #endif
             audioSystemFormat = mHandle->format;
             break;
         case SNDRV_PCM_FORMAT_S16_LE:
-            audioSystemFormat = AudioSystem::PCM_16_BIT;
+            audioSystemFormat = AUDIO_FORMAT_PCM_16_BIT;
             break;
 
         default:
             LOG_FATAL("Unknown AudioSystem bit width %d!", audioSystemFormat);
-            audioSystemFormat = AudioSystem::PCM_16_BIT;
+            audioSystemFormat = AUDIO_FORMAT_PCM_16_BIT;
             break;
     }
 
@@ -363,15 +373,15 @@
                 break;
                 // Do not fall through
             case 4:
-                channels |= AudioSystem::CHANNEL_OUT_BACK_LEFT;
-                channels |= AudioSystem::CHANNEL_OUT_BACK_RIGHT;
+                channels |= AUDIO_CHANNEL_OUT_BACK_LEFT;
+                channels |= AUDIO_CHANNEL_OUT_BACK_RIGHT;
                 // Fall through...
             default:
             case 2:
-                channels |= AudioSystem::CHANNEL_OUT_FRONT_RIGHT;
+                channels |= AUDIO_CHANNEL_OUT_FRONT_RIGHT;
                 // Fall through...
             case 1:
-                channels |= AudioSystem::CHANNEL_OUT_FRONT_LEFT;
+                channels |= AUDIO_CHANNEL_OUT_FRONT_LEFT;
                 break;
         }
     else
@@ -379,16 +389,16 @@
 #ifdef QCOM_SSR_ENABLED
             // For 5.1 recording
             case 6 :
-                channels |= AudioSystem::CHANNEL_IN_5POINT1;
+                channels |= AUDIO_CHANNEL_IN_5POINT1;
                 break;
                 // Do not fall through...
 #endif
             default:
             case 2:
-                channels |= AudioSystem::CHANNEL_IN_RIGHT;
+                channels |= AUDIO_CHANNEL_IN_RIGHT;
                 // Fall through...
             case 1:
-                channels |= AudioSystem::CHANNEL_IN_LEFT;
+                channels |= AUDIO_CHANNEL_IN_LEFT;
                 break;
         }
 
@@ -400,6 +410,7 @@
     ALOGD("close");
     if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) ||
        (!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
+       mParent->mVoipMicMute = false;
        mParent->mVoipBitRate = 0;
        mParent->mVoipStreamCount = 0;
     }
diff --git a/alsa_sound/Android.mk b/alsa_sound/Android.mk
index 738b969..9139af9 100644
--- a/alsa_sound/Android.mk
+++ b/alsa_sound/Android.mk
@@ -11,25 +11,53 @@
 
 LOCAL_ARM_MODE := arm
 LOCAL_CFLAGS := -D_POSIX_SOURCE
-LOCAL_CFLAGS += -DQCOM_CSDCLIENT_ENABLED
 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_FM_TX_ENABLED
+#LOCAL_CFLAGS += -DQCOM_OUTPUT_FLAGS_ENABLED
+LOCAL_CFLAGS += -DQCOM_PROXY_DEVICE_ENABLED
+#LOCAL_CFLAGS += -DQCOM_SSR_ENABLED
+LOCAL_CFLAGS += -DQCOM_USBAUDIO_ENABLED
+LOCAL_CFLAGS += -DQCOM_VOIP_ENABLED
 
-ifeq ($(strip $(BOARD_USES_FLUENCE_INCALL)),true)
-LOCAL_CFLAGS += -DUSES_FLUENCE_INCALL
+ifeq ($(call is-board-platform,msm8974),true)
+  LOCAL_CFLAGS += -DTARGET_8974
 endif
 
-ifeq ($(strip $(BOARD_USES_SEPERATED_AUDIO_INPUT)),true)
-LOCAL_CFLAGS += -DSEPERATED_AUDIO_INPUT
+ifneq ($(ALSA_DEFAULT_SAMPLE_RATE),)
+    LOCAL_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
+
+#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
+
 LOCAL_SRC_FILES := \
-  AudioHardwareALSA.cpp 	\
-  AudioStreamOutALSA.cpp 	\
-  AudioStreamInALSA.cpp 	\
-  ALSAStreamOps.cpp		\
-  audio_hw_hal.cpp \
-  AudioUsbALSA.cpp \
-  AudioUtil.cpp
+  AudioHardwareALSA.cpp         \
+  AudioStreamOutALSA.cpp        \
+  AudioStreamInALSA.cpp         \
+  ALSAStreamOps.cpp             \
+  audio_hw_hal.cpp              \
+  AudioUsbALSA.cpp              \
+  AudioUtil.cpp                 \
+  AudioSessionOut.cpp           \
+  ALSADevice.cpp
 
 LOCAL_STATIC_LIBRARIES := \
     libmedia_helper \
@@ -59,20 +87,37 @@
 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_MODULE := audio.primary.msm8960
+ifeq ($(call is-board-platform,msm8974),true)
+  LOCAL_MODULE := audio.primary.msm8974
+endif
+
+ifeq ($(call is-board-platform,msm8960),true)
+  LOCAL_MODULE := audio.primary.msm8960
+endif
+
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
 LOCAL_MODULE_TAGS := optional
 
 include $(BUILD_SHARED_LIBRARY)
 
-ifeq (1,0) # use default audio policy manager
-# This is the ALSA audio policy manager
-
 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_FM_TX_ENABLED
+#LOCAL_CFLAGS += -DQCOM_OUTPUT_FLAGS_ENABLED
+LOCAL_CFLAGS += -DQCOM_PROXY_DEVICE_ENABLED
+#LOCAL_CFLAGS += -DQCOM_SSR_ENABLED
+LOCAL_CFLAGS += -DQCOM_USBAUDIO_ENABLED
+LOCAL_CFLAGS += -DQCOM_VOIP_ENABLED
+
 
 ifeq ($(BOARD_HAVE_BLUETOOTH),true)
   LOCAL_CFLAGS += -DWITH_A2DP
@@ -82,7 +127,15 @@
     audio_policy_hal.cpp \
     AudioPolicyManagerALSA.cpp
 
-LOCAL_MODULE := audio_policy.msm8960
+
+ifeq ($(call is-board-platform,msm8974),true)
+  LOCAL_MODULE := audio_policy.msm8974
+endif
+
+ifeq ($(call is-board-platform,msm8960),true)
+  LOCAL_MODULE := audio_policy.msm8960
+endif
+
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
 LOCAL_MODULE_TAGS := optional
 
@@ -99,51 +152,5 @@
 LOCAL_C_INCLUDES += hardware/libhardware_legacy/audio
 
 include $(BUILD_SHARED_LIBRARY)
-endif
 
-# This is the ALSA module which behaves closely like the original
-
-include $(CLEAR_VARS)
-
-LOCAL_PRELINK_MODULE := false
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
-
-LOCAL_CFLAGS := -D_POSIX_SOURCE -Wno-multichar
-LOCAL_CFLAGS += -DQCOM_ACDB_ENABLED
-
-ifeq ($(strip $(BOARD_USES_FLUENCE_INCALL)),true)
-LOCAL_CFLAGS += -DUSES_FLUENCE_INCALL
-endif
-
-ifeq ($(strip $(BOARD_USES_SEPERATED_AUDIO_INPUT)),true)
-LOCAL_CFLAGS += -DSEPERATED_AUDIO_INPUT
-endif
-
-ifneq ($(ALSA_DEFAULT_SAMPLE_RATE),)
-    LOCAL_CFLAGS += -DALSA_DEFAULT_SAMPLE_RATE=$(ALSA_DEFAULT_SAMPLE_RATE)
-endif
-
-LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/libalsa-intf
-
-LOCAL_SRC_FILES:= \
-    alsa_default.cpp \
-    ALSAControl.cpp \
-    AudioUtil.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    liblog    \
-    libalsa-intf
-
-ifeq ($(TARGET_SIMULATOR),true)
- LOCAL_LDLIBS += -ldl
-else
- LOCAL_SHARED_LIBRARIES += libdl
-endif
-
-LOCAL_MODULE:= alsa.msm8960
-LOCAL_MODULE_TAGS := optional
-
-  include $(BUILD_SHARED_LIBRARY)
 endif
diff --git a/alsa_sound/AudioHardwareALSA.cpp b/alsa_sound/AudioHardwareALSA.cpp
index a53f161..6cf142f 100644
--- a/alsa_sound/AudioHardwareALSA.cpp
+++ b/alsa_sound/AudioHardwareALSA.cpp
@@ -1,7 +1,7 @@
 /* AudioHardwareALSA.cpp
  **
  ** Copyright 2008-2010 Wind River Systems
- ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ ** Copyright (c) 2012, 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.
@@ -26,7 +26,7 @@
 #include <math.h>
 
 #define LOG_TAG "AudioHardwareALSA"
-//#define LOG_NDEBUG 0
+#define LOG_NDEBUG 0
 #define LOG_NDDEBUG 0
 #include <utils/Log.h>
 #include <utils/String8.h>
@@ -37,6 +37,7 @@
 #include <cutils/properties.h>
 #include <media/AudioRecord.h>
 #include <hardware_legacy/power.h>
+#include <pthread.h>
 
 #include "AudioHardwareALSA.h"
 #ifdef QCOM_USBAUDIO_ENABLED
@@ -44,6 +45,13 @@
 #endif
 #include "AudioUtil.h"
 
+//#define OUTPUT_BUFFER_LOG
+#ifdef OUTPUT_BUFFER_LOG
+    FILE *outputBufferFile1;
+    char outputfilename [50] = "/data/output_proxy";
+    static int number = 0;
+#endif
+
 extern "C"
 {
     //
@@ -72,39 +80,35 @@
 }
 
 AudioHardwareALSA::AudioHardwareALSA() :
-    mALSADevice(0),mVoipStreamCount(0),mVoipBitRate(0)
+    mALSADevice(0),mVoipStreamCount(0),mVoipMicMute(false),mVoipBitRate(0)
     ,mCallState(0),mAcdbHandle(NULL),mCsdHandle(NULL),mMicMute(0)
 {
     FILE *fp;
     char soundCardInfo[200];
-    hw_module_t *module;
-    char platform[128], baseband[128];
-    int err = hw_get_module(ALSA_HARDWARE_MODULE_ID,
-            (hw_module_t const**)&module);
-    int codec_rev = 2;
-    ALOGD("hw_get_module(ALSA_HARDWARE_MODULE_ID) returned err %d", err);
-    if (err == 0) {
-        hw_device_t* device;
-        err = module->methods->open(module, ALSA_HARDWARE_NAME, &device);
-        if (err == 0) {
-            mALSADevice = (alsa_device_t *)device;
-            mALSADevice->init(mALSADevice, mDeviceList);
-            mCSCallActive = 0;
-            mVolteCallActive = 0;
-            mIsFmActive = 0;
-            mDevSettingsFlag = 0;
+    char platform[128], baseband[128], audio_init[128], platformVer[128];
+    int codec_rev = 2, verNum = 0;
+    mALSADevice = new ALSADevice();
+    mDeviceList.clear();
+    mCSCallActive = 0;
+    mVolteCallActive = 0;
+    mSGLTECallActive = 0;
+    mIsFmActive = 0;
+    mDevSettingsFlag = 0;
+    bool audio_init_done = false;
+    int sleep_retry = 0;
 #ifdef QCOM_USBAUDIO_ENABLED
-            mAudioUsbALSA = new AudioUsbALSA();
-            musbPlaybackState = 0;
-            musbRecordingState = 0;
+    mAudioUsbALSA = new AudioUsbALSA();
+    musbPlaybackState = 0;
+    musbRecordingState = 0;
 #endif
 #ifdef USES_FLUENCE_INCALL
-            mDevSettingsFlag |= TTY_OFF | DMIC_FLAG;
+    mDevSettingsFlag |= TTY_OFF | DMIC_FLAG;
 #else
-            mDevSettingsFlag |= TTY_OFF;
+    mDevSettingsFlag |= TTY_OFF;
 #endif
-            mBluetoothVGS = false;
-            mFusion3Platform = false;
+    mBluetoothVGS = false;
+    mFusion3Platform = false;
+    mIsVoicePathActive = false;
 
 #ifdef QCOM_ACDB_ENABLED
             mAcdbHandle = ::dlopen("/system/lib/libacdbloader.so", RTLD_NOW);
@@ -133,61 +137,141 @@
              }
              mALSADevice->setCsdHandle(mCsdHandle);
 #endif
-            if((fp = fopen("/proc/asound/cards","r")) == NULL) {
-                ALOGE("Cannot open /proc/asound/cards file to get sound card info");
-            } else {
-                while((fgets(soundCardInfo, sizeof(soundCardInfo), fp) != NULL)) {
-                    ALOGV("SoundCardInfo %s", soundCardInfo);
-                    if (strstr(soundCardInfo, "msm8960-tabla1x-snd-card")) {
-                        codec_rev = 1;
-                        break;
-                    } else if (strstr(soundCardInfo, "msm-snd-card")) {
-                        codec_rev = 2;
-                        break;
-                    } else if (strstr(soundCardInfo, "msm8930-sitar-snd-card")) {
-                        codec_rev = 3;
-                        break;
-                    }
-                }
-                fclose(fp);
-            }
-
-            if (codec_rev == 1) {
-                    ALOGV("Detected tabla 1.x sound card");
-                    snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm");
-            } else if (codec_rev == 3) {
-                    ALOGV("Detected sitar 1.x sound card");
-                    snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Sitar");
-            } else {
-                    property_get("ro.board.platform", platform, "");
-                    property_get("ro.baseband", baseband, "");
-                    if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband)) {
-                        ALOGV("Detected Fusion tabla 2.x");
-                        mFusion3Platform = true;
-                        snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x_Fusion3");
-                    } else {
-                        ALOGV("Detected tabla 2.x sound card");
-                        snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x");
-                    }
-            }
-
-            if (mUcMgr < 0) {
-                ALOGE("Failed to open ucm instance: %d", errno);
-            } else {
-                ALOGI("ucm instance opened: %u", (unsigned)mUcMgr);
-                mUcMgr->acdb_handle = NULL;
-#ifdef QCOM_ACDB_ENABLED
-                if (mAcdbHandle) {
-                    mUcMgr->acdb_handle = static_cast<void*> (mAcdbHandle);
-                }
-#endif
-            }
-        } else {
-            ALOGE("ALSA Module could not be opened!!!");
-        }
+    if((fp = fopen("/proc/asound/cards","r")) == NULL) {
+        ALOGE("Cannot open /proc/asound/cards file to get sound card info");
     } else {
-        ALOGE("ALSA Module not found!!!");
+        while((fgets(soundCardInfo, sizeof(soundCardInfo), fp) != NULL)) {
+            ALOGV("SoundCardInfo %s", soundCardInfo);
+            if (strstr(soundCardInfo, "msm8960-tabla1x-snd-card")) {
+                codec_rev = 1;
+                break;
+            } else if (strstr(soundCardInfo, "msm-snd-card")) {
+                codec_rev = 2;
+                break;
+            } else if (strstr(soundCardInfo, "msm8930-sitar-snd-card")) {
+                codec_rev = 3;
+                break;
+            } else if (strstr(soundCardInfo, "msm8974-taiko-mtp-snd-card")) {
+                codec_rev = 40;
+                break;
+            } else if (strstr(soundCardInfo, "msm8974-taiko-cdp-snd-card")) {
+                codec_rev = 41;
+                break;
+            } else if (strstr(soundCardInfo, "msm8974-taiko-fluid-snd-card")) {
+                codec_rev = 42;
+                break;
+            } else if (strstr(soundCardInfo, "msm8974-taiko-liquid-snd-card")) {
+                codec_rev = 43;
+                break;
+            }
+        }
+        fclose(fp);
     }
+
+    while (audio_init_done == false && sleep_retry < MAX_SLEEP_RETRY) {
+        property_get("qcom.audio.init", audio_init, NULL);
+        ALOGD("qcom.audio.init is set to %s\n",audio_init);
+        if(!strncmp(audio_init, "complete", sizeof("complete"))) {
+            audio_init_done = true;
+        } else {
+            ALOGD("Sleeping for 50 ms");
+            usleep(AUDIO_INIT_SLEEP_WAIT*1000);
+            sleep_retry++;
+        }
+    }
+
+    if (codec_rev == 1) {
+        ALOGV("Detected tabla 1.x sound card");
+        snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm");
+    } else if (codec_rev == 3) {
+        ALOGV("Detected sitar 1.x sound card");
+        snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Sitar");
+    } else if (codec_rev == 40) {
+        ALOGV("Detected taiko sound card");
+        snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Taiko");
+    } else if (codec_rev == 41) {
+        ALOGV("Detected taiko sound card");
+        snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Taiko_CDP");
+    } else if (codec_rev == 42) {
+        ALOGV("Detected taiko sound card");
+        snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Taiko_Fluid");
+    } else if (codec_rev == 43) {
+        ALOGV("Detected taiko liquid sound card");
+        snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Taiko_liquid");
+    } else {
+        property_get("ro.board.platform", platform, "");
+        property_get("ro.baseband", baseband, "");
+        if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband)) {
+            ALOGV("Detected Fusion tabla 2.x");
+            mFusion3Platform = true;
+            if((fp = fopen("/sys/devices/system/soc/soc0/platform_version","r")) == NULL) {
+                ALOGE("Cannot open /sys/devices/system/soc/soc0/platform_version file");
+
+                snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x_Fusion3");
+            } else {
+                while((fgets(platformVer, sizeof(platformVer), fp) != NULL)) {
+                    ALOGV("platformVer %s", platformVer);
+
+                    verNum = atoi(platformVer);
+                    if (verNum == 0x10001) {
+                        snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_I2SFusion");
+                        break;
+                    } else {
+                        snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x_Fusion3");
+                        break;
+                    }
+                }
+            }
+            fclose(fp);
+        } else {
+            ALOGV("Detected tabla 2.x sound card");
+            snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x");
+        }
+    }
+
+    if (mUcMgr < 0) {
+        ALOGE("Failed to open ucm instance: %d", errno);
+    } else {
+        ALOGI("ucm instance opened: %u", (unsigned)mUcMgr);
+    }
+
+    //set default AudioParameters
+    AudioParameter param;
+    String8 key;
+    String8 value;
+
+    //Set default AudioParameter for fluencetype
+    key  = String8(FLUENCE_KEY);
+    char fluence_key[20] = "none";
+    property_get("ro.qc.sdk.audio.fluencetype",fluence_key,"0");
+    if (0 == strncmp("fluencepro", fluence_key, sizeof("fluencepro"))) {
+        mDevSettingsFlag |= QMIC_FLAG;
+        mDevSettingsFlag &= (~DMIC_FLAG);
+        value = String8("fluencepro");
+        ALOGD("FluencePro quadMic feature Enabled");
+    } else if (0 == strncmp("fluence", fluence_key, sizeof("fluence"))) {
+        mDevSettingsFlag |= DMIC_FLAG;
+        mDevSettingsFlag &= (~QMIC_FLAG);
+        value = String8("fluence");
+        ALOGD("Fluence dualmic feature Enabled");
+    } else if (0 == strncmp("none", fluence_key, sizeof("none"))) {
+        mDevSettingsFlag &= (~DMIC_FLAG);
+        mDevSettingsFlag &= (~QMIC_FLAG);
+        value = String8("none");
+        ALOGD("Fluence feature Disabled");
+    }
+    param.add(key, value);
+    mALSADevice->setFlags(mDevSettingsFlag);
+
+    //mALSADevice->setDeviceList(&mDeviceList);
+    mRouteAudioToA2dp = false;
+    mA2dpDevice = NULL;
+    mA2dpStream = NULL;
+    mA2DPActiveUseCases = USECASE_NONE;
+    mIsA2DPEnabled = false;
+    mKillA2DPThread = false;
+    mA2dpThreadAlive = false;
+    mA2dpThread = NULL;
 }
 
 AudioHardwareALSA::~AudioHardwareALSA()
@@ -197,7 +281,7 @@
         snd_use_case_mgr_close(mUcMgr);
     }
     if (mALSADevice) {
-        mALSADevice->common.close(&mALSADevice->common);
+        delete mALSADevice;
     }
     for(ALSAHandleList::iterator it = mDeviceList.begin();
             it != mDeviceList.end(); ++it) {
@@ -256,11 +340,13 @@
     vol = 100 - vol;
 
     if (mALSADevice) {
-        if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
+        if(newMode == AUDIO_MODE_IN_COMMUNICATION) {
             mALSADevice->setVoipVolume(vol);
-        } else if (newMode == AudioSystem::MODE_IN_CALL){
+        } else if (newMode == AUDIO_MODE_IN_CALL){
                if (mCSCallActive == CS_ACTIVE)
                    mALSADevice->setVoiceVolume(vol);
+               else if (mSGLTECallActive == CS_ACTIVE_SESSION2)
+                   mALSADevice->setSGLTEVolume(vol);
                if (mVolteCallActive == IMS_ACTIVE)
                    mALSADevice->setVoLTEVolume(vol);
         }
@@ -272,6 +358,7 @@
 #ifdef QCOM_FM_ENABLED
 status_t  AudioHardwareALSA::setFmVolume(float value)
 {
+    Mutex::Autolock autoLock(mLock);
     status_t status = NO_ERROR;
 
     int vol;
@@ -306,10 +393,10 @@
     if (mode != mMode) {
         status = AudioHardwareBase::setMode(mode);
     }
-
-    if (mode == AudioSystem::MODE_IN_CALL) {
-        mCallState = CS_ACTIVE;
-    }else if (mode == AudioSystem::MODE_NORMAL) {
+    if (mode == AUDIO_MODE_IN_CALL) {
+        if (mCallState == CS_INACTIVE)
+            mCallState = CS_ACTIVE;
+    }else if (mode == AUDIO_MODE_NORMAL) {
         mCallState = 0;
     }
 
@@ -330,18 +417,18 @@
     key = String8(TTY_MODE_KEY);
     if (param.get(key, value) == NO_ERROR) {
         mDevSettingsFlag &= TTY_CLEAR;
-        if (value == "tty_full") {
+        if (value == "full") {
             mDevSettingsFlag |= TTY_FULL;
-        } else if (value == "tty_hco") {
+        } else if (value == "hco") {
             mDevSettingsFlag |= TTY_HCO;
-        } else if (value == "tty_vco") {
+        } else if (value == "vco") {
             mDevSettingsFlag |= TTY_VCO;
         } else {
             mDevSettingsFlag |= TTY_OFF;
         }
         ALOGI("Changed TTY Mode=%s", value.string());
         mALSADevice->setFlags(mDevSettingsFlag);
-        if(mMode != AudioSystem::MODE_IN_CALL){
+        if(mMode != AUDIO_MODE_IN_CALL){
            return NO_ERROR;
         }
         doRouting(0);
@@ -438,6 +525,43 @@
         param.remove(key);
     }
 
+    key = String8("a2dp_connected");
+    if (param.get(key, value) == NO_ERROR) {
+        if (value == "true") {
+            status_t err = openA2dpOutput();
+            if(err) {
+                ALOGE("openA2DPOutput failed = %d",err);
+                return err;
+            }
+        } else {
+            uint32_t activeUsecase = getA2DPActiveUseCases_l();
+            stopA2dpPlayback(activeUsecase);
+            status_t err = closeA2dpOutput();
+            if(err) {
+                ALOGE("closeA2dpOutput = %d" ,err);
+            }
+        }
+        param.remove(key);
+    }
+
+    key = String8("A2dpSuspended");
+    if (param.get(key, value) == NO_ERROR) {
+        if (value == "true") {
+             if (mA2dpDevice != NULL) {
+                 mA2dpDevice->set_parameters(mA2dpDevice,keyValuePairs);
+             }
+        }
+        param.remove(key);
+    }
+
+    key = String8("a2dp_sink_address");
+    if (param.get(key, value) == NO_ERROR) {
+        if (mA2dpStream != NULL) {
+            mA2dpStream->common.set_parameters(&mA2dpStream->common,keyValuePairs);
+        }
+        param.remove(key);
+    }
+
     key = String8(VOIPRATE_KEY);
     if (param.get(key, value) == NO_ERROR) {
             mVoipBitRate = atoi(value);
@@ -496,6 +620,7 @@
 {
     AudioParameter param = AudioParameter(keys);
     String8 value;
+    int device;
 
     String8 key = String8(DUALMIC_KEY);
     if (param.get(key, value) == NO_ERROR) {
@@ -518,6 +643,12 @@
     }
 
 #ifdef QCOM_FM_ENABLED
+
+    key = String8(AudioParameter::keyHandleA2dpDevice);
+    if ( param.get(key,value) == NO_ERROR ) {
+        param.add(key, String8("true"));
+    }
+
     key = String8("Fm-radio");
     if ( param.get(key,value) == NO_ERROR ) {
         if ( mIsFmActive ) {
@@ -531,6 +662,57 @@
         if(mBluetoothVGS)
            param.addInt(String8("isVGS"), true);
     }
+#ifdef QCOM_SSR_ENABLED
+    key = String8(AudioParameter::keySSR);
+    if (param.get(key, value) == NO_ERROR) {
+        char ssr_enabled[6] = "false";
+        property_get("ro.qc.sdk.audio.ssr",ssr_enabled,"0");
+        if (!strncmp("true", ssr_enabled, 4)) {
+            value = String8("true");
+        }
+        param.add(key, value);
+    }
+#endif
+
+    key = String8("A2dpSuspended");
+    if (param.get(key, value) == NO_ERROR) {
+        if (mA2dpDevice != NULL) {
+            value = mA2dpDevice->get_parameters(mA2dpDevice,key);
+        }
+        param.add(key, value);
+    }
+
+    key = String8("a2dp_sink_address");
+    if (param.get(key, value) == NO_ERROR) {
+        if (mA2dpStream != NULL) {
+            value = mA2dpStream->common.get_parameters(&mA2dpStream->common,key);
+        }
+        param.add(key, value);
+    }
+
+    key = String8(VOICE_PATH_ACTIVE);
+    if (param.get(key, value) == NO_ERROR) {
+        if (mIsVoicePathActive) {
+            value = String8("true");
+        } else {
+            value = String8("false");
+        }
+        param.add(key, value);
+
+        ALOGV("AudioHardwareALSA::getParameters() mIsVoicePathActive %d",
+              mIsVoicePathActive);
+    }
+
+    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);
+    }
 
     ALOGV("AudioHardwareALSA::getParameters() %s", param.toString().string());
     return param.toString();
@@ -583,7 +765,7 @@
 }
 #endif
 
-void AudioHardwareALSA::doRouting(int device)
+status_t AudioHardwareALSA::doRouting(int device)
 {
     Mutex::Autolock autoLock(mLock);
     int newMode = mode();
@@ -592,38 +774,34 @@
     if ((device == AudioSystem::DEVICE_IN_VOICE_CALL)
 #ifdef QCOM_FM_ENABLED
         || (device == AudioSystem::DEVICE_IN_FM_RX)
-        || (device == AudioSystem::DEVICE_OUT_DIRECTOUTPUT)
         || (device == AudioSystem::DEVICE_IN_FM_RX_A2DP)
 #endif
         || (device == AudioSystem::DEVICE_IN_COMMUNICATION)
         ) {
         ALOGV("Ignoring routing for FM/INCALL/VOIP recording");
-        return;
+        return NO_ERROR;
     }
+    ALOGV("device = 0x%x,mCurDevice 0x%x", device, mCurDevice);
     if (device == 0)
         device = mCurDevice;
-    ALOGV("doRouting: device %d newMode %d mCSCallActive %d mVolteCallActive %d"
-         "mIsFmActive %d", device, newMode, mCSCallActive, mVolteCallActive,
-         mIsFmActive);
-
+    ALOGV("doRouting: device %#x newMode %d mCSCallActive %d mVolteCallActive %d"
+          "mSGLTECallActive %d mIsFmActive %d", device, newMode, mCSCallActive,
+          mVolteCallActive, mSGLTECallActive, mIsFmActive);
     isRouted = routeVoLTECall(device, newMode);
     isRouted |= routeVoiceCall(device, newMode);
+    isRouted |= routeSGLTECall(device, newMode);
 
     if(!isRouted) {
 #ifdef QCOM_USBAUDIO_ENABLED
         if(!(device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) &&
             !(device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) &&
             !(device & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) &&
-             (musbPlaybackState)){
+             (musbPlaybackState || musbRecordingState)){
                 //USB unplugged
-                device &= ~ AudioSystem::DEVICE_OUT_PROXY;
-                device &= ~ AudioSystem::DEVICE_IN_PROXY;
                 ALSAHandleList::iterator it = mDeviceList.end();
                 it--;
                 mALSADevice->route(&(*it), (uint32_t)device, newMode);
                 ALOGD("USB UNPLUGGED, setting musbPlaybackState to 0");
-                musbPlaybackState = 0;
-                musbRecordingState = 0;
                 closeUSBRecording();
                 closeUSBPlayback();
         } else if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
@@ -631,8 +809,11 @@
                     ALOGD("Routing everything to prox now");
                     ALSAHandleList::iterator it = mDeviceList.end();
                     it--;
-                    mALSADevice->route(&(*it), AudioSystem::DEVICE_OUT_PROXY,
-                                       newMode);
+                    if (device != mCurDevice) {
+                        if(musbPlaybackState)
+                            closeUSBPlayback();
+                    }
+                    mALSADevice->route(&(*it), device, newMode);
                     for(it = mDeviceList.begin(); it != mDeviceList.end(); ++it) {
                          if((!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
                             (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA))) {
@@ -640,6 +821,12 @@
                                  startUsbPlaybackIfNotStarted();
                                  musbPlaybackState |= USBPLAYBACKBIT_LPA;
                                  break;
+                         } else if((!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+                                   (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
+                                    ALOGD("doRouting: Tunnel Player device switch to proxy");
+                                    startUsbPlaybackIfNotStarted();
+                                    musbPlaybackState |= USBPLAYBACKBIT_TUNNEL;
+                                    break;
                          } else if((!strcmp(it->useCase, SND_USE_CASE_VERB_VOICECALL)) ||
                                    (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOICE))) {
                                     ALOGV("doRouting: VOICE device switch to proxy");
@@ -658,41 +845,134 @@
                     }
         } else
 #endif
-        {
+        if (device & AudioSystem::DEVICE_OUT_ALL_A2DP &&
+            mRouteAudioToA2dp == true )  {
+            ALOGV(" A2DP Enabled - Routing everything to proxy now");
+            if (device != mCurDevice) {
+                pauseIfUseCaseTunnelOrLPA();
+            }
+            ALSAHandleList::iterator it = mDeviceList.end();
+            it--;
+            status_t err = NO_ERROR;
+            uint32_t activeUsecase = useCaseStringToEnum(it->useCase);
+            ALOGD("doRouting-startA2dpPlayback_l-A2DPHardwareOutput-enable");
+            if ((activeUsecase == USECASE_HIFI_LOW_POWER) ||
+                (activeUsecase == USECASE_HIFI_TUNNEL)) {
+                if (device != mCurDevice) {
+                    if((mCurDevice & AudioSystem::DEVICE_OUT_ALL_A2DP) &&
+                       (device     & AudioSystem::DEVICE_OUT_ALL_A2DP)) {
+                        activeUsecase = getA2DPActiveUseCases_l();
+                        stopA2dpPlayback_l(activeUsecase);
+                        mRouteAudioToA2dp = true;
+                    }
+                    mALSADevice->route(&(*it),(uint32_t)device, newMode);
+                }
+                err = startA2dpPlayback_l(activeUsecase);
+                if(err) {
+                    ALOGW("startA2dpPlayback_l for hardware output failed err = %d", err);
+                    stopA2dpPlayback_l(activeUsecase);
+                }
+            } else {
+                //WHY NO check for prev device here?
+                if (device != mCurDevice) {
+                    if((mCurDevice & AudioSystem::DEVICE_OUT_ALL_A2DP) &&
+                       (device     & AudioSystem::DEVICE_OUT_ALL_A2DP)) {
+                        activeUsecase = getA2DPActiveUseCases_l();
+                        stopA2dpPlayback_l(activeUsecase);
+                        mALSADevice->route(&(*it),(uint32_t)device, newMode);
+                        mRouteAudioToA2dp = true;
+                        startA2dpPlayback_l(activeUsecase);
+                    } else {
+                       mALSADevice->route(&(*it),(uint32_t)device, newMode);
+                    }
+                }
+                if (activeUsecase == USECASE_FM){
+                    err = startA2dpPlayback_l(activeUsecase);
+                    if(err) {
+                        ALOGW("startA2dpPlayback_l for hardware output failed err = %d", err);
+                        stopA2dpPlayback_l(activeUsecase);
+                    }
+                }
+            }
+            if (device != mCurDevice) {
+                resumeIfUseCaseTunnelOrLPA();
+            }
+            if(err) {
+                mRouteAudioToA2dp = false;
+                mALSADevice->route(&(*it),(uint32_t)mCurDevice, newMode);
+                return err;
+            }
+        } else if(device & AudioSystem::DEVICE_OUT_ALL &&
+                  !(device & AudioSystem::DEVICE_OUT_ALL_A2DP) &&
+                  mRouteAudioToA2dp == true ) {
+            ALOGV(" A2DP Disable on hardware output");
+            ALSAHandleList::iterator it = mDeviceList.end();
+            it--;
+            status_t err;
+            uint32_t activeUsecase = getA2DPActiveUseCases_l();
+            err = stopA2dpPlayback_l(activeUsecase);
+            if(err) {
+                ALOGW("stop A2dp playback for hardware output failed = %d", err);
+                return err;
+            }
+            if (device != mCurDevice) {
+                mALSADevice->route(&(*it),(uint32_t)device, newMode);
+            }
+        } else {
+             setInChannels(device);
              ALSAHandleList::iterator it = mDeviceList.end();
              it--;
              mALSADevice->route(&(*it), (uint32_t)device, newMode);
         }
     }
     mCurDevice = device;
+    return NO_ERROR;
+}
+
+void AudioHardwareALSA::setInChannels(int device)
+{
+     ALSAHandleList::iterator it;
+
+     if (device & AudioSystem::DEVICE_IN_BUILTIN_MIC) {
+         for(it = mDeviceList.begin(); it != mDeviceList.end(); ++it) {
+             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))) {
+                 mALSADevice->setInChannels(it->channels);
+                 return;
+             }
+         }
+     }
+
+     mALSADevice->setInChannels(1);
 }
 
 uint32_t AudioHardwareALSA::getVoipMode(int format)
 {
     switch(format) {
-    case AudioSystem::PCM_16_BIT:
+    case AUDIO_FORMAT_PCM_16_BIT:
                return MODE_PCM;
          break;
-    case AudioSystem::AMR_NB:
+    case AUDIO_FORMAT_AMR_NB:
                return MODE_AMR;
          break;
-    case AudioSystem::AMR_WB:
+    case AUDIO_FORMAT_AMR_WB:
                return MODE_AMR_WB;
          break;
 
-#ifdef QCOM_QCHAT_ENABLED
-    case AudioSystem::EVRC:
+#ifdef QCOM_AUDIO_FORMAT_ENABLED
+    case AUDIO_FORMAT_EVRC:
                return MODE_IS127;
          break;
 
-    case AudioSystem::EVRCB:
+    case AUDIO_FORMAT_EVRCB:
                return MODE_4GV_NB;
          break;
-    case AudioSystem::EVRCWB:
+    case AUDIO_FORMAT_EVRCWB:
                return MODE_4GV_WB;
          break;
 #endif
-
     default:
                return MODE_PCM;
     }
@@ -700,6 +980,9 @@
 
 AudioStreamOut *
 AudioHardwareALSA::openOutputStream(uint32_t devices,
+#ifdef QCOM_OUTPUT_FLAGS_ENABLED
+                                    audio_output_flags_t flags,
+#endif
                                     int *format,
                                     uint32_t *channels,
                                     uint32_t *sampleRate,
@@ -712,7 +995,30 @@
     audio_output_flags_t flag = static_cast<audio_output_flags_t> (*status);
 
     status_t err = BAD_VALUE;
-    *status = NO_ERROR;
+#ifdef QCOM_OUTPUT_FLAGS_ENABLED
+    if (flags & AUDIO_OUTPUT_FLAG_LPA) {
+        AudioSessionOutALSA *out = new AudioSessionOutALSA(this, devices, *format, *channels,
+                                                           *sampleRate, 0, &err);
+        if(err != NO_ERROR) {
+            delete out;
+            out = NULL;
+        }
+        if (status) *status = err;
+        return out;
+    }
+
+    if (flags & AUDIO_OUTPUT_FLAG_TUNNEL) {
+        AudioSessionOutALSA *out = new AudioSessionOutALSA(this, devices, *format, *channels,
+                                                           *sampleRate, 1, &err);
+        if(err != NO_ERROR) {
+            delete out;
+            out = NULL;
+        }
+        if (status) *status = err;
+        return out;
+    }
+#endif
+
     AudioStreamOutALSA *out = 0;
     ALSAHandleList::iterator it;
 
@@ -722,9 +1028,14 @@
         return out;
     }
 
+    if(devices & AudioSystem::DEVICE_OUT_ALL_A2DP) {
+        ALOGV("Set Capture from proxy true");
+        mRouteAudioToA2dp = true;
 
-# if 0
-    if((devices == AudioSystem::DEVICE_OUT_DIRECTOUTPUT) &&
+    }
+
+#ifdef QCOM_OUTPUT_FLAGS_ENABLED
+    if((flags & AUDIO_OUTPUT_FLAG_DIRECT) && (flags & AUDIO_OUTPUT_FLAG_VOIP_RX)&&
        ((*sampleRate == VOIP_SAMPLING_RATE_8K) || (*sampleRate == VOIP_SAMPLING_RATE_16K))) {
         bool voipstream_active = false;
         for(it = mDeviceList.begin();
@@ -738,6 +1049,7 @@
         }
       if(voipstream_active == false) {
          mVoipStreamCount = 0;
+         mVoipMicMute = false;
          alsa_handle_t alsa_handle;
          unsigned long bufferSize;
          if(*sampleRate == VOIP_SAMPLING_RATE_8K) {
@@ -755,7 +1067,7 @@
           alsa_handle.bufferSize = bufferSize;
           alsa_handle.devices = devices;
           alsa_handle.handle = 0;
-          if(*format == AudioSystem::PCM_16_BIT)
+          if(*format == AUDIO_FORMAT_PCM_16_BIT)
               alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
           else
               alsa_handle.format = *format;
@@ -781,17 +1093,17 @@
              (mCurDevice & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
              (mCurDevice & AudioSystem::DEVICE_OUT_PROXY)){
               ALOGD("Routing to proxy for normal voip call in openOutputStream");
-              mCurDevice |= AudioSystem::DEVICE_OUT_PROXY;
-              alsa_handle.devices = AudioSystem::DEVICE_OUT_PROXY;
-              mALSADevice->route(&(*it), mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
-              ALOGD("enabling VOIP in openoutputstream, musbPlaybackState: %d", musbPlaybackState);
+              mALSADevice->route(&(*it), mCurDevice, AUDIO_MODE_IN_COMMUNICATION);
+#ifdef QCOM_USBAUDIO_ENABLED
+                ALOGD("enabling VOIP in openoutputstream, musbPlaybackState: %d", musbPlaybackState);
               startUsbPlaybackIfNotStarted();
               musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
               ALOGD("Starting recording in openoutputstream, musbRecordingState: %d", musbRecordingState);
               startUsbRecordingIfNotStarted();
               musbRecordingState |= USBRECBIT_VOIPCALL;
-          } else{
-              mALSADevice->route(&(*it), mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
+#endif
+           } else{
+              mALSADevice->route(&(*it), mCurDevice, AUDIO_MODE_IN_COMMUNICATION);
           }
           if(!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
               snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_IP_VOICECALL);
@@ -884,7 +1196,6 @@
         if (status) *status = err;
         return out;
     } else {
-
       alsa_handle_t alsa_handle;
       unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
 
@@ -901,54 +1212,52 @@
       alsa_handle.latency = PLAYBACK_LATENCY;
       alsa_handle.rxHandle = 0;
       alsa_handle.ucMgr = mUcMgr;
-      alsa_handle.isDeepbufferOutput = false;
+      alsa_handle.session = NULL;
+      alsa_handle.isFastOutput = false;
 
       char *use_case;
       snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
 
-      if (flag & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
-      ALOGD("openOutputStream: DeepBuffer Output");
-          alsa_handle.isDeepbufferOutput = true;
-          if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
-               strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI, sizeof(alsa_handle.useCase));
-          } else {
-               strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_MUSIC, sizeof(alsa_handle.useCase));
-          }
-      } else {
-      ALOGD("openOutputStream: Lowlatency Output");
+#ifdef QCOM_OUTPUT_FLAGS_ENABLED
+      if (flags & AUDIO_OUTPUT_FLAG_FAST) {
           alsa_handle.bufferSize = PLAYBACK_LOW_LATENCY_BUFFER_SIZE;
-          alsa_handle.latency = PLAYBACK_LOW_LATENCY_MEASURED;
+          alsa_handle.latency = PLAYBACK_LOW_LATENCY;
+          alsa_handle.isFastOutput = true;
           if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
                strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC, sizeof(alsa_handle.useCase));
           } else {
                strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC, sizeof(alsa_handle.useCase));
           }
+      } else
+#endif
+      {
+          if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
+               strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI, sizeof(alsa_handle.useCase));
+          } else {
+               strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_MUSIC, sizeof(alsa_handle.useCase));
+          }
       }
       free(use_case);
       mDeviceList.push_back(alsa_handle);
       ALSAHandleList::iterator it = mDeviceList.end();
       it--;
-      ALOGV("useCase %s", it->useCase);
-#ifdef QCOM_USBAUDIO_ENABLED
-      if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
-         (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
-          ALOGD("Routing to proxy for normal playback in openOutputStream");
-          devices |= AudioSystem::DEVICE_OUT_PROXY;
-      }
-#endif
+      ALOGD("useCase %s", it->useCase);
       mALSADevice->route(&(*it), devices, mode());
-      if (flag & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
-          if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI)) {
-             snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI);
-          } else {
-             snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_MUSIC);
-          }
-      } else {
+#ifdef QCOM_OUTPUT_FLAGS_ENABLED
+      if (flags & AUDIO_OUTPUT_FLAG_FAST) {
           if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) {
              snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC);
           } else {
              snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC);
           }
+      } else
+#endif
+      {
+          if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI)) {
+             snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI);
+          } else {
+             snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_MUSIC);
+          }
       }
       err = mALSADevice->open(&(*it));
       if (err) {
@@ -969,100 +1278,6 @@
     delete out;
 }
 
-#ifdef QCOM_TUNNEL_LPA_ENABLED
-AudioStreamOut *
-AudioHardwareALSA::openOutputSession(uint32_t devices,
-                                     int *format,
-                                     status_t *status,
-                                     int sessionId,
-                                     uint32_t samplingRate,
-                                     uint32_t channels)
-{
-    Mutex::Autolock autoLock(mLock);
-    ALOGD("openOutputSession = %d" ,sessionId);
-    AudioStreamOutALSA *out = 0;
-    status_t err = BAD_VALUE;
-
-    alsa_handle_t alsa_handle;
-    unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
-
-    for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
-        bufferSize &= ~b;
-
-    alsa_handle.module = mALSADevice;
-    alsa_handle.bufferSize = bufferSize;
-    alsa_handle.devices = devices;
-    alsa_handle.handle = 0;
-    alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
-    alsa_handle.channels = DEFAULT_CHANNEL_MODE;
-    alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
-    alsa_handle.latency = VOICE_LATENCY;
-    alsa_handle.rxHandle = 0;
-    alsa_handle.ucMgr = mUcMgr;
-
-    char *use_case;
-    if(sessionId == TUNNEL_SESSION_ID) {
-        snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
-        if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
-            strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_TUNNEL, sizeof(alsa_handle.useCase));
-        } else {
-            strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_TUNNEL, sizeof(alsa_handle.useCase));
-        }
-    } else {
-        snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
-        if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
-            strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER, sizeof(alsa_handle.useCase));
-        } else {
-            strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_LPA, sizeof(alsa_handle.useCase));
-        }
-    }
-    free(use_case);
-    mDeviceList.push_back(alsa_handle);
-    ALSAHandleList::iterator it = mDeviceList.end();
-    it--;
-    ALOGD("useCase %s", it->useCase);
-#ifdef QCOM_USBAUDIO_ENABLED
-    if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
-       (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
-        ALOGD("Routing to proxy for LPA in openOutputSession");
-        devices |= AudioSystem::DEVICE_OUT_PROXY;
-        mALSADevice->route(&(*it), devices, mode());
-        devices = AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
-        ALOGD("Starting USBPlayback for LPA");
-        startUsbPlaybackIfNotStarted();
-        musbPlaybackState |= USBPLAYBACKBIT_LPA;
-    } else
-#endif
-    {
-        mALSADevice->route(&(*it), devices, mode());
-    }
-    if(sessionId == TUNNEL_SESSION_ID) {
-        if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) {
-            snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI_TUNNEL);
-        } else {
-            snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_TUNNEL);
-        }
-    }
-    else {
-        if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) {
-            snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI_LOW_POWER);
-        } else {
-            snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_LPA);
-        }
-    }
-    err = mALSADevice->open(&(*it));
-    out = new AudioStreamOutALSA(this, &(*it));
-
-    if (status) *status = err;
-       return out;
-}
-
-void
-AudioHardwareALSA::closeOutputSession(AudioStreamOut* out)
-{
-    delete out;
-}
-#endif
 
 AudioStreamIn *
 AudioHardwareALSA::openInputStream(uint32_t devices,
@@ -1081,9 +1296,10 @@
     AudioStreamInALSA *in = 0;
     ALSAHandleList::iterator it;
 
-    ALOGD("openInputStream: devices 0x%x channels %d sampleRate %d", devices, *channels, *sampleRate);
+    ALOGD("openInputStream: devices 0x%x format 0x%x channels %d sampleRate %d", devices, *format, *channels, *sampleRate);
     if (devices & (devices - 1)) {
         if (status) *status = err;
+        ALOGE("openInputStream failed error:0x%x devices:%x",err,devices);
         return in;
     }
 
@@ -1101,6 +1317,7 @@
         }
         if(voipstream_active == false) {
            mVoipStreamCount = 0;
+           mVoipMicMute = false;
            alsa_handle_t alsa_handle;
            unsigned long bufferSize;
            if(*sampleRate == VOIP_SAMPLING_RATE_8K) {
@@ -1118,7 +1335,7 @@
            alsa_handle.bufferSize = bufferSize;
            alsa_handle.devices = devices;
            alsa_handle.handle = 0;
-          if(*format == AudioSystem::PCM_16_BIT)
+          if(*format == AUDIO_FORMAT_PCM_16_BIT)
               alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
           else
               alsa_handle.format = *format;
@@ -1143,7 +1360,7 @@
            if((mCurDevice == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
               (mCurDevice == AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
               ALOGD("Routing everything from proxy for voipcall");
-              mALSADevice->route(&(*it), AudioSystem::DEVICE_IN_PROXY, AudioSystem::MODE_IN_COMMUNICATION);
+              mALSADevice->route(&(*it), AudioSystem::DEVICE_IN_PROXY, AUDIO_MODE_IN_COMMUNICATION);
               ALOGD("enabling VOIP in openInputstream, musbPlaybackState: %d", musbPlaybackState);
               startUsbPlaybackIfNotStarted();
               musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
@@ -1153,7 +1370,7 @@
            } else
 #endif
            {
-               mALSADevice->route(&(*it),mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
+               mALSADevice->route(&(*it),mCurDevice, AUDIO_MODE_IN_COMMUNICATION);
            }
            if(!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
                snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_IP_VOICECALL);
@@ -1163,8 +1380,10 @@
            if(sampleRate) {
                it->sampleRate = *sampleRate;
            }
-           if(channels)
+           if(channels) {
                it->channels = AudioSystem::popCount(*channels);
+               setInChannels(devices);
+           }
            err = mALSADevice->startVoipCall(&(*it));
            if (err) {
                ALOGE("Error opening pcm input device");
@@ -1188,7 +1407,10 @@
         alsa_handle.bufferSize = bufferSize;
         alsa_handle.devices = devices;
         alsa_handle.handle = 0;
-        alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
+        if(*format == AUDIO_FORMAT_PCM_16_BIT)
+            alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
+        else
+            alsa_handle.format = *format;
         alsa_handle.channels = VOICE_CHANNEL_MODE;
         alsa_handle.sampleRate = android::AudioRecord::DEFAULT_SAMPLE_RATE;
         alsa_handle.latency = RECORD_LATENCY;
@@ -1197,27 +1419,37 @@
         snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
         if ((use_case != NULL) && (strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
             if ((devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
-                (newMode == AudioSystem::MODE_IN_CALL)) {
+                (newMode == AUDIO_MODE_IN_CALL)) {
                 ALOGD("openInputStream: into incall recording, channels %d", *channels);
                 mIncallMode = *channels;
-                if ((*channels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
-                    (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
+                if ((*channels & AUDIO_CHANNEL_IN_VOICE_UPLINK) &&
+                    (*channels & AUDIO_CHANNEL_IN_VOICE_DNLINK)) {
                     if (mFusion3Platform) {
                         mALSADevice->setVocRecMode(INCALL_REC_STEREO);
                         strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
                                 sizeof(alsa_handle.useCase));
                     } else {
-                        strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
-                                sizeof(alsa_handle.useCase));
+                        if (*format == AUDIO_FORMAT_AMR_WB) {
+                            strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL,
+                                    sizeof(alsa_handle.useCase));
+                        } else {
+                            strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
+                                    sizeof(alsa_handle.useCase));
+                        }
                     }
-                } else if (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
+                } else if (*channels & AUDIO_CHANNEL_IN_VOICE_DNLINK) {
                     if (mFusion3Platform) {
                         mALSADevice->setVocRecMode(INCALL_REC_MONO);
                         strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
                                 sizeof(alsa_handle.useCase));
                     } else {
-                        strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
-                                sizeof(alsa_handle.useCase));
+                        if (*format == AUDIO_FORMAT_AMR_WB) {
+                            strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL,
+                                    sizeof(alsa_handle.useCase));
+                        } else {
+                            strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
+                                    sizeof(alsa_handle.useCase));
+                        }
                     }
                 }
 #ifdef QCOM_FM_ENABLED
@@ -1227,37 +1459,50 @@
                 strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, sizeof(alsa_handle.useCase));
 #endif
             } else {
-        char value[128];
-        property_get("persist.audio.lowlatency.rec",value,"0");
+                char value[128];
+                property_get("persist.audio.lowlatency.rec",value,"0");
                 if (!strcmp("true", value)) {
                     strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC, sizeof(alsa_handle.useCase));
+                } else if (*format == AUDIO_FORMAT_AMR_WB) {
+                    ALOGV("Format AMR_WB, open compressed capture");
+                    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));
                 }
             }
         } else {
             if ((devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
-                (newMode == AudioSystem::MODE_IN_CALL)) {
+                (newMode == AUDIO_MODE_IN_CALL)) {
                 ALOGD("openInputStream: incall recording, channels %d", *channels);
                 mIncallMode = *channels;
-                if ((*channels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
-                    (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
+                if ((*channels & AUDIO_CHANNEL_IN_VOICE_UPLINK) &&
+                    (*channels & AUDIO_CHANNEL_IN_VOICE_DNLINK)) {
                     if (mFusion3Platform) {
                         mALSADevice->setVocRecMode(INCALL_REC_STEREO);
                         strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_INCALL_REC,
                                 sizeof(alsa_handle.useCase));
                     } else {
-                        strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_UL_DL_REC,
-                                sizeof(alsa_handle.useCase));
+                        if (*format == AUDIO_FORMAT_AMR_WB) {
+                            strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL,
+                                    sizeof(alsa_handle.useCase));
+                        } else {
+                            strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_UL_DL_REC,
+                                    sizeof(alsa_handle.useCase));
+                        }
                     }
-                } else if (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
+                } else if (*channels & AUDIO_CHANNEL_IN_VOICE_DNLINK) {
                     if (mFusion3Platform) {
                         mALSADevice->setVocRecMode(INCALL_REC_MONO);
                         strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_INCALL_REC,
                                 sizeof(alsa_handle.useCase));
                     } else {
-                       strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_DL_REC,
-                               sizeof(alsa_handle.useCase));
+                        if (*format == AUDIO_FORMAT_AMR_WB) {
+                            strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL,
+                                    sizeof(alsa_handle.useCase));
+                        } else {
+                            strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_DL_REC,
+                                    sizeof(alsa_handle.useCase));
+                        }
                     }
                 }
 #ifdef QCOM_FM_ENABLED
@@ -1271,6 +1516,8 @@
                 property_get("persist.audio.lowlatency.rec",value,"0");
                 if (!strcmp("true", value)) {
                     strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC, sizeof(alsa_handle.useCase));
+                } else if (*format == AUDIO_FORMAT_AMR_WB) {
+                    strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, sizeof(alsa_handle.useCase));
                 } else {
                     strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_REC, sizeof(alsa_handle.useCase));
                 }
@@ -1283,13 +1530,14 @@
         //update channel info before do routing
         if(channels) {
             it->channels = AudioSystem::popCount((*channels) &
-                      (AudioSystem::CHANNEL_IN_STEREO
-                       | AudioSystem::CHANNEL_IN_MONO
+                      (AUDIO_CHANNEL_IN_STEREO
+                       | AUDIO_CHANNEL_IN_MONO
 #ifdef QCOM_SSR_ENABLED
-                       | AudioSystem::CHANNEL_IN_5POINT1
+                       | AUDIO_CHANNEL_IN_5POINT1
 #endif
                        ));
             ALOGV("updated channel info: channels=%d", it->channels);
+            setInChannels(devices);
         }
         if (devices == AudioSystem::DEVICE_IN_VOICE_CALL){
            /* Add current devices info to devices to do route */
@@ -1320,12 +1568,15 @@
 
         if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC) ||
            !strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC) ||
+           !strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED) ||
 #ifdef QCOM_FM_ENABLED
            !strcmp(it->useCase, SND_USE_CASE_VERB_FM_REC) ||
            !strcmp(it->useCase, SND_USE_CASE_VERB_FM_A2DP_REC) ||
 #endif
            !strcmp(it->useCase, SND_USE_CASE_VERB_DL_REC) ||
            !strcmp(it->useCase, SND_USE_CASE_VERB_UL_DL_REC) ||
+           !strcmp(it->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL) ||
+           !strcmp(it->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL) ||
            !strcmp(it->useCase, SND_USE_CASE_VERB_INCALL_REC)) {
             snd_use_case_set(mUcMgr, "_verb", it->useCase);
         } else {
@@ -1336,10 +1587,25 @@
         }
         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: Use larger buffer size for 5.1(%s) recording ", it->useCase);
+            ALOGV("OpenInoutStream: getInputBufferSize sampleRate:%d format:%d, channels:%d", it->sampleRate,*format,it->channels);
             it->bufferSize = getInputBufferSize(it->sampleRate,*format,it->channels);
         }
+
+#ifdef QCOM_SSR_ENABLED
+        //Check if SSR is supported by reading system property
+        char ssr_enabled[6] = "false";
+        property_get("ro.qc.sdk.audio.ssr",ssr_enabled,"0");
+        if (strncmp("true", ssr_enabled, 4)) {
+            if (status) *status = err;
+            ALOGE("openInputStream: FAILED:%d. Surround sound recording is not supported",*status);
+            return in;
+        }
+#endif
         err = mALSADevice->open(&(*it));
+        if (*format == AUDIO_FORMAT_AMR_WB) {
+             ALOGV("### Setting bufsize to 61");
+             it->bufferSize = 61;
+        }
         if (err) {
            ALOGE("Error opening pcm input device");
         } else {
@@ -1359,11 +1625,28 @@
 
 status_t AudioHardwareALSA::setMicMute(bool state)
 {
-    if (mMicMute != state) {
-        mMicMute = state;
-        ALOGD("setMicMute: mMicMute %d", mMicMute);
-        if(mALSADevice) {
-            mALSADevice->setMicMute(state);
+    int newMode = mode();
+    ALOGD("setMicMute  newMode %d state:%d",newMode,state);
+    if(newMode == AUDIO_MODE_IN_COMMUNICATION) {
+        if (mVoipMicMute != state) {
+             mVoipMicMute = state;
+            ALOGD("setMicMute: mVoipMicMute %d", mVoipMicMute);
+            if(mALSADevice) {
+                mALSADevice->setVoipMicMute(state);
+            }
+        }
+    } else {
+        if (mMicMute != state) {
+              mMicMute = state;
+              ALOGD("setMicMute: mMicMute %d", mMicMute);
+              if(mALSADevice) {
+                 if(mCSCallActive == CS_ACTIVE)
+                    mALSADevice->setMicMute(state);
+                 else if(mSGLTECallActive == CS_ACTIVE_SESSION2)
+                    mALSADevice->setSGLTEMicMute(state);
+                 if(mVolteCallActive == IMS_ACTIVE)
+                    mALSADevice->setVoLTEMicMute(state);
+              }
         }
     }
     return NO_ERROR;
@@ -1371,7 +1654,12 @@
 
 status_t AudioHardwareALSA::getMicMute(bool *state)
 {
-    *state = mMicMute;
+    int newMode = mode();
+    if(newMode == AUDIO_MODE_IN_COMMUNICATION) {
+        *state = mVoipMicMute;
+    } else {
+        *state = mMicMute;
+    }
     return NO_ERROR;
 }
 
@@ -1383,7 +1671,7 @@
 size_t AudioHardwareALSA::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
 {
     size_t bufferSize = 0;
-    if (format == AudioSystem::PCM_16_BIT) {
+    if (format == AUDIO_FORMAT_PCM_16_BIT) {
         if(sampleRate == 8000 || sampleRate == 16000 || sampleRate == 32000) {
             bufferSize = (sampleRate * channelCount * 20 * sizeof(int16_t)) / 1000;
         } else if (sampleRate == 11025 || sampleRate == 12000) {
@@ -1402,7 +1690,9 @@
 #ifdef QCOM_FM_ENABLED
 void AudioHardwareALSA::handleFm(int device)
 {
-int newMode = mode();
+    int newMode = mode();
+    uint32_t activeUsecase = USECASE_NONE;
+
     if(device & AudioSystem::DEVICE_OUT_FM && mIsFmActive == 0) {
         // Start FM Radio on current active device
         unsigned long bufferSize = FM_BUFFER_SIZE;
@@ -1433,12 +1723,6 @@
         mDeviceList.push_back(alsa_handle);
         ALSAHandleList::iterator it = mDeviceList.end();
         it--;
-        if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
-           (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
-            device |= AudioSystem::DEVICE_OUT_PROXY;
-            alsa_handle.devices = AudioSystem::DEVICE_OUT_PROXY;
-            ALOGD("Routing to proxy for FM case");
-        }
         mALSADevice->route(&(*it), (uint32_t)device, newMode);
         if(!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) {
             snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_DIGITAL_RADIO);
@@ -1446,12 +1730,25 @@
             snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_FM);
         }
         mALSADevice->startFm(&(*it));
+        activeUsecase = useCaseStringToEnum(it->useCase);
+#ifdef QCOM_USBAUDIO_ENABLED
         if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
            (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
             ALOGD("Starting FM, musbPlaybackState %d", musbPlaybackState);
             startUsbPlaybackIfNotStarted();
             musbPlaybackState |= USBPLAYBACKBIT_FM;
         }
+#endif
+        if(device & AudioSystem::DEVICE_OUT_ALL_A2DP) {
+            status_t err = NO_ERROR;
+            mRouteAudioToA2dp = true;
+            err = startA2dpPlayback_l(activeUsecase);
+            if(err) {
+                ALOGE("startA2dpPlayback_l for hardware output failed err = %d", err);
+                stopA2dpPlayback_l(activeUsecase);
+            }
+        }
+
     } else if (!(device & AudioSystem::DEVICE_OUT_FM) && mIsFmActive == 1) {
         //i Stop FM Radio
         ALOGV("Stop FM");
@@ -1460,17 +1757,27 @@
             if((!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
               (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_FM))) {
                 mALSADevice->close(&(*it));
+                activeUsecase = useCaseStringToEnum(it->useCase);
                 //mALSADevice->route(&(*it), (uint32_t)device, newMode);
                 mDeviceList.erase(it);
                 break;
             }
         }
         mIsFmActive = 0;
+#ifdef QCOM_USBAUDIO_ENABLED
         musbPlaybackState &= ~USBPLAYBACKBIT_FM;
         if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
            (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
             closeUsbPlaybackIfNothingActive();
         }
+#endif
+        if(mRouteAudioToA2dp == true) {
+            status_t err = NO_ERROR;
+            err = stopA2dpPlayback_l(activeUsecase);
+            if(err)
+                ALOGE("stopA2dpPlayback_l for hardware output failed err = %d", err);
+        }
+
     }
 }
 #endif
@@ -1488,6 +1795,8 @@
             break;
         }
     }
+    mIsVoicePathActive = false;
+
 #ifdef QCOM_USBAUDIO_ENABLED
    if(musbPlaybackState & USBPLAYBACKBIT_VOICECALL) {
           ALOGD("Voice call ended on USB");
@@ -1527,13 +1836,7 @@
     mDeviceList.push_back(alsa_handle);
     ALSAHandleList::iterator it = mDeviceList.end();
     it--;
-#ifdef QCOM_USBAUDIO_ENABLED
-    if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
-       (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
-        device |= AudioSystem::DEVICE_OUT_PROXY;
-        alsa_handle.devices = device;
-    }
-#endif
+    setInChannels(device);
     mALSADevice->route(&(*it), (uint32_t)device, mode);
     if (!strcmp(it->useCase, verb)) {
         snd_use_case_set(mUcMgr, "_verb", verb);
@@ -1541,6 +1844,8 @@
         snd_use_case_set(mUcMgr, "_enamod", modifier);
     }
     mALSADevice->startVoiceCall(&(*it));
+    mIsVoicePathActive = true;
+
 #ifdef QCOM_USBAUDIO_ENABLED
     if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
        (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
@@ -1613,6 +1918,70 @@
     }
     return isRouted;
 }
+
+bool AudioHardwareALSA::routeSGLTECall(int device, int newMode)
+{
+int SGLTECallState = mCallState&0xF00;
+ bool isRouted = false;
+ switch (SGLTECallState) {
+    case CS_INACTIVE_SESSION2:
+        if (mSGLTECallActive != CS_INACTIVE_SESSION2) {
+            ALOGV("doRouting: Disabling voice call session2");
+            disableVoiceCall((char *)SND_USE_CASE_VERB_SGLTECALL,
+                (char *)SND_USE_CASE_MOD_PLAY_SGLTE, newMode, device);
+            isRouted = true;
+            mSGLTECallActive = CS_INACTIVE_SESSION2;
+        }
+    break;
+    case CS_ACTIVE_SESSION2:
+        if (mSGLTECallActive == CS_INACTIVE_SESSION2) {
+            ALOGV("doRouting: Enabling CS voice call session2 ");
+            enableVoiceCall((char *)SND_USE_CASE_VERB_SGLTECALL,
+                (char *)SND_USE_CASE_MOD_PLAY_SGLTE, newMode, device);
+            isRouted = true;
+            mSGLTECallActive = CS_ACTIVE_SESSION2;
+        } else if (mSGLTECallActive == CS_HOLD_SESSION2) {
+             ALOGV("doRouting: Resume voice call session2 from hold state");
+             ALSAHandleList::iterator vt_it;
+             for(vt_it = mDeviceList.begin();
+                 vt_it != mDeviceList.end(); ++vt_it) {
+                 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_SGLTECALL,
+                     strlen(SND_USE_CASE_VERB_SGLTECALL))) ||
+                     (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_SGLTE,
+                     strlen(SND_USE_CASE_MOD_PLAY_SGLTE)))) {
+                     alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
+                     mSGLTECallActive = CS_ACTIVE_SESSION2;
+                     if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0)
+                         ALOGE("SGLTE resume failed");
+                     break;
+                 }
+             }
+        }
+    break;
+    case CS_HOLD_SESSION2:
+        if (mSGLTECallActive == CS_ACTIVE_SESSION2) {
+            ALOGV("doRouting: Voice call session2 going to Hold");
+             ALSAHandleList::iterator vt_it;
+             for(vt_it = mDeviceList.begin();
+                 vt_it != mDeviceList.end(); ++vt_it) {
+                 if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_SGLTECALL,
+                     strlen(SND_USE_CASE_VERB_SGLTECALL))) ||
+                     (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_SGLTE,
+                         strlen(SND_USE_CASE_MOD_PLAY_SGLTE)))) {
+                         mSGLTECallActive = CS_HOLD_SESSION2;
+                         alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
+                         if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0)
+                             ALOGE("Voice session2 pause failed");
+                         break;
+                }
+            }
+        }
+    break;
+    }
+    return isRouted;
+}
+
+
 bool AudioHardwareALSA::routeVoLTECall(int device, int newMode)
 {
 int volteCallState = mCallState&0xF0;
@@ -1675,4 +2044,378 @@
     return isRouted;
 }
 
+void AudioHardwareALSA::pauseIfUseCaseTunnelOrLPA() {
+    for (ALSAHandleList::iterator it = mDeviceList.begin();
+           it != mDeviceList.end(); it++) {
+        if((!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
+                strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) ||
+            (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
+                strlen(SND_USE_CASE_MOD_PLAY_TUNNEL))) ||
+            (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
+                strlen(SND_USE_CASE_VERB_HIFI_LOW_POWER))) ||
+            (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA,
+                strlen(SND_USE_CASE_MOD_PLAY_LPA)))) {
+                it->session->pause_l();
+        }
+    }
+}
+
+void AudioHardwareALSA::resumeIfUseCaseTunnelOrLPA() {
+    for (ALSAHandleList::iterator it = mDeviceList.begin();
+           it != mDeviceList.end(); it++) {
+        if((!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
+                strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) ||
+            (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
+                strlen(SND_USE_CASE_MOD_PLAY_TUNNEL))) ||
+            (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
+                strlen(SND_USE_CASE_VERB_HIFI_LOW_POWER))) ||
+            (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA,
+                strlen(SND_USE_CASE_MOD_PLAY_LPA)))) {
+                it->session->resume_l();
+        }
+    }
+}
+
+status_t AudioHardwareALSA::startA2dpPlayback(uint32_t activeUsecase) {
+
+    Mutex::Autolock autoLock(mLock);
+    status_t err = startA2dpPlayback_l(activeUsecase);
+    if(err) {
+        ALOGE("startA2dpPlayback_l  = %d", err);
+    }
+    return err;
+}
+status_t AudioHardwareALSA::startA2dpPlayback_l(uint32_t activeUsecase) {
+
+    ALOGV("startA2dpPlayback_l::usecase = %d ", activeUsecase);
+    status_t err = NO_ERROR;
+
+    if (activeUsecase != USECASE_NONE && !mIsA2DPEnabled) {
+        //setA2DPActiveUseCases_l(activeUsecase);
+        Mutex::Autolock autolock1(mA2dpMutex);
+        err = mALSADevice->openProxyDevice();
+        if(err) {
+            ALOGE("openProxyDevice failed = %d", err);
+        }
+
+        err = openA2dpOutput();
+        if(err) {
+            ALOGE("openA2DPOutput failed = %d",err);
+            return err;
+        }
+
+        mKillA2DPThread = false;
+        err = pthread_create(&mA2dpThread, (const pthread_attr_t *) NULL,
+                a2dpThreadWrapper,
+                this);
+        if(err) {
+            ALOGE("thread create failed = %d", err);
+            return err;
+        }
+        mA2dpThreadAlive = true;
+        mIsA2DPEnabled = true;
+
+#ifdef OUTPUT_BUFFER_LOG
+    sprintf(outputfilename, "%s%d%s", outputfilename, number,".pcm");
+    outputBufferFile1 = fopen (outputfilename, "ab");
+    number++;
+#endif
+    }
+
+    setA2DPActiveUseCases_l(activeUsecase);
+    mALSADevice->resumeProxy();
+
+    ALOGV("A2DP signal");
+    mA2dpCv.signal();
+    return err;
+}
+
+status_t AudioHardwareALSA::stopA2dpPlayback(uint32_t activeUsecase) {
+     Mutex::Autolock autoLock(mLock);
+     status_t err = stopA2dpPlayback_l(activeUsecase);
+     if(err) {
+         ALOGE("stopA2dpPlayback = %d", err);
+     }
+     return err;
+}
+
+status_t AudioHardwareALSA::stopA2dpPlayback_l(uint32_t activeUsecase) {
+
+     ALOGV("stopA2dpPlayback  = %d", activeUsecase);
+     status_t err = NO_ERROR;
+     suspendA2dpPlayback_l(activeUsecase);
+     {
+         Mutex::Autolock autolock1(mA2dpMutex);
+         ALOGV("stopA2dpPlayback  getA2DPActiveUseCases_l = %d",
+                getA2DPActiveUseCases_l());
+
+         if(!getA2DPActiveUseCases_l()) {
+             mIsA2DPEnabled = false;
+
+             mA2dpMutex.unlock();
+             err = stopA2dpThread();
+             mA2dpMutex.lock();
+
+             if(err) {
+                 ALOGE("stopA2dpOutput = %d" ,err);
+             }
+
+             err = closeA2dpOutput();
+             if(err) {
+                  ALOGE("closeA2dpOutput = %d" ,err);
+             }
+
+             err = mALSADevice->closeProxyDevice();
+             if(err) {
+                 ALOGE("closeProxyDevice failed = %d", err);
+             }
+
+             mA2DPActiveUseCases = 0x0;
+             mRouteAudioToA2dp = false;
+
+#ifdef OUTPUT_BUFFER_LOG
+    ALOGV("close file output");
+    fclose (outputBufferFile1);
+#endif
+         }
+     }
+     return err;
+}
+
+status_t AudioHardwareALSA::openA2dpOutput()
+{
+    hw_module_t *mod;
+    int      format = AUDIO_FORMAT_PCM_16_BIT;
+    uint32_t channels = AUDIO_CHANNEL_OUT_STEREO;
+    uint32_t sampleRate = AFE_PROXY_SAMPLE_RATE;
+    status_t status;
+    ALOGV("openA2dpOutput");
+    struct audio_config config;
+    config.sample_rate = AFE_PROXY_SAMPLE_RATE;
+    config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+    config.format = AUDIO_FORMAT_PCM_16_BIT;
+
+    //TODO : Confirm AUDIO_HARDWARE_MODULE_ID_A2DP ???
+    int rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID/*_A2DP*/, (const char*)"a2dp",
+                                    (const hw_module_t**)&mod);
+    if (rc) {
+        ALOGE("Could not get a2dp hardware module");
+        return NO_INIT;
+    }
+
+    rc = audio_hw_device_open(mod, &mA2dpDevice);
+    if(rc) {
+        ALOGE("couldn't open a2dp audio hw device");
+        return NO_INIT;
+    }
+    //TODO: unique id 0?
+    status = mA2dpDevice->open_output_stream(mA2dpDevice, 0,((audio_devices_t)(AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP)),
+                                    (audio_output_flags_t)AUDIO_OUTPUT_FLAG_NONE, &config, &mA2dpStream);
+    if(status != NO_ERROR) {
+        ALOGE("Failed to open output stream for a2dp: status %d", status);
+    }
+    return status;
+}
+
+status_t AudioHardwareALSA::closeA2dpOutput()
+{
+    ALOGV("closeA2dpOutput");
+    if(!mA2dpDevice){
+        ALOGE("No Aactive A2dp output found");
+        return NO_ERROR;
+    }
+
+    mA2dpDevice->close_output_stream(mA2dpDevice, mA2dpStream);
+    mA2dpStream = NULL;
+
+    audio_hw_device_close(mA2dpDevice);
+    mA2dpDevice = NULL;
+    return NO_ERROR;
+}
+
+status_t AudioHardwareALSA::stopA2dpThread()
+{
+    ALOGV("stopA2dpThread");
+    status_t err = NO_ERROR;
+    if (!mA2dpThreadAlive) {
+        ALOGD("Return - thread not live");
+        return NO_ERROR;
+    }
+    mKillA2DPThread = true;
+    err = mALSADevice->exitReadFromProxy();
+    if(err) {
+        ALOGE("exitReadFromProxy failed = %d", err);
+    }
+    mA2dpCv.signal();
+    int ret = pthread_join(mA2dpThread,NULL);
+    ALOGD("a2dp thread killed = %d", ret);
+    return err;
+}
+
+void *AudioHardwareALSA::a2dpThreadWrapper(void *me) {
+    static_cast<AudioHardwareALSA *>(me)->a2dpThreadFunc();
+    return NULL;
+}
+
+void AudioHardwareALSA::a2dpThreadFunc() {
+    if(!mA2dpStream) {
+        ALOGE("No valid a2dp output stream found");
+        return;
+    }
+    if(!mALSADevice->isProxyDeviceOpened()) {
+        ALOGE("No valid mProxyPcmHandle found");
+        return;
+    }
+
+    pid_t tid  = gettid();
+    androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
+    prctl(PR_SET_NAME, (unsigned long)"A2DPThread", 0, 0, 0);
+
+    int ionBufCount = 0;
+    uint32_t bytesWritten = 0;
+    uint32_t numBytesRemaining = 0;
+    uint32_t bytesAvailInBuffer = 0;
+    void  *data;
+    int err = NO_ERROR;
+    ssize_t size = 0;
+
+    mALSADevice->resetProxyVariables();
+
+    ALOGV("mKillA2DPThread = %d", mKillA2DPThread);
+    while(!mKillA2DPThread) {
+
+        {
+            Mutex::Autolock autolock1(mA2dpMutex);
+            if (!mA2dpStream || !mIsA2DPEnabled ||
+                !mALSADevice->isProxyDeviceOpened() ||
+                (mALSADevice->isProxyDeviceSuspended()) ||
+                (err != NO_ERROR)) {
+                ALOGD("A2DPThreadEntry:: proxy opened = %d,\
+                        proxy suspended = %d,err =%d,\
+                        mA2dpStream = %p",\
+                        mALSADevice->isProxyDeviceOpened(),\
+                        mALSADevice->isProxyDeviceSuspended(),err,mA2dpStream);
+                ALOGD("A2DPThreadEntry:: Waiting on mA2DPCv");
+                mA2dpCv.wait(mA2dpMutex);
+                ALOGD("A2DPThreadEntry:: received signal to wake up");
+                mA2dpMutex.unlock();
+                continue;
+            }
+        }
+        err = mALSADevice->readFromProxy(&data, &size);
+        if(err < 0) {
+           ALOGE("ALSADevice readFromProxy returned err = %d,data = %p,\
+                    size = %ld", err, data, size);
+           continue;
+        }
+
+#ifdef OUTPUT_BUFFER_LOG
+    if (outputBufferFile1)
+    {
+        fwrite (data,1,size,outputBufferFile1);
+    }
+#endif
+        void *copyBuffer = data;
+        numBytesRemaining = size;
+        while (err == OK && (numBytesRemaining  > 0) && !mKillA2DPThread
+                && mIsA2DPEnabled ) {
+            {
+                Mutex::Autolock autolock1(mA2dpMutex);
+                bytesAvailInBuffer = mA2dpStream->common.get_buffer_size(&mA2dpStream->common);
+            }
+            uint32_t writeLen = bytesAvailInBuffer > numBytesRemaining ?
+                    numBytesRemaining : bytesAvailInBuffer;
+            ALOGV("Writing %d bytes to A2DP ", writeLen);
+            {
+                Mutex::Autolock autolock1(mA2dpMutex);
+                bytesWritten = mA2dpStream->write(mA2dpStream,copyBuffer, writeLen);
+            }
+            ALOGV("bytesWritten = %d",bytesWritten);
+            //Need to check warning here - void used in arithmetic
+            copyBuffer = (char *)copyBuffer + bytesWritten;
+            numBytesRemaining -= bytesWritten;
+            ALOGV("@_@bytes To write2:%d",numBytesRemaining);
+        }
+    }
+
+    mALSADevice->resetProxyVariables();
+    mA2dpThreadAlive = false;
+    ALOGD("A2DP Thread is dying");
+}
+
+void AudioHardwareALSA::setA2DPActiveUseCases_l(uint32_t activeUsecase)
+{
+   mA2DPActiveUseCases |= activeUsecase;
+   ALOGD("mA2DPActiveUseCases = %u, activeUsecase = %u", mA2DPActiveUseCases, activeUsecase);
+}
+
+uint32_t AudioHardwareALSA::getA2DPActiveUseCases_l()
+{
+   ALOGD("getA2DPActiveUseCases_l: mA2DPActiveUseCases = %u", mA2DPActiveUseCases);
+   return mA2DPActiveUseCases;
+}
+
+void AudioHardwareALSA::clearA2DPActiveUseCases_l(uint32_t activeUsecase) {
+
+   mA2DPActiveUseCases &= ~activeUsecase;
+   ALOGD("clear - mA2DPActiveUseCases = %u, activeUsecase = %u", mA2DPActiveUseCases, activeUsecase);
+
+}
+
+uint32_t AudioHardwareALSA::useCaseStringToEnum(const char *usecase)
+{
+   ALOGV("useCaseStringToEnum usecase:%s",usecase);
+   uint32_t activeUsecase = USECASE_NONE;
+
+   if ((!strncmp(usecase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
+                    strlen(SND_USE_CASE_VERB_HIFI_LOW_POWER))) ||
+       (!strncmp(usecase, SND_USE_CASE_MOD_PLAY_LPA,
+                    strlen(SND_USE_CASE_MOD_PLAY_LPA)))) {
+       activeUsecase = USECASE_HIFI_LOW_POWER;
+   } else if ((!strncmp(usecase, SND_USE_CASE_VERB_HIFI_TUNNEL,
+                           strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) ||
+              (!strncmp(usecase, SND_USE_CASE_MOD_PLAY_TUNNEL,
+                           strlen(SND_USE_CASE_MOD_PLAY_TUNNEL)))) {
+       activeUsecase = USECASE_HIFI_TUNNEL;
+   } else if ((!strncmp(usecase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC,
+                           strlen(SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC )))||
+               (!strncmp(usecase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC,
+                           strlen(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)))) {
+       activeUsecase = USECASE_HIFI_LOWLATENCY;
+   } else if ((!strncmp(usecase, SND_USE_CASE_VERB_DIGITAL_RADIO,
+                           strlen(SND_USE_CASE_VERB_DIGITAL_RADIO))) ||
+               (!strncmp(usecase, SND_USE_CASE_MOD_PLAY_FM,
+                           strlen(SND_USE_CASE_MOD_PLAY_FM)))||
+               (!strncmp(usecase, SND_USE_CASE_VERB_FM_REC,
+                           strlen(SND_USE_CASE_VERB_FM_REC)))||
+               (!strncmp(usecase, SND_USE_CASE_MOD_CAPTURE_FM,
+                           strlen(SND_USE_CASE_MOD_CAPTURE_FM)))){
+       activeUsecase = USECASE_FM;
+    } else if ((!strncmp(usecase, SND_USE_CASE_VERB_HIFI,
+                           strlen(SND_USE_CASE_VERB_HIFI)))||
+               (!strncmp(usecase, SND_USE_CASE_MOD_PLAY_MUSIC,
+                           strlen(SND_USE_CASE_MOD_PLAY_MUSIC)))) {
+       activeUsecase = USECASE_HIFI;
+    }
+    return activeUsecase;
+}
+
+bool  AudioHardwareALSA::suspendA2dpPlayback(uint32_t activeUsecase) {
+
+    Mutex::Autolock autoLock(mLock);
+    suspendA2dpPlayback_l(activeUsecase);
+    return NO_ERROR;
+}
+
+bool  AudioHardwareALSA::suspendA2dpPlayback_l(uint32_t activeUsecase) {
+
+    Mutex::Autolock autolock1(mA2dpMutex);
+    ALOGD("suspendA2dpPlayback_l activeUsecase = %d, mRouteAudioToA2dp = %d",\
+            activeUsecase, mRouteAudioToA2dp);
+    clearA2DPActiveUseCases_l(activeUsecase);
+    if((!getA2DPActiveUseCases_l()) && mIsA2DPEnabled )
+        return mALSADevice->suspendProxy();
+    return NO_ERROR;
+}
+
 }       // namespace android_audio_legacy
diff --git a/alsa_sound/AudioHardwareALSA.h b/alsa_sound/AudioHardwareALSA.h
index 932b18f..201e8ce 100644
--- a/alsa_sound/AudioHardwareALSA.h
+++ b/alsa_sound/AudioHardwareALSA.h
@@ -1,7 +1,7 @@
 /* AudioHardwareALSA.h
  **
  ** Copyright 2008-2010, Wind River Systems
- ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ ** Copyright (c) 2012, 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.
@@ -19,8 +19,6 @@
 #ifndef ANDROID_AUDIO_HARDWARE_ALSA_H
 #define ANDROID_AUDIO_HARDWARE_ALSA_H
 
-#define QCOM_CSDCLIENT_ENABLED 1
-
 #include <utils/List.h>
 #include <hardware_legacy/AudioHardwareBase.h>
 
@@ -30,15 +28,20 @@
 #include <hardware/audio.h>
 #include <utils/threads.h>
 #include <dlfcn.h>
-
 #ifdef QCOM_USBAUDIO_ENABLED
 #include <AudioUsbALSA.h>
 #endif
+#include <sys/poll.h>
+#include <sys/eventfd.h>
 
 extern "C" {
-   #include <sound/asound.h>
-   #include "alsa_audio.h"
-   #include "msm8960_use_cases.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"
+    #include "msm8960_use_cases.h"
 }
 
 #include <hardware/hardware.h>
@@ -47,6 +50,7 @@
 {
 using android::List;
 using android::Mutex;
+using android::Condition;
 class AudioHardwareALSA;
 
 /**
@@ -69,7 +73,11 @@
 #define PLAYBACK_LOW_LATENCY_BUFFER_SIZE   1024
 #define PLAYBACK_LOW_LATENCY  22000
 #define PLAYBACK_LOW_LATENCY_MEASURED  42000
+#ifdef TARGET_8974
+#define DEFAULT_IN_BUFFER_SIZE 512
+#else
 #define DEFAULT_IN_BUFFER_SIZE 320
+#endif
 #define MIN_CAPTURE_BUFFER_SIZE_PER_CH   320
 #define MAX_CAPTURE_BUFFER_SIZE_PER_CH   2048
 #define FM_BUFFER_SIZE        1024
@@ -92,6 +100,7 @@
 
 #define DUALMIC_KEY         "dualmic_enabled"
 #define FLUENCE_KEY         "fluence"
+#define VOIPCHECK_KEY         "voip_flag"
 #define ANC_KEY             "anc_enabled"
 #define TTY_MODE_KEY        "tty_mode"
 #define BT_SAMPLERATE_KEY   "bt_samplerate"
@@ -101,6 +110,7 @@
 #define FENS_KEY            "fens_enable"
 #define ST_KEY              "st_enable"
 #define INCALLMUSIC_KEY     "incall_music_enabled"
+#define VOICE_PATH_ACTIVE   "voice_path_active"
 
 #define ANC_FLAG        0x00000001
 #define DMIC_FLAG       0x00000002
@@ -123,6 +133,7 @@
 static int USBPLAYBACKBIT_VOIPCALL = (1 << 2);
 static int USBPLAYBACKBIT_FM = (1 << 3);
 static int USBPLAYBACKBIT_LPA = (1 << 4);
+static int USBPLAYBACKBIT_TUNNEL = (1 << 5);
 
 static int USBRECBIT_REC = (1 << 0);
 static int USBRECBIT_VOICECALL = (1 << 1);
@@ -143,10 +154,20 @@
 #endif
 
 #define MODE_CALL_KEY  "CALL_KEY"
+#ifndef ALSA_DEFAULT_SAMPLE_RATE
+#define ALSA_DEFAULT_SAMPLE_RATE 44100 // in Hz
+#endif
 
-struct alsa_device_t;
+#define NUM_FDS 2
+#define AFE_PROXY_SAMPLE_RATE 48000
+#define AFE_PROXY_CHANNEL_COUNT 2
+
+#define MAX_SLEEP_RETRY 100  /*  Will check 100 times before continuing */
+#define AUDIO_INIT_SLEEP_WAIT 50 /* 50 ms */
+
 static uint32_t FLUENCE_MODE_ENDFIRE   = 0;
 static uint32_t FLUENCE_MODE_BROADSIDE = 1;
+class ALSADevice;
 
 enum {
     INCALL_REC_MONO,
@@ -157,28 +178,60 @@
     CS_INACTIVE   = 0x0,
     CS_ACTIVE     = 0x1,
     CS_HOLD       = 0x2,
+    CS_INACTIVE_SESSION2   = 0x0,
+    CS_ACTIVE_SESSION2     = 0x100,
+    CS_HOLD_SESSION2       = 0x200,
     IMS_INACTIVE  = 0x0,
     IMS_ACTIVE    = 0x10,
     IMS_HOLD      = 0x20
 };
 
-
+class AudioSessionOutALSA;
 struct alsa_handle_t {
-    alsa_device_t *     module;
+    ALSADevice*         module;
     uint32_t            devices;
     char                useCase[MAX_STR_LEN];
     struct pcm *        handle;
     snd_pcm_format_t    format;
     uint32_t            channels;
     uint32_t            sampleRate;
+    int                 mode;
     unsigned int        latency;         // Delay in usec
     unsigned int        bufferSize;      // Size of sample buffer
     unsigned int        periodSize;
-    bool                isDeepbufferOutput;
+    bool                isFastOutput;
     struct pcm *        rxHandle;
     snd_use_case_mgr_t  *ucMgr;
+    AudioSessionOutALSA *session;
 };
 
+struct output_metadata_handle_t {
+    uint32_t            metadataLength;
+    uint32_t            bufferLength;
+    uint64_t            timestamp;
+    uint32_t            reserved[12];
+};
+typedef struct buf_info;
+
+/** Structure to save buffer information for applying effects for
+ *  LPA buffers */
+struct buf_info {
+    int bufsize;
+    int nBufs;
+    int **buffers;
+};
+
+#ifdef __cplusplus
+/**
+ *Observer class to post the Events from HAL to Flinger
+*/
+class AudioEventObserver {
+public:
+    virtual ~AudioEventObserver() {}
+    virtual void postEOS(int64_t delayUs) = 0;
+};
+#endif
+
 typedef List < alsa_handle_t > ALSAHandleList;
 
 struct use_case_t {
@@ -187,39 +240,119 @@
 
 typedef List < use_case_t > ALSAUseCaseList;
 
-struct alsa_device_t {
-    hw_device_t common;
+class ALSADevice
+{
 
-    status_t (*init)(alsa_device_t *, ALSAHandleList &);
-    status_t (*open)(alsa_handle_t *);
-    status_t (*close)(alsa_handle_t *);
-    status_t (*standby)(alsa_handle_t *);
-    status_t (*route)(alsa_handle_t *, uint32_t, int);
-    status_t (*startVoiceCall)(alsa_handle_t *);
-    status_t (*startVoipCall)(alsa_handle_t *);
-    status_t (*startFm)(alsa_handle_t *);
-    void     (*setVoiceVolume)(int);
-    void     (*setVoipVolume)(int);
-    void     (*setMicMute)(int);
-    void     (*setVoipMicMute)(int);
-    void     (*setVoipConfig)(int, int);
-    status_t (*setFmVolume)(int);
-    void     (*setBtscoRate)(int);
-    status_t (*setLpaVolume)(int);
-    void     (*enableWideVoice)(bool);
-    void     (*enableFENS)(bool);
-    void     (*setFlags)(uint32_t);
-    status_t (*setCompressedVolume)(int);
-    void     (*enableSlowTalk)(bool);
-    void     (*setVocRecMode)(uint8_t);
-    void     (*setVoLTEMicMute)(int);
-    void     (*setVoLTEVolume)(int);
+public:
+
+    ALSADevice();
+    virtual ~ALSADevice();
+//    status_t init(alsa_device_t *module, ALSAHandleList &list);
+    status_t open(alsa_handle_t *handle);
+    status_t close(alsa_handle_t *handle);
+    status_t standby(alsa_handle_t *handle);
+    status_t route(alsa_handle_t *handle, uint32_t devices, int mode);
+    status_t startVoiceCall(alsa_handle_t *handle);
+    status_t startVoipCall(alsa_handle_t *handle);
+    status_t startFm(alsa_handle_t *handle);
+    void     setVoiceVolume(int volume);
+    void     setVoipVolume(int volume);
+    void     setMicMute(int state);
+    void     setVoipMicMute(int state);
+    void     setVoipConfig(int mode, int rate);
+    status_t setFmVolume(int vol);
+    void     setBtscoRate(int rate);
+    status_t setLpaVolume(int vol);
+    void     enableWideVoice(bool flag);
+    void     enableFENS(bool flag);
+    void     setFlags(uint32_t flag);
+    status_t setCompressedVolume(int vol);
+    void     enableSlowTalk(bool flag);
+    void     setVocRecMode(uint8_t mode);
+    void     setVoLTEMicMute(int state);
+    void     setVoLTEVolume(int vol);
+    void     setSGLTEMicMute(int state);
+    void     setSGLTEVolume(int vol);
+    status_t setEcrxDevice(char *device);
+    void     setInChannels(int);
+    //TODO:check if this needs to be public
+    void     disableDevice(alsa_handle_t *handle);
+    char    *getUCMDeviceFromAcdbId(int acdb_id);
 #ifdef SEPERATED_AUDIO_INPUT
-    void     (*setInput)(int);
+    void     setInput(int);
 #endif
 #ifdef QCOM_CSDCLIENT_ENABLED
-    void     (*setCsdHandle)(void*);
+    void     setCsdHandle(void*);
 #endif
+
+protected:
+    friend class AudioHardwareALSA;
+private:
+    void     switchDevice(alsa_handle_t *handle, uint32_t devices, uint32_t mode);
+    int      getUseCaseType(const char *useCase);
+    status_t setHDMIChannelCount();
+    status_t setHardwareParams(alsa_handle_t *handle);
+    int      deviceName(alsa_handle_t *handle, unsigned flags, char **value);
+    status_t setSoftwareParams(alsa_handle_t *handle);
+    bool     platform_is_Fusion3();
+    status_t getMixerControl(const char *name, unsigned int &value, int index = 0);
+    status_t setMixerControl(const char *name, unsigned int value, int index = -1);
+    status_t setMixerControl(const char *name, const char *);
+    status_t setMixerControlExt(const char *name, int count, char **setValues);
+    char *   getUCMDevice(uint32_t devices, int input, char *rxDevice);
+    status_t  start(alsa_handle_t *handle);
+
+    status_t   openProxyDevice();
+    status_t   closeProxyDevice();
+    bool       isProxyDeviceOpened();
+    bool       isProxyDeviceSuspended();
+    bool       suspendProxy();
+    bool       resumeProxy();
+    void       resetProxyVariables();
+    ssize_t    readFromProxy(void **captureBuffer , ssize_t *bufferSize);
+    status_t   exitReadFromProxy();
+    void       initProxyParams();
+    status_t   startProxy();
+
+private:
+    char mMicType[25];
+    char mCurRxUCMDevice[50];
+    char mCurTxUCMDevice[50];
+    uint32_t mFluenceMode;
+    int mFmVolume;
+    uint32_t mDevSettingsFlag;
+    int mBtscoSamplerate;
+    ALSAUseCaseList mUseCaseList;
+    void *mcsd_handle;
+    int mCallMode;
+    struct mixer*  mMixer;
+    int mInChannels;
+    bool mIsSglte;
+#ifdef SEPERATED_AUDIO_INPUT
+    int mInput_source
+#endif
+//   ALSAHandleList  *mDeviceList;
+
+    struct proxy_params {
+        bool                mExitRead;
+        struct pcm          *mProxyPcmHandle;
+        uint32_t            mCaptureBufferSize;
+        void                *mCaptureBuffer;
+        enum {
+            EProxyClosed    = 0,
+            EProxyOpened    = 1,
+            EProxySuspended = 2,
+            EProxyCapture   = 3,
+        };
+
+        uint32_t mProxyState;
+        struct snd_xferi mX;
+        unsigned mAvail;
+        struct pollfd mPfdProxy[NUM_FDS];
+        long mFrames;
+    };
+    struct proxy_params mProxyParams;
+
 };
 
 // ----------------------------------------------------------------------------
@@ -244,21 +377,6 @@
 
 };
 
-class ALSAControl
-{
-public:
-    ALSAControl(const char *device = "/dev/snd/controlC0");
-    virtual                ~ALSAControl();
-
-    status_t                get(const char *name, unsigned int &value, int index = 0);
-    status_t                set(const char *name, unsigned int value, int index = -1);
-    status_t                set(const char *name, const char *);
-    status_t                setext(const char *name, int count, char **setValues);
-
-private:
-    struct mixer*             mHandle;
-};
-
 class ALSAStreamOps
 {
 public:
@@ -337,11 +455,155 @@
 
 private:
     uint32_t            mFrameCount;
+    uint32_t            mUseCase;
 
 protected:
     AudioHardwareALSA *     mParent;
 };
 
+// ----------------------------------------------------------------------------
+
+class AudioSessionOutALSA : public AudioStreamOut
+{
+public:
+    AudioSessionOutALSA(AudioHardwareALSA *parent,
+                        uint32_t   devices,
+                        int        format,
+                        uint32_t   channels,
+                        uint32_t   samplingRate,
+                        int        type,
+                        status_t   *status);
+    virtual            ~AudioSessionOutALSA();
+
+    virtual uint32_t    sampleRate() const
+    {
+        return mSampleRate;
+    }
+
+    virtual size_t      bufferSize() const
+    {
+        return mBufferSize;
+    }
+
+    virtual uint32_t    channels() const
+    {
+        return mChannels;
+    }
+
+    virtual int         format() const
+    {
+        return mFormat;
+    }
+
+    virtual uint32_t    latency() const;
+
+    virtual ssize_t     write(const void *buffer, size_t bytes);
+
+    virtual status_t    start();
+    virtual status_t    pause();
+    virtual status_t    flush();
+    virtual status_t    stop();
+
+    virtual status_t    dump(int fd, const Vector<String16>& args);
+
+    status_t            setVolume(float left, float right);
+
+    virtual status_t    standby();
+
+    virtual status_t    setParameters(const String8& keyValuePairs);
+
+    virtual String8     getParameters(const String8& keys);
+
+
+    // return the number of audio frames written by the audio dsp to DAC since
+    // the output has exited standby
+    virtual status_t    getRenderPosition(uint32_t *dspFrames);
+
+    virtual status_t    getNextWriteTimestamp(int64_t *timestamp);
+
+    virtual status_t    setObserver(void *observer);
+
+    virtual status_t    getBufferInfo(buf_info **buf);
+    virtual status_t    isBufferAvailable(int *isAvail);
+    status_t            pause_l();
+    status_t            resume_l();
+
+    void updateMetaData(size_t bytes);
+
+private:
+    Mutex               mLock;
+    uint32_t            mFrameCount;
+    uint32_t            mSampleRate;
+    uint32_t            mChannels;
+    size_t              mBufferSize;
+    int                 mFormat;
+    uint32_t            mStreamVol;
+
+    bool                mPaused;
+    bool                mSeeking;
+    bool                mReachedEOS;
+    bool                mSkipWrite;
+    bool                mEosEventReceived;
+    AudioHardwareALSA  *mParent;
+    alsa_handle_t *     mAlsaHandle;
+    ALSADevice *     mAlsaDevice;
+    snd_use_case_mgr_t *mUcMgr;
+    AudioEventObserver *mObserver;
+    output_metadata_handle_t mOutputMetadataTunnel;
+    uint32_t            mOutputMetadataLength;
+    uint32_t            mUseCase;
+    status_t            openDevice(char *pUseCase, bool bIsUseCase, int devices);
+
+    status_t            closeDevice(alsa_handle_t *pDevice);
+    void                createEventThread();
+    void                bufferAlloc(alsa_handle_t *handle);
+    void                bufferDeAlloc();
+    bool                isReadyToPostEOS(int errPoll, void *fd);
+    status_t            drain();
+    status_t            openAudioSessionDevice(int type, int devices);
+    // make sure the event thread also exited
+    void                requestAndWaitForEventThreadExit();
+    int32_t             writeToDriver(char *buffer, int bytes);
+    static void *       eventThreadWrapper(void *me);
+    void                eventThreadEntry();
+    void                reset();
+
+    //Structure to hold mem buffer information
+    class BuffersAllocated {
+    public:
+        BuffersAllocated(void *buf1, int32_t nSize) :
+        memBuf(buf1), memBufsize(nSize), bytesToWrite(0)
+        {}
+        void* memBuf;
+        int32_t memBufsize;
+        uint32_t bytesToWrite;
+    };
+    List<BuffersAllocated> mEmptyQueue;
+    List<BuffersAllocated> mFilledQueue;
+    List<BuffersAllocated> mBufPool;
+
+    //Declare all the threads
+    pthread_t mEventThread;
+
+    //Declare the condition Variables and Mutex
+    Mutex mEmptyQueueMutex;
+    Mutex mFilledQueueMutex;
+
+    Condition mWriteCv;
+    Condition mEventCv;
+    bool mKillEventThread;
+    bool mEventThreadAlive;
+    int mInputBufferSize;
+    int mInputBufferCount;
+
+    //event fd to signal the EOS and Kill from the userspace
+    int mEfd;
+
+public:
+    bool mRouteAudioToA2dp;
+};
+
+
 class AudioStreamInALSA : public AudioStreamIn, public ALSAStreamOps
 {
 public:
@@ -414,14 +676,14 @@
 private:
     void                resetFramesLost();
 
-#ifdef QCOM_CSDCLIENT_ENABLED
-    int                 start_csd_record(int);
-    int                 stop_csd_record(void);
-#endif
-
     unsigned int        mFramesLost;
     AudioSystem::audio_in_acoustics mAcoustics;
 
+#ifdef QCOM_CSDCLIENT_ENABLED
+    int start_csd_record(int param);
+    int stop_csd_record();
+#endif
+
 #ifdef QCOM_SSR_ENABLED
     // Function to read coefficients from files.
     status_t            readCoeffsFromFile();
@@ -485,22 +747,12 @@
     // parameters is not supported
     virtual size_t    getInputBufferSize(uint32_t sampleRate, int format, int channels);
 
-#ifdef QCOM_TUNNEL_LPA_ENABLED
-    /** This method creates and opens the audio hardware output
-      *  session for LPA */
-    virtual AudioStreamOut* openOutputSession(
-            uint32_t devices,
-            int *format,
-            status_t *status,
-            int sessionId,
-            uint32_t samplingRate=0,
-            uint32_t channels=0);
-    virtual void closeOutputSession(AudioStreamOut* out);
-#endif
-
     /** This method creates and opens the audio hardware output stream */
     virtual AudioStreamOut* openOutputStream(
             uint32_t devices,
+#ifdef QCOM_OUTPUT_FLAGS_ENABLED
+            audio_output_flags_t flags,
+#endif
             int *format=0,
             uint32_t *channels=0,
             uint32_t *sampleRate=0,
@@ -517,6 +769,14 @@
             AudioSystem::audio_in_acoustics acoustics);
     virtual    void        closeInputStream(AudioStreamIn* in);
 
+    status_t    startA2dpPlayback(uint32_t activeUsecase);
+    status_t    stopA2dpPlayback(uint32_t activeUsecase);
+    bool        suspendA2dpPlayback(uint32_t activeUsecase);
+
+    status_t    startA2dpPlayback_l(uint32_t activeUsecase);
+    status_t    stopA2dpPlayback_l(uint32_t activeUsecase);
+    bool        suspendA2dpPlayback_l(uint32_t activeUsecase);
+
     /**This method dumps the state of the audio hardware */
     //virtual status_t dumpState(int fd, const Vector<String16>& args);
 
@@ -527,10 +787,24 @@
         return mMode;
     }
 
+    void pauseIfUseCaseTunnelOrLPA();
+    void resumeIfUseCaseTunnelOrLPA();
+
+private:
+    status_t     openA2dpOutput();
+    status_t     closeA2dpOutput();
+    status_t     stopA2dpThread();
+    void       a2dpThreadFunc();
+    static void*        a2dpThreadWrapper(void *context);
+    void        setA2DPActiveUseCases_l(uint32_t activeUsecase);
+    uint32_t    getA2DPActiveUseCases_l();
+    void        clearA2DPActiveUseCases_l(uint32_t activeUsecase);
+    uint32_t    useCaseStringToEnum(const char *usecase);
+
 protected:
     virtual status_t    dump(int fd, const Vector<String16>& args);
     virtual uint32_t    getVoipMode(int format);
-    void                doRouting(int device);
+    status_t            doRouting(int device);
 #ifdef QCOM_FM_ENABLED
     void                handleFm(int device);
 #endif
@@ -542,16 +816,19 @@
     void                startUsbPlaybackIfNotStarted();
     void                startUsbRecordingIfNotStarted();
 #endif
+    void                setInChannels(int device);
 
     void                disableVoiceCall(char* verb, char* modifier, int mode, int device);
     void                enableVoiceCall(char* verb, char* modifier, int mode, int device);
     bool                routeVoiceCall(int device, int	newMode);
     bool                routeVoLTECall(int device, int newMode);
+    bool                routeSGLTECall(int device, int newMode);
+    friend class AudioSessionOutALSA;
     friend class AudioStreamOutALSA;
     friend class AudioStreamInALSA;
     friend class ALSAStreamOps;
 
-    alsa_device_t *     mALSADevice;
+    ALSADevice*     mALSADevice;
 
     ALSAHandleList      mDeviceList;
 
@@ -563,17 +840,19 @@
 
     snd_use_case_mgr_t *mUcMgr;
 
-    uint32_t            mCurDevice;
+    int32_t            mCurDevice;
     /* The flag holds all the audio related device settings from
      * Settings and Qualcomm Settings applications */
     uint32_t            mDevSettingsFlag;
     uint32_t            mVoipStreamCount;
+    bool                mVoipMicMute;
     uint32_t            mVoipBitRate;
     uint32_t            mIncallMode;
 
     bool                mMicMute;
     int mCSCallActive;
     int mVolteCallActive;
+    int mSGLTECallActive;
     int mCallState;
     int mIsFmActive;
     bool mBluetoothVGS;
@@ -582,8 +861,33 @@
     int musbPlaybackState;
     int musbRecordingState;
 #endif
+    bool mIsVoicePathActive;
+
     void *mAcdbHandle;
     void *mCsdHandle;
+    //A2DP variables
+    audio_stream_out   *mA2dpStream;
+    audio_hw_device_t  *mA2dpDevice;
+
+    bool                mKillA2DPThread;
+    bool                mA2dpThreadAlive;
+    pthread_t           mA2dpThread;
+    Mutex               mA2dpMutex;
+    Condition           mA2dpCv;
+    volatile bool       mIsA2DPEnabled;
+
+    enum {
+      USECASE_NONE = 0x0,
+      USECASE_HIFI = 0x1,
+      USECASE_HIFI_LOWLATENCY = 0x2,
+      USECASE_HIFI_LOW_POWER = 0x4,
+      USECASE_HIFI_TUNNEL = 0x8,
+      USECASE_FM = 0x10,
+    };
+    uint32_t mA2DPActiveUseCases;
+
+public:
+    bool mRouteAudioToA2dp;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/alsa_sound/AudioPolicyManagerALSA.cpp b/alsa_sound/AudioPolicyManagerALSA.cpp
old mode 100644
new mode 100755
index 98f8203..3345cb9
--- a/alsa_sound/AudioPolicyManagerALSA.cpp
+++ b/alsa_sound/AudioPolicyManagerALSA.cpp
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2009 The Android Open Source Project
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, 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.
@@ -17,11 +17,29 @@
 
 #define LOG_TAG "AudioPolicyManagerALSA"
 //#define LOG_NDEBUG 0
-#define LOG_NDDEBUG 0
-#include <utils/Log.h>
+//#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
+
+#include <utils/Log.h>
 #include "AudioPolicyManagerALSA.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>
+
+#define MAX_POLL_VOICE_SETUP 20
 
 namespace android_audio_legacy {
 
@@ -29,11 +47,1201 @@
 // AudioPolicyManagerALSA
 // ----------------------------------------------------------------------------
 
-//Compiling error seen (only) on mako-pdk project if AudioParamer doesn't exist in this file
-//No issue is seen on QCOM jb-mailine if remvong this line
-//AudioParameter param;
+AudioParameter param;
 
-// ---  class factory
+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 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 (!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 (mHasUsb && 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 (mHasUsb && audio_is_usb_device(device)) {
+                // handle USB device disconnection
+                mUsbCardAndDevice = "";
+            }
+            // 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) ||
+                        (mOutputs.valueFor(outputs[i])->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
+                    closeOutput(outputs[i]);
+                }
+            }
+        }
+
+        updateDevicesAndOutputs();
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+        if (state == AudioSystem::DEVICE_STATE_AVAILABLE &&
+            (mAvailableOutputDevices & AUDIO_DEVICE_OUT_PROXY) &&
+            audio_is_a2dp_device(device) ) {
+            ALOGV("Delay the proxy device open");
+            return NO_ERROR;
+        }
+#endif
+
+#ifdef QCOM_FM_ENABLED
+        audio_devices_t newDevice = AudioPolicyManagerBase::getNewDevice(mPrimaryOutput, false /*fromCache*/);
+        if(device == AUDIO_DEVICE_OUT_FM) {
+            if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
+                ALOGV("setDeviceConnectionState() changeRefCount Inc");
+                mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::FM, 1);
+            }
+            else {
+                ALOGV("setDeviceConnectionState() changeRefCount Dec");
+                mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::FM, -1);
+            }
+            if(newDevice == 0){
+                newDevice = getDeviceForStrategy(STRATEGY_MEDIA, false);
+            }
+            AudioParameter param = AudioParameter();
+            param.addInt(String8(AudioParameter::keyHandleFm), (int)newDevice);
+            ALOGV("setDeviceConnectionState() setParameters handle_fm");
+            mpClientInterface->setParameters(mPrimaryOutput, param.toString());
+        }
+#endif
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+#ifdef QCOM_ANC_HEADSET_ENABLED
+            audio_devices_t newDevice = getNewDevice(mOutputs.keyAt(i), true /*fromCache*/);
+            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) &&
+                (!mHasUsb || (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();
+    }
+
+    // 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);
+    }
+
+    if (isStateInCall(state)) {
+
+        if(!isStateInCall(oldState)) {
+            audio_io_handle_t activeInput = getActiveInput();
+
+            /* Block the policy manager until voice path is setup. This is
+             * done to prevent telephony from signaling call connect before the
+             * entire voice path is established.
+             */
+            for (int i = 0; i < MAX_POLL_VOICE_SETUP; i++) {
+                usleep(100000);
+                String8 voiceActive = mpClientInterface->getParameters(activeInput,
+                                             String8("voice_path_active"));
+
+                if (!voiceActive.compare(String8("voice_path_active=true"))) {
+                    ALOGV("setPhoneState: Voice path is active");
+                    break;
+                } else {
+                    ALOGV("setPhoneState: voice path is not active");
+                }
+            }
+        }
+
+        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) {
+                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*/));
+            }
+        }
+    }
+
+    // change routing is necessary
+    setOutputDevice(mPrimaryOutput, newDevice, force, delayMs);
+
+    // 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);
+        // 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);
+        }
+    }
+
+    // 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 (size_t i = 0; i < mOutputs.size(); i++) {
+        audio_io_handle_t output = mOutputs.keyAt(i);
+        audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/);
+        setOutputDevice(output, newDevice, (newDevice != 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());
+        }
+    }
+
+}
+
+
+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.
+                if (shouldWait && (desc->refCount() != 0) && (waitMs < desc->latency())) {
+                    waitMs = desc->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);
+        }
+    }
+    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();
+            audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+            // delay the device switch by twice the latency because stopOutput() is executed when
+            // the track stop() command is received and at that time the audio track buffer can
+            // still contain data that needs to be drained. The latency only covers the audio HAL
+            // and kernel buffers. Also the latency does not always include additional delay in the
+            // audio path (audio DSP, CODEC ...)
+            setOutputDevice(output, newDevice, false, outputDesc->mLatency*2);
+
+            // force restoring the device selection on other active outputs if it differs from the
+            // one being selected for this output
+            for (size_t i = 0; i < mOutputs.size(); i++) {
+                audio_io_handle_t curOutput = mOutputs.keyAt(i);
+                AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+                if (curOutput != output &&
+                        desc->refCount() != 0 &&
+                        outputDesc->sharesHwModuleWith(desc) &&
+                        newDevice != desc->device()) {
+                    setOutputDevice(curOutput,
+                                    getNewDevice(curOutput, false /*fromCache*/),
+                                    true,
+                                    outputDesc->mLatency*2);
+                }
+            }
+            // update the outputs if stopping one with a stream that can affect notification routing
+            handleNotificationRoutingForStream(stream);
+        }
+        return NO_ERROR;
+    } else {
+        ALOGW("stopOutput() refcount is already 0 for output %d", output);
+        return INVALID_OPERATION;
+    }
+}
+
+status_t AudioPolicyManager::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;
+        }
+    }
+
+    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);
+
+    mpClientInterface->setParameters(input, param.toString());
+
+    inputDesc->mRefCount = 1;
+    return NO_ERROR;
+}
+
+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 (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() &&
+                    (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;
+        }
+#ifdef QCOM_FM_ENABLED
+        if (mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM) {
+            device |= 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) {
+                // no sonification on remote submix (e.g. WFD)
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+            }
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+            //handle proxy device begin
+            if ((device2 == AUDIO_DEVICE_NONE) ||
+                (device2 == AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_PROXY;
+                if(device2 != 0) {
+                    ALOGV("getDeviceForStrategy() STRATEGY_MEDIA use DEVICE_OUT_PROXY:%x",device2);
+                    // No combo device allowed with proxy device
+                    device = 0;
+                }
+            }
+#endif
+            if ((device2 == AUDIO_DEVICE_NONE) &&
+                    (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+                    !mA2dpSuspended) {
+                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) &&
+                    (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_ANALOG_DOCK)) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+            }
+            if (device2 == AUDIO_DEVICE_NONE) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+            }
+#ifdef QCOM_FM_ENABLED
+            if (device2 == AUDIO_DEVICE_NONE) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM_TX;
+            }
+#endif
+
+            // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
+            // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
+            device |= device2;
+            if (device) break;
+            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;
+        }
+
+#ifdef QCOM_FM_ENABLED
+        if (mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM) {
+            device |= AUDIO_DEVICE_OUT_FM;
+        }
+#endif
+
+        } 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;
+    }
+    // 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;
+    }
+
+    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);
+
+#ifdef QCOM_FM_ENABLED
+    //if changing from a combined headset + speaker + FM  route, unmute media streams
+    if (mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM)
+        muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+#endif
+
+    return muteWaitMs;
+}
+
+audio_devices_t AudioPolicyManager::getDeviceForInputSource(int inputSource)
+{
+    uint32_t device = AUDIO_DEVICE_NONE;
+
+    switch(inputSource) {
+    case AUDIO_SOURCE_DEFAULT:
+    case AUDIO_SOURCE_MIC:
+    case AUDIO_SOURCE_VOICE_RECOGNITION:
+    case AUDIO_SOURCE_VOICE_COMMUNICATION:
+        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_CAMCORDER:
+        if (mAvailableInputDevices & AUDIO_DEVICE_IN_BACK_MIC) {
+            device = AUDIO_DEVICE_IN_BACK_MIC;
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            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) {
+            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;
+#ifdef QCOM_FM_ENABLED
+   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;
+}
+
+
+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) {
+            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;
+    }
+}
+
 
 
 extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
@@ -46,4 +1254,5 @@
     delete interface;
 }
 
-}; // namespace androidi_audio_legacy
+
+}; // namespace android
diff --git a/alsa_sound/AudioPolicyManagerALSA.h b/alsa_sound/AudioPolicyManagerALSA.h
index 2a7dfdb..af3cef6 100644
--- a/alsa_sound/AudioPolicyManagerALSA.h
+++ b/alsa_sound/AudioPolicyManagerALSA.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2009 The Android Open Source Project
- * Copyright (C) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, 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.
@@ -37,5 +37,65 @@
 
         virtual ~AudioPolicyManager() {}
 
+        // AudioPolicyInterface
+        virtual status_t setDeviceConnectionState(audio_devices_t device,
+                                                          AudioSystem::device_connection_state state,
+                                                          const char *device_address);
+        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 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);
+
+        // indicates to the audio policy manager that the input starts being used.
+        virtual status_t startInput(audio_io_handle_t input);
+        // 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);
+
+        // 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();
+
+protected:
+
+        // 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);
 };
 };
diff --git a/alsa_sound/AudioSessionOut.cpp b/alsa_sound/AudioSessionOut.cpp
new file mode 100644
index 0000000..b37f7a0
--- /dev/null
+++ b/alsa_sound/AudioSessionOut.cpp
@@ -0,0 +1,895 @@
+/* AudioSessionOutALSA.cpp
+ **
+ ** Copyright 2008-2009 Wind River Systems
+ ** Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ **
+ ** 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 <errno.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <math.h>
+
+#define LOG_TAG "AudioSessionOutALSA"
+#define LOG_NDEBUG 0
+#define LOG_NDDEBUG 0
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <cutils/properties.h>
+#include <media/AudioRecord.h>
+#include <hardware_legacy/power.h>
+
+#include <linux/ioctl.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <pthread.h>
+#include <sys/poll.h>
+#include <sys/eventfd.h>
+#include <linux/unistd.h>
+
+#include "AudioHardwareALSA.h"
+
+namespace sys_write {
+    ssize_t lib_write(int fd, const void *buf, size_t count) {
+        return write(fd, buf, count);
+    }
+};
+namespace android_audio_legacy
+{
+#define LPA_MODE 0
+#define TUNNEL_MODE 1
+#define NUM_FDS 2
+#define KILL_EVENT_THREAD 1
+#define BUFFER_COUNT 4
+#define LPA_BUFFER_SIZE 256*1024
+#define TUNNEL_BUFFER_SIZE 600*1024
+#define MONO_CHANNEL_MODE 1
+// ----------------------------------------------------------------------------
+
+AudioSessionOutALSA::AudioSessionOutALSA(AudioHardwareALSA *parent,
+                                         uint32_t   devices,
+                                         int        format,
+                                         uint32_t   channels,
+                                         uint32_t   samplingRate,
+                                         int        type,
+                                         status_t   *status)
+{
+
+    alsa_handle_t alsa_handle;
+    char *use_case;
+    bool bIsUseCaseSet = false;
+
+    Mutex::Autolock autoLock(mLock);
+    // Default initilization
+    mParent             = parent;
+    mAlsaDevice         = mParent->mALSADevice;
+    mUcMgr              = mParent->mUcMgr;
+    mFormat             = format;
+    mSampleRate         = samplingRate;
+    mChannels           = channels;
+
+
+    mBufferSize         = 0;
+    *status             = BAD_VALUE;
+
+    mPaused             = false;
+    mSeeking            = false;
+    mReachedEOS         = false;
+    mSkipWrite          = false;
+
+    mAlsaHandle         = NULL;
+    mUseCase            = AudioHardwareALSA::USECASE_NONE;
+
+    mInputBufferSize    = type ? TUNNEL_BUFFER_SIZE : LPA_BUFFER_SIZE;
+    mInputBufferCount   = BUFFER_COUNT;
+    mEfd = -1;
+    mEosEventReceived   = false;
+    mEventThread        = NULL;
+    mEventThreadAlive   = false;
+    mKillEventThread    = false;
+    mObserver           = NULL;
+    mOutputMetadataLength = 0;
+
+    if(devices == 0) {
+        ALOGE("No output device specified");
+        return;
+    }
+    if((format == AUDIO_FORMAT_PCM_16_BIT) && (channels == 0 || channels > 6)) {
+        ALOGE("Invalid number of channels %d", channels);
+        return;
+    }
+
+    if(devices & AudioSystem::DEVICE_OUT_ALL_A2DP) {
+        ALOGV("Set Capture from proxy true");
+        mParent->mRouteAudioToA2dp = true;
+    }
+
+    //open device based on the type (LPA or Tunnel) and devices
+    //TODO: Check format type for linear vs non-linear to determine LPA/Tunnel
+    openAudioSessionDevice(type, devices);
+
+    //Creates the event thread to poll events from LPA/Compress Driver
+    createEventThread();
+
+    ALOGV("mParent->mRouteAudioToA2dp = %d", mParent->mRouteAudioToA2dp);
+    if (mParent->mRouteAudioToA2dp) {
+        status_t err = NO_ERROR;
+        mUseCase = mParent->useCaseStringToEnum(mAlsaHandle->useCase);
+        err = mParent->startA2dpPlayback_l(mUseCase);
+        *status = err;
+    }
+
+    *status = NO_ERROR;
+}
+
+AudioSessionOutALSA::~AudioSessionOutALSA()
+{
+    ALOGD("~AudioSessionOutALSA");
+
+    mSkipWrite = true;
+    mWriteCv.signal();
+    if (mParent->mRouteAudioToA2dp) {
+         status_t err = mParent->stopA2dpPlayback(mUseCase);
+         if(err){
+             ALOGE("stopA2dpPlayback return err  %d", err);
+         }
+    }
+    //TODO: This might need to be Locked using Parent lock
+    reset();
+}
+
+status_t AudioSessionOutALSA::setVolume(float left, float right)
+{
+    Mutex::Autolock autoLock(mLock);
+    float volume;
+    status_t status = NO_ERROR;
+
+    volume = (left + right) / 2;
+    if (volume < 0.0) {
+        ALOGW("AudioSessionOutALSA::setVolume(%f) under 0.0, assuming 0.0\n", volume);
+        volume = 0.0;
+    } else if (volume > 1.0) {
+        ALOGW("AudioSessionOutALSA::setVolume(%f) over 1.0, assuming 1.0\n", volume);
+        volume = 1.0;
+    }
+    mStreamVol = lrint((volume * 0x2000)+0.5);
+
+    ALOGV("Setting stream volume to %d (available range is 0 to 0x2000)\n", mStreamVol);
+    if(mAlsaHandle) {
+        if(!strcmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER) ||
+           !strcmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) {
+            ALOGD("setLpaVolume(%u)\n", mStreamVol);
+            ALOGD("Setting LPA volume to %d (available range is 0 to 100)\n", mStreamVol);
+            mAlsaHandle->module->setLpaVolume(mStreamVol);
+            return status;
+        }
+        else if(!strcmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL) ||
+                !strcmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL)) {
+            ALOGD("setCompressedVolume(%u)\n", mStreamVol);
+            ALOGD("Setting Compressed volume to %d (available range is 0 to 100)\n", mStreamVol);
+            mAlsaHandle->module->setCompressedVolume(mStreamVol);
+            return status;
+        }
+    }
+    return INVALID_OPERATION;
+}
+
+
+status_t AudioSessionOutALSA::openAudioSessionDevice(int type, int devices)
+{
+    char* use_case;
+    status_t status = NO_ERROR;
+    //1.) Based on the current device and session type (LPA/Tunnel), open a device
+    //    with verb or modifier
+    snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
+    if (type == LPA_MODE) {
+        if ((use_case == NULL) || (!strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
+                                            strlen(SND_USE_CASE_VERB_INACTIVE)))) {
+            status = openDevice(SND_USE_CASE_VERB_HIFI_LOW_POWER, true, devices);
+        } else {
+            status = openDevice(SND_USE_CASE_MOD_PLAY_LPA, false, devices);
+        }
+    } else if (type == TUNNEL_MODE) {
+        if ((use_case == NULL) || (!strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
+                                            strlen(SND_USE_CASE_VERB_INACTIVE)))) {
+            status = openDevice(SND_USE_CASE_VERB_HIFI_TUNNEL, true, devices);
+        } else {
+            status = openDevice(SND_USE_CASE_MOD_PLAY_TUNNEL, false, devices);
+        }
+        mOutputMetadataLength = sizeof(output_metadata_handle_t);
+        ALOGD("openAudioSessionDevice - mOutputMetadataLength = %d", mOutputMetadataLength);
+    }
+    if(use_case) {
+        free(use_case);
+        use_case = NULL;
+    }
+    if(status != NO_ERROR) {
+        return status;
+    }
+
+    //2.) Get the device handle
+    ALSAHandleList::iterator it = mParent->mDeviceList.end();
+    it--;
+
+    mAlsaHandle = &(*it);
+    ALOGV("mAlsaHandle %p, mAlsaHandle->useCase %s",mAlsaHandle, mAlsaHandle->useCase);
+
+    //3.) mmap the buffers for playback
+    status_t err = mmap_buffer(mAlsaHandle->handle);
+    if(err) {
+        ALOGE("MMAP buffer failed - playback err = %d", err);
+        return err;
+    }
+    ALOGV("buffer pointer %p ", mAlsaHandle->handle->addr);
+
+    //4.) prepare the driver for playback and allocate the buffers
+    status = pcm_prepare(mAlsaHandle->handle);
+    if (status) {
+        ALOGE("PCM Prepare failed - playback err = %d", err);
+        return status;
+    }
+    bufferAlloc(mAlsaHandle);
+    mBufferSize = mAlsaHandle->periodSize;
+    return NO_ERROR;
+}
+
+ssize_t AudioSessionOutALSA::write(const void *buffer, size_t bytes)
+{
+    Mutex::Autolock autoLock(mLock);
+    int err;
+    ALOGV("write Empty Queue size() = %d, Filled Queue size() = %d ",
+         mEmptyQueue.size(),mFilledQueue.size());
+
+    if(mFilledQueue.empty() && !bytes) {
+        mReachedEOS = true;
+        mEosEventReceived = true;
+        ALOGV("mObserver: posting EOS");
+        mObserver->postEOS(0);
+    }
+
+    //1.) Dequeue the buffer from empty buffer queue. Copy the data to be
+    //    written into the buffer. Then Enqueue the buffer to the filled
+    //    buffer queue
+    mEmptyQueueMutex.lock();
+    List<BuffersAllocated>::iterator it = mEmptyQueue.begin();
+    BuffersAllocated buf = *it;
+    if(bytes)
+        mEmptyQueue.erase(it);
+    mEmptyQueueMutex.unlock();
+
+    memset(buf.memBuf, 0, mAlsaHandle->handle->period_size);
+    if((!strncmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
+            strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) ||
+            (!strncmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
+            strlen(SND_USE_CASE_MOD_PLAY_TUNNEL)))) {
+        updateMetaData(bytes);
+
+        memcpy(buf.memBuf, &mOutputMetadataTunnel, mOutputMetadataLength);
+        ALOGD("Copy Metadata = %d, bytes = %d", mOutputMetadataLength, bytes);
+
+        if(bytes == 0) {
+          err = pcm_write(mAlsaHandle->handle, buf.memBuf, mAlsaHandle->handle->period_size);
+          buf.bytesToWrite = bytes;
+          return err;
+        }
+    }
+    memcpy((buf.memBuf + mOutputMetadataLength), buffer, bytes);
+    buf.bytesToWrite = bytes;
+
+    //2.) Write the buffer to the Driver
+    ALOGV("PCM write start");
+    err = pcm_write(mAlsaHandle->handle, buf.memBuf, mAlsaHandle->handle->period_size);
+    ALOGV("PCM write complete");
+    if (bytes < (mAlsaHandle->handle->period_size - mOutputMetadataLength)) {
+        ALOGV("Last buffer case");
+        if ( ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_START) < 0 ) {
+            ALOGE("Audio Start failed");
+        } else {
+            mAlsaHandle->handle->start = 1;
+        }
+        mReachedEOS = true;
+    }
+
+    mFilledQueueMutex.lock();
+    mFilledQueue.push_back(buf);
+    mFilledQueueMutex.unlock();
+    return err;
+}
+
+void AudioSessionOutALSA::bufferAlloc(alsa_handle_t *handle) {
+    void  *mem_buf = NULL;
+    int i = 0;
+
+    int32_t nSize = mAlsaHandle->handle->period_size;
+    ALOGV("number of input buffers = %d", mInputBufferCount);
+    ALOGV("memBufferAlloc calling with required size %d", nSize);
+    for (i = 0; i < mInputBufferCount; i++) {
+        mem_buf = (int32_t *)mAlsaHandle->handle->addr + (nSize * i/sizeof(int));
+        ALOGV("Buffer pointer %p ", mem_buf);
+        BuffersAllocated buf(mem_buf, nSize);
+        memset(buf.memBuf, 0x0, nSize);
+        mEmptyQueue.push_back(buf);
+        mBufPool.push_back(buf);
+        ALOGV("The MEM that is allocated - buffer is %x",\
+            (unsigned int)mem_buf);
+    }
+}
+
+void AudioSessionOutALSA::bufferDeAlloc() {
+    while (!mBufPool.empty()) {
+        List<BuffersAllocated>::iterator it = mBufPool.begin();
+        ALOGV("Removing input buffer from Buffer Pool ");
+        mBufPool.erase(it);
+   }
+}
+
+void AudioSessionOutALSA::requestAndWaitForEventThreadExit() {
+    if (!mEventThreadAlive)
+        return;
+    mKillEventThread = true;
+    if(mEfd != -1) {
+        ALOGE("Writing to mEfd %d",mEfd);
+        uint64_t writeValue = KILL_EVENT_THREAD;
+        sys_write::lib_write(mEfd, &writeValue, sizeof(uint64_t));
+    }
+    pthread_join(mEventThread,NULL);
+    ALOGV("event thread killed");
+}
+
+void * AudioSessionOutALSA::eventThreadWrapper(void *me) {
+    static_cast<AudioSessionOutALSA *>(me)->eventThreadEntry();
+    return NULL;
+}
+
+void  AudioSessionOutALSA::eventThreadEntry() {
+    //1.) Initialize the variables required for polling events
+    int rc = 0;
+    int err_poll = 0;
+    int avail = 0;
+    int i = 0;
+    struct pollfd pfd[NUM_FDS];
+    int timeout = -1;
+
+    //2.) Set the priority for the event thread
+    pid_t tid  = gettid();
+    androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
+    prctl(PR_SET_NAME, (unsigned long)"HAL Audio EventThread", 0, 0, 0);
+
+    //3.) Allocate two FDs for polling.
+    //    1st FD: Polling on the Driver's timer_fd. This is used for getting write done
+    //            events from the driver
+    //    2nd FD: Polling on a local fd so we can interrup the event thread locally
+    //            when playback is stopped from Apps
+    //    The event thread will when a write is performed on one of these FDs
+    ALOGV("Allocating poll fd");
+    if(!mKillEventThread) {
+        pfd[0].fd = mAlsaHandle->handle->timer_fd;
+        pfd[0].events = (POLLIN | POLLERR | POLLNVAL);
+        mEfd = eventfd(0,0);
+        pfd[1].fd = mEfd;
+        pfd[1].events = (POLLIN | POLLERR | POLLNVAL);
+    }
+
+    //4.) Start a poll for write done events from driver.
+    while(!mKillEventThread && ((err_poll = poll(pfd, NUM_FDS, timeout)) >=0)) {
+        ALOGV("pfd[0].revents =%d ", pfd[0].revents);
+        ALOGV("pfd[1].revents =%d ", pfd[1].revents);
+        // Handle Poll errors
+        if (err_poll == EINTR)
+            ALOGE("Timer is intrrupted");
+        if ((pfd[1].revents & POLLERR) || (pfd[1].revents & POLLNVAL)) {
+            pfd[1].revents = 0;
+            ALOGE("POLLERR or INVALID POLL");
+        }
+
+        //POLLIN event on 2nd FD. Kill from event thread
+        if (pfd[1].revents & POLLIN) {
+            uint64_t u;
+            read(mEfd, &u, sizeof(uint64_t));
+            ALOGV("POLLIN event occured on the event fd, value written to %llu",
+                 (unsigned long long)u);
+            pfd[1].revents = 0;
+            if (u == KILL_EVENT_THREAD) {
+                continue;
+            }
+        }
+
+        //Poll error on Driver's timer fd
+        if((pfd[0].revents & POLLERR) || (pfd[0].revents & POLLNVAL)) {
+            pfd[0].revents = 0;
+            continue;
+        }
+
+        //Pollin event on Driver's timer fd
+        if (pfd[0].revents & POLLIN && !mKillEventThread) {
+            struct snd_timer_tread rbuf[4];
+            read(mAlsaHandle->handle->timer_fd, rbuf, sizeof(struct snd_timer_tread) * 4 );
+            pfd[0].revents = 0;
+            if (mPaused)
+                continue;
+            ALOGV("After an event occurs");
+
+            mFilledQueueMutex.lock();
+            if (mFilledQueue.empty()) {
+                ALOGV("Filled queue is empty");
+                mFilledQueueMutex.unlock();
+                continue;
+            }
+            // Transfer a buffer that was consumed by the driver from filled queue
+            // to empty queue
+
+            BuffersAllocated buf = *(mFilledQueue.begin());
+            mFilledQueue.erase(mFilledQueue.begin());
+            ALOGV("mFilledQueue %d", mFilledQueue.size());
+
+            //Post EOS in case the filled queue is empty and EOS is reached.
+            if (mFilledQueue.empty() && mReachedEOS) {
+                 mFilledQueueMutex.unlock();
+                 if (mObserver != NULL) {
+                     if((!strncmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
+                             strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) ||
+                             (!strncmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
+                             strlen(SND_USE_CASE_MOD_PLAY_TUNNEL)))) {
+                         ALOGD("Audio Drain DONE ++");
+                         if ( ioctl(mAlsaHandle->handle->fd, SNDRV_COMPRESS_DRAIN) < 0 ) {
+                             ALOGE("Audio Drain failed");
+                         }
+                         ALOGD("Audio Drain DONE --");
+                     }
+                     ALOGV("Posting the EOS to the observer player %p", mObserver);
+                     mEosEventReceived = true;
+                    if(mReachedEOS) {
+                        ALOGV("mObserver: posting EOS");
+                        mObserver->postEOS(0);
+                    }
+                }
+            }
+            mFilledQueueMutex.unlock();
+
+            mEmptyQueueMutex.lock();
+            mEmptyQueue.push_back(buf);
+            mEmptyQueueMutex.unlock();
+            mWriteCv.signal();
+        }
+    }
+
+    //5.) Close mEfd that was created
+    mEventThreadAlive = false;
+    if (mEfd != -1) {
+        close(mEfd);
+        mEfd = -1;
+    }
+    ALOGV("Event Thread is dying.");
+    return;
+
+}
+
+void AudioSessionOutALSA::createEventThread() {
+    ALOGV("Creating Event Thread");
+    mKillEventThread = false;
+    mEventThreadAlive = true;
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+    pthread_create(&mEventThread, &attr, eventThreadWrapper, this);
+    ALOGV("Event Thread created");
+}
+
+status_t AudioSessionOutALSA::start()
+{
+    Mutex::Autolock autoLock(mLock);
+    if (mPaused) {
+        status_t err = NO_ERROR;
+        if (mSeeking) {
+            drain();
+            mSeeking = false;
+        } else if (ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_PAUSE,0) < 0) {
+            ALOGE("Resume failed on use case %s", mAlsaHandle->useCase);
+            return UNKNOWN_ERROR;
+        }
+        mPaused = false;
+        if (mParent->mRouteAudioToA2dp) {
+            err = mParent->startA2dpPlayback_l(mUseCase);
+            if(err != NO_ERROR) {
+                ALOGE("start Proxy from start returned error = %d",err);
+                return err;
+            }
+        }
+    }
+    else {
+        //Signal the driver to start rendering data
+        if (ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_START)) {
+            ALOGE("start:SNDRV_PCM_IOCTL_START failed\n");
+            return UNKNOWN_ERROR;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::pause()
+{
+    Mutex::Autolock autoLock(mLock);
+    status_t err = NO_ERROR;
+    ALOGD("Pausing the driver");
+    //Signal the driver to pause rendering data
+    if (ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_PAUSE,1) < 0) {
+        ALOGE("PAUSE failed on use case %s", mAlsaHandle->useCase);
+        return UNKNOWN_ERROR;
+    }
+    mPaused = true;
+
+    if(err) {
+        ALOGE("pause returned error");
+        return err;
+    }
+    if (mParent->mRouteAudioToA2dp) {
+        err = mParent->suspendA2dpPlayback(mUseCase);
+        if(err != NO_ERROR) {
+            ALOGE("Suspend Proxy from Pause returned error = %d",err);
+            return err;
+        }
+    }
+    return err;
+
+}
+
+status_t AudioSessionOutALSA::pause_l()
+{
+    if (!mPaused) {
+        if (ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_PAUSE,1) < 0) {
+            ALOGE("PAUSE failed on use case %s", mAlsaHandle->useCase);
+            return UNKNOWN_ERROR;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::resume_l()
+{
+    status_t err = NO_ERROR;
+    if (!mPaused) {
+        if (ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_PAUSE,0) < 0) {
+            ALOGE("Resume failed on use case %s", mAlsaHandle->useCase);
+            return UNKNOWN_ERROR;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::drain()
+{
+    mAlsaHandle->handle->start = 0;
+    int err = pcm_prepare(mAlsaHandle->handle);
+    if(err != OK) {
+        ALOGE("pcm_prepare -seek = %d",err);
+        //Posting EOS
+        if (mObserver)
+            mObserver->postEOS(0);
+        return UNKNOWN_ERROR;
+    }
+
+    ALOGV("drain Empty Queue size() = %d, Filled Queue size() = %d ",
+         mEmptyQueue.size(), mFilledQueue.size());
+
+    mAlsaHandle->handle->sync_ptr->flags =
+        SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;
+    sync_ptr(mAlsaHandle->handle);
+    ALOGV("appl_ptr=%d",(int)mAlsaHandle->handle->sync_ptr->c.control.appl_ptr);
+    return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::flush()
+{
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("AudioSessionOutALSA flush");
+    int err;
+    {
+        Mutex::Autolock autoLockEmptyQueue(mEmptyQueueMutex);
+        Mutex::Autolock autoLockFilledQueue(mFilledQueueMutex);
+        // 1.) Clear the Empty and Filled buffer queue
+        mEmptyQueue.clear();
+        mFilledQueue.clear();
+
+        // 2.) Add all the available buffers to Request Queue (Maintain order)
+        List<BuffersAllocated>::iterator it = mBufPool.begin();
+        for (; it!=mBufPool.end(); ++it) {
+            memset(it->memBuf, 0x0, (*it).memBufsize);
+            mEmptyQueue.push_back(*it);
+        }
+    }
+
+    ALOGV("Transferred all the buffers from Filled queue to "
+          "Empty queue to handle seek");
+    mReachedEOS = false;
+    // 3.) If its in start state,
+    //          Pause and flush the driver and Resume it again
+    //    If its in paused state,
+    //          Set the seek flag, Resume will take care of flushing the
+    //          driver
+    if (!mPaused && !mEosEventReceived) {
+        if ((err = ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_PAUSE,1)) < 0) {
+            ALOGE("Audio Pause failed");
+            return UNKNOWN_ERROR;
+        }
+        //mReachedEOS = false;
+        if ((err = drain()) != OK)
+            return err;
+    } else {
+        mSeeking = true;
+    }
+
+    //4.) Skip the current write from the decoder and signal to the Write get
+    //   the next set of data from the decoder
+    mSkipWrite = true;
+    mWriteCv.signal();
+
+    ALOGV("AudioSessionOutALSA::flush completed");
+    return NO_ERROR;
+}
+
+
+
+status_t AudioSessionOutALSA::stop()
+{
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("AudioSessionOutALSA- stop");
+    // close all the existing PCM devices
+    mSkipWrite = true;
+    mWriteCv.signal();
+
+    if (mParent->mRouteAudioToA2dp) {
+        status_t err = mParent->suspendA2dpPlayback(mUseCase);
+        if(err) {
+            ALOGE("stop-suspendA2dpPlayback- return err = %d", err);
+            return err;
+        }
+    }
+
+    ALOGV("stop -");
+
+    return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::standby()
+{
+    Mutex::Autolock autoLock(mParent->mLock);
+    status_t err = NO_ERROR;
+    if (mParent->mRouteAudioToA2dp) {
+         ALOGD("Standby - stopA2dpPlayback_l - mUseCase = %d",mUseCase);
+         err = mParent->stopA2dpPlayback_l(mUseCase);
+         if(err){
+             ALOGE("stopA2dpPlayback return err  %d", err);
+         }
+    }
+    return err;
+}
+
+#define USEC_TO_MSEC(x) ((x + 999) / 1000)
+
+uint32_t AudioSessionOutALSA::latency() const
+{
+    // Android wants latency in milliseconds.
+    return USEC_TO_MSEC (mAlsaHandle->latency);
+}
+
+status_t AudioSessionOutALSA::setObserver(void *observer)
+{
+    ALOGV("Registering the callback \n");
+    mObserver = reinterpret_cast<AudioEventObserver *>(observer);
+    return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::dump(int fd, const Vector<String16>& args)
+{
+    return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::getNextWriteTimestamp(int64_t *timestamp)
+{
+    struct snd_compr_tstamp tstamp;
+    tstamp.timestamp = -1;
+    if (ioctl(mAlsaHandle->handle->fd, SNDRV_COMPRESS_TSTAMP, &tstamp)){
+        ALOGE("Failed SNDRV_COMPRESS_TSTAMP\n");
+        return UNKNOWN_ERROR;
+    } else {
+        ALOGV("Timestamp returned = %lld\n", tstamp.timestamp);
+        *timestamp = tstamp.timestamp;
+        return NO_ERROR;
+    }
+    return NO_ERROR;
+}
+
+// return the number of audio frames written by the audio dsp to DAC since
+// the output has exited standby
+status_t AudioSessionOutALSA::getRenderPosition(uint32_t *dspFrames)
+{
+    Mutex::Autolock autoLock(mLock);
+    *dspFrames = mFrameCount;
+    return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::getBufferInfo(buf_info **buf) {
+    if (!mAlsaHandle) {
+        return NO_ERROR;
+    }
+    buf_info *tempbuf = (buf_info *)malloc(sizeof(buf_info) + mInputBufferCount*sizeof(int *));
+    ALOGV("Get buffer info");
+    tempbuf->bufsize = mAlsaHandle->handle->period_size;
+    tempbuf->nBufs = mInputBufferCount;
+    tempbuf->buffers = (int **)((char*)tempbuf + sizeof(buf_info));
+    List<BuffersAllocated>::iterator it = mBufPool.begin();
+    for (int i = 0; i < mInputBufferCount; i++) {
+        tempbuf->buffers[i] = (int *)it->memBuf;
+        it++;
+    }
+    *buf = tempbuf;
+    return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::isBufferAvailable(int *isAvail) {
+
+    Mutex::Autolock autoLock(mLock);
+    ALOGV("isBufferAvailable Empty Queue size() = %d, Filled Queue size() = %d ",
+          mEmptyQueue.size(),mFilledQueue.size());
+    *isAvail = false;
+    // 1.) Wait till a empty buffer is available in the Empty buffer queue
+    mEmptyQueueMutex.lock();
+    if (mEmptyQueue.empty()) {
+        ALOGV("Write: waiting on mWriteCv");
+        mLock.unlock();
+        mWriteCv.wait(mEmptyQueueMutex);
+        mLock.lock();
+        if (mSkipWrite) {
+            ALOGV("Write: Flushing the previous write buffer");
+            mSkipWrite = false;
+            mEmptyQueueMutex.unlock();
+            return NO_ERROR;
+        }
+        ALOGV("isBufferAvailable: received a signal to wake up");
+    }
+    mEmptyQueueMutex.unlock();
+
+    *isAvail = true;
+    return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::openDevice(char *useCase, bool bIsUseCase, int devices)
+{
+    alsa_handle_t alsa_handle;
+    status_t status = NO_ERROR;
+    ALOGV("openDevice: E usecase %s", useCase);
+    alsa_handle.module      = mAlsaDevice;
+    alsa_handle.bufferSize  = mInputBufferSize;
+    alsa_handle.devices     = devices;
+    alsa_handle.handle      = 0;
+    alsa_handle.format      = (mFormat == AUDIO_FORMAT_PCM_16_BIT ? SNDRV_PCM_FORMAT_S16_LE : mFormat);
+    //ToDo: Add conversion from channel Mask to channel count.
+    if (mChannels == AUDIO_CHANNEL_OUT_MONO)
+        alsa_handle.channels = MONO_CHANNEL_MODE;
+    else
+        alsa_handle.channels = DEFAULT_CHANNEL_MODE;
+    alsa_handle.sampleRate  = mSampleRate;
+    alsa_handle.latency     = PLAYBACK_LATENCY;
+    alsa_handle.rxHandle    = 0;
+    alsa_handle.ucMgr       = mUcMgr;
+    alsa_handle.session     = this;
+    strlcpy(alsa_handle.useCase, useCase, sizeof(alsa_handle.useCase));
+
+    mAlsaDevice->route(&alsa_handle, devices, mParent->mode());
+    if (bIsUseCase) {
+        snd_use_case_set(mUcMgr, "_verb", useCase);
+    } else {
+        snd_use_case_set(mUcMgr, "_enamod", useCase);
+    }
+
+    status = mAlsaDevice->open(&alsa_handle);
+    if(status != NO_ERROR) {
+        ALOGE("Could not open the ALSA device for use case %s", alsa_handle.useCase);
+        mAlsaDevice->close(&alsa_handle);
+    } else{
+        mParent->mDeviceList.push_back(alsa_handle);
+    }
+    return status;
+}
+
+status_t AudioSessionOutALSA::closeDevice(alsa_handle_t *pHandle)
+{
+    status_t status = NO_ERROR;
+    ALOGV("closeDevice: useCase %s", pHandle->useCase);
+    //TODO: remove from mDeviceList
+    if(pHandle) {
+        status = mAlsaDevice->close(pHandle);
+    }
+    return status;
+}
+
+status_t AudioSessionOutALSA::setParameters(const String8& keyValuePairs)
+{
+    Mutex::Autolock autoLock(mLock);
+    AudioParameter param = AudioParameter(keyValuePairs);
+    String8 key = String8(AudioParameter::keyRouting);
+    int device;
+    if (param.getInt(key, device) == NO_ERROR) {
+        // Ignore routing if device is 0.
+        if(device) {
+            ALOGV("setParameters(): keyRouting with device %#x", device);
+            if(device & AudioSystem::DEVICE_OUT_ALL_A2DP) {
+                mParent->mRouteAudioToA2dp = true;
+                ALOGD("setParameters(): A2DP device %#x", device);
+            }
+            mParent->doRouting(device);
+        }
+        param.remove(key);
+    }
+    return NO_ERROR;
+}
+
+String8 AudioSessionOutALSA::getParameters(const String8& keys)
+{
+    Mutex::Autolock autoLock(mLock);
+    AudioParameter param = AudioParameter(keys);
+    String8 value;
+    String8 key = String8(AudioParameter::keyRouting);
+
+    if (param.get(key, value) == NO_ERROR) {
+        param.addInt(key, (int)mAlsaHandle->devices);
+    }
+
+    ALOGV("getParameters() %s", param.toString().string());
+    return param.toString();
+}
+
+void AudioSessionOutALSA::reset() {
+    mParent->mLock.lock();
+    requestAndWaitForEventThreadExit();
+
+    if(mAlsaHandle) {
+        ALOGV("closeDevice mAlsaHandle");
+        closeDevice(mAlsaHandle);
+        mAlsaHandle = NULL;
+    }
+    ALOGV("Erase device list");
+    for(ALSAHandleList::iterator it = mParent->mDeviceList.begin();
+            it != mParent->mDeviceList.end(); ++it) {
+        if((!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
+                            strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) ||
+           (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
+                            strlen(SND_USE_CASE_MOD_PLAY_TUNNEL))) ||
+           (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
+                            strlen(SND_USE_CASE_VERB_HIFI_LOW_POWER))) ||
+           (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA,
+                            strlen(SND_USE_CASE_MOD_PLAY_LPA)))) {
+            mParent->mDeviceList.erase(it);
+            break;
+        }
+    }
+    mParent->mLock.unlock();
+}
+void AudioSessionOutALSA::updateMetaData(size_t bytes) {
+    mOutputMetadataTunnel.metadataLength = sizeof(mOutputMetadataTunnel);
+    mOutputMetadataTunnel.timestamp = 0;
+    mOutputMetadataTunnel.bufferLength =  bytes;
+    ALOGD("bytes = %d , mAlsaHandle->handle->period_size = %d ",
+            bytes, mAlsaHandle->handle->period_size);
+}
+
+}       // namespace android_audio_legacy
diff --git a/alsa_sound/AudioStreamInALSA.cpp b/alsa_sound/AudioStreamInALSA.cpp
index 3b66c24..86fb532 100644
--- a/alsa_sound/AudioStreamInALSA.cpp
+++ b/alsa_sound/AudioStreamInALSA.cpp
@@ -1,7 +1,7 @@
 /* AudioStreamInALSA.cpp
  **
  ** Copyright 2008-2009 Wind River Systems
- ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ ** Copyright (c) 2012, 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.
@@ -41,7 +41,6 @@
 static int (*csd_start_record)(int);
 static int (*csd_stop_record)(void);
 #endif
-
 #ifdef QCOM_SSR_ENABLED
 #include "surround_filters_interface.h"
 #endif
@@ -69,8 +68,8 @@
         AudioSystem::audio_in_acoustics audio_acoustics) :
     ALSAStreamOps(parent, handle),
     mFramesLost(0),
-    mAcoustics(audio_acoustics),
-    mParent(parent)
+    mParent(parent),
+    mAcoustics(audio_acoustics)
 #ifdef QCOM_SSR_ENABLED
     , mFp_4ch(NULL),
     mFp_6ch(NULL),
@@ -90,7 +89,9 @@
     // Call surround sound library init if device is Surround Sound
     if ( handle->channels == 6) {
         if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
-            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
+            || !strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, strlen(SND_USE_CASE_VERB_HIFI_REC_COMPRESSED))
+            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))
+            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) {
 
             err = initSurroundSoundLibrary(handle->bufferSize);
             if ( NO_ERROR != err) {
@@ -125,13 +126,13 @@
 
 ssize_t AudioStreamInALSA::read(void *buffer, ssize_t bytes)
 {
-    int period_size;
+    unsigned int period_size;
 
     ALOGV("read:: buffer %p, bytes %d", buffer, bytes);
 
     int n;
     status_t          err;
-    ssize_t            read = 0;
+    size_t            read = 0;
     char *use_case;
     int newMode = mParent->mode();
 
@@ -142,10 +143,10 @@
         snd_use_case_get(mHandle->ucMgr, "_verb", (const char **)&use_case);
         if ((use_case != NULL) && (strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
             if ((mHandle->devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
-                (newMode == AudioSystem::MODE_IN_CALL)) {
+                (newMode == AUDIO_MODE_IN_CALL)) {
                 ALOGD("read:: mParent->mIncallMode=%d", mParent->mIncallMode);
-                if ((mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
-                    (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
+                if ((mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_UPLINK) &&
+                    (mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_DNLINK)) {
 #ifdef QCOM_CSDCLIENT_ENABLED
                     if (mParent->mFusion3Platform) {
                         mParent->mALSADevice->setVocRecMode(INCALL_REC_STEREO);
@@ -155,10 +156,15 @@
                     } else
 #endif
                     {
-                        strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
-                                sizeof(mHandle->useCase));
+                        if (mHandle->format == AUDIO_FORMAT_AMR_WB) {
+                            strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL,
+                                    sizeof(mHandle->useCase));
+                        } else {
+                            strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
+                                    sizeof(mHandle->useCase));
+                        }
                     }
-                } else if (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
+                } else if (mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_DNLINK) {
 #ifdef QCOM_CSDCLIENT_ENABLED
                     if (mParent->mFusion3Platform) {
                         mParent->mALSADevice->setVocRecMode(INCALL_REC_MONO);
@@ -168,8 +174,13 @@
                     } else
 #endif
                     {
-                        strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
-                                sizeof(mHandle->useCase));
+                        if (mHandle->format == AUDIO_FORMAT_AMR_WB) {
+                            strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL,
+                                    sizeof(mHandle->useCase));
+                        } else {
+                            strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
+                                    sizeof(mHandle->useCase));
+                        }
                     }
                 }
 #ifdef QCOM_FM_ENABLED
@@ -181,20 +192,22 @@
             } else if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)) {
                 strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, sizeof(mHandle->useCase));
             } else {
-                    char value[128];
-                    property_get("persist.audio.lowlatency.rec",value,"0");
-                    if (!strcmp("true", value)) {
-                        strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC, sizeof(mHandle->useCase));
-                    } else {
-                        strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, sizeof(mHandle->useCase));
-                    }
+                char value[128];
+                property_get("persist.audio.lowlatency.rec",value,"0");
+                if (!strcmp("true", value)) {
+                    strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC, sizeof(mHandle->useCase));
+                } else if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED)) {
+                    strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, sizeof(mHandle->useCase));
+                } else {
+                    strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, sizeof(mHandle->useCase));
+                }
             }
         } else {
             if ((mHandle->devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
-                (newMode == AudioSystem::MODE_IN_CALL)) {
+                (newMode == AUDIO_MODE_IN_CALL)) {
                 ALOGD("read:: ---- mParent->mIncallMode=%d", mParent->mIncallMode);
-                if ((mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
-                    (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
+                if ((mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_UPLINK) &&
+                    (mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_DNLINK)) {
 #ifdef QCOM_CSDCLIENT_ENABLED
                     if (mParent->mFusion3Platform) {
                         mParent->mALSADevice->setVocRecMode(INCALL_REC_STEREO);
@@ -204,10 +217,15 @@
                     } else
 #endif
                     {
-                        strlcpy(mHandle->useCase, SND_USE_CASE_VERB_UL_DL_REC,
-                                sizeof(mHandle->useCase));
+                        if (mHandle->format == AUDIO_FORMAT_AMR_WB) {
+                            strlcpy(mHandle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL,
+                                    sizeof(mHandle->useCase));
+                        } else {
+                            strlcpy(mHandle->useCase, SND_USE_CASE_VERB_UL_DL_REC,
+                                    sizeof(mHandle->useCase));
+                        }
                     }
-                } else if (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
+                } else if (mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_DNLINK) {
 #ifdef QCOM_CSDCLIENT_ENABLED
                    if (mParent->mFusion3Platform) {
                        mParent->mALSADevice->setVocRecMode(INCALL_REC_MONO);
@@ -217,8 +235,14 @@
                    } else
 #endif
                    {
-                       strlcpy(mHandle->useCase, SND_USE_CASE_VERB_DL_REC,
-                               sizeof(mHandle->useCase));
+                        if (mHandle->format == AUDIO_FORMAT_AMR_WB) {
+                            strlcpy(mHandle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL,
+                                    sizeof(mHandle->useCase));
+                        }
+                        else {
+                            strlcpy(mHandle->useCase, SND_USE_CASE_VERB_DL_REC,
+                                    sizeof(mHandle->useCase));
+                        }
                    }
                 }
 #ifdef QCOM_FM_ENABLED
@@ -229,14 +253,16 @@
 #endif
             } else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)){
                     strlcpy(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, sizeof(mHandle->useCase));
+            } else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)){
+                strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, sizeof(mHandle->useCase));
             } else {
-                    char value[128];
-                    property_get("persist.audio.lowlatency.rec",value,"0");
-                    if (!strcmp("true", value)) {
-                        strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC, sizeof(mHandle->useCase));
-                    } else {
-                        strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC, sizeof(mHandle->useCase));
-                    }
+                char value[128];
+                property_get("persist.audio.lowlatency.rec",value,"0");
+                if (!strcmp("true", value)) {
+                    strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC, sizeof(mHandle->useCase));
+                } else {
+                    strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC, sizeof(mHandle->useCase));
+                }
             }
         }
         free(use_case);
@@ -245,11 +271,11 @@
 #ifdef QCOM_USBAUDIO_ENABLED
             if((mDevices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) ||
                (mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)) {
-                mHandle->module->route(mHandle, (mDevices | AudioSystem::DEVICE_IN_PROXY) , AudioSystem::MODE_IN_COMMUNICATION);
+                mHandle->module->route(mHandle, (mDevices | AudioSystem::DEVICE_IN_PROXY) , AUDIO_MODE_IN_COMMUNICATION);
             }else
 #endif
             {
-                mHandle->module->route(mHandle, mDevices , AudioSystem::MODE_IN_COMMUNICATION);
+                mHandle->module->route(mHandle, mDevices , AUDIO_MODE_IN_COMMUNICATION);
             }
         } else {
 #ifdef QCOM_USBAUDIO_ENABLED
@@ -265,6 +291,7 @@
         }
         if (!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC) ||
             !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC) ||
+            !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED) ||
             !strcmp(mHandle->useCase, SND_USE_CASE_VERB_FM_REC) ||
             !strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL) ||
             !strcmp(mHandle->useCase, SND_USE_CASE_VERB_FM_A2DP_REC) ||
@@ -412,6 +439,39 @@
         buffer = buffer_start;
     } else
 #endif
+    if (mHandle->format == AUDIO_FORMAT_AMR_WB &&
+        (strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) &&
+        (strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
+        ALOGV("AUDIO_FORMAT_AMR_WB");
+        do {
+            if (read_pending < 61) {
+                read_pending = 61;
+            }
+            //We should pcm_read period_size to get complete data from driver
+            n = pcm_read(mHandle->handle, buffer, period_size);
+            if (n < 0) {
+                ALOGE("pcm_read() returned failure: %d", n);
+                return 0;
+            } else {
+                struct snd_compr_audio_info *header = (struct snd_compr_audio_info *) buffer;
+                if (header->frame_size > 0) {
+                    if (sizeof(*header) + header->reserved[0] + header->frame_size > period_size) {
+                        ALOGE("AMR WB read buffer overflow. Assign bigger buffer size");
+                        header->frame_size = period_size - sizeof(*header) - header->reserved[0];
+                    }
+                    read += header->frame_size;
+                    read_pending -= header->frame_size;
+                    ALOGV("buffer: %p, data offset: %p, header size: %u, reserved[0]: %u",
+                            buffer, ((uint8_t*)buffer) + sizeof(*header) + header->reserved[0],
+                            sizeof(*header), header->reserved[0]);
+                    memmove(buffer, ((uint8_t*)buffer) + sizeof(*header) + header->reserved[0], header->frame_size);
+                    buffer += header->frame_size;
+                } else {
+                    ALOGW("pcm_read() with zero frame size");
+                }
+            }
+        } while (mHandle->handle && read < bytes);
+    } else
     {
 
         do {
@@ -424,24 +484,24 @@
             ALOGV("pcm_read() returned n = %d", n);
             if (n && (n == -EIO || n == -EAGAIN || n == -EPIPE || n == -EBADFD)) {
                 mParent->mLock.lock();
-                ALOGW("pcm_read() returned error n %d, Recovering from error\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))) ||
-                (!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
-                    pcm_close(mHandle->rxHandle);
-                    mHandle->rxHandle = NULL;
-                    mHandle->module->startVoipCall(mHandle);
+                if (mHandle->handle != NULL) {
+                    ALOGW("pcm_read() returned error n %d, Recovering from error\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))) ||
+                    (!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
+                        pcm_close(mHandle->rxHandle);
+                        mHandle->rxHandle = NULL;
+                        mHandle->module->startVoipCall(mHandle);
+                    }
+                    else
+                        mHandle->module->open(mHandle);
+                    if(mHandle->handle == NULL) {
+                       ALOGE("read:: PCM device re-open failed");
+                       mParent->mLock.unlock();
+                       return 0;
+                    }
                 }
-                else
-                    mHandle->module->open(mHandle);
-
-                if(mHandle->handle == NULL) {
-                   ALOGE("read:: PCM device re-open failed");
-                   mParent->mLock.unlock();
-                   return 0;
-                }
-
                 mParent->mLock.unlock();
                 continue;
             }
@@ -452,11 +512,7 @@
             else {
                 read += static_cast<ssize_t>((period_size));
                 read_pending -= period_size;
-                //Set mute by cleanning buffers read
-                if (mParent->mMicMute) {
-                    memset(buffer, 0, period_size);
-                }
-                buffer = ((uint8_t *)buffer) + period_size;
+                buffer += period_size;
             }
 
         } while (mHandle->handle && read < bytes);
@@ -488,10 +544,10 @@
         (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
         if((mParent->mVoipStreamCount)) {
 #ifdef QCOM_USBAUDIO_ENABLED
-            ALOGD("musbRecordingState: %d, mVoipStreamCount:%d",mParent->musbRecordingState,
+            ALOGV("musbRecordingState: %d, mVoipStreamCount:%d",mParent->musbRecordingState,
                   mParent->mVoipStreamCount );
             if(mParent->mVoipStreamCount == 1) {
-                ALOGD("Deregistering VOIP Call bit, musbPlaybackState:%d,"
+                ALOGV("Deregistering VOIP Call bit, musbPlaybackState:%d,"
                        "musbRecordingState:%d", mParent->musbPlaybackState, mParent->musbRecordingState);
                 mParent->musbPlaybackState &= ~USBPLAYBACKBIT_VOIPCALL;
                 mParent->musbRecordingState &= ~USBRECBIT_VOIPCALL;
@@ -502,6 +558,7 @@
                return NO_ERROR;
         }
         mParent->mVoipStreamCount = 0;
+        mParent->mVoipMicMute = 0;
 #ifdef QCOM_USBAUDIO_ENABLED
     } else {
         ALOGD("Deregistering REC bit, musbRecordingState:%d", mParent->musbRecordingState);
diff --git a/alsa_sound/AudioStreamOutALSA.cpp b/alsa_sound/AudioStreamOutALSA.cpp
index 2adb5d8..05c71ae 100644
--- a/alsa_sound/AudioStreamOutALSA.cpp
+++ b/alsa_sound/AudioStreamOutALSA.cpp
@@ -1,7 +1,7 @@
 /* AudioStreamOutALSA.cpp
  **
  ** Copyright 2008-2009 Wind River Systems
- ** Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ ** Copyright (c) 2012, 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.
@@ -53,12 +53,19 @@
 AudioStreamOutALSA::AudioStreamOutALSA(AudioHardwareALSA *parent, alsa_handle_t *handle) :
     ALSAStreamOps(parent, handle),
     mParent(parent),
-    mFrameCount(0)
+    mFrameCount(0),
+    mUseCase(AudioHardwareALSA::USECASE_NONE)
 {
 }
 
 AudioStreamOutALSA::~AudioStreamOutALSA()
 {
+    if (mParent->mRouteAudioToA2dp) {
+         status_t err = mParent->stopA2dpPlayback(mUseCase);
+         if (err) {
+             ALOGE("stopA2dpPlayback return err  %d", err);
+         }
+    }
     close();
 }
 
@@ -84,21 +91,7 @@
     }
     vol = lrint((volume * 0x2000)+0.5);
 
-    if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER) ||
-       !strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) {
-        ALOGV("setLpaVolume(%f)\n", volume);
-        ALOGV("Setting LPA volume to %d (available range is 0 to 100)\n", vol);
-        mHandle->module->setLpaVolume(vol);
-        return status;
-    }
-    else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL) ||
-            !strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL)) {
-        ALOGV("setCompressedVolume(%f)\n", volume);
-        ALOGV("Setting Compressed volume to %d (available range is 0 to 100)\n", vol);
-        mHandle->module->setCompressedVolume(vol);
-        return status;
-    }
-    else if(!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL,
+    if(!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL,
             sizeof(mHandle->useCase)) || !strncmp(mHandle->useCase,
             SND_USE_CASE_MOD_PLAY_VOIP, sizeof(mHandle->useCase))) {
         ALOGV("Avoid Software volume by returning success\n");
@@ -120,98 +113,103 @@
 
     int write_pending = bytes;
 
-    if((mHandle->handle == NULL) && (mHandle->rxHandle == NULL) &&
-         (strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) &&
-         (strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
+    if((strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) &&
+       (strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
         mParent->mLock.lock();
-
-        ALOGD("mHandle->useCase: %s", mHandle->useCase);
-        snd_use_case_get(mHandle->ucMgr, "_verb", (const char **)&use_case);
-        if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
-            if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)){
-                strlcpy(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL,
-                        sizeof(SND_USE_CASE_VERB_IP_VOICECALL));
-            } else if(!strcmp(mHandle->useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) {
-                strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI2,
-                        sizeof(SND_USE_CASE_MOD_PLAY_MUSIC2));
-            } else if (!strcmp(mHandle->useCase,SND_USE_CASE_MOD_PLAY_MUSIC)){
-                strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI,
-                        sizeof(SND_USE_CASE_MOD_PLAY_MUSIC));
-            } else if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) {
-                strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC,
-                        sizeof(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC));
+        /* PCM handle might be closed and reopened immediately to flush
+         * the buffers, recheck and break if PCM handle is valid */
+        if (mHandle->handle == NULL && mHandle->rxHandle == NULL) {
+            ALOGV("mDevices =0x%x", mDevices);
+            if(mDevices &  AudioSystem::DEVICE_OUT_ALL_A2DP) {
+                ALOGV("StreamOut write - mRouteAudioToA2dp = %d ", mParent->mRouteAudioToA2dp);
+                mParent->mRouteAudioToA2dp = true;
             }
-        } else {
-            if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)){
-                strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP,
-                        sizeof(SND_USE_CASE_MOD_PLAY_VOIP));
-            } else if(!strcmp(mHandle->useCase,SND_USE_CASE_VERB_HIFI2)) {
-                strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
-                        sizeof(SND_USE_CASE_MOD_PLAY_MUSIC2));
-            } else if (!strcmp(mHandle->useCase,SND_USE_CASE_VERB_HIFI)){
-                strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
-                        sizeof(SND_USE_CASE_MOD_PLAY_MUSIC));
-            } else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) {
-                strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC,
-                        sizeof(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC));
+            ALOGV("write: mHandle->useCase: %s", mHandle->useCase);
+            snd_use_case_get(mHandle->ucMgr, "_verb", (const char **)&use_case);
+            if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
+                if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)){
+                     strlcpy(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL,sizeof(mHandle->useCase));
+                } else if (mHandle->isFastOutput){
+                           strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC, sizeof(mHandle->useCase));
+                } else {
+                           strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI, sizeof(mHandle->useCase));
+                }
+            } else {
+                if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)) {
+                    strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP,sizeof(mHandle->useCase));
+                } else if (mHandle->isFastOutput){
+                           strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC, sizeof(mHandle->useCase));
+                } else {
+                           strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC, sizeof(mHandle->useCase));
+                }
             }
-        }
-        free(use_case);
-        if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
-           (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
-#ifdef QCOM_USBAUDIO_ENABLED
-            if((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
-                  (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
-                  (mDevices & AudioSystem::DEVICE_OUT_PROXY)) {
-                mDevices |= AudioSystem::DEVICE_OUT_PROXY;
-                mHandle->module->route(mHandle, mDevices , mParent->mode());
-            }else
-#endif
-            {
-              mHandle->module->route(mHandle, mDevices , AudioSystem::MODE_IN_COMMUNICATION);
-            }
-#ifdef QCOM_USBAUDIO_ENABLED
-        } else if((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
-                  (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
-                  (mDevices & AudioSystem::DEVICE_OUT_PROXY)) {
-            mDevices |= AudioSystem::DEVICE_OUT_PROXY;
-            mHandle->module->route(mHandle, mDevices , mParent->mode());
-#endif
-        } else {
-            mHandle->module->route(mHandle, mDevices , mParent->mode());
-        }
-        if (!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI) ||
-            !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI2) ||
-            !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC) ||
-            !strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
-            snd_use_case_set(mHandle->ucMgr, "_verb", mHandle->useCase);
-        } else {
-            snd_use_case_set(mHandle->ucMgr, "_enamod", mHandle->useCase);
-        }
-        if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
-          (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
-             err = mHandle->module->startVoipCall(mHandle);
-        }
-        else
-             mHandle->module->open(mHandle);
-        if(mHandle->handle == NULL) {
-            ALOGE("write:: device open failed");
-            mParent->mLock.unlock();
-            return bytes;
-        }
-#ifdef QCOM_USBAUDIO_ENABLED
-        if((mHandle->devices == AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET)||
-               (mHandle->devices == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)){
+            free(use_case);
             if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
                (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
-                mParent->musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
+#ifdef QCOM_USBAUDIO_ENABLED
+                if((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
+                      (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
+                      (mDevices & AudioSystem::DEVICE_OUT_PROXY)) {
+                    mHandle->module->route(mHandle, mDevices , mParent->mode());
+                }else
+#endif
+                {
+                  mHandle->module->route(mHandle, mDevices , AUDIO_MODE_IN_COMMUNICATION);
+                }
+#ifdef QCOM_USBAUDIO_ENABLED
+            } else if((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
+                      (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
+                      (mDevices & AudioSystem::DEVICE_OUT_PROXY)) {
+                mHandle->module->route(mHandle, mDevices , mParent->mode());
+#endif
             } else {
-                mParent->startUsbPlaybackIfNotStarted();
-                mParent->musbPlaybackState |= USBPLAYBACKBIT_MUSIC;
+                  mHandle->module->route(mHandle, mDevices , mParent->mode());
+            }
+            if (!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI) ||
+                !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI2) ||
+                !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC) ||
+                !strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
+                snd_use_case_set(mHandle->ucMgr, "_verb", mHandle->useCase);
+            } else {
+                snd_use_case_set(mHandle->ucMgr, "_enamod", mHandle->useCase);
+            }
+            if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
+              (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
+                 err = mHandle->module->startVoipCall(mHandle);
+            }
+            else
+                 mHandle->module->open(mHandle);
+            if(mHandle->handle == NULL) {
+                ALOGE("write:: device open failed");
+                mParent->mLock.unlock();
+                return bytes;
+            }
+#ifdef QCOM_USBAUDIO_ENABLED
+            if((mHandle->devices == AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET)||
+                   (mHandle->devices == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)){
+                if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
+                   (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
+                    mParent->musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
+                } else {
+                    mParent->startUsbPlaybackIfNotStarted();
+                    mParent->musbPlaybackState |= USBPLAYBACKBIT_MUSIC;
+                }
+            }
+#endif
+        }
+        if (mParent->mRouteAudioToA2dp) {
+            mUseCase = mParent->useCaseStringToEnum(mHandle->useCase);
+            if (! (mParent->getA2DPActiveUseCases_l() & mUseCase )){
+                ALOGD("startA2dpPlayback_l from write :: useCase = %s", mHandle->useCase);
+                status_t err = NO_ERROR;
+                err = mParent->startA2dpPlayback_l(mUseCase);
+                if(err) {
+                    ALOGE("startA2dpPlayback_l from write return err = %d", err);
+                    mParent->mLock.unlock();
+                    return err;
+                }
             }
         }
-#endif
-
         mParent->mLock.unlock();
     }
 
@@ -224,7 +222,7 @@
         ALOGV("Starting playback on USB");
         if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL) ||
            !strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)) {
-            ALOGD("Setting VOIPCALL bit here, musbPlaybackState %d", mParent->musbPlaybackState);
+            ALOGV("Setting VOIPCALL bit here, musbPlaybackState %d", mParent->musbPlaybackState);
             mParent->musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
         }else{
             ALOGV("enabling music, musbPlaybackState: %d ", mParent->musbPlaybackState);
@@ -310,16 +308,24 @@
                  mParent->musbRecordingState &= ~USBRECBIT_VOIPCALL;
                  mParent->closeUsbPlaybackIfNothingActive();
                  mParent->closeUsbRecordingIfNothingActive();
+
+                 if (mParent->mRouteAudioToA2dp) {
+                     //TODO: HANDLE VOIP A2DP
+                 }
              }
 #endif
                 return NO_ERROR;
          }
          mParent->mVoipStreamCount = 0;
+         mParent->mVoipMicMute = 0;
     }
 #ifdef QCOM_USBAUDIO_ENABLED
       else if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
               (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA))) {
         mParent->musbPlaybackState &= ~USBPLAYBACKBIT_LPA;
+    } else if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+              (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
+        mParent->musbPlaybackState &= ~USBPLAYBACKBIT_TUNNEL;
     } else {
         mParent->musbPlaybackState &= ~USBPLAYBACKBIT_MUSIC;
     }
@@ -327,6 +333,14 @@
     mParent->closeUsbPlaybackIfNothingActive();
 #endif
 
+    if (mParent->mRouteAudioToA2dp) {
+         ALOGD("close-suspendA2dpPlayback_l::mUseCase = %d",mUseCase);
+         status_t err = mParent->suspendA2dpPlayback_l(mUseCase);
+         if(err) {
+             ALOGE("suspendA2dpPlayback from hardware output close return err = %d", err);
+             return err;
+         }
+    }
     ALSAStreamOps::close();
 
     return NO_ERROR;
@@ -348,6 +362,10 @@
         (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA))) {
         ALOGV("Deregistering LPA bit");
         mParent->musbPlaybackState &= ~USBPLAYBACKBIT_LPA;
+    } else if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+             (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
+        ALOGD("Deregistering Tunnel Player bit");
+        mParent->musbPlaybackState &= ~USBPLAYBACKBIT_TUNNEL;
     } else {
         ALOGV("Deregistering MUSIC bit, musbPlaybackState: %d", mParent->musbPlaybackState);
         mParent->musbPlaybackState &= ~USBPLAYBACKBIT_MUSIC;
@@ -355,6 +373,12 @@
 #endif
 
     mHandle->module->standby(mHandle);
+    if (mParent->mRouteAudioToA2dp) {
+        status_t err = mParent->stopA2dpPlayback_l(mUseCase);
+        if(err) {
+            ALOGE("stopA2dpPlayback return err  %d", err);
+        }
+    }
 
 #ifdef QCOM_USBAUDIO_ENABLED
     mParent->closeUsbPlaybackIfNothingActive();
diff --git a/alsa_sound/AudioUsbALSA.cpp b/alsa_sound/AudioUsbALSA.cpp
index 3316e3e..02847dc 100644
--- a/alsa_sound/AudioUsbALSA.cpp
+++ b/alsa_sound/AudioUsbALSA.cpp
@@ -1,5 +1,6 @@
 /* AudioUsbALSA.cpp
-Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+
+Copyright (c) 2012, The Linux Foundation. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
@@ -54,6 +55,9 @@
 
 #define USB_PERIOD_SIZE 2048
 #define PROXY_PERIOD_SIZE 3072
+#define PROXY_SUPPORTED_RATE_8000 8000
+#define PROXY_SUPPORTED_RATE_16000 16000
+#define PROXY_SUPPORTED_RATE_48000 48000
 
 namespace android_audio_legacy
 {
@@ -63,6 +67,10 @@
     musbpfdPlayback = -1;
     mkillPlayBackThread = false;
     mkillRecordingThread = false;
+    musbRecordingHandle = NULL;
+    mproxyRecordingHandle = NULL;
+    musbPlaybackHandle  = NULL;
+    mproxyPlaybackHandle = NULL;
 }
 
 AudioUsbALSA::~AudioUsbALSA()
@@ -117,7 +125,11 @@
 
     fileSize = st.st_size;
 
-    read_buf = (char *)malloc(BUFFSIZE);
+    if ((read_buf = (char *)malloc(BUFFSIZE)) == NULL) {
+        ALOGE("ERROR: Unable to allocate memory to hold stream caps");
+        close(fd);
+        return NO_MEMORY;
+    }
     memset(read_buf, 0x0, BUFFSIZE);
     err = read(fd, read_buf, BUFFSIZE);
     str_start = strstr(read_buf, type);
@@ -175,8 +187,19 @@
         return UNKNOWN_ERROR;
     }
     size = target - ratesStrStart;
-    ratesStr = (char *)malloc(size + 1) ;
-    ratesStrForVal = (char *)malloc(size + 1) ;
+    if ((ratesStr = (char *)malloc(size + 1)) == NULL) {
+        ALOGE("ERROR: Unable to allocate memory to hold sample rate strings");
+        close(fd);
+        free(read_buf);
+        return NO_MEMORY;
+    }
+    if ((ratesStrForVal = (char *)malloc(size + 1)) == NULL) {
+        ALOGE("ERROR: Unable to allocate memory to hold sample rate string");
+        close(fd);
+        free(ratesStr);
+        free(read_buf);
+        return NO_MEMORY;
+    }
     memcpy(ratesStr, ratesStrStart, size);
     memcpy(ratesStrForVal, ratesStrStart, size);
     ratesStr[size] = '\0';
@@ -205,16 +228,22 @@
     }
 
     ratesSupported[0] = atoi(nextSRString);
+    ALOGV("ratesSupported[0] for playback: %d", ratesSupported[0]);
     for (i = 1; i<size; i++) {
         nextSRString = strtok_r(NULL, " ,.-", &temp_ptr);
         ratesSupported[i] = atoi(nextSRString);
         ALOGV("ratesSupported[%d] for playback: %d",i, ratesSupported[i]);
     }
 
-    for (i = 0; i<=size; i++) {
-        if (ratesSupported[i] <= 48000) {
-            sampleRate = ratesSupported[i];
-            break;
+    for (i = 0; i<size; i++) {
+        if ((ratesSupported[i] > sampleRate) && (ratesSupported[i] <= 48000)) {
+            // Sample Rate should be one of the proxy supported rates only
+            // This is because proxy port is used to read from/write to DSP .
+            if ((ratesSupported[i] == PROXY_SUPPORTED_RATE_8000) ||
+                (ratesSupported[i] == PROXY_SUPPORTED_RATE_16000) ||
+                (ratesSupported[i] == PROXY_SUPPORTED_RATE_48000)) {
+                sampleRate = ratesSupported[i];
+            }
         }
     }
     ALOGD("sampleRate: %d", sampleRate);
@@ -232,42 +261,60 @@
 void AudioUsbALSA::exitPlaybackThread(uint64_t writeVal)
 {
     ALOGD("exitPlaybackThread, mproxypfdPlayback: %d", mproxypfdPlayback);
-    if (writeVal == SIGNAL_EVENT_KILLTHREAD) {
-        int err;
-
-        err = closeDevice(mproxyPlaybackHandle);
-        if (err) {
-            ALOGE("Info: Could not close proxy %p", mproxyPlaybackHandle);
-        }
-        err = closeDevice(musbPlaybackHandle);
-        if (err) {
-            ALOGE("Info: Could not close USB device %p", musbPlaybackHandle);
-        }
-    }
+    mkillPlayBackThread = true;
     if ((mproxypfdPlayback != -1) && (musbpfdPlayback != -1)) {
         write(mproxypfdPlayback, &writeVal, sizeof(uint64_t));
         write(musbpfdPlayback, &writeVal, sizeof(uint64_t));
-        mkillPlayBackThread = true;
         pthread_join(mPlaybackUsb,NULL);
+        mPlaybackUsb = NULL;
+    }
+    if (writeVal == SIGNAL_EVENT_KILLTHREAD) {
+        int err;
+        {
+            Mutex::Autolock autoLock(mLock);
+            err = closeDevice(mproxyPlaybackHandle);
+            if (err) {
+                ALOGE("Info: Could not close proxy %p", mproxyPlaybackHandle);
+            }
+            err = closeDevice(musbPlaybackHandle);
+            if (err) {
+                ALOGE("Info: Could not close USB device %p", musbPlaybackHandle);
+            }
+        }
     }
 }
 
 void AudioUsbALSA::exitRecordingThread(uint64_t writeVal)
 {
+    //TODO: Need to use userspace fd to kill the thread.
+    // Not a valid assumption to blindly close the thread.
     ALOGD("exitRecordingThread");
-    if (writeVal == SIGNAL_EVENT_KILLTHREAD) {
-        int err;
+    mkillRecordingThread = true;
 
-        err = closeDevice(mproxyRecordingHandle);
-        if (err) {
-            ALOGE("Info: Could not close proxy for recording %p", mproxyRecordingHandle);
-        }
-        err = closeDevice(musbRecordingHandle);
-        if (err) {
-            ALOGE("Info: Could not close USB recording device %p", musbRecordingHandle);
+    if ((pfdProxyRecording[0].fd != -1) && (pfdUsbRecording[0].fd != -1)) {
+        write(pfdProxyRecording[0].fd, &writeVal, sizeof(uint64_t));
+        write(pfdUsbRecording[0].fd, &writeVal, sizeof(uint64_t));
+        pthread_join(mRecordingUsb,NULL);
+        mRecordingUsb = NULL;
+    }
+    if (writeVal == SIGNAL_EVENT_KILLTHREAD ) {
+        int err;
+        {
+            Mutex::Autolock autoLock(mLock);
+            err = closeDevice(mproxyRecordingHandle);
+            if (err) {
+                ALOGE("Info: Could not close proxy for recording %p", mproxyRecordingHandle);
+            } else {
+                mproxyRecordingHandle = NULL;
+            }
+            err = closeDevice(musbRecordingHandle);
+            if (err) {
+                ALOGE("Info: Could not close USB recording device %p", musbRecordingHandle);
+            } else {
+                musbRecordingHandle = NULL;
+            }
         }
     }
-    mkillRecordingThread = true;
 }
 
 void AudioUsbALSA::setkillUsbRecordingThread(bool val){
@@ -308,6 +355,7 @@
 
     if (param_set_hw_params(txHandle, params)) {
         ALOGE("ERROR: cannot set hw params");
+        free(params);
         return NO_INIT;
     }
 
@@ -321,6 +369,7 @@
          txHandle->buffer_size, txHandle->period_size,
          txHandle->period_cnt);
 
+    free(params);
     return NO_ERROR;
 }
 
@@ -347,7 +396,8 @@
         params->start_threshold = (pcm->flags & PCM_MONO) ? pcm->period_size/2 : pcm->period_size/4;
         params->xfer_align = (pcm->flags & PCM_MONO) ? pcm->period_size/2 : pcm->period_size/4;
     }
-    params->stop_threshold = pcm->buffer_size;
+    //Setting stop threshold to a huge value to avoid trigger stop being called internally
+    params->stop_threshold = 0x0FFFFFFF;
 
     params->xfer_align = (pcm->flags & PCM_MONO) ? pcm->period_size/2 : pcm->period_size/4;
     params->silence_size = 0;
@@ -355,9 +405,10 @@
 
     if (param_set_sw_params(pcm, params)) {
         ALOGE("ERROR: cannot set sw params");
+        free(params);
         return NO_INIT;
     }
-
+    free(params);
     return NO_ERROR;
 }
 
@@ -383,7 +434,6 @@
     long frames;
     static int start = 0;
     struct snd_xferi x;
-    int filed;
     unsigned avail, bufsize;
     int bytes_written;
     uint32_t sampleRate;
@@ -391,8 +441,8 @@
     u_int8_t *srcUsb_addr = NULL;
     u_int8_t *dstProxy_addr = NULL;
     int err;
-    const char *fn = "/data/RecordPcm.pcm";
-    filed = open(fn, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0664);
+    pfdProxyRecording[0].fd = -1;
+    pfdUsbRecording[0].fd = -1 ;
 
     err = getCap((char *)"Capture:", mchannelsCapture, msampleRateCapture);
     if (err) {
@@ -420,7 +470,13 @@
                                             msampleRateCapture, mchannelsCapture,768,false);
     if (!mproxyRecordingHandle) {
         ALOGE("ERROR: Could not configure Proxy for recording");
-        closeDevice(musbRecordingHandle);
+        {
+            Mutex::Autolock autoLock(mLock);
+            err = closeDevice(musbRecordingHandle);
+            if(err == OK) {
+                musbRecordingHandle = NULL;
+            }
+        }
         return;
     } else {
         ALOGD("Proxy Configured for recording");
@@ -558,7 +614,7 @@
 
         bytes_written = mproxyRecordingHandle->sync_ptr->c.control.appl_ptr - mproxyRecordingHandle->sync_ptr->s.status.hw_ptr;
         if ((bytes_written >= mproxyRecordingHandle->sw_p->start_threshold) && (!mproxyRecordingHandle->start)) {
-            if (!mkillPlayBackThread) {
+            if (!mkillRecordingThread) {
                 err = startDevice(mproxyRecordingHandle, &mkillRecordingThread);
                 if (err == EPIPE) {
                     continue;
@@ -571,9 +627,19 @@
     }
     /***************  End sync up after write -- Proxy *********************/
     if (mkillRecordingThread) {
-        closeDevice(mproxyRecordingHandle);
-        closeDevice(musbRecordingHandle);
+        {
+            Mutex::Autolock autoLock(mLock);
+            err = closeDevice(mproxyRecordingHandle);
+            if(err == OK) {
+                mproxyRecordingHandle = NULL;
+            }
+            err = closeDevice(musbRecordingHandle);
+            if(err == OK) {
+                musbRecordingHandle = NULL;
+            }
+        }
     }
+    mRecordingUsb = NULL;
     ALOGD("Exiting USB Recording thread");
 }
 
@@ -606,29 +672,41 @@
     err = setHardwareParams(handle, sampleRate, channelCount,periodSize);
     if (err != NO_ERROR) {
         ALOGE("ERROR: setHardwareParams failed");
-        closeDevice(handle);
-        return NULL;
+        {
+             Mutex::Autolock autoLock(mLock);
+             closeDevice(handle);
+             return NULL;
+        }
     }
 
     err = setSoftwareParams(handle, playback);
     if (err != NO_ERROR) {
         ALOGE("ERROR: setSoftwareParams failed");
-        closeDevice(handle);
-        return NULL;
+        {
+            Mutex::Autolock autoLock(mLock);
+            closeDevice(handle);
+            return NULL;
+        }
     }
 
     err = mmap_buffer(handle);
     if (err) {
         ALOGE("ERROR: mmap_buffer failed");
-        closeDevice(handle);
-        return NULL;
+        {
+            Mutex::Autolock autoLock(mLock);
+            closeDevice(handle);
+            return NULL;
+        }
     }
 
     err = pcm_prepare(handle);
     if (err) {
         ALOGE("ERROR: pcm_prepare failed");
-        closeDevice(handle);
-        return NULL;
+        {
+            Mutex::Autolock autoLock(mLock);
+            closeDevice(handle);
+            return NULL;
+        }
     }
 
     return handle;
@@ -756,7 +834,7 @@
         return;
     }
 
-    if (pfdUsbPlayback[0].revents & POLLERR || pfdProxyPlayback[0].revents & POLLHUP ||
+    if (pfdUsbPlayback[0].revents & POLLERR || pfdUsbPlayback[0].revents & POLLHUP ||
         pfdUsbPlayback[0].revents & POLLNVAL) {
         ALOGE("Info: usb throwing error");
         mkillPlayBackThread = true;
@@ -780,8 +858,6 @@
     unsigned int tmp;
     int numOfBytesWritten;
     int err;
-    int filed;
-    const char *fn = "/data/test.pcm";
     mdstUsb_addr = NULL;
     msrcProxy_addr = NULL;
 
@@ -801,7 +877,13 @@
                                          msampleRatePlayback, mchannelsPlayback, USB_PERIOD_SIZE, true);
     if (!musbPlaybackHandle) {
         ALOGE("ERROR: configureUsbDevice failed, returning");
-        closeDevice(musbPlaybackHandle);
+        {
+            Mutex::Autolock autoLock(mLock);
+            err = closeDevice(musbPlaybackHandle);
+            if(err == OK) {
+                musbPlaybackHandle = NULL;
+            }
+        }
         return;
     } else {
         ALOGD("USB Configured for playback");
@@ -819,7 +901,13 @@
                                msampleRatePlayback, mchannelsPlayback, PROXY_PERIOD_SIZE, false);
     if (!mproxyPlaybackHandle) {
         ALOGE("ERROR: Could not configure Proxy, returning");
-        closeDevice(musbPlaybackHandle);
+        {
+            Mutex::Autolock autoLock(mLock);
+            err = closeDevice(musbPlaybackHandle);
+            if(err == OK) {
+                musbPlaybackHandle = NULL;
+            }
+        }
         return;
     } else {
         ALOGD("Proxy Configured for playback");
@@ -833,7 +921,7 @@
         pfdProxyPlayback[0].events = (POLLIN);                                 // | POLLERR | POLLNVAL);
         mproxypfdPlayback = eventfd(0,0);
         pfdProxyPlayback[1].fd = mproxypfdPlayback;
-        pfdProxyPlayback[1].events = (POLLIN | POLLOUT| POLLERR | POLLNVAL);
+        pfdProxyPlayback[1].events = (POLLIN | POLLERR | POLLNVAL);
     }
 
     frames = (mproxyPlaybackHandle->flags & PCM_MONO) ? (proxyPeriod / 2) : (proxyPeriod / 4);
@@ -842,9 +930,17 @@
 
     u_int8_t *proxybuf = ( u_int8_t *) malloc(PROXY_PERIOD_SIZE);
     u_int8_t *usbbuf = ( u_int8_t *) malloc(USB_PERIOD_SIZE);
-    memset(proxybuf, 0x0, PROXY_PERIOD_SIZE);
-    memset(usbbuf, 0x0, USB_PERIOD_SIZE);
 
+    if (proxybuf == NULL || usbbuf == NULL) {
+        ALOGE("ERROR: Unable to allocate USB audio buffer(s): proxybuf=%p, usbbuf=%p",
+              proxybuf, usbbuf);
+        /* Don't run the playback loop if we failed to allocate either of these buffers.
+           If either pointer is non-NULL they'll be freed after the end of the loop. */
+        mkillPlayBackThread = true;
+    } else {
+        memset(proxybuf, 0x0, PROXY_PERIOD_SIZE);
+        memset(usbbuf, 0x0, USB_PERIOD_SIZE);
+    }
 
     /***********************keep reading from proxy and writing to USB******************************************/
     while (mkillPlayBackThread != true) {
@@ -928,12 +1024,12 @@
                 err = syncPtr(mproxyPlaybackHandle, &mkillPlayBackThread);
                 if (err == EPIPE) {
                     continue;
-                } else if (err != NO_ERROR) {
+                } else if (err != NO_ERROR && err != ENODEV) {
                     break;
                 }
             }
         }
-        //ALOGE("usbSizeFilled %d, proxySizeRemaining %d ",usbSizeFilled,proxySizeRemaining);
+        //ALOGV("usbSizeFilled %d, proxySizeRemaining %d ",usbSizeFilled,proxySizeRemaining);
         if (usbPeriod - usbSizeFilled <= proxySizeRemaining) {
             memcpy(usbbuf + usbSizeFilled, proxybuf + proxyPeriod - proxySizeRemaining, usbPeriod - usbSizeFilled);
             proxySizeRemaining -= (usbPeriod - usbSizeFilled);
@@ -1000,20 +1096,20 @@
                 err = syncPtr(musbPlaybackHandle, &mkillPlayBackThread);
                 if (err == EPIPE) {
                     continue;
-                } else if (err != NO_ERROR) {
+                } else if (err != NO_ERROR && err != ENODEV ) {
                     break;
                 }
             }
 
             bytes_written = musbPlaybackHandle->sync_ptr->c.control.appl_ptr - musbPlaybackHandle->sync_ptr->s.status.hw_ptr;
-            ALOGE("Appl ptr %d , hw_ptr %d, difference %d",musbPlaybackHandle->sync_ptr->c.control.appl_ptr, musbPlaybackHandle->sync_ptr->s.status.hw_ptr, bytes_written);
+            ALOGV("Appl ptr %lu , hw_ptr %lu, difference %d",musbPlaybackHandle->sync_ptr->c.control.appl_ptr, musbPlaybackHandle->sync_ptr->s.status.hw_ptr, bytes_written);
 
             /*
                 Following is the check to prevent USB from going to bad state.
                 This happens in case of an underrun where there is not enough
                 data from the proxy
             */
-	    if (bytes_written <= usbPeriod && musbPlaybackHandle->start) {
+            if (bytes_written <= usbPeriod && musbPlaybackHandle->start) {
                 ioctl(musbPlaybackHandle->fd, SNDRV_PCM_IOCTL_PAUSE,1);
                 pcm_prepare(musbPlaybackHandle);
                 musbPlaybackHandle->start = false;
@@ -1033,16 +1129,36 @@
             /***************  End sync up after write -- USB *********************/
         }
     }
-    if (mkillPlayBackThread) {
-        if (proxybuf)
-            free(proxybuf);
-        if (usbbuf)
-            free(usbbuf);
+    if (proxybuf)
+        free(proxybuf);
+    if (usbbuf)
+        free(usbbuf);
+    if(mproxypfdPlayback != -1) {
+        close(mproxypfdPlayback);
         mproxypfdPlayback = -1;
-        musbpfdPlayback = -1;
-        closeDevice(mproxyPlaybackHandle);
-        closeDevice(musbPlaybackHandle);
     }
+    if(musbpfdPlayback != -1) {
+        close(musbpfdPlayback);
+        musbpfdPlayback = -1;
+    }
+    if(mkillPlayBackThread) {
+        {
+            Mutex::Autolock autoLock(mLock);
+            err = closeDevice(mproxyPlaybackHandle);
+            if(err == OK) {
+                mproxyPlaybackHandle = NULL;
+            } else {
+                ALOGE("mproxyPlaybackHandle - err = %d", err);
+            }
+            err = closeDevice(musbPlaybackHandle);
+            if(err == OK) {
+                musbPlaybackHandle = NULL;
+            } else {
+                ALOGE("musbPlaybackHandle - err = %d", err);
+            }
+        }
+    }
+    mPlaybackUsb = NULL;
     ALOGD("Exiting USB Playback Thread");
 }
 
diff --git a/alsa_sound/AudioUsbALSA.h b/alsa_sound/AudioUsbALSA.h
index 4204eb0..d408d1e 100644
--- a/alsa_sound/AudioUsbALSA.h
+++ b/alsa_sound/AudioUsbALSA.h
@@ -1,6 +1,6 @@
 /* AudioUsbALSA.h
 
-Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+  Copyright (c) 2012, The Linux Foundation. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
@@ -85,6 +85,7 @@
     pthread_t mPlaybackUsb;
     pthread_t mRecordingUsb;
     snd_use_case_mgr_t *mUcMgr;
+    Mutex    mLock;
 
     //Helper functions
     struct pcm * configureDevice(unsigned flags, char* hw, int sampleRate, int channelCount, int periodSize, bool playback);
diff --git a/alsa_sound/AudioUtil.cpp b/alsa_sound/AudioUtil.cpp
index 3549f24..98131e9 100644
--- a/alsa_sound/AudioUtil.cpp
+++ b/alsa_sound/AudioUtil.cpp
@@ -1,6 +1,6 @@
 /* AudioUtil.cpp
  *
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (c) 2012, 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.
diff --git a/alsa_sound/AudioUtil.h b/alsa_sound/AudioUtil.h
index 6575315..70e5194 100644
--- a/alsa_sound/AudioUtil.h
+++ b/alsa_sound/AudioUtil.h
@@ -1,6 +1,6 @@
 /* AudioUtil.h
  *
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (c) 2012, 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.
diff --git a/alsa_sound/alsa_default.cpp b/alsa_sound/alsa_default.cpp
deleted file mode 100644
index 7f477b5..0000000
--- a/alsa_sound/alsa_default.cpp
+++ /dev/null
@@ -1,1798 +0,0 @@
-/* alsa_default.cpp
- **
- ** Copyright 2009 Wind River Systems
- ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#define LOG_TAG "ALSAModule"
-//#define LOG_NDEBUG 0
-#define LOG_NDDEBUG 0
-#include <utils/Log.h>
-#include <cutils/properties.h>
-#include <linux/ioctl.h>
-#include "AudioUtil.h"
-#include "AudioHardwareALSA.h"
-#include <media/AudioRecord.h>
-#include <dlfcn.h>
-#ifdef QCOM_CSDCLIENT_ENABLED
-extern "C" {
-static int (*csd_disable_device)();
-static int (*csd_enable_device)(int, int, uint32_t);
-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
-
-#ifndef ALSA_DEFAULT_SAMPLE_RATE
-#define ALSA_DEFAULT_SAMPLE_RATE 44100 // in Hz
-#endif
-
-#define BTSCO_RATE_16KHZ 16000
-#define USECASE_TYPE_RX 1
-#define USECASE_TYPE_TX 2
-#define MAX_HDMI_CHANNEL_CNT 6
-
-namespace android_audio_legacy
-{
-
-static int      s_device_open(const hw_module_t*, const char*, hw_device_t**);
-static int      s_device_close(hw_device_t*);
-static status_t s_init(alsa_device_t *, ALSAHandleList &);
-static status_t s_open(alsa_handle_t *);
-static status_t s_close(alsa_handle_t *);
-static status_t s_standby(alsa_handle_t *);
-static status_t s_route(alsa_handle_t *, uint32_t, int);
-static status_t s_start_voice_call(alsa_handle_t *);
-static status_t s_start_voip_call(alsa_handle_t *);
-static status_t s_start_fm(alsa_handle_t *);
-static void     s_set_voice_volume(int);
-static void     s_set_voip_volume(int);
-static void     s_set_mic_mute(int);
-static void     s_set_voip_mic_mute(int);
-static void     s_set_voip_config(int, int);
-static status_t s_set_fm_vol(int);
-static void     s_set_btsco_rate(int);
-static status_t s_set_lpa_vol(int);
-static void     s_enable_wide_voice(bool flag);
-static void     s_enable_fens(bool flag);
-static void     s_set_flags(uint32_t flags);
-static status_t s_set_compressed_vol(int);
-static void     s_enable_slow_talk(bool flag);
-static void     s_set_voc_rec_mode(uint8_t mode);
-static void     s_set_volte_mic_mute(int state);
-static void     s_set_volte_volume(int vol);
-#ifdef SEPERATED_AUDIO_INPUT
-static void     s_setInput(int);
-
-static int input_source;
-#endif
-#ifdef QCOM_CSDCLIENT_ENABLED
-static void     s_set_csd_handle(void*);
-#endif
-
-static char mic_type[25];
-static char curRxUCMDevice[50];
-static char curTxUCMDevice[50];
-static int fluence_mode;
-static int fmVolume;
-#ifdef USES_FLUENCE_INCALL
-static uint32_t mDevSettingsFlag = TTY_OFF | DMIC_FLAG;
-#else
-static uint32_t mDevSettingsFlag = TTY_OFF;
-#endif
-static int btsco_samplerate = 8000;
-static ALSAUseCaseList mUseCaseList;
-static void *csd_handle;
-
-static hw_module_methods_t s_module_methods = {
-    open            : s_device_open
-};
-
-extern "C" {
-hw_module_t HAL_MODULE_INFO_SYM = {
-    tag             : HARDWARE_MODULE_TAG,
-    version_major   : 1,
-    version_minor   : 0,
-    id              : ALSA_HARDWARE_MODULE_ID,
-    name            : "QCOM ALSA module",
-    author          : "QuIC Inc",
-    methods         : &s_module_methods,
-    dso             : 0,
-    reserved        : {0,},
-};
-}
-
-static int s_device_open(const hw_module_t* module, const char* name,
-        hw_device_t** device)
-{
-    char value[128];
-    alsa_device_t *dev;
-    dev = (alsa_device_t *) malloc(sizeof(*dev));
-    if (!dev) return -ENOMEM;
-
-    memset(dev, 0, sizeof(*dev));
-
-    /* initialize the procs */
-    dev->common.tag = HARDWARE_DEVICE_TAG;
-    dev->common.version = 0;
-    dev->common.module = (hw_module_t *) module;
-    dev->common.close = s_device_close;
-    dev->init = s_init;
-    dev->open = s_open;
-    dev->close = s_close;
-    dev->route = s_route;
-    dev->standby = s_standby;
-    dev->startVoiceCall = s_start_voice_call;
-    dev->startVoipCall = s_start_voip_call;
-    dev->startFm = s_start_fm;
-    dev->setVoiceVolume = s_set_voice_volume;
-    dev->setVoipVolume = s_set_voip_volume;
-    dev->setMicMute = s_set_mic_mute;
-    dev->setVoipMicMute = s_set_voip_mic_mute;
-    dev->setVoipConfig = s_set_voip_config;
-    dev->setFmVolume = s_set_fm_vol;
-    dev->setBtscoRate = s_set_btsco_rate;
-    dev->setLpaVolume = s_set_lpa_vol;
-    dev->enableWideVoice = s_enable_wide_voice;
-    dev->enableFENS = s_enable_fens;
-    dev->setFlags = s_set_flags;
-    dev->setCompressedVolume = s_set_compressed_vol;
-    dev->enableSlowTalk = s_enable_slow_talk;
-    dev->setVocRecMode = s_set_voc_rec_mode;
-    dev->setVoLTEMicMute = s_set_volte_mic_mute;
-    dev->setVoLTEVolume = s_set_volte_volume;
-#ifdef SEPERATED_AUDIO_INPUT
-    dev->setInput = s_setInput;
-#endif
-#ifdef QCOM_CSDCLIENT_ENABLED
-    dev->setCsdHandle = s_set_csd_handle;
-#endif
-    *device = &dev->common;
-
-    property_get("persist.audio.handset.mic",value,"0");
-    strlcpy(mic_type, value, sizeof(mic_type));
-    property_get("persist.audio.fluence.mode",value,"0");
-    if (!strcmp("broadside", value)) {
-        fluence_mode = FLUENCE_MODE_BROADSIDE;
-    } else {
-        fluence_mode = FLUENCE_MODE_ENDFIRE;
-    }
-    strlcpy(curRxUCMDevice, "None", sizeof(curRxUCMDevice));
-    strlcpy(curTxUCMDevice, "None", sizeof(curTxUCMDevice));
-    ALOGV("ALSA module opened");
-
-    return 0;
-}
-
-static int s_device_close(hw_device_t* device)
-{
-    free(device);
-    device = NULL;
-    return 0;
-}
-
-// ----------------------------------------------------------------------------
-
-static const int DEFAULT_SAMPLE_RATE = ALSA_DEFAULT_SAMPLE_RATE;
-
-static void switchDevice(alsa_handle_t *handle, uint32_t devices, uint32_t mode);
-static char *getUCMDevice(uint32_t devices, int input, char *rxDevice);
-static void disableDevice(alsa_handle_t *handle);
-int getUseCaseType(const char *useCase);
-
-static int callMode = AudioSystem::MODE_NORMAL;
-// ----------------------------------------------------------------------------
-
-bool platform_is_Fusion3()
-{
-    char platform[128], baseband[128];
-    property_get("ro.board.platform", platform, "");
-    property_get("ro.baseband", baseband, "");
-    if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband))
-        return true;
-    else
-        return false;
-}
-
-int deviceName(alsa_handle_t *handle, unsigned flags, char **value)
-{
-    int ret = 0;
-    char ident[70];
-
-    if (flags & PCM_IN) {
-        strlcpy(ident, "CapturePCM/", sizeof(ident));
-    } else {
-        strlcpy(ident, "PlaybackPCM/", sizeof(ident));
-    }
-    strlcat(ident, handle->useCase, sizeof(ident));
-    ret = snd_use_case_get(handle->ucMgr, ident, (const char **)value);
-    ALOGD("Device value returned is %s", (*value));
-    return ret;
-}
-
-status_t setHDMIChannelCount()
-{
-    status_t err = NO_ERROR;
-    int channel_count = 0;
-    const char *channel_cnt_str = NULL;
-    EDID_AUDIO_INFO info = { 0 };
-
-    ALSAControl control("/dev/snd/controlC0");
-    if (AudioUtil::getHDMIAudioSinkCaps(&info)) {
-        for (int i = 0; i < info.nAudioBlocks && i < MAX_EDID_BLOCKS; i++) {
-            if (info.AudioBlocksArray[i].nChannels > channel_count &&
-                  info.AudioBlocksArray[i].nChannels <= MAX_HDMI_CHANNEL_CNT) {
-                channel_count = info.AudioBlocksArray[i].nChannels;
-            }
-        }
-    }
-
-    switch (channel_count) {
-    case 6: channel_cnt_str = "Six"; break;
-    case 5: channel_cnt_str = "Five"; break;
-    case 4: channel_cnt_str = "Four"; break;
-    case 3: channel_cnt_str = "Three"; break;
-    default: channel_cnt_str = "Two"; break;
-    }
-    ALOGD("HDMI channel count: %s", channel_cnt_str);
-    control.set("HDMI_RX Channels", channel_cnt_str);
-
-    return err;
-}
-
-status_t setHardwareParams(alsa_handle_t *handle)
-{
-    struct snd_pcm_hw_params *params;
-    unsigned long bufferSize, reqBuffSize;
-    unsigned int periodTime, bufferTime;
-    unsigned int requestedRate = handle->sampleRate;
-    int status = 0;
-    int channels = handle->channels;
-    snd_pcm_format_t format = SNDRV_PCM_FORMAT_S16_LE;
-
-    params = (snd_pcm_hw_params*) calloc(1, sizeof(struct snd_pcm_hw_params));
-    if (!params) {
-        ALOGE("Failed to allocate ALSA hardware parameters!");
-        return NO_INIT;
-    }
-
-    reqBuffSize = handle->bufferSize;
-    ALOGD("setHardwareParams: reqBuffSize %d channels %d sampleRate %d",
-         (int) reqBuffSize, handle->channels, handle->sampleRate);
-
-#ifdef QCOM_SSR_ENABLED
-    if (channels == 6) {
-        if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
-            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
-            ALOGV("HWParams: Use 4 channels in kernel for 5.1(%s) recording ", handle->useCase);
-            channels = 4;
-        }
-    }
-#endif
-
-    param_init(params);
-    param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS,
-                   SNDRV_PCM_ACCESS_RW_INTERLEAVED);
-    if (handle->format != SNDRV_PCM_FORMAT_S16_LE) {
-        if (handle->format == AudioSystem::AMR_NB
-            || handle->format == AudioSystem::AMR_WB
-#ifdef QCOM_QCHAT_ENABLED
-            || handle->format == AudioSystem::EVRC
-            || handle->format == AudioSystem::EVRCB
-            || handle->format == AudioSystem::EVRCWB
-#endif
-            )
-              format = SNDRV_PCM_FORMAT_SPECIAL;
-    }
-    param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
-                   format);
-    param_set_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
-                   SNDRV_PCM_SUBFORMAT_STD);
-    param_set_int(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, reqBuffSize);
-    param_set_int(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
-    param_set_int(params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
-                   channels * 16);
-    param_set_int(params, SNDRV_PCM_HW_PARAM_CHANNELS,
-                  channels);
-    param_set_int(params, SNDRV_PCM_HW_PARAM_RATE, handle->sampleRate);
-    param_set_hw_refine(handle->handle, params);
-
-    if (param_set_hw_params(handle->handle, params)) {
-        ALOGE("cannot set hw params");
-        return NO_INIT;
-    }
-    param_dump(params);
-
-    handle->handle->buffer_size = pcm_buffer_size(params);
-    handle->handle->period_size = pcm_period_size(params);
-    handle->handle->period_cnt = handle->handle->buffer_size/handle->handle->period_size;
-    ALOGD("setHardwareParams: buffer_size %d, period_size %d, period_cnt %d",
-        handle->handle->buffer_size, handle->handle->period_size,
-        handle->handle->period_cnt);
-    handle->handle->rate = handle->sampleRate;
-    handle->handle->channels = handle->channels;
-    handle->periodSize = handle->handle->period_size;
-    if (strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC) &&
-        strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC) &&
-        (6 != handle->channels)) {
-        //Do not update buffersize for 5.1 recording
-        handle->bufferSize = handle->handle->period_size;
-    }
-
-    return NO_ERROR;
-}
-
-status_t setSoftwareParams(alsa_handle_t *handle)
-{
-    struct snd_pcm_sw_params* params;
-    struct pcm* pcm = handle->handle;
-
-    unsigned long periodSize = pcm->period_size;
-    int channels = handle->channels;
-
-    params = (snd_pcm_sw_params*) calloc(1, sizeof(struct snd_pcm_sw_params));
-    if (!params) {
-        LOG_ALWAYS_FATAL("Failed to allocate ALSA software parameters!");
-        return NO_INIT;
-    }
-
-#ifdef QCOM_SSR_ENABLED
-    if (channels == 6) {
-        if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
-            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
-            ALOGV("SWParams: Use 4 channels in kernel for 5.1(%s) recording ", handle->useCase);
-            channels = 4;
-        }
-    }
-#endif
-
-    // Get the current software parameters
-    params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
-    params->period_step = 1;
-    if(((!strcmp(handle->useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
-        (!strcmp(handle->useCase,SND_USE_CASE_VERB_IP_VOICECALL)))){
-          ALOGV("setparam:  start & stop threshold for Voip ");
-          params->avail_min = handle->channels - 1 ? periodSize/4 : periodSize/2;
-          params->start_threshold = periodSize/2;
-          params->stop_threshold = INT_MAX;
-     } else {
-         params->avail_min = periodSize/(channels * 2);
-         params->start_threshold = periodSize/(channels * 2);
-         params->stop_threshold = INT_MAX;
-     }
-    params->silence_threshold = 0;
-    params->silence_size = 0;
-
-    if (param_set_sw_params(handle->handle, params)) {
-        ALOGE("cannot set sw params");
-        return NO_INIT;
-    }
-    return NO_ERROR;
-}
-
-void switchDevice(alsa_handle_t *handle, uint32_t devices, uint32_t mode)
-{
-    const char **mods_list;
-    use_case_t useCaseNode;
-    unsigned usecase_type = 0;
-    bool inCallDevSwitch = false;
-    char *rxDevice, *txDevice, ident[70], *use_case = NULL;
-    int err = 0, index, mods_size;
-    int rx_dev_id, tx_dev_id;
-    ALOGD("%s: device %d mode:%d", __FUNCTION__, devices, mode);
-
-    if ((mode == AudioSystem::MODE_IN_CALL)  || (mode == AudioSystem::MODE_IN_COMMUNICATION)) {
-        if ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
-            (devices & AudioSystem::DEVICE_IN_WIRED_HEADSET)) {
-            devices = devices | (AudioSystem::DEVICE_OUT_WIRED_HEADSET |
-                      AudioSystem::DEVICE_IN_WIRED_HEADSET);
-        } else if (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) {
-            devices = devices | (AudioSystem::DEVICE_OUT_WIRED_HEADPHONE |
-                      AudioSystem::DEVICE_IN_BUILTIN_MIC);
-        } else if (devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) {
-            if (mode == AudioSystem::MODE_IN_CALL) {
-                devices |= AudioSystem::DEVICE_OUT_EARPIECE;
-//use QCOM_BACK_MIC_ENABLED only when BACK_MIC is supported by HW
-#ifdef QCOM_BACK_MIC_ENABLED
-            } else if (mode == AudioSystem::MODE_IN_COMMUNICATION) {
-                if (!strncmp(curRxUCMDevice, SND_USE_CASE_DEV_SPEAKER, MAX_LEN(curRxUCMDevice, SND_USE_CASE_DEV_SPEAKER))) {
-                    devices &= ~AudioSystem::DEVICE_IN_BUILTIN_MIC;
-                    devices |= AudioSystem::DEVICE_IN_BACK_MIC;
-                }
-#endif
-            }
-        } else if (devices & AudioSystem::DEVICE_OUT_EARPIECE) {
-            devices = devices | AudioSystem::DEVICE_IN_BUILTIN_MIC;
-        } else if (devices & AudioSystem::DEVICE_OUT_SPEAKER) {
-#ifdef QCOM_BACK_MIC_ENABLED
-            devices = devices | (AudioSystem::DEVICE_IN_BACK_MIC |
-#else
-            devices = devices | (AudioSystem::DEVICE_IN_BUILTIN_MIC |
-#endif
-                       AudioSystem::DEVICE_OUT_SPEAKER);
-        } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO) ||
-                   (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET) ||
-                   (devices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {
-            devices = devices | (AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET |
-                      AudioSystem::DEVICE_OUT_BLUETOOTH_SCO);
-#ifdef QCOM_ANC_HEADSET_ENABLED
-        } else if ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
-                   (devices & AudioSystem::DEVICE_IN_ANC_HEADSET)) {
-            devices = devices | (AudioSystem::DEVICE_OUT_ANC_HEADSET |
-                      AudioSystem::DEVICE_IN_ANC_HEADSET);
-        } else if (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE) {
-            devices = devices | (AudioSystem::DEVICE_OUT_ANC_HEADPHONE |
-                      AudioSystem::DEVICE_IN_BUILTIN_MIC);
-#endif
-        } else if (devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
-            if (mode == AudioSystem::MODE_IN_CALL)
-#ifdef QCOM_BACK_MIC_ENABLED
-                devices = devices | (AudioSystem::DEVICE_IN_BACK_MIC |
-#else
-                devices = devices | (AudioSystem::DEVICE_IN_BUILTIN_MIC |
-#endif
-                           AudioSystem::DEVICE_OUT_SPEAKER);
-            else
-                devices = devices | (AudioSystem::DEVICE_OUT_AUX_DIGITAL |
-#ifdef QCOM_BACK_MIC_ENABLED
-                          AudioSystem::DEVICE_IN_BACK_MIC);
-#else
-                          AudioSystem::DEVICE_IN_BUILTIN_MIC);
-#endif
-#ifdef QCOM_PROXY_DEVICE_ENABLED
-        } else if ((devices & AudioSystem::DEVICE_OUT_PROXY) ||
-                  (devices & AudioSystem::DEVICE_IN_PROXY)) {
-            devices = devices | (AudioSystem::DEVICE_OUT_PROXY |
-                      AudioSystem::DEVICE_IN_PROXY);
-#endif
-        }
-    }
-#ifdef QCOM_SSR_ENABLED
-    if ((devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) && ( 6 == handle->channels)) {
-        if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
-            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
-            ALOGV(" switchDevice , use ssr devices for channels:%d usecase:%s",handle->channels,handle->useCase);
-            s_set_flags(SSRQMIC_FLAG);
-        }
-    }
-#endif
-
-    rxDevice = getUCMDevice(devices & AudioSystem::DEVICE_OUT_ALL, 0, NULL);
-    txDevice = getUCMDevice(devices & AudioSystem::DEVICE_IN_ALL, 1, rxDevice);
-
-    if ((rxDevice != NULL) && (txDevice != NULL)) {
-        if (((strncmp(rxDevice, curRxUCMDevice, MAX_STR_LEN)) ||
-            (strncmp(txDevice, curTxUCMDevice, MAX_STR_LEN))) &&
-            ((mode == AudioSystem::MODE_IN_CALL)  ||
-            (mode == AudioSystem::MODE_IN_COMMUNICATION)))
-            inCallDevSwitch = true;
-    }
-
-#ifdef QCOM_CSDCLIENT_ENABLED
-    if (platform_is_Fusion3() && (inCallDevSwitch == true)) {
-        if (csd_disable_device == NULL) {
-            ALOGE("dlsym:Error:%s Loading csd_client_disable_device", dlerror());
-        } else {
-            err = csd_disable_device();
-            if (err < 0)
-            {
-                ALOGE("csd_client_disable_device, failed, error %d", err);
-            }
-        }
-    }
-#endif
-
-    snd_use_case_get(handle->ucMgr, "_verb", (const char **)&use_case);
-    mods_size = snd_use_case_get_list(handle->ucMgr, "_enamods", &mods_list);
-    if (rxDevice != NULL) {
-        if ((strncmp(curRxUCMDevice, "None", 4)) &&
-            ((strncmp(rxDevice, curRxUCMDevice, 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);
-                if (usecase_type & USECASE_TYPE_RX) {
-                    ALOGD("Deroute use case %s type is %d\n", use_case, usecase_type);
-                    strlcpy(useCaseNode.useCase, use_case, MAX_STR_LEN);
-                    snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE);
-                    mUseCaseList.push_front(useCaseNode);
-                }
-            }
-            if (mods_size) {
-                for(index = 0; index < mods_size; index++) {
-                    usecase_type = getUseCaseType(mods_list[index]);
-                    if (usecase_type & USECASE_TYPE_RX) {
-                        ALOGD("Deroute use case %s type is %d\n", mods_list[index], usecase_type);
-                        strlcpy(useCaseNode.useCase, mods_list[index], MAX_STR_LEN);
-                        snd_use_case_set(handle->ucMgr, "_dismod", mods_list[index]);
-                        mUseCaseList.push_back(useCaseNode);
-                    }
-                }
-            }
-            snd_use_case_set(handle->ucMgr, "_disdev", curRxUCMDevice);
-        }
-    }
-    if (txDevice != NULL) {
-        if ((strncmp(curTxUCMDevice, "None", 4)) &&
-            ((strncmp(txDevice, curTxUCMDevice, 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);
-                if ((usecase_type & USECASE_TYPE_TX) && (!(usecase_type & USECASE_TYPE_RX))) {
-                    ALOGD("Deroute use case %s type is %d\n", use_case, usecase_type);
-                    strlcpy(useCaseNode.useCase, use_case, MAX_STR_LEN);
-                    snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE);
-                    mUseCaseList.push_front(useCaseNode);
-                }
-            }
-            if (mods_size) {
-                for(index = 0; index < mods_size; index++) {
-                    usecase_type = getUseCaseType(mods_list[index]);
-                    if ((usecase_type & USECASE_TYPE_TX) && (!(usecase_type & USECASE_TYPE_RX))) {
-                        ALOGD("Deroute use case %s type is %d\n", mods_list[index], usecase_type);
-                        strlcpy(useCaseNode.useCase, mods_list[index], MAX_STR_LEN);
-                        snd_use_case_set(handle->ucMgr, "_dismod", mods_list[index]);
-                        mUseCaseList.push_back(useCaseNode);
-                    }
-                }
-            }
-            snd_use_case_set(handle->ucMgr, "_disdev", curTxUCMDevice);
-       }
-    }
-    ALOGD("%s,rxDev:%s, txDev:%s, curRxDev:%s, curTxDev:%s\n", __FUNCTION__, rxDevice, txDevice, curRxUCMDevice, curTxUCMDevice);
-
-    if (rxDevice != NULL) {
-        snd_use_case_set(handle->ucMgr, "_enadev", rxDevice);
-        strlcpy(curRxUCMDevice, rxDevice, sizeof(curRxUCMDevice));
-#ifdef QCOM_FM_ENABLED
-        if (devices & AudioSystem::DEVICE_OUT_FM)
-            s_set_fm_vol(fmVolume);
-#endif
-    }
-    if (txDevice != NULL) {
-       snd_use_case_set(handle->ucMgr, "_enadev", txDevice);
-       strlcpy(curTxUCMDevice, txDevice, sizeof(curTxUCMDevice));
-    }
-    for(ALSAUseCaseList::iterator it = mUseCaseList.begin(); it != mUseCaseList.end(); ++it) {
-        ALOGD("Route use case %s\n", it->useCase);
-        if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
-            strlen(SND_USE_CASE_VERB_INACTIVE))) && (!strncmp(use_case, it->useCase, MAX_UC_LEN))) {
-            snd_use_case_set(handle->ucMgr, "_verb", it->useCase);
-        } else {
-            snd_use_case_set(handle->ucMgr, "_enamod", it->useCase);
-        }
-    }
-    if (!mUseCaseList.empty())
-        mUseCaseList.clear();
-    if (use_case != NULL) {
-        free(use_case);
-        use_case = NULL;
-    }
-    ALOGD("switchDevice: curTxUCMDevivce %s curRxDevDevice %s", curTxUCMDevice, curRxUCMDevice);
-
-    if (platform_is_Fusion3() && (inCallDevSwitch == true)) {
-        /* get tx acdb id */
-        memset(&ident,0,sizeof(ident));
-        strlcpy(ident, "ACDBID/", sizeof(ident));
-        strlcat(ident, curTxUCMDevice, 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, curRxUCMDevice, sizeof(ident));
-        rx_dev_id = snd_use_case_get(handle->ucMgr, ident, NULL);
-
-        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;
-        }
-
-#ifdef QCOM_CSDCLIENT_ENABLED
-        ALOGV("rx_dev_id=%d, tx_dev_id=%d\n", rx_dev_id, tx_dev_id);
-        if (csd_enable_device == NULL) {
-            ALOGE("dlsym:Error:%s Loading csd_client_enable_device", dlerror());
-        } else {
-            err = csd_enable_device(rx_dev_id, tx_dev_id, mDevSettingsFlag);
-            if (err < 0)
-            {
-                ALOGE("csd_client_disable_device failed, error %d", err);
-            }
-        }
-#endif
-    }
-
-    if (rxDevice != NULL) {
-        free(rxDevice);
-        rxDevice = NULL;
-    }
-    if (txDevice != NULL) {
-        free(txDevice);
-        txDevice = NULL;
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-static status_t s_init(alsa_device_t *module, ALSAHandleList &list)
-{
-    ALOGV("s_init: Initializing devices for ALSA module");
-
-    list.clear();
-
-    return NO_ERROR;
-}
-
-static status_t s_open(alsa_handle_t *handle)
-{
-    char *devName;
-    unsigned flags = 0;
-    int err = NO_ERROR;
-
-    if(handle->devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
-        err = setHDMIChannelCount();
-        if(err != OK) {
-            ALOGE("setHDMIChannelCount err = %d", err);
-            return err;
-        }
-    }
-    /* No need to call s_close for LPA as pcm device open and close is handled by LPAPlayer in stagefright */
-    if((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA))
-    ||(!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) || (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
-        ALOGV("s_open: Opening LPA /Tunnel playback");
-        return NO_ERROR;
-    }
-
-    s_close(handle);
-
-    ALOGV("s_open: handle %p", handle);
-
-    // ASoC multicomponent requires a valid path (frontend/backend) for
-    // the device to be opened
-
-    // The PCM stream is opened in blocking mode, per ALSA defaults.  The
-    // AudioFlinger seems to assume blocking mode too, so asynchronous mode
-    // should not be used.
-    if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
-        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) ||
-        (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
-        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
-        ALOGV("LPA/tunnel use case");
-        flags |= PCM_MMAP;
-        flags |= DEBUG_ON;
-    } else if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI)) ||
-        (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI2)) ||
-        (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) ||
-        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
-        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
-        (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC))) {
-        ALOGV("Music case");
-        flags = PCM_OUT;
-    } else {
-        flags = PCM_IN;
-    }
-    if (handle->channels == 1) {
-        flags |= PCM_MONO;
-    }
-    else if (handle->channels == 4 ) {
-        flags |= PCM_QUAD;
-    } else if (handle->channels == 6 ) {
-#ifdef QCOM_SSR_ENABLED
-        if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
-            || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
-            flags |= PCM_QUAD;
-        } else {
-            flags |= PCM_5POINT1;
-        }
-#else
-        flags |= PCM_5POINT1;
-#endif
-    }
-    else {
-        flags |= PCM_STEREO;
-    }
-    if (deviceName(handle, flags, &devName) < 0) {
-        ALOGE("Failed to get pcm device node: %s", devName);
-        return NO_INIT;
-    }
-    if (devName != NULL) {
-        handle->handle = pcm_open(flags, (char*)devName);
-    } else {
-        ALOGE("Failed to get pcm device node");
-        return NO_INIT;
-    }
-
-    if (!handle->handle) {
-        ALOGE("s_open: Failed to initialize ALSA device '%s'", devName);
-        free(devName);
-        return NO_INIT;
-    }
-
-    handle->handle->flags = flags;
-    err = setHardwareParams(handle);
-
-    if (err == NO_ERROR) {
-        err = setSoftwareParams(handle);
-    }
-
-    if(err != NO_ERROR) {
-        ALOGE("Set HW/SW params failed: Closing the pcm stream");
-        s_standby(handle);
-    }
-
-    free(devName);
-    return NO_ERROR;
-}
-
-static status_t s_start_voip_call(alsa_handle_t *handle)
-{
-
-    char* devName;
-    char* devName1;
-    unsigned flags = 0;
-    int err = NO_ERROR;
-    uint8_t voc_pkt[VOIP_BUFFER_MAX_SIZE];
-
-    s_close(handle);
-    flags = PCM_OUT;
-    flags |= PCM_MONO;
-    ALOGV("s_open:s_start_voip_call  handle %p", handle);
-
-    if (deviceName(handle, flags, &devName) < 0) {
-         ALOGE("Failed to get pcm device node");
-         return NO_INIT;
-    }
-
-    if (devName != NULL) {
-        handle->handle = pcm_open(flags, (char*)devName);
-    } else {
-         ALOGE("Failed to get pcm device node");
-         return NO_INIT;
-    }
-
-     if (!handle->handle) {
-          free(devName);
-          ALOGE("s_open: Failed to initialize ALSA device '%s'", devName);
-          return NO_INIT;
-     }
-
-     if (!pcm_ready(handle->handle)) {
-         ALOGE(" pcm ready failed");
-     }
-
-     handle->handle->flags = flags;
-     err = setHardwareParams(handle);
-
-     if (err == NO_ERROR) {
-         err = setSoftwareParams(handle);
-     }
-
-     err = pcm_prepare(handle->handle);
-     if(err != NO_ERROR) {
-         ALOGE("DEVICE_OUT_DIRECTOUTPUT: pcm_prepare failed");
-     }
-
-     /* first write required start dsp */
-     memset(&voc_pkt,0,sizeof(voc_pkt));
-     pcm_write(handle->handle,&voc_pkt,handle->handle->period_size);
-     handle->rxHandle = handle->handle;
-     free(devName);
-     ALOGV("s_open: DEVICE_IN_COMMUNICATION ");
-     flags = PCM_IN;
-     flags |= PCM_MONO;
-     handle->handle = 0;
-
-     if (deviceName(handle, flags, &devName1) < 0) {
-        ALOGE("Failed to get pcm device node");
-        return NO_INIT;
-     }
-    if (devName != NULL) {
-        handle->handle = pcm_open(flags, (char*)devName1);
-    } else {
-         ALOGE("Failed to get pcm device node");
-         return NO_INIT;
-    }
-
-     if (!handle->handle) {
-         free(devName);
-         ALOGE("s_open: Failed to initialize ALSA device '%s'", devName);
-         return NO_INIT;
-     }
-
-     if (!pcm_ready(handle->handle)) {
-        ALOGE(" pcm ready in failed");
-     }
-
-     handle->handle->flags = flags;
-
-     err = setHardwareParams(handle);
-
-     if (err == NO_ERROR) {
-         err = setSoftwareParams(handle);
-     }
-
-
-     err = pcm_prepare(handle->handle);
-     if(err != NO_ERROR) {
-         ALOGE("DEVICE_IN_COMMUNICATION: pcm_prepare failed");
-     }
-
-     /* first read required start dsp */
-     memset(&voc_pkt,0,sizeof(voc_pkt));
-     pcm_read(handle->handle,&voc_pkt,handle->handle->period_size);
-     return NO_ERROR;
-}
-
-static status_t s_start_voice_call(alsa_handle_t *handle)
-{
-    char* devName;
-    unsigned flags = 0;
-    int err = NO_ERROR;
-
-    ALOGV("s_start_voice_call: handle %p", handle);
-
-    // ASoC multicomponent requires a valid path (frontend/backend) for
-    // the device to be opened
-
-    flags = PCM_OUT | PCM_MONO;
-    if (deviceName(handle, flags, &devName) < 0) {
-        ALOGE("Failed to get pcm device node");
-        return NO_INIT;
-    }
-    if (devName != NULL) {
-        handle->handle = pcm_open(flags, (char*)devName);
-    } else {
-         ALOGE("Failed to get pcm device node");
-         return NO_INIT;
-    }
-    if (!handle->handle) {
-        ALOGE("s_start_voicecall: could not open PCM device");
-        goto Error;
-    }
-
-    handle->handle->flags = flags;
-    err = setHardwareParams(handle);
-    if(err != NO_ERROR) {
-        ALOGE("s_start_voice_call: setHardwareParams failed");
-        goto Error;
-    }
-
-    err = setSoftwareParams(handle);
-    if(err != NO_ERROR) {
-        ALOGE("s_start_voice_call: setSoftwareParams failed");
-        goto Error;
-    }
-
-    err = pcm_prepare(handle->handle);
-    if(err != NO_ERROR) {
-        ALOGE("s_start_voice_call: pcm_prepare failed");
-        goto Error;
-    }
-
-    if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
-        ALOGE("s_start_voice_call:SNDRV_PCM_IOCTL_START failed\n");
-        goto Error;
-    }
-
-    // Store the PCM playback device pointer in rxHandle
-    handle->rxHandle = handle->handle;
-    free(devName);
-
-    // Open PCM capture device
-    flags = PCM_IN | PCM_MONO;
-    if (deviceName(handle, flags, &devName) < 0) {
-        ALOGE("Failed to get pcm device node");
-        goto Error;
-    }
-    if (devName != NULL) {
-        handle->handle = pcm_open(flags, (char*)devName);
-    } else {
-         ALOGE("Failed to get pcm device node");
-         return NO_INIT;
-    }
-    if (!handle->handle) {
-        free(devName);
-        goto Error;
-    }
-
-    handle->handle->flags = flags;
-    err = setHardwareParams(handle);
-    if(err != NO_ERROR) {
-        ALOGE("s_start_voice_call: setHardwareParams failed");
-        goto Error;
-    }
-
-    err = setSoftwareParams(handle);
-    if(err != NO_ERROR) {
-        ALOGE("s_start_voice_call: setSoftwareParams failed");
-        goto Error;
-    }
-
-    err = pcm_prepare(handle->handle);
-    if(err != NO_ERROR) {
-        ALOGE("s_start_voice_call: pcm_prepare failed");
-        goto Error;
-    }
-
-    if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
-        ALOGE("s_start_voice_call:SNDRV_PCM_IOCTL_START failed\n");
-        goto Error;
-    }
-
-    if (platform_is_Fusion3()) {
-#ifdef QCOM_CSDCLIENT_ENABLED
-        if (csd_start_voice == NULL) {
-            ALOGE("dlsym:Error:%s Loading csd_client_start_voice", dlerror());
-        } else {
-            err = csd_start_voice();
-            if (err < 0){
-                ALOGE("s_start_voice_call: csd_client error %d\n", err);
-                goto Error;
-            }
-        }
-#endif
-    }
-
-    free(devName);
-    return NO_ERROR;
-
-Error:
-    ALOGE("s_start_voice_call: Failed to initialize ALSA device '%s'", devName);
-    free(devName);
-    s_close(handle);
-    return NO_INIT;
-}
-
-static status_t s_start_fm(alsa_handle_t *handle)
-{
-    char *devName;
-    unsigned flags = 0;
-    int err = NO_ERROR;
-
-    ALOGV("s_start_fm: handle %p", handle);
-
-    // ASoC multicomponent requires a valid path (frontend/backend) for
-    // the device to be opened
-
-    flags = PCM_OUT | PCM_STEREO;
-    if (deviceName(handle, flags, &devName) < 0) {
-        ALOGE("Failed to get pcm device node");
-        goto Error;
-    }
-    if (devName != NULL) {
-        handle->handle = pcm_open(flags, (char*)devName);
-    } else {
-         ALOGE("Failed to get pcm device node");
-         return NO_INIT;
-    }
-    if (!handle->handle) {
-        ALOGE("s_start_fm: could not open PCM device");
-        goto Error;
-    }
-
-    handle->handle->flags = flags;
-    err = setHardwareParams(handle);
-    if(err != NO_ERROR) {
-        ALOGE("s_start_fm: setHardwareParams failed");
-        goto Error;
-    }
-
-    err = setSoftwareParams(handle);
-    if(err != NO_ERROR) {
-        ALOGE("s_start_fm: setSoftwareParams failed");
-        goto Error;
-    }
-
-    err = pcm_prepare(handle->handle);
-    if(err != NO_ERROR) {
-        ALOGE("s_start_fm: setSoftwareParams failed");
-        goto Error;
-    }
-
-    if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
-        ALOGE("s_start_fm: SNDRV_PCM_IOCTL_START failed\n");
-        goto Error;
-    }
-
-    // Store the PCM playback device pointer in rxHandle
-    handle->rxHandle = handle->handle;
-    free(devName);
-
-    // Open PCM capture device
-    flags = PCM_IN | PCM_STEREO;
-    if (deviceName(handle, flags, &devName) < 0) {
-        ALOGE("Failed to get pcm device node");
-        goto Error;
-    }
-    if (devName != NULL) {
-        handle->handle = pcm_open(flags, (char*)devName);
-    } else {
-         ALOGE("Failed to get pcm device node");
-         return NO_INIT;
-    }
-    if (!handle->handle) {
-        goto Error;
-    }
-
-    handle->handle->flags = flags;
-    err = setHardwareParams(handle);
-    if(err != NO_ERROR) {
-        ALOGE("s_start_fm: setHardwareParams failed");
-        goto Error;
-    }
-
-    err = setSoftwareParams(handle);
-    if(err != NO_ERROR) {
-        ALOGE("s_start_fm: setSoftwareParams failed");
-        goto Error;
-    }
-
-    err = pcm_prepare(handle->handle);
-    if(err != NO_ERROR) {
-        ALOGE("s_start_fm: pcm_prepare failed");
-        goto Error;
-    }
-
-    if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
-        ALOGE("s_start_fm: SNDRV_PCM_IOCTL_START failed\n");
-        goto Error;
-    }
-
-    s_set_fm_vol(fmVolume);
-    free(devName);
-    return NO_ERROR;
-
-Error:
-    free(devName);
-    s_close(handle);
-    return NO_INIT;
-}
-
-static status_t s_set_fm_vol(int value)
-{
-    status_t err = NO_ERROR;
-
-    ALSAControl control("/dev/snd/controlC0");
-    control.set("Internal FM RX Volume",value,0);
-    fmVolume = value;
-
-    return err;
-}
-
-static status_t s_set_lpa_vol(int value)
-{
-    status_t err = NO_ERROR;
-
-    ALSAControl control("/dev/snd/controlC0");
-    control.set("LPA RX Volume",value,0);
-
-    return err;
-}
-
-static status_t s_start(alsa_handle_t *handle)
-{
-    status_t err = NO_ERROR;
-
-    if(!handle->handle) {
-        ALOGE("No active PCM driver to start");
-        return err;
-    }
-
-    err = pcm_prepare(handle->handle);
-
-    return err;
-}
-
-static status_t s_close(alsa_handle_t *handle)
-{
-    int ret;
-    status_t err = NO_ERROR;
-     struct pcm *h = handle->rxHandle;
-
-    handle->rxHandle = 0;
-    ALOGV("s_close: handle %p h %p", handle, h);
-    if (h) {
-        if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_VOICECALL) ||
-             !strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_VOICE)) &&
-            platform_is_Fusion3()) {
-#ifdef QCOM_CSDCLIENT_ENABLED
-            if (csd_stop_voice == NULL) {
-                ALOGE("dlsym:Error:%s Loading csd_client_disable_device", dlerror());
-            } else {
-                err = csd_stop_voice();
-                if (err < 0) {
-                    ALOGE("s_close: csd_client error %d\n", err);
-                }
-            }
-#endif
-        }
-
-        ALOGV("s_close rxHandle\n");
-        err = pcm_close(h);
-        if(err != NO_ERROR) {
-            ALOGE("s_close: pcm_close failed for rxHandle with err %d", err);
-        }
-    }
-
-    h = handle->handle;
-    handle->handle = 0;
-
-    if (h) {
-        ALOGV("s_close handle h %p\n", h);
-        err = pcm_close(h);
-        if(err != NO_ERROR) {
-            ALOGE("s_close: pcm_close failed for handle with err %d", err);
-        }
-
-        disableDevice(handle);
-    } else if((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
-              (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) ||
-              (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
-              (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))){
-        disableDevice(handle);
-    }
-
-    return err;
-}
-
-/*
-    this is same as s_close, but don't discard
-    the device/mode info. This way we can still
-    close the device, hit idle and power-save, reopen the pcm
-    for the same device/mode after resuming
-*/
-static status_t s_standby(alsa_handle_t *handle)
-{
-    int ret;
-    status_t err = NO_ERROR;
-    struct pcm *h = handle->rxHandle;
-    handle->rxHandle = 0;
-    ALOGV("s_standby: handle %p h %p", handle, h);
-    if (h) {
-        ALOGD("s_standby  rxHandle\n");
-        err = pcm_close(h);
-        if(err != NO_ERROR) {
-            ALOGE("s_standby: pcm_close failed for rxHandle with err %d", err);
-        }
-    }
-
-    h = handle->handle;
-    handle->handle = 0;
-
-    if (h) {
-          ALOGV("s_standby handle h %p\n", h);
-        err = pcm_close(h);
-        if(err != NO_ERROR) {
-            ALOGE("s_standby: pcm_close failed for handle with err %d", err);
-        }
-        disableDevice(handle);
-    } else if((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
-              (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) ||
-              (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
-              (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
-        disableDevice(handle);
-    }
-
-    return err;
-}
-
-static status_t s_route(alsa_handle_t *handle, uint32_t devices, int mode)
-{
-    status_t status = NO_ERROR;
-
-    ALOGD("s_route: devices 0x%x in mode %d", devices, mode);
-    callMode = mode;
-    switchDevice(handle, devices, mode);
-    return status;
-}
-
-int getUseCaseType(const char *useCase)
-{
-    ALOGD("use case is %s\n", useCase);
-    if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI,
-            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI)) ||
-        !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
-            MAX_LEN(useCase, SND_USE_CASE_VERB_HIFI2)) ||
-        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC,
-            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) ||
-        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
-            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
-        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
-            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
-        !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
-            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI2)) ||
-        !strncmp(useCase, SND_USE_CASE_VERB_DIGITAL_RADIO,
-            MAX_LEN(useCase,SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
-            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
-            MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC,
-            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
-            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LPA,
-            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LPA)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
-            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_FM,
-            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))) {
-        return USECASE_TYPE_RX;
-    } else if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC,
-            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC)) ||
-        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC,
-            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC)) ||
-        !strncmp(useCase, SND_USE_CASE_VERB_FM_REC,
-            MAX_LEN(useCase,SND_USE_CASE_VERB_FM_REC)) ||
-        !strncmp(useCase, SND_USE_CASE_VERB_FM_A2DP_REC,
-            MAX_LEN(useCase,SND_USE_CASE_VERB_FM_A2DP_REC)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC,
-            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC,
-            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_FM,
-            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_FM)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM,
-            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_A2DP_FM))) {
-        return USECASE_TYPE_TX;
-    } else if (!strncmp(useCase, SND_USE_CASE_VERB_VOICECALL,
-            MAX_LEN(useCase,SND_USE_CASE_VERB_VOICECALL)) ||
-        !strncmp(useCase, SND_USE_CASE_VERB_IP_VOICECALL,
-            MAX_LEN(useCase,SND_USE_CASE_VERB_IP_VOICECALL)) ||
-        !strncmp(useCase, SND_USE_CASE_VERB_DL_REC,
-            MAX_LEN(useCase,SND_USE_CASE_VERB_DL_REC)) ||
-        !strncmp(useCase, SND_USE_CASE_VERB_UL_DL_REC,
-            MAX_LEN(useCase,SND_USE_CASE_VERB_UL_DL_REC)) ||
-        !strncmp(useCase, SND_USE_CASE_VERB_INCALL_REC,
-            MAX_LEN(useCase,SND_USE_CASE_VERB_INCALL_REC)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE,
-            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOIP,
-            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
-            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
-            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
-            MAX_LEN(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE)) ||
-        !strncmp(useCase, SND_USE_CASE_VERB_VOLTE,
-            MAX_LEN(useCase,SND_USE_CASE_VERB_VOLTE)) ||
-        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
-            MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_VOLTE))) {
-        return (USECASE_TYPE_RX | USECASE_TYPE_TX);
-    } else {
-        ALOGE("unknown use case %s\n", useCase);
-        return 0;
-    }
-}
-
-static void disableDevice(alsa_handle_t *handle)
-{
-    unsigned usecase_type = 0;
-    int i, mods_size;
-    char *useCase;
-    const char **mods_list;
-
-    snd_use_case_get(handle->ucMgr, "_verb", (const char **)&useCase);
-    if (useCase != NULL) {
-        if (!strncmp(useCase, handle->useCase, MAX_UC_LEN)) {
-            snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE);
-        } else {
-            snd_use_case_set(handle->ucMgr, "_dismod", handle->useCase);
-        }
-        free(useCase);
-        snd_use_case_get(handle->ucMgr, "_verb", (const char **)&useCase);
-        if (strncmp(useCase, SND_USE_CASE_VERB_INACTIVE,
-               strlen(SND_USE_CASE_VERB_INACTIVE)))
-            usecase_type |= getUseCaseType(useCase);
-        mods_size = snd_use_case_get_list(handle->ucMgr, "_enamods", &mods_list);
-        ALOGV("Number of modifiers %d\n", mods_size);
-        if (mods_size) {
-            for(i = 0; i < mods_size; i++) {
-                ALOGV("index %d modifier %s\n", i, mods_list[i]);
-                usecase_type |= getUseCaseType(mods_list[i]);
-            }
-        }
-        ALOGV("usecase_type is %d\n", usecase_type);
-        if (!(usecase_type & USECASE_TYPE_TX) && (strncmp(curTxUCMDevice, "None", 4)))
-            snd_use_case_set(handle->ucMgr, "_disdev", curTxUCMDevice);
-        if (!(usecase_type & USECASE_TYPE_RX) && (strncmp(curRxUCMDevice, "None", 4)))
-            snd_use_case_set(handle->ucMgr, "_disdev", curRxUCMDevice);
-    } else {
-        ALOGE("Invalid state, no valid use case found to disable");
-    }
-    free(useCase);
-}
-
-char *getUCMDevice(uint32_t devices, int input, char *rxDevice)
-{
-    if (!input) {
-        if (!(mDevSettingsFlag & TTY_OFF) &&
-            (callMode == AudioSystem::MODE_IN_CALL) &&
-            ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
-             (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) {
-#ifdef QCOM_ANC_HEADSET_ENABLED
-             ||
-             (devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
-             (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE))) {
-#endif
-             if (mDevSettingsFlag & TTY_VCO) {
-                 return strdup(SND_USE_CASE_DEV_TTY_HEADSET_RX);
-             } else if (mDevSettingsFlag & TTY_FULL) {
-                 return strdup(SND_USE_CASE_DEV_TTY_FULL_RX);
-             } else if (mDevSettingsFlag & TTY_HCO) {
-                 return strdup(SND_USE_CASE_DEV_TTY_HANDSET_RX); /* HANDSET RX */
-             }
-        }else if ((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) ||
-                  (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)) {
-             return strdup(SND_USE_CASE_DEV_PROXY_RX); /* PROXY RX */
-        } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
-            ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
-            (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) {
-            if (mDevSettingsFlag & ANC_FLAG) {
-                return strdup(SND_USE_CASE_DEV_SPEAKER_ANC_HEADSET); /* COMBO SPEAKER+ANC HEADSET RX */
-            } else {
-                return strdup(SND_USE_CASE_DEV_SPEAKER_HEADSET); /* COMBO SPEAKER+HEADSET RX */
-            }
-        } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
-            ((devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL))) {
-            return strdup(SND_USE_CASE_DEV_HDMI_SPEAKER);
-#ifdef QCOM_ANC_HEADSET_ENABLED
-        } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
-            ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
-            (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE))) {
-            return strdup(SND_USE_CASE_DEV_SPEAKER_ANC_HEADSET); /* COMBO SPEAKER+ANC HEADSET RX */
-        } 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 */
-#endif
-        } else if (devices & AudioSystem::DEVICE_OUT_EARPIECE) {
-            if (callMode == AudioSystem::MODE_IN_CALL) {
-                return strdup(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) {
-            if (callMode == AudioSystem::MODE_IN_CALL) {
-                return strdup(SND_USE_CASE_DEV_VOC_SPEAKER); /* Voice SPEAKER RX */
-            } else
-                return strdup(SND_USE_CASE_DEV_SPEAKER); /* SPEAKER RX */
-        } else if ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
-                   (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) {
-            if (mDevSettingsFlag & ANC_FLAG) {
-                if (callMode == AudioSystem::MODE_IN_CALL) {
-                    return strdup(SND_USE_CASE_DEV_VOC_ANC_HEADSET); /* Voice ANC HEADSET RX */
-                } else
-                    return strdup(SND_USE_CASE_DEV_ANC_HEADSET); /* ANC HEADSET RX */
-            } else {
-                if (callMode == AudioSystem::MODE_IN_CALL) {
-                    return strdup(SND_USE_CASE_DEV_VOC_HEADPHONE); /* Voice HEADSET RX */
-                } else
-                    return strdup(SND_USE_CASE_DEV_HEADPHONES); /* HEADSET RX */
-            }
-#ifdef QCOM_ANC_HEADSET_ENABLED
-        } else if ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
-                   (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE)) {
-            if (callMode == AudioSystem::MODE_IN_CALL) {
-                return strdup(SND_USE_CASE_DEV_VOC_ANC_HEADSET); /* Voice ANC HEADSET RX */
-            } else
-                return strdup(SND_USE_CASE_DEV_ANC_HEADSET); /* ANC HEADSET RX */
-#endif
-        } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO) ||
-                  (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET) ||
-                  (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT)) {
-            if (btsco_samplerate == BTSCO_RATE_16KHZ)
-                return strdup(SND_USE_CASE_DEV_BTSCO_WB_RX); /* BTSCO RX*/
-            else
-                return strdup(SND_USE_CASE_DEV_BTSCO_NB_RX); /* BTSCO RX*/
-        } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP) ||
-                   (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) ||
-#ifdef QCOM_VOIP_ENABLED
-                   (devices & AudioSystem::DEVICE_OUT_DIRECTOUTPUT) ||
-#endif
-                   (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) {
-            /* Nothing to be done, use current active device */
-            if (strncmp(curRxUCMDevice, "None", 4)) {
-                return strdup(curRxUCMDevice);
-            }
-        } else if (devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
-            return strdup(SND_USE_CASE_DEV_HDMI); /* HDMI RX */
-#ifdef QCOM_PROXY_DEVICE_ENABLED
-        } else if (devices & AudioSystem::DEVICE_OUT_PROXY) {
-            return strdup(SND_USE_CASE_DEV_PROXY_RX); /* PROXY RX */
-#endif
-#ifdef QCOM_FM_TX_ENABLED
-        } else if (devices & AudioSystem::DEVICE_OUT_FM_TX) {
-            return strdup(SND_USE_CASE_DEV_FM_TX); /* FM Tx */
-#endif
-        } else if (devices & AudioSystem::DEVICE_OUT_DEFAULT) {
-            if (callMode == AudioSystem::MODE_IN_CALL) {
-                return strdup(SND_USE_CASE_DEV_VOC_SPEAKER); /* Voice SPEAKER RX */
-            } else
-                return strdup(SND_USE_CASE_DEV_SPEAKER); /* SPEAKER RX */
-        } else {
-            ALOGD("No valid output device: %u", devices);
-        }
-    } else {
-        if (!(mDevSettingsFlag & TTY_OFF) &&
-            (callMode == AudioSystem::MODE_IN_CALL) &&
-            ((devices & AudioSystem::DEVICE_IN_WIRED_HEADSET))) {
-#ifdef QCOM_ANC_HEADSET_ENABLED
-            ||(devices & AudioSystem::DEVICE_IN_ANC_HEADSET))) {
-#endif
-             if (mDevSettingsFlag & TTY_HCO) {
-                 return strdup(SND_USE_CASE_DEV_TTY_HEADSET_TX);
-             } else if (mDevSettingsFlag & TTY_FULL) {
-                 return strdup(SND_USE_CASE_DEV_TTY_FULL_TX);
-             } else if (mDevSettingsFlag & TTY_VCO) {
-                 if (!strncmp(mic_type, "analog", 6)) {
-                     return strdup(SND_USE_CASE_DEV_TTY_HANDSET_ANALOG_TX);
-                 } else {
-                     return strdup(SND_USE_CASE_DEV_TTY_HANDSET_TX);
-                 }
-             }
-        } else if (devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) {
-            if (!strncmp(mic_type, "analog", 6)) {
-                return strdup(SND_USE_CASE_DEV_HANDSET); /* HANDSET TX */
-            } else {
-                if (mDevSettingsFlag & DMIC_FLAG) {
-#ifdef USES_FLUENCE_INCALL
-                    if(callMode == AudioSystem::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 (((rxDevice != NULL) &&
-                        !strncmp(rxDevice, SND_USE_CASE_DEV_SPEAKER,
-                        (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) ||
-                        !strncmp(curRxUCMDevice, SND_USE_CASE_DEV_SPEAKER,
-                        (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) {
-                        if (fluence_mode == FLUENCE_MODE_ENDFIRE) {
-                            return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */
-                        } else if (fluence_mode == FLUENCE_MODE_BROADSIDE) {
-                            return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */
-                        }
-                    } else {
-                        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 */
-                        }
-                    }
-#endif
-                } else if (mDevSettingsFlag & QMIC_FLAG){
-                    return strdup(SND_USE_CASE_DEV_QUAD_MIC);
-                }
-#ifdef QCOM_SSR_ENABLED
-                else if (mDevSettingsFlag & SSRQMIC_FLAG){
-                    ALOGV("return SSRQMIC_FLAG: 0x%x devices:0x%x",mDevSettingsFlag,devices);
-                    // Mapping for quad mic input device.
-                    return strdup(SND_USE_CASE_DEV_SSR_QUAD_MIC); /* SSR Quad MIC */
-                }
-#endif
-#ifdef SEPERATED_AUDIO_INPUT
-                if(input_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
-                    return strdup(SND_USE_CASE_DEV_VOICE_RECOGNITION ); /* VOICE RECOGNITION TX */
-                }
-#endif
-                else {
-#ifdef QCOM_BACK_MIC_ENABLED
-                    return strdup(SND_USE_CASE_DEV_HANDSET); /* BUILTIN-MIC TX */
-#else
-                    return strdup(SND_USE_CASE_DEV_LINE); /* BUILTIN-MIC TX */
-#endif
-                }
-            }
-        } else if (devices & AudioSystem::DEVICE_IN_AUX_DIGITAL) {
-            return strdup(SND_USE_CASE_DEV_HDMI_TX); /* HDMI TX */
-#ifdef QCOM_ANC_HEADSET_ENABLED
-        } else if (devices & AudioSystem::DEVICE_IN_ANC_HEADSET) {
-            return strdup(SND_USE_CASE_DEV_HEADSET); /* HEADSET TX */
-#endif
-        } else if (devices & AudioSystem::DEVICE_IN_WIRED_HEADSET) {
-            if (callMode == AudioSystem::MODE_IN_CALL) {
-                return strdup(SND_USE_CASE_DEV_VOC_HEADSET); /* Voice HEADSET TX */
-            } else
-                return strdup(SND_USE_CASE_DEV_HEADSET); /* HEADSET TX */
-        } else if (devices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
-             if (btsco_samplerate == BTSCO_RATE_16KHZ)
-                 return strdup(SND_USE_CASE_DEV_BTSCO_WB_TX); /* BTSCO TX*/
-             else
-                 return strdup(SND_USE_CASE_DEV_BTSCO_NB_TX); /* BTSCO TX*/
-#ifdef QCOM_USBAUDIO_ENABLED
-        } else if ((devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) ||
-                   (devices & AudioSystem::DEVICE_IN_PROXY)) {
-            return strdup(SND_USE_CASE_DEV_PROXY_TX); /* PROXY TX */
-#endif
-        } else if ((devices & AudioSystem::DEVICE_IN_COMMUNICATION) ||
-                   (devices & AudioSystem::DEVICE_IN_VOICE_CALL)) {
-            /* Nothing to be done, use current active device */
-            if (strncmp(curTxUCMDevice, "None", 4)) {
-                return strdup(curTxUCMDevice);
-            }
-#ifdef QCOM_FM_ENABLED
-        } 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 */
-            if (strncmp(curTxUCMDevice, "None", 4)) {
-                return strdup(curTxUCMDevice);
-            } else {
-                return strdup(SND_USE_CASE_DEV_DUMMY_TX);
-            }
-#endif
-        } else if ((devices & AudioSystem::DEVICE_IN_AMBIENT) ||
-                   (devices & AudioSystem::DEVICE_IN_BACK_MIC)) {
-            ALOGI("No proper mapping found with UCM device list, setting default");
-            if (!strncmp(mic_type, "analog", 6)) {
-                return strdup(SND_USE_CASE_DEV_HANDSET); /* HANDSET TX */
-            } else {
-                if (callMode == AudioSystem::MODE_IN_CALL) {
-                    return strdup(SND_USE_CASE_DEV_VOC_LINE); /* Voice BUILTIN-MIC TX */
-#ifdef SEPERATED_AUDIO_INPUT
-                } else if(input_source == AUDIO_SOURCE_CAMCORDER) {
-                    return strdup(SND_USE_CASE_DEV_CAMCORDER_TX ); /* CAMCORDER TX */
-#endif
-                } else
-                    return strdup(SND_USE_CASE_DEV_LINE); /* BUILTIN-MIC TX */
-            }
-        } else {
-            ALOGD("No valid input device: %u", devices);
-        }
-    }
-    return NULL;
-}
-
-void s_set_voice_volume(int vol)
-{
-    int err = 0;
-    ALOGV("s_set_voice_volume: volume %d", vol);
-    ALSAControl control("/dev/snd/controlC0");
-    control.set("Voice Rx Volume", vol, 0);
-
-    if (platform_is_Fusion3()) {
-#ifdef QCOM_CSDCLIENT_ENABLED
-        if (csd_volume == NULL) {
-            ALOGE("dlsym:Error:%s Loading csd_client_volume", dlerror());
-        } else {
-            err = csd_volume(vol);
-            if (err < 0) {
-                ALOGE("s_set_voice_volume: csd_client error %d", err);
-            }
-        }
-#endif
-    }
-}
-
-void s_set_volte_volume(int vol)
-{
-    ALOGV("s_set_volte_volume: volume %d", vol);
-    ALSAControl control("/dev/snd/controlC0");
-    control.set("VoLTE Rx Volume", vol, 0);
-}
-
-
-void s_set_voip_volume(int vol)
-{
-    ALOGV("s_set_voip_volume: volume %d", vol);
-    ALSAControl control("/dev/snd/controlC0");
-    control.set("Voip Rx Volume", vol, 0);
-}
-void s_set_mic_mute(int state)
-{
-    int err = 0;
-    ALOGV("s_set_mic_mute: state %d", state);
-    ALSAControl control("/dev/snd/controlC0");
-    control.set("Voice Tx Mute", state, 0);
-
-    if (platform_is_Fusion3()) {
-#ifdef QCOM_CSDCLIENT_ENABLED
-        if (csd_mic_mute == NULL) {
-            ALOGE("dlsym:Error:%s Loading csd_mic_mute", dlerror());
-        } else {
-            err=csd_mic_mute(state);
-            if (err < 0) {
-                ALOGE("s_set_mic_mute: csd_client error %d", err);
-            }
-        }
-#endif
-    }
-}
-void s_set_volte_mic_mute(int state)
-{
-    ALOGV("s_set_volte_mic_mute: state %d", state);
-    ALSAControl control("/dev/snd/controlC0");
-    control.set("VoLTE Tx Mute", state, 0);
-}
-
-void s_set_voip_mic_mute(int state)
-{
-    ALOGV("s_set_voip_mic_mute: state %d", state);
-    ALSAControl control("/dev/snd/controlC0");
-    control.set("Voip Tx Mute", state, 0);
-}
-
-void s_set_voip_config(int mode, int rate)
-{
-    ALOGV("s_set_voip_config: mode %d,rate %d", mode, rate);
-    ALSAControl control("/dev/snd/controlC0");
-    char** setValues;
-    setValues = (char**)malloc(2*sizeof(char*));
-    if (setValues == NULL) {
-          return;
-    }
-    setValues[0] = (char*)malloc(4*sizeof(char));
-    if (setValues[0] == NULL) {
-          free(setValues);
-          return;
-    }
-
-    setValues[1] = (char*)malloc(8*sizeof(char));
-    if (setValues[1] == NULL) {
-          free(setValues);
-          free(setValues[0]);
-          return;
-    }
-
-    sprintf(setValues[0], "%d",mode);
-    sprintf(setValues[1], "%d",rate);
-
-    control.setext("Voip Mode Rate Config", 2, setValues);
-    free(setValues[1]);
-    free(setValues[0]);
-    free(setValues);
-    return;
-}
-
-void s_set_btsco_rate(int rate)
-{
-    btsco_samplerate = rate;
-}
-
-void s_enable_wide_voice(bool flag)
-{
-    int err = 0;
-
-    ALOGV("s_enable_wide_voice: flag %d", flag);
-    ALSAControl control("/dev/snd/controlC0");
-    if(flag == true) {
-        control.set("Widevoice Enable", 1, 0);
-    } else {
-        control.set("Widevoice Enable", 0, 0);
-    }
-
-    if (platform_is_Fusion3()) {
-#ifdef QCOM_CSDCLIENT_ENABLED
-        if (csd_wide_voice == NULL) {
-            ALOGE("dlsym:Error:%s Loading csd_wide_voice", dlerror());
-        } else {
-            err = csd_wide_voice(flag);
-            if (err < 0) {
-                ALOGE("enableWideVoice: csd_client_wide_voice error %d", err);
-            }
-        }
-#endif
-    }
-}
-
-void s_set_voc_rec_mode(uint8_t mode)
-{
-    ALOGV("s_set_voc_rec_mode: mode %d", mode);
-    ALSAControl control("/dev/snd/controlC0");
-    control.set("Incall Rec Mode", mode, 0);
-}
-
-void s_enable_fens(bool flag)
-{
-    int err = 0;
-
-    ALOGV("s_enable_fens: flag %d", flag);
-    ALSAControl control("/dev/snd/controlC0");
-    if(flag == true) {
-        control.set("FENS Enable", 1, 0);
-    } else {
-        control.set("FENS Enable", 0, 0);
-    }
-
-    if (platform_is_Fusion3()) {
-#ifdef QCOM_CSDCLIENT_ENABLED
-        if (csd_fens == NULL) {
-            ALOGE("dlsym:Error:%s Loading csd_fens", dlerror());
-        } else {
-            err = csd_fens(flag);
-            if (err < 0) {
-                ALOGE("s_enable_fens: csd_client error %d", err);
-            }
-        }
-#endif
-    }
-}
-
-void s_enable_slow_talk(bool flag)
-{
-    int err = 0;
-
-    ALOGV("s_enable_slow_talk: flag %d", flag);
-    ALSAControl control("/dev/snd/controlC0");
-    if(flag == true) {
-        control.set("Slowtalk Enable", 1, 0);
-    } else {
-        control.set("Slowtalk Enable", 0, 0);
-    }
-
-    if (platform_is_Fusion3()) {
-#ifdef QCOM_CSDCLIENT_ENABLED
-        if (csd_slow_talk == NULL) {
-            ALOGE("dlsym:Error:%s Loading csd_slow_talk", dlerror());
-        } else {
-            err = csd_slow_talk(flag);
-            if (err < 0) {
-                ALOGE("s_enable_slow_talk: csd_client error %d", err);
-            }
-        }
-#endif
-    }
-}
-
-void s_set_flags(uint32_t flags)
-{
-    ALOGV("s_set_flags: flags %d", flags);
-    mDevSettingsFlag = flags;
-}
-
-static status_t s_set_compressed_vol(int value)
-{
-    status_t err = NO_ERROR;
-
-    ALSAControl control("/dev/snd/controlC0");
-    control.set("COMPRESSED RX Volume",value,0);
-
-    return err;
-}
-
-#ifdef SEPERATED_AUDIO_INPUT
-void s_setInput(int input)
-{
-    input_source = input;
-    ALOGD("s_setInput() : input_source = %d",input_source);
-}
-#endif
-
-#ifdef QCOM_CSDCLIENT_ENABLED
-static void  s_set_csd_handle(void* handle)
-{
-    csd_handle = static_cast<void*>(handle);
-    ALOGI("%s csd_handle: %p", __func__, csd_handle);
-
-    csd_disable_device = (int (*)())::dlsym(csd_handle,"csd_client_disable_device");
-    csd_enable_device = (int (*)(int,int,uint32_t))::dlsym(csd_handle,"csd_client_enable_device");
-    csd_start_voice = (int (*)())::dlsym(csd_handle,"csd_client_start_voice");
-    csd_stop_voice = (int (*)())::dlsym(csd_handle,"csd_client_stop_voice");
-    csd_volume = (int (*)(int))::dlsym(csd_handle,"csd_client_volume");
-    csd_mic_mute = (int (*)(int))::dlsym(csd_handle,"csd_client_mic_mute");
-    csd_wide_voice = (int (*)(uint8_t))::dlsym(csd_handle,"csd_client_wide_voice");
-    csd_fens = (int (*)(uint8_t))::dlsym(csd_handle,"csd_client_fens");
-    csd_slow_talk = (int (*)(uint8_t))::dlsym(csd_handle,"csd_client_slow_talk");
-}
-#endif
-
-}
diff --git a/alsa_sound/audio_hw_hal.cpp b/alsa_sound/audio_hw_hal.cpp
index ab15e27..8e7f208 100644
--- a/alsa_sound/audio_hw_hal.cpp
+++ b/alsa_sound/audio_hw_hal.cpp
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2011 The Android Open Source Project
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, 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.
@@ -76,23 +76,14 @@
     { 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 },
 #ifdef QCOM_ANC_HEADSET_ENABLED
     { AudioSystem::DEVICE_OUT_ANC_HEADSET, AUDIO_DEVICE_OUT_ANC_HEADSET },
     { AudioSystem::DEVICE_OUT_ANC_HEADPHONE, AUDIO_DEVICE_OUT_ANC_HEADPHONE },
 #endif
-#ifdef QCOM_FM_ENABLED
-    { AudioSystem::DEVICE_OUT_FM, AUDIO_DEVICE_OUT_FM },
-#endif
-#ifdef QCOM_FM_TX_ENABLED
-    { AudioSystem::DEVICE_OUT_FM_TX, AUDIO_DEVICE_OUT_FM_TX },
-#endif
-#ifdef QCOM_VOIP_ENABLED
-    { AudioSystem::DEVICE_OUT_DIRECTOUTPUT, AUDIO_DEVICE_OUT_DIRECTOUTPUT },
-#endif
 #ifdef QCOM_PROXY_DEVICE_ENABLED
     { AudioSystem::DEVICE_OUT_PROXY, AUDIO_DEVICE_OUT_PROXY },
 #endif
+    { 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 },
@@ -102,16 +93,20 @@
     { 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 },
 #ifdef QCOM_ANC_HEADSET_ENABLED
     { AudioSystem::DEVICE_IN_ANC_HEADSET, AUDIO_DEVICE_IN_ANC_HEADSET },
 #endif
-#ifdef QCOM_FM_ENABLED
-    { AudioSystem::DEVICE_IN_FM_RX, AUDIO_DEVICE_IN_FM_RX },
-    { AudioSystem::DEVICE_IN_FM_RX_A2DP, AUDIO_DEVICE_IN_FM_RX_A2DP },
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+    { AudioSystem::DEVICE_IN_PROXY, AUDIO_DEVICE_IN_PROXY },
 #endif
+    { AudioSystem::DEVICE_IN_DEFAULT, AUDIO_DEVICE_IN_DEFAULT },
 };
 
+// the "audio_devices" enumeration defined in hardware/libhardware_legacy is obsolete,
+// use type "audio_devices_t" and audio device enumeration from system/audio.h instead.
+// Do not use convert_audio_device if audio hal uses device definition from system/core
+// There's no need to conver audio device if HAL uses AUDIO_DEVICE_XXX defintions instead
+// of AudioSystem::Device_XXX.
 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;
@@ -151,7 +146,7 @@
     struct qcom_stream_out *out =
         reinterpret_cast<struct qcom_stream_out *>(stream);
 
-    ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+    ALOGV("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
     /* TODO: implement this */
     return 0;
 }
@@ -181,7 +176,7 @@
 {
     struct qcom_stream_out *out =
         reinterpret_cast<struct qcom_stream_out *>(stream);
-    ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+    ALOGV("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
     /* TODO: implement me */
     return 0;
 }
@@ -301,7 +296,7 @@
     struct qcom_stream_in *in =
         reinterpret_cast<struct qcom_stream_in *>(stream);
 
-    ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+    ALOGV("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
     /* TODO: implement this */
     return 0;
 }
@@ -331,7 +326,7 @@
 {
     struct qcom_stream_in *in =
         reinterpret_cast<struct qcom_stream_in *>(stream);
-    ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+    ALOGV("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
     /* TODO: implement me */
     return 0;
 }
@@ -436,6 +431,69 @@
     return reinterpret_cast<const struct qcom_audio_device *>(dev);
 }
 
+static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev)
+{
+    /* XXX: The old AudioHardwareInterface interface is not smart enough to
+     * tell us this, so we'll lie and basically tell AF that we support the
+     * below input/output devices and cross our fingers. To do things properly,
+     * audio hardware interfaces that need advanced features (like this) should
+     * convert to the new HAL interface and not use this wrapper. */
+    return (/* OUT */
+            AUDIO_DEVICE_OUT_EARPIECE |
+            AUDIO_DEVICE_OUT_SPEAKER |
+            AUDIO_DEVICE_OUT_WIRED_HEADSET |
+            AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+            AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
+            AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+            AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
+            AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
+            AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+            AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
+            AUDIO_DEVICE_OUT_AUX_DIGITAL |
+            AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
+            AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
+            AUDIO_DEVICE_OUT_USB_ACCESSORY |
+            AUDIO_DEVICE_OUT_USB_DEVICE |
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX |
+#ifdef QCOM_ANC_HEADSET_ENABLED
+            AUDIO_DEVICE_OUT_ANC_HEADSET |
+            AUDIO_DEVICE_OUT_ANC_HEADPHONE |
+#endif
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+            AUDIO_DEVICE_OUT_PROXY |
+#endif
+#ifdef QCOM_FM_ENABLED
+            AUDIO_DEVICE_OUT_FM |
+            AUDIO_DEVICE_OUT_FM_TX |
+#endif
+            AUDIO_DEVICE_OUT_DEFAULT |
+            /* IN */
+            AUDIO_DEVICE_IN_COMMUNICATION |
+            AUDIO_DEVICE_IN_AMBIENT |
+            AUDIO_DEVICE_IN_BUILTIN_MIC |
+            AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET |
+            AUDIO_DEVICE_IN_WIRED_HEADSET |
+            AUDIO_DEVICE_IN_AUX_DIGITAL |
+            AUDIO_DEVICE_IN_VOICE_CALL |
+            AUDIO_DEVICE_IN_BACK_MIC |
+            AUDIO_DEVICE_IN_REMOTE_SUBMIX |
+            AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET |
+            AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET |
+            AUDIO_DEVICE_IN_USB_ACCESSORY |
+            AUDIO_DEVICE_IN_USB_DEVICE |
+#ifdef QCOM_ANC_HEADSET_ENABLED
+            AUDIO_DEVICE_IN_ANC_HEADSET |
+#endif
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+            AUDIO_DEVICE_IN_PROXY |
+#endif
+#ifdef QCOM_FM_ENABLED
+            AUDIO_DEVICE_IN_FM_RX |
+            AUDIO_DEVICE_IN_FM_RX_A2DP |
+#endif
+            AUDIO_DEVICE_IN_DEFAULT);
+}
+
 static int adev_init_check(const struct audio_hw_device *dev)
 {
     const struct qcom_audio_device *qadev = to_cladev(dev);
@@ -511,43 +569,6 @@
     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;
-
-    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
 
 static int adev_open_output_stream(struct audio_hw_device *dev,
                                    audio_io_handle_t handle,
@@ -569,6 +590,9 @@
     status = static_cast<audio_output_flags_t> (flags);
 
     out->qcom_out = qadev->hwif->openOutputStream(devices,
+#ifdef QCOM_OUTPUT_FLAGS_ENABLED
+                                                    flags,
+#endif
                                                     (int *)&config->format,
                                                     &config->channel_mask,
                                                     &config->sample_rate,
@@ -721,6 +745,7 @@
     qadev->device.common.module = const_cast<hw_module_t*>(module);
     qadev->device.common.close = qcom_adev_close;
 
+    qadev->device.get_supported_devices = adev_get_supported_devices;
     qadev->device.init_check = adev_init_check;
     qadev->device.set_voice_volume = adev_set_voice_volume;
     qadev->device.set_master_volume = adev_set_master_volume;
@@ -735,9 +760,6 @@
     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
     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;
diff --git a/alsa_sound/audio_policy_hal.cpp b/alsa_sound/audio_policy_hal.cpp
index 1057a0f..4657295 100644
--- a/alsa_sound/audio_policy_hal.cpp
+++ b/alsa_sound/audio_policy_hal.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (c) 2012, 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.
@@ -125,45 +125,6 @@
     return qap->apm->initCheck();
 }
 
-#ifdef QCOM_TUNNEL_LPA_ENABLED
-static audio_io_handle_t ap_get_session(struct audio_policy *pol,
-                                       audio_stream_type_t stream,
-                                       audio_format_t format,
-                                       audio_policy_output_flags_t flags,
-                                       int sessionId,
-                                       uint32_t samplingRate,
-                                       uint32_t channels)
-{
-    struct qcom_audio_policy *qap = to_qap(pol);
-
-    ALOGV("%s: tid %d", __func__, gettid());
-    return qap->apm->getSession((AudioSystem::stream_type)stream,
-                               format, (AudioSystem::output_flags)flags,
-                               sessionId,
-                               samplingRate,
-                               channels);
-}
-
-static void ap_pause_session(struct audio_policy *pol, audio_io_handle_t output,
-                          audio_stream_type_t stream)
-{
-    struct qcom_audio_policy *qap = to_qap(pol);
-    qap->apm->pauseSession(output, (AudioSystem::stream_type)stream);
-}
-
-static void ap_resume_session(struct audio_policy *pol, audio_io_handle_t output,
-                          audio_stream_type_t stream)
-{
-    struct qcom_audio_policy *qap = to_qap(pol);
-    qap->apm->resumeSession(output, (AudioSystem::stream_type)stream);
-}
-
-static void ap_release_session(struct audio_policy *pol, audio_io_handle_t output)
-{
-    struct qcom_audio_policy *qap = to_qap(pol);
-    qap->apm->releaseSession(output);
-}
-#endif
 
 static audio_io_handle_t ap_get_output(struct audio_policy *pol,
                                        audio_stream_type_t stream,
@@ -248,7 +209,7 @@
     struct qcom_audio_policy *qap = to_qap(pol);
     return qap->apm->setStreamVolumeIndex((AudioSystem::stream_type)stream,
                                           index,
-                                          AUDIO_DEVICE_OUT_DEFAULT); 
+                                          AUDIO_DEVICE_OUT_DEFAULT);
 }
 
 static int ap_get_stream_volume_index(const struct audio_policy *pol,
@@ -298,14 +259,14 @@
 }
 
 static audio_io_handle_t ap_get_output_for_effect(struct audio_policy *pol,
-                                            struct effect_descriptor_s *desc)
+                                            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,
-                              struct effect_descriptor_s *desc,
+                              const struct effect_descriptor_s *desc,
                               audio_io_handle_t io,
                               uint32_t strategy,
                               int session,
@@ -327,7 +288,7 @@
     return qap->apm->setEffectEnabled(id, enabled);
 }
 
-static bool ap_is_stream_active(const struct audio_policy *pol, 
+static bool ap_is_stream_active(const struct audio_policy *pol,
                                 audio_stream_type_t stream,
                                 uint32_t in_past_ms)
 {
@@ -365,12 +326,6 @@
         ap_set_can_mute_enforced_audible;
     qap->policy.init_check = ap_init_check;
     qap->policy.get_output = ap_get_output;
-#ifdef QCOM_TUNNEL_LPA_ENABLED
-    qap->policy.get_session = ap_get_session;
-    qap->policy.pause_session = ap_pause_session;
-    qap->policy.resume_session = ap_resume_session;
-    qap->policy.release_session = ap_release_session;
-#endif
     qap->policy.start_output = ap_start_output;
     qap->policy.stop_output = ap_stop_output;
     qap->policy.release_output = ap_release_output;
diff --git a/libalsa-intf/Android.mk b/libalsa-intf/Android.mk
index 5d509b3..cadfa32 100644
--- a/libalsa-intf/Android.mk
+++ b/libalsa-intf/Android.mk
@@ -2,20 +2,25 @@
 
 ifeq ($(strip $(BOARD_USES_ALSA_AUDIO)),true)
 # Any prebuilt files with default TAGS can use the below:
-
 include $(CLEAR_VARS)
 #LOCAL_SRC_FILES:= aplay.c alsa_pcm.c alsa_mixer.c
 LOCAL_SRC_FILES:= aplay.c
 LOCAL_MODULE:= aplay
 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_MODULE_TAGS:= debug
 include $(BUILD_EXECUTABLE)
 
 include $(CLEAR_VARS)
 #LOCAL_SRC_FILES:= arec.c alsa_pcm.c
 LOCAL_SRC_FILES:= arec.c
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES  := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
 LOCAL_MODULE:= arec
 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_MODULE_TAGS:= debug
 include $(BUILD_EXECUTABLE)
 
@@ -23,6 +28,8 @@
 LOCAL_SRC_FILES:= amix.c
 LOCAL_MODULE:= amix
 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_MODULE_TAGS:= debug
 include $(BUILD_EXECUTABLE)
 
@@ -30,6 +37,8 @@
 LOCAL_SRC_FILES:= alsaucm_test.c
 LOCAL_MODULE:= alsaucm_test
 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_MODULE_TAGS:= debug
 include $(BUILD_EXECUTABLE)
 
@@ -42,8 +51,14 @@
 LOCAL_MODULE:= libalsa-intf
 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 += -DCONFIG_DIR=\"/system/etc/snd_soc_msm/\"
+LOCAL_SHARED_LIBRARIES += libacdbloader
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-acdb-util
+endif
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
 ifeq ($(TARGET_SIMULATOR),true)
  LOCAL_LDLIBS += -ldl
 else
diff --git a/libalsa-intf/Makefile.am b/libalsa-intf/Makefile.am
index a05d073..58cb7ca 100644
--- a/libalsa-intf/Makefile.am
+++ b/libalsa-intf/Makefile.am
@@ -27,15 +27,25 @@
 libalsa_intfdir = $(prefix)/snd_soc_msm
 dist_libalsa_intf_DATA    = snd_soc_msm/snd_soc_msm \
                             snd_soc_msm/snd_soc_msm_2x \
+                            snd_soc_msm/snd_soc_msm_2x_mpq \
                             snd_soc_msm/snd_soc_msm_2x_Fusion3 \
-                            snd_soc_msm/snd_soc_msm_Sitar
+                            snd_soc_msm/snd_soc_msm_Sitar \
+                            snd_soc_msm/snd_soc_msm_I2S \
+                            snd_soc_msm/snd_soc_msm_auxpcm \
+                            snd_soc_msm/snd_soc_msm_2x_auxpcm \
+                            snd_soc_msm/snd_soc_msm_2x_mpq_auxpcm \
+                            snd_soc_msm/snd_soc_msm_2x_Fusion3_auxpcm \
+                            snd_soc_msm/snd_soc_msm_Sitar_auxpcm \
+                            snd_soc_msm/snd_soc_msm_I2SFusion \
+                            snd_soc_msm/snd_soc_msm_Taiko \
+                            snd_soc_msm/snd_soc_msm_Taiko_liquid
 libalsa_intf_la_CFLAGS = $(AM_CFLAGS) -DUSE_GLIB @GLIB_CFLAGS@ -DCONFIG_DIR=\"/etc/snd_soc_msm/\"
 libalsa_intf_la_CPPFLAGS = $(AM_CPPFLAGS) -DUSE_GLIB @GLIB_CFLAGS@
 libalsa_intf_la_LDFLAGS = $(ACDBLOADER_LIBS) -lm -lpthread @GLIB_LIBS@ -shared -version-info 1:0:0
 
 requiredlibs = libalsa_intf.la
 
-bin_PROGRAMS = aplay amix arec
+bin_PROGRAMS = aplay amix arec alsaucm_test
 
 aplay_SOURCES = aplay.c
 aplay_LDADD = -lpthread $(requiredlibs)
@@ -45,3 +55,6 @@
 
 arec_SOURCES = arec.c
 arec_LDADD = -lpthread $(requiredlibs)
+
+alsaucm_test_SOURCES = alsaucm_test.c
+alsaucm_test_LDADD = -lpthread $(requiredlibs)
diff --git a/libalsa-intf/alsa_audio.h b/libalsa-intf/alsa_audio.h
index 7f2acf0..1555851 100644
--- a/libalsa-intf/alsa_audio.h
+++ b/libalsa-intf/alsa_audio.h
@@ -43,12 +43,6 @@
     int device_no;
     int start;
 };
-
-enum decoder_alias {
-    FORMAT_MP3,
-    FORMAT_AC3_PASS_THROUGH = 2,
-};
-
 #define FORMAT(v) SNDRV_PCM_FORMAT_##v
 
 #define PCM_OUT        0x00000000
@@ -58,6 +52,7 @@
 #define PCM_MONO       0x01000000
 #define PCM_QUAD       0x02000000
 #define PCM_5POINT1    0x04000000
+#define PCM_7POINT1    0x08000000
 
 #define PCM_44100HZ    0x00000000
 #define PCM_48000HZ    0x00100000
@@ -149,9 +144,12 @@
 int param_set_hw_refine(struct pcm *pcm, struct snd_pcm_hw_params *params);
 int param_set_hw_params(struct pcm *pcm, struct snd_pcm_hw_params *params);
 int param_set_sw_params(struct pcm *pcm, struct snd_pcm_sw_params *sparams);
+int get_compressed_format(const char *format);
 void param_dump(struct snd_pcm_hw_params *p);
 int pcm_prepare(struct pcm *pcm);
 long pcm_avail(struct pcm *pcm);
+int pcm_set_channel_map(struct pcm *pcm, struct mixer *mixer,
+                        int max_channels, char *chmap);
 
 /* Returns a human readable reason for the last error. */
 const char *pcm_error(struct pcm *pcm);
@@ -188,104 +186,524 @@
 
 #define MAX_NUM_CODECS 32
 
+#ifndef QCOM_COMPRESSED_AUDIO_ENABLED
 /* compressed audio support */
-#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
-struct snd_compr_caps {
-        __u32 num_codecs;
-        __u32 min_fragment_size;
-        __u32 max_fragment_size;
-        __u32 min_fragments;
-        __u32 max_fragments;
-        __u32 codecs[MAX_NUM_CODECS];
-        __u32 reserved[11];
-};
+
+/* 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 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 {
-        int quality;
-        __u32 managed;
-        __u32 max_bit_rate;
-        __u32 min_bit_rate;
-        __u32 downmix;
+	__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;
+	__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;
+	__u32 num;
+	__u32 gain;
 };
 
 struct snd_enc_generic {
-        __u32 bw;       /* encoder bandwidth */
-        int reserved[15];
+	__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_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;
-        union snd_codec_options options;
-        __u32 reserved[3];
+	__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 {
-        size_t fragment_size;
-        int fragments;
+	__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;
+	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 {
-        size_t copied_bytes;
-        size_t copied_total;
-        size_t decoded;
-        size_t rendered;
-        __u32 sampling_rate;
-        uint64_t timestamp;
+	__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;
 };
 
-#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)
+/**
+ * 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_IOCTL_VERSION	_IOR('C', 0x00, int)
+#define SNDRV_COMPRESS_GET_CAPS		_IOWR('C', 0x10, struct snd_compr_caps)
+#define SNDRV_COMPRESS_GET_CODEC_CAPS	_IOWR('C', 0x11,\
+						struct snd_compr_codec_caps)
+#define SNDRV_COMPRESS_SET_PARAMS	_IOW('C', 0x12, struct snd_compr_params)
+#define SNDRV_COMPRESS_GET_PARAMS	_IOR('C', 0x13, struct snd_codec)
+#define SNDRV_COMPRESS_TSTAMP		_IOR('C', 0x20, struct snd_compr_tstamp)
+#define SNDRV_COMPRESS_AVAIL		_IOR('C', 0x21, struct snd_compr_avail)
+#define SNDRV_COMPRESS_PAUSE		_IO('C', 0x30)
+#define SNDRV_COMPRESS_RESUME		_IO('C', 0x31)
+#define SNDRV_COMPRESS_START		_IO('C', 0x32)
+#define SNDRV_COMPRESS_STOP		_IO('C', 0x33)
+#define SNDRV_COMPRESS_DRAIN		_IO('C', 0x34)
+/*
+ * 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 cdcdcea..81817d9 100644
--- a/libalsa-intf/alsa_mixer.c
+++ b/libalsa-intf/alsa_mixer.c
@@ -488,7 +488,6 @@
     if (count < ctl->info->count || count > ctl->info->count)
         return -EINVAL;
 
-
     memset(&ev, 0, sizeof(ev));
     ev.id.numid = ctl->info->id.numid;
     switch (ctl->info->type) {
@@ -511,6 +510,13 @@
         }
         break;
     }
+    case SNDRV_CTL_ELEM_TYPE_ENUMERATED: {
+        for (n = 0; n < ctl->info->count; n++) {
+            fprintf( stderr, "Value: %d idx:%d\n", atoi(argv[n]), n);
+            ev.value.enumerated.item[n] = (unsigned int)atoi(argv[n]);
+        }
+        break;
+    }
     default:
         errno = EINVAL;
         return errno;
diff --git a/libalsa-intf/alsa_pcm.c b/libalsa-intf/alsa_pcm.c
index a814ae8..4f55437 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
@@ -78,7 +80,7 @@
       IMA_ADPCM,
       MPEG,
       GSM,
-      SPECIAL = 31, 
+      SPECIAL = 31,
       S24_3LE,
       S24_3BE,
       U24_3LE,
@@ -118,7 +120,7 @@
         {"A_LAW", "A-Law"},
         {"IMA_ADPCM", "Ima-ADPCM"},
         {"MPEG", "MPEG"},
-        {"GSM", "GSM"}, 
+        {"GSM", "GSM"},
         [31] = {"SPECIAL", "Special"},
         {"S24_3LE", "Signed 24 bit Little Endian in 3bytes"},
         {"S24_3BE", "Signed 24 bit Big Endian in 3bytes"},
@@ -133,6 +135,18 @@
         {"U18_3LE", "Unsigned 18 bit Little Endian in 3bytes"},
         {"U18_3BE", "Unsigned 18 bit Big Endian in 3bytes"},
 };
+enum decoder_alias {
+    FORMAT_MP3              = SND_AUDIOCODEC_MP3,
+    FORMAT_AAC              = SND_AUDIOCODEC_AAC,
+    FORMAT_AC3_PASS_THROUGH = SND_AUDIOCODEC_AC3_PASS_THROUGH,
+    FORMAT_WMA              = SND_AUDIOCODEC_WMA,
+    FORMAT_WMA_PRO          = SND_AUDIOCODEC_WMA_PRO,
+    FORMAT_DTS              = SND_AUDIOCODEC_DTS,
+    FORMAT_DTS_LBR          = SND_AUDIOCODEC_DTS_LBR,
+    FORMAT_DTS_PASS_THROUGH = SND_AUDIOCODEC_DTS_PASS_THROUGH,
+    FORMAT_AMRWB            = SND_AUDIOCODEC_AMRWB,
+    FORMAT_AMRWB_PLUS       = SND_AUDIOCODEC_AMRWBPLUS
+};
 
 int get_compressed_format(const char *format)
 {
@@ -143,6 +157,30 @@
         } else if (strcmp(ch, "AC3_PASS_THROUGH") == 0) {
                 printf("AC3 PASS THROUGH is selected\n");
                 return FORMAT_AC3_PASS_THROUGH;
+        } else if (strcmp(ch, "AAC") == 0) {
+                printf("AAC is selected\n");
+                return FORMAT_AAC;
+        } else if (strcmp(ch, "AC3_PASS_THROUGH") == 0) {
+                printf("AC3_PASS_THROUGH is selected\n");
+                return FORMAT_AC3_PASS_THROUGH;
+        } else if (strcmp(ch, "WMA") == 0) {
+                printf("WMA is selected\n");
+                return FORMAT_WMA;
+        }else if (strcmp(ch, "WMA_PRO") == 0) {
+                printf("WMA_PRO is selected\n");
+                return FORMAT_WMA_PRO;
+        }else if (strcmp(ch, "DTS") == 0) {
+                printf("DTS is selected\n");
+                return FORMAT_DTS;
+        } else if (strcmp(ch, "DTS_LBR") == 0) {
+                printf("DTS_LBR is selected\n");
+                return FORMAT_DTS_LBR;
+        } else if (strcmp(ch, "AMR_WB") == 0) {
+                printf("AMR_WB is selected\n");
+                return FORMAT_AMRWB;
+        }else if (strcmp(ch, "AMR_WB_PLUS") == 0) {
+                printf("FORMAT_AMRWB_PLUS is selected\n");
+                return FORMAT_AMRWB_PLUS;
         } else {
                 printf("invalid format\n");
                 return -1;
@@ -409,7 +447,20 @@
                 avail += pcm->sw_p->boundary;
         return avail;
      } else {
-         long avail = sync_ptr->s.status.hw_ptr - sync_ptr->c.control.appl_ptr + ((pcm->flags & PCM_MONO) ? pcm->buffer_size/2 : pcm->buffer_size/4);
+         int buffer_size = 0;
+         long avail;
+         if(pcm->flags & PCM_MONO)
+             buffer_size = pcm->buffer_size/2;
+         else if(pcm->flags & PCM_QUAD)
+             buffer_size = pcm->buffer_size/8;
+         else if(pcm->flags & PCM_5POINT1)
+             buffer_size = pcm->buffer_size/12;
+         else if(pcm->flags & PCM_7POINT1)
+             buffer_size = pcm->buffer_size/16;
+         else
+             buffer_size = pcm->buffer_size/4;
+
+         avail = sync_ptr->s.status.hw_ptr - sync_ptr->c.control.appl_ptr + buffer_size;
          if (avail < 0)
               avail += pcm->sw_p->boundary;
          else if ((unsigned long) avail >= pcm->sw_p->boundary)
@@ -437,7 +488,18 @@
     char *ptr;
     unsigned size;
     struct snd_pcm_channel_info ch;
-    int channels = (pcm->flags & PCM_MONO) ? 1 : 2;
+    int channels;
+
+    if(pcm->flags & PCM_MONO)
+        channels = 1;
+    else if(pcm->flags & PCM_QUAD)
+        channels = 4;
+    else if(pcm->flags & PCM_5POINT1)
+        channels = 6;
+    else if(pcm->flags & PCM_7POINT1)
+        channels = 8;
+    else
+        channels = 2;
 
     size = pcm->buffer_size;
     if (pcm->flags & DEBUG_ON)
@@ -461,8 +523,19 @@
     unsigned long pcm_offset = 0;
     struct snd_pcm_sync_ptr *sync_ptr = pcm->sync_ptr;
     unsigned int appl_ptr = 0;
+    int channels;
+    if(pcm->flags & PCM_MONO)
+        channels = 1;
+    else if(pcm->flags & PCM_QUAD)
+        channels = 4;
+    else if(pcm->flags & PCM_5POINT1)
+        channels = 6;
+    else if(pcm->flags & PCM_7POINT1)
+        channels = 8;
+    else
+        channels = 2;
 
-    appl_ptr = (pcm->flags & PCM_MONO) ? sync_ptr->c.control.appl_ptr*2 : sync_ptr->c.control.appl_ptr*4;
+    appl_ptr = sync_ptr->c.control.appl_ptr*2*channels;
     pcm_offset = (appl_ptr % (unsigned long)pcm->buffer_size);
     return pcm->addr + pcm_offset;
 
@@ -475,7 +548,17 @@
     unsigned size;
     u_int8_t *dst_addr, *mmaped_addr;
     u_int8_t *src_addr = data;
-    int channels = (pcm->flags & PCM_MONO) ? 1 : 2;
+    int channels;
+    if(pcm->flags & PCM_MONO)
+        channels = 1;
+    else if(pcm->flags & PCM_QUAD)
+        channels = 4;
+    else if(pcm->flags & PCM_5POINT1)
+        channels = 6;
+    else if(pcm->flags & PCM_7POINT1)
+        channels = 8;
+    else
+        channels = 2;
 
     dst_addr = dst_address(pcm);
 
@@ -497,9 +580,20 @@
     unsigned size;
     u_int8_t *dst_addr, *mmaped_addr;
     u_int8_t *src_addr;
-    int channels = (pcm->flags & PCM_MONO) ? 1 : 2;
-    unsigned int tmp = (pcm->flags & PCM_MONO) ? sync_ptr->c.control.appl_ptr*2 : sync_ptr->c.control.appl_ptr*4;
+    int channels;
+    unsigned int tmp;
 
+    if(pcm->flags & PCM_MONO)
+        channels = 1;
+    else if(pcm->flags & PCM_QUAD)
+        channels = 4;
+    else if(pcm->flags & PCM_5POINT1)
+        channels = 6;
+    else if(pcm->flags & PCM_7POINT1)
+        channels = 8;
+    else
+        channels = 2;
+    tmp = sync_ptr->c.control.appl_ptr*2*channels;
     pcm_offset = (tmp % (unsigned long)pcm->buffer_size);
     dst_addr = data;
     src_addr = pcm->addr + pcm_offset;
@@ -528,8 +622,18 @@
     long frames;
     int err;
     int bytes_written;
-
-    frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4);
+    int channels;
+    if(pcm->flags & PCM_MONO)
+        channels = 1;
+    else if(pcm->flags & PCM_QUAD)
+        channels = 4;
+    else if(pcm->flags & PCM_5POINT1)
+        channels = 6;
+    else if(pcm->flags & PCM_7POINT1)
+        channels = 8;
+    else
+        channels = 2;
+    frames = count / (2*channels);
 
     pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;
     err = sync_ptr(pcm);
@@ -576,7 +680,17 @@
 static int pcm_write_nmmap(struct pcm *pcm, void *data, unsigned count)
 {
     struct snd_xferi x;
-    int channels = (pcm->flags & PCM_MONO) ? 1 : ((pcm->flags & PCM_5POINT1)? 6 : 2 );
+    int channels;
+    if(pcm->flags & PCM_MONO)
+        channels = 1;
+    else if(pcm->flags & PCM_QUAD)
+        channels = 4;
+    else if(pcm->flags & PCM_5POINT1)
+        channels = 6;
+    else if(pcm->flags & PCM_7POINT1)
+        channels = 8;
+    else
+        channels = 2;
 
     if (pcm->flags & PCM_IN)
         return -EINVAL;
@@ -626,6 +740,8 @@
         x.frames = (count / 8);
     } else if (pcm->flags & PCM_5POINT1) {
         x.frames = (count / 12);
+    } else if (pcm->flags & PCM_7POINT1) {
+        x.frames = (count / 16);
     } else {
         x.frames = (count / 4);
     }
@@ -647,6 +763,20 @@
                 pcm->underruns++;
                 pcm->running = 0;
                 continue;
+            } else if (errno == ESTRPIPE) {
+                ALOGV("Resume from suspended\n");
+                for (;;) {
+                    if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_RESUME)) {
+                        if (errno == EAGAIN ) {
+                            if (pcm_prepare(pcm))
+                                return -errno;
+                        }
+                        /* send resume command again */
+                        continue;
+                    } else
+                        break;
+                }
+                continue;
             }
             ALOGE("Arec: error%d\n", errno);
             return -errno;
@@ -854,3 +984,46 @@
 {
     return pcm->fd >= 0;
 }
+
+int pcm_set_channel_map(struct pcm *pcm, struct mixer *mixer,
+                        int max_channels, char *chmap)
+{
+    struct mixer_ctl *ctl;
+    char control_name[44]; // max length of name is 44 as defined
+    char device_num[3]; // device number upto 2 digit
+    char **set_values;
+    int i;
+
+    ALOGV("pcm_set_channel_map");
+    set_values = (char**)malloc(max_channels*sizeof(char*));
+    if(set_values) {
+        for(i=0; i< max_channels; i++) {
+            set_values[i] = (char*)malloc(4*sizeof(char));
+            if(set_values[i]) {
+                sprintf(set_values[i],"%d",chmap[i]);
+            } else {
+                ALOGE("memory allocation for set channel map failed");
+                return -1;
+            }
+        }
+    } else {
+        ALOGE("memory allocation for set channel map failed");
+        return -1;
+    }
+    strlcpy(control_name, "Playback Channel Map", sizeof(control_name));
+    sprintf(device_num, "%d", pcm->device_no);
+    strcat(control_name, device_num);
+    ALOGV("pcm_set_channel_map: control name:%s", control_name);
+    ctl = mixer_get_control(mixer, control_name, 0);
+    if(ctl == NULL) {
+        ALOGE(stderr, "Could not get the mixer control\n");
+        return -1;
+    }
+    mixer_ctl_set_value(ctl, max_channels, set_values);
+    for(i=0; i< max_channels; i++)
+        if(set_values[i])
+            free(set_values[i]);
+    if(set_values)
+        free(set_values);
+    return 0;
+}
diff --git a/libalsa-intf/alsa_ucm.c b/libalsa-intf/alsa_ucm.c
index 3548f67..0886d54 100644
--- a/libalsa-intf/alsa_ucm.c
+++ b/libalsa-intf/alsa_ucm.c
@@ -58,13 +58,15 @@
 #include <sys/time.h>
 #include <sys/poll.h>
 #include <stdint.h>
-#include <dlfcn.h>
 
 #include <linux/ioctl.h>
 #include "msm8960_use_cases.h"
 #if defined(QC_PROP)
-    static void (*acdb_send_audio_cal)(int,int);
-    static void (*acdb_send_voice_cal)(int,int);
+    #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
 #define PARSE_DEBUG 0
 
@@ -442,6 +444,42 @@
                     ret = -ENODEV;
                 }
             }
+        } else if (!strncmp(ident1, "EC_REF_RXMixerCTL", 17)) {
+            ident2 = strtok_r(NULL, "/", &temp_ptr);
+            index = 0; verb_index = 0;
+            verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
+            if((verb_index < 0) ||
+               (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
+                SND_UCM_END_OF_LIST, 3)) ||
+                (verb_list[verb_index].verb_ctrls == NULL)) {
+                ALOGE("Invalid current verb value: %s - %d",
+                     uc_mgr->card_ctxt_ptr->current_verb, verb_index);
+                pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
+                return -EINVAL;
+            }
+            ctrl_list = verb_list[verb_index].device_ctrls;
+            if (ident2 != NULL) {
+                while(strncmp(ctrl_list[index].case_name, ident2, strlen(ident2)+1)) {
+                    if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST,
+                        strlen(SND_UCM_END_OF_LIST))){
+                        ret = -EINVAL;
+                        break;
+                    } else {
+                        index++;
+                    }
+                }
+            }
+            if (ret < 0) {
+                ALOGE("No valid device/modifier found with given identifier: %s",
+                      ident2);
+            } else {
+                if (verb_list[verb_index].device_ctrls[index].ec_ref_rx_mixer_ctl) {
+                    *value = strdup(verb_list[verb_index].device_ctrls[index].ec_ref_rx_mixer_ctl);
+                } else {
+                    *value = NULL;
+                    ret = -ENODEV;
+                }
+            }
         } else {
             ALOGE("Unsupported identifier value: %s", ident1);
             *value = NULL;
@@ -543,10 +581,18 @@
 
     if ((!strncmp(use_case, SND_USE_CASE_VERB_VOICECALL,
         strlen(SND_USE_CASE_VERB_VOICECALL))) ||
+        (!strncmp(use_case, SND_USE_CASE_VERB_SGLTECALL,
+        strlen(SND_USE_CASE_VERB_SGLTECALL))) ||
+        (!strncmp(use_case, SND_USE_CASE_VERB_VOLTE,
+        strlen(SND_USE_CASE_VERB_VOLTE))) ||
         (!strncmp(use_case, SND_USE_CASE_VERB_IP_VOICECALL,
         strlen(SND_USE_CASE_VERB_IP_VOICECALL))) ||
         (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOICE,
         strlen(SND_USE_CASE_MOD_PLAY_VOICE))) ||
+        (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_SGLTE,
+        strlen(SND_USE_CASE_MOD_PLAY_SGLTE))) ||
+        (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOLTE,
+        strlen(SND_USE_CASE_MOD_PLAY_VOLTE))) ||
         (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOIP,
         strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
         ALOGV("check_devices_for_voice_call(): voice cap detected\n");
@@ -584,8 +630,12 @@
 
     /* Check if voice call use case/modifier exists */
     if ((!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
+        SND_USE_CASE_VERB_VOLTE, strlen(SND_USE_CASE_VERB_VOLTE))) ||
+	(!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
         SND_USE_CASE_VERB_VOICECALL, strlen(SND_USE_CASE_VERB_VOICECALL))) ||
         (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
+        SND_USE_CASE_VERB_SGLTECALL, strlen(SND_USE_CASE_VERB_SGLTECALL))) ||
+        (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
         SND_USE_CASE_VERB_IP_VOICECALL,
         strlen(SND_USE_CASE_VERB_IP_VOICECALL)))) {
         voice_acdb = 1;
@@ -597,8 +647,12 @@
             if ((ident_value =
                 snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
                 index))) {
-                if ((!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOICE,
+                if ((!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOLTE,
+                    strlen(SND_USE_CASE_MOD_PLAY_VOLTE))) ||
+		    (!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOICE,
                     strlen(SND_USE_CASE_MOD_PLAY_VOICE))) ||
+                    (!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_SGLTE,
+                    strlen(SND_USE_CASE_MOD_PLAY_SGLTE))) ||
                     (!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOIP,
                     strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
                     voice_acdb = 1;
@@ -673,15 +727,8 @@
                     ALOGD("Voice acdb: rx id %d tx id %d",
                           uc_mgr->current_rx_device,
                           uc_mgr->current_tx_device);
-                    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("ucm: 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);
-                        }
-                   }
+                    acdb_loader_send_voice_cal(uc_mgr->current_rx_device,
+                        uc_mgr->current_tx_device);
                 } else {
                     ALOGV("Voice acdb: Required acdb already pushed \
                          rx id %d tx id %d", uc_mgr->current_rx_device,
@@ -792,22 +839,15 @@
                 (check_devices_for_voice_call(uc_mgr, use_case) != NULL))
                 return ret;
             ALOGD("Set mixer controls for %s enable %d", use_case, enable);
-            if (ctrl_list[uc_index].acdb_id && ctrl_list[uc_index].capability) {
+            if ((ctrl_list[uc_index].acdb_id >= 0) && ctrl_list[uc_index].capability) {
                 if (enable) {
-                    if (snd_use_case_apply_voice_acdb(uc_mgr, uc_index)) {
-                        ALOGV("acdb_id %d cap %d enable %d",
-                            ctrl_list[uc_index].acdb_id,
+                    snd_use_case_apply_voice_acdb(uc_mgr, uc_index);
+                    ALOGD("acdb_id %d cap %d enable %d",
+                                        ctrl_list[uc_index].acdb_id,
                             ctrl_list[uc_index].capability, enable);
-                        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("ucm: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);
-                            }
-                        }
-                    }
+                    acdb_loader_send_audio_cal(
+                            ctrl_list[uc_index].acdb_id,
+                            ctrl_list[uc_index].capability);
                 }
             }
             if (enable) {
@@ -826,7 +866,7 @@
                           mixer_list[index].control_name, 0);
                 if (ctl) {
                     if (mixer_list[index].type == TYPE_INT) {
-                        ALOGV("Setting mixer control: %s, value: %d",
+                        ALOGD("Setting mixer control: %s, value: %d",
                              mixer_list[index].control_name,
                              mixer_list[index].value);
                         ret = mixer_ctl_set(ctl, mixer_list[index].value);
@@ -839,7 +879,7 @@
                             ALOGE("Failed to set multi value control %s\n",
                                 mixer_list[index].control_name);
                     } else {
-                        ALOGV("Setting mixer control: %s, value: %s",
+                        ALOGD("Setting mixer control: %s, value: %s",
                             mixer_list[index].control_name,
                             mixer_list[index].string);
                         ret = mixer_ctl_select(ctl, mixer_list[index].string);
@@ -885,8 +925,12 @@
            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
             MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL2,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL2)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
             MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI2)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_HIFI3,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI3)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_DIGITAL_RADIO,
             MAX_LEN(useCase,SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
@@ -895,25 +939,41 @@
             MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
             MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC3,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC3)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LPA,
             MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LPA)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
             MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL2,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL2)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_FM,
-            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))) {
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))||
+        !strncmp(useCase, SND_USE_CASE_MOD_PSEUDO_TUNNEL,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PSEUDO_TUNNEL))||
+        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_PSEUDO_TUNNEL,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_PSEUDO_TUNNEL))) {
         return CAP_RX;
     } else if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC,
             MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC2,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC2)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_FM_REC,
             MAX_LEN(useCase,SND_USE_CASE_VERB_FM_REC)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_FM_A2DP_REC,
             MAX_LEN(useCase,SND_USE_CASE_VERB_FM_A2DP_REC)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC,
             MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC2,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC2)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC,
             MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC,
             MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_FM,
             MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_FM)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM,
@@ -921,22 +981,34 @@
         return CAP_TX;
     } else if (!strncmp(useCase, SND_USE_CASE_VERB_VOICECALL,
             MAX_LEN(useCase,SND_USE_CASE_VERB_VOICECALL)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_SGLTECALL,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_SGLTECALL)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_IP_VOICECALL,
             MAX_LEN(useCase,SND_USE_CASE_VERB_IP_VOICECALL)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_DL_REC,
             MAX_LEN(useCase,SND_USE_CASE_VERB_DL_REC)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_UL_DL_REC,
             MAX_LEN(useCase,SND_USE_CASE_VERB_UL_DL_REC)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL)) ||
+        !strncmp(useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL,
+            MAX_LEN(useCase,SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_INCALL_REC,
             MAX_LEN(useCase,SND_USE_CASE_VERB_INCALL_REC)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE,
             MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_PLAY_SGLTE,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_SGLTE)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOIP,
             MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
             MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
             MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL)) ||
+        !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL,
+            MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL)) ||
         !strncmp(useCase, SND_USE_CASE_VERB_VOLTE,
             MAX_LEN(useCase,SND_USE_CASE_VERB_VOLTE)) ||
         !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
@@ -960,7 +1032,7 @@
     card_mctrl_t *dev_list, *uc_list;
     char *current_device, use_case[MAX_UC_LEN];
     int list_size, index, uc_index, ret = 0, intdev_flag = 0;
-    int verb_index, capability = 0, ident_cap = 0, dev_cap =0;
+    int verb_index, capability = 0, ident_cap = 0, dev_cap = 0;
 
     ALOGV("set_use_case_ident_for_all_devices(): %s", ident);
     if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
@@ -982,49 +1054,50 @@
         current_device =
         snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head, index);
         if (current_device != NULL) {
-            uc_index = get_use_case_index(uc_mgr, current_device,
-                       CTRL_LIST_DEVICE);
+            if ((uc_index = get_use_case_index(uc_mgr, current_device,
+                       CTRL_LIST_DEVICE)) < 0) {
+                ALOGE("No valid device found: %s", current_device);
+                continue;
+            }
             dev_cap = dev_list[uc_index].capability;
             if (!capability) {
                 capability = dev_list[uc_index].capability;
             } else if (capability != dev_list[uc_index].capability) {
                 capability = CAP_VOICE;
             }
-            if (ident_cap == CAP_VOICE  || ident_cap == dev_cap) {
+            if (ident_cap == CAP_VOICE || dev_cap == ident_cap) {
                 if (enable) {
                     if (!snd_ucm_get_status_at_index(
                         uc_mgr->card_ctxt_ptr->dev_list_head, current_device)) {
                         if (uc_index >= 0) {
                             ALOGV("Applying mixer controls for device: %s",
-                                  current_device);
+                                current_device);
                             ret = snd_use_case_apply_mixer_controls(uc_mgr,
-                                  current_device, enable, CTRL_LIST_DEVICE, uc_index);
+                                  current_device, enable, CTRL_LIST_DEVICE,
+                                  uc_index);
                             if (!ret)
                                 snd_ucm_set_status_at_index(
                                   uc_mgr->card_ctxt_ptr->dev_list_head,
                                   current_device, enable, dev_cap);
                         }
-                     } else if (ident_cap == CAP_VOICE) {
+                    } else if (ident_cap == CAP_VOICE) {
                         snd_use_case_apply_voice_acdb(uc_mgr, uc_index);
-                     }
-                 }
-                 strlcpy(use_case, ident, sizeof(use_case));
-                 strlcat(use_case, current_device, sizeof(use_case));
-                 ALOGV("Applying mixer controls for use case: %s", use_case);
-                 if ((uc_index =
-                      get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) {
-                      ALOGV("No valid use case found: %s", use_case);
-                      intdev_flag++;
-                 } else {
-                      if (capability == CAP_VOICE || ident_cap == CAP_VOICE ||
-                          capability == ident_cap) {
-                          ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
-                                enable, ctrl_list_type, uc_index);
-                      }
-                 }
-                 use_case[0] = 0;
-                 free(current_device);
-             }
+                    }
+                }
+                strlcpy(use_case, ident, sizeof(use_case));
+                strlcat(use_case, current_device, sizeof(use_case));
+                ALOGV("Applying mixer controls for use case: %s", use_case);
+                if ((uc_index =
+                    get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) {
+                    ALOGV("No valid use case found: %s", use_case);
+                    intdev_flag++;
+                } else {
+                    ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
+                          enable, ctrl_list_type, uc_index);
+                }
+                use_case[0] = 0;
+                free(current_device);
+            }
         }
     }
     if (intdev_flag) {
@@ -1064,7 +1137,11 @@
         uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
     if (device != NULL) {
         if (enable) {
-            dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
+            if ((dev_index =
+                get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE)) < 0) {
+                ALOGE("No valid device found: %s", device);
+                return dev_index;
+            }
             capability = dev_list[dev_index].capability;
             if (!snd_ucm_get_status_at_index(
                 uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
@@ -1078,10 +1155,14 @@
         }
         strlcpy(use_case, ident, sizeof(use_case));
         strlcat(use_case, device, sizeof(use_case));
-    ALOGV("Applying mixer controls for use case: %s", use_case);
+	ALOGV("Applying mixer controls for use case: %s", use_case);
         if ((uc_index = get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) {
             ALOGV("No valid use case found: %s", use_case );
-            uc_index = get_use_case_index(uc_mgr, ident, ctrl_list_type);
+            if ((uc_index =
+                get_use_case_index(uc_mgr, ident, ctrl_list_type)) < 0) {
+                    ALOGE("No valid use case found: %s", ident);
+                    return uc_index;
+            }
             if (snd_use_case_apply_mixer_controls(uc_mgr, ident, enable,
                 ctrl_list_type, uc_index) < 0) {
                  ALOGV("use case %s not valid without device combination also",
@@ -1092,7 +1173,11 @@
                       ctrl_list_type, uc_index);
         }
     } else {
-        uc_index = get_use_case_index(uc_mgr, ident, ctrl_list_type);
+        if ((uc_index =
+            get_use_case_index(uc_mgr, ident, ctrl_list_type)) < 0) {
+            ALOGE("No valid use case found: %s", ident);
+            return uc_index;
+        }
         if (snd_use_case_apply_mixer_controls(uc_mgr, ident, enable,
             ctrl_list_type, uc_index) < 0) {
              ALOGV("use case %s not valid without device combination also",
@@ -1121,7 +1206,11 @@
         verb_index = 0;
     dev_list =
          uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
-    dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
+    if ((dev_index =
+        get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE)) < 0) {
+        ALOGE("No valid device %s found", device);
+        return dev_index;
+    }
     if (dev_index >= 0)
         capability = dev_list[dev_index].capability;
     if (strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_USE_CASE_VERB_INACTIVE,
@@ -1175,8 +1264,10 @@
             use_case[0] = 0;
             strlcpy(use_case, uc_mgr->card_ctxt_ptr->current_verb,
                 sizeof(use_case));
-            uc_index = get_use_case_index(uc_mgr, use_case, CTRL_LIST_VERB);
-            if (capability == CAP_VOICE ||
+            if ((uc_index =
+                get_use_case_index(uc_mgr, use_case, CTRL_LIST_VERB)) < 0) {
+                ALOGE("No valid use case %s found", use_case);
+            } else if (capability == CAP_VOICE ||
                 capability ==
                 getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ||
                 getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ==
@@ -1246,9 +1337,11 @@
                 }
                 use_case[0] = 0;
                 strlcpy(use_case, ident_value, sizeof(use_case));
-                uc_index =
-                    get_use_case_index(uc_mgr, ident_value, CTRL_LIST_MODIFIER);
-                if (capability == CAP_VOICE ||
+                if ((uc_index =
+                    get_use_case_index(uc_mgr, ident_value,
+                    CTRL_LIST_MODIFIER)) < 0) {
+                    ALOGE("No valid use case %s found", ident_value);
+                } else if (capability == CAP_VOICE ||
                     capability == getUseCaseType(ident_value) ||
                     getUseCaseType(ident_value) == CAP_VOICE) {
                     ALOGV("set %d for use case value: %s", enable, use_case);
@@ -1318,14 +1411,29 @@
         verb_index = 0;
     dev_list =
          uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
-    dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
+    if ((dev_index =
+        get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE)) < 0) {
+        ALOGE("No valid device %s found", device);
+        return dev_index;
+    }
     capability = dev_list[dev_index].capability;
     if (usecase != NULL) {
         strlcpy(use_case, usecase, sizeof(use_case));
         strlcat(use_case, device, sizeof(use_case));
         if ((uc_index = get_use_case_index(uc_mgr, use_case,
             get_usecase_type(uc_mgr, usecase))) < 0) {
-            ALOGV("No valid use case found: %s", use_case);
+            ALOGV("No valid use case found: %s,\
+                   set %d for use case value: %s",use_case, enable, usecase);
+            if ((uc_index =
+                get_use_case_index(uc_mgr, usecase, get_usecase_type(uc_mgr, usecase))) < 0) {
+                    ALOGE("No valid use case found: %s", usecase);
+            } else {
+                ret = snd_use_case_apply_mixer_controls(uc_mgr, usecase, enable,
+                          get_usecase_type(uc_mgr, usecase), uc_index);
+                if (ret != 0)
+                    ALOGE("No valid controls exists for usecase %s and device %s, \
+                         enable: %d", usecase, device, enable);
+            }
         } else {
             if (enable) {
                 if (!snd_ucm_get_status_at_index(
@@ -1539,10 +1647,15 @@
                 ALOGE("Invalid device: Device not part of enabled device list");
             } else {
                 ALOGV("disdev: device value to be disabled: %s", value);
-                index = get_use_case_index(uc_mgr, value, CTRL_LIST_DEVICE);
-                /* Apply Mixer controls for corresponding device and modifier */
-                ret = snd_use_case_apply_mixer_controls(uc_mgr, value, 0,
+                if ((index =
+                    get_use_case_index(uc_mgr, value, CTRL_LIST_DEVICE)) < 0) {
+                    ALOGE("Device %s not found", value);
+                    ret = -EINVAL;
+                } else {
+                    /* Apply Mixer controls for device and modifier */
+                    ret = snd_use_case_apply_mixer_controls(uc_mgr, value, 0,
                           CTRL_LIST_DEVICE, index);
+                }
             }
         }
     } else if (!strncmp(identifier, "_enamod", 7)) {
@@ -2297,13 +2410,14 @@
         close(fd);
         return -EINVAL;
     }
-    read_buf = (char *) mmap(0, st.st_size, PROT_READ | PROT_WRITE,
+    read_buf = (char *) mmap(0, st.st_size+1, PROT_READ | PROT_WRITE,
                MAP_PRIVATE, fd, 0);
     if (read_buf == MAP_FAILED) {
         ALOGE("failed to mmap file error %d\n", errno);
         close(fd);
         return -EINVAL;
     }
+    read_buf[st.st_size] = '\0';
     current_str = read_buf;
     verb_count = get_verb_count(current_str);
     (*uc_mgr)->card_ctxt_ptr->use_case_verb_list =
@@ -3243,6 +3357,7 @@
     list->acdb_id = 0;
     list->capability = 0;
     list->effects_mixer_ctl = NULL;
+    list->ec_ref_rx_mixer_ctl = NULL;
     current_str = *cur_str; next_str = *nxt_str;
     while(strncasecmp(current_str, "EndSection", 10)) {
         current_str = next_str;
@@ -3300,7 +3415,14 @@
                       &list->effects_mixer_ctl);
             if (ret < 0)
                 break;
-            ALOGV("Effects mixer ctl: %s: %d\n", list->effects_mixer_ctl);
+            ALOGV("Effects mixer ctl: %s:\n", list->effects_mixer_ctl);
+        } else if (strcasestr(current_str, "EC_REF_RXMixerCTL") != NULL) {
+            ret = snd_ucm_extract_ec_ref_rx_mixer_ctl(current_str,
+                      &list->ec_ref_rx_mixer_ctl);
+            ALOGV("EC_REF_RX mixer ctl: ret:%d\n", ret);
+            if (ret < 0)
+                break;
+            ALOGE("EC_REF_RX mixer ctl: %s\n", list->ec_ref_rx_mixer_ctl);
         }
         if (strcasestr(current_str, "EnableSequence") != NULL) {
             controls_count = get_controls_count(next_str);
@@ -3420,6 +3542,32 @@
     return ret;
 }
 
+
+/* Extract Effects Mixer ID of device from config file
+ * Returns 0 on sucess, negative error code otherwise
+ */
+static int snd_ucm_extract_ec_ref_rx_mixer_ctl(char *buf, char **mixer_name)
+{
+    int ret = 0;
+    char *p, *name = *mixer_name, *temp_ptr;
+
+    p = strtok_r(buf, "\"", &temp_ptr);
+    while (p != NULL) {
+        p = strtok_r(NULL, "\"", &temp_ptr);
+        if (p == NULL)
+            break;
+        name = (char *)malloc((strlen(p)+1)*sizeof(char));
+        if(name == NULL) {
+            ret = -ENOMEM;
+            break;
+        }
+        strlcpy(name, p, (strlen(p)+1)*sizeof(char));
+        *mixer_name = name;
+        break;
+    }
+    return ret;
+}
+
 /* Extract a playback and capture device name of use case from config file
  * Returns 0 on sucess, negative error code otherwise
  */
@@ -3639,6 +3787,9 @@
         if(list[case_index].effects_mixer_ctl) {
             list[case_index].effects_mixer_ctl = NULL;
         }
+        if(list[case_index].ec_ref_rx_mixer_ctl) {
+            list[case_index].ec_ref_rx_mixer_ctl = NULL;
+        }
     }
 }
 
diff --git a/libalsa-intf/alsa_ucm.h b/libalsa-intf/alsa_ucm.h
index a72ca27..d83275c 100644
--- a/libalsa-intf/alsa_ucm.h
+++ b/libalsa-intf/alsa_ucm.h
@@ -102,6 +102,7 @@
 #define SND_USE_CASE_VERB_VOICE			"Voice"
 #define SND_USE_CASE_VERB_VOICE_LOW_POWER	"Voice Low Power"
 #define SND_USE_CASE_VERB_VOICECALL		"Voice Call"
+#define SND_USE_CASE_VERB_SGLTECALL             "SGLTE"
 #define SND_USE_CASE_VERB_IP_VOICECALL		"Voice Call IP"
 #define SND_USE_CASE_VERB_ANALOG_RADIO		"FM Analog Radio"
 #define SND_USE_CASE_VERB_DIGITAL_RADIO		"FM Digital Radio"
@@ -149,6 +150,7 @@
 #define SND_USE_CASE_MOD_CAPTURE_MUSIC		"Capture Music"
 #define SND_USE_CASE_MOD_PLAY_MUSIC		"Play Music"
 #define SND_USE_CASE_MOD_PLAY_VOICE		"Play Voice"
+#define SND_USE_CASE_MOD_PLAY_SGLTE             "Play SGLTE"
 #define SND_USE_CASE_MOD_PLAY_TONE		"Play Tone"
 #define SND_USE_CASE_MOD_ECHO_REF		"Echo Reference"
 /* add new modifiers to end of list */
diff --git a/libalsa-intf/alsaucm_test.c b/libalsa-intf/alsaucm_test.c
index e01cf59..e7d927d 100644
--- a/libalsa-intf/alsaucm_test.c
+++ b/libalsa-intf/alsaucm_test.c
@@ -36,6 +36,11 @@
 #include <errno.h>
 #include <stdlib.h>
 
+#ifndef ANDROID
+#include <stdint.h>
+#define strlcat g_strlcat
+#endif
+
 #include "alsa_ucm.h"
 #include "msm8960_use_cases.h"
 
@@ -208,7 +213,6 @@
             fprintf(stderr, "%s: error failed to open sound card %s: %d\n", cmd->cmd_str, identifier, err);
             return err;
         }
-        snd_use_case_mgr_wait_for_parsing(uc_mgr);
         break;
 
     case UCM_LISTCARDS:
diff --git a/libalsa-intf/aplay.c b/libalsa-intf/aplay.c
index c060277..62a58fa 100644
--- a/libalsa-intf/aplay.c
+++ b/libalsa-intf/aplay.c
@@ -27,6 +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
@@ -41,14 +45,28 @@
 
 #define FORMAT_PCM 1
 #define LOG_NDEBUG 1
+
+struct output_metadata_handle_t {
+    uint32_t            metadataLength;
+    uint32_t            bufferLength;
+    uint64_t            timestamp;
+    uint32_t            reserved[12];
+};
+
+static struct output_metadata_handle_t outputMetadataTunnel;
+
 static pcm_flag = 1;
 static debug = 0;
 static uint32_t play_max_sz = 2147483648LL;
 static int format = SNDRV_PCM_FORMAT_S16_LE;
 static int period = 0;
 static int compressed = 0;
+static int set_channel_map = 0;
+static char channel_map[8];
 static char *compr_codec;
 static int piped = 0;
+static int outputMetadataLength = 0;
+static int eosSet = 0;
 
 static struct option long_options[] =
 {
@@ -61,6 +79,7 @@
     {"format", 1, 0, 'F'},
     {"period", 1, 0, 'B'},
     {"compressed", 0, 0, 'T'},
+    {"channelMap", 0, 0, 'X'},
     {0, 0, 0, 0}
 };
 
@@ -80,6 +99,13 @@
     uint32_t data_sz;
 };
 
+
+void updateMetaData(size_t bytes) {
+   outputMetadataTunnel.metadataLength = sizeof(outputMetadataTunnel);
+   outputMetadataTunnel.timestamp = 0;
+   outputMetadataTunnel.bufferLength =  bytes;
+   fprintf(stderr, "bytes = %d\n", bytes);
+}
 static int set_params(struct pcm *pcm)
 {
      struct snd_pcm_hw_params *params;
@@ -88,7 +114,17 @@
      unsigned long periodSize, bufferSize, reqBuffSize;
      unsigned int periodTime, bufferTime;
      unsigned int requestedRate = pcm->rate;
-     int channels = (pcm->flags & PCM_MONO) ? 1 : ((pcm->flags & PCM_5POINT1)? 6 : 2 );
+     int channels;
+     if(pcm->flags & PCM_MONO)
+         channels = 1;
+     else if(pcm->flags & PCM_QUAD)
+         channels = 4;
+     else if(pcm->flags & PCM_5POINT1)
+         channels = 6;
+     else if(pcm->flags & PCM_7POINT1)
+         channels = 8;
+     else
+         channels = 2;
 
      params = (struct snd_pcm_hw_params*) calloc(1, sizeof(struct snd_pcm_hw_params));
      if (!params) {
@@ -161,6 +197,25 @@
     return 0;
 }
 
+void send_channel_map_driver(struct pcm *pcm)
+{
+    int i, ret;
+    struct mixer *mixer;
+    const char* device = "/dev/snd/controlC0";
+
+    mixer = mixer_open(device);
+    if (!mixer) {
+        fprintf(stderr,"oops: %s: %d\n", strerror(errno), __LINE__);
+        return;
+    }
+    ret = pcm_set_channel_map(pcm, mixer, 8, channel_map);
+    if (ret < 0)
+        fprintf(stderr, "could not set channel mask\n");
+    mixer_close(mixer);
+
+    return;
+}
+
 static int play_file(unsigned rate, unsigned channels, int fd,
               unsigned flags, const char *device, unsigned data_sz)
 {
@@ -183,8 +238,12 @@
 
     if (channels == 1)
         flags |= PCM_MONO;
+    else if (channels == 4)
+	flags |= PCM_QUAD;
     else if (channels == 6)
 	flags |= PCM_5POINT1;
+    else if (channels == 8)
+	flags |= PCM_7POINT1;
     else
         flags |= PCM_STEREO;
 
@@ -202,7 +261,6 @@
         return -EBADFD;
     }
 
-#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
     if (compressed) {
        struct snd_compr_caps compr_cap;
        struct snd_compr_params compr_params;
@@ -214,12 +272,16 @@
        if (!period)
            period = compr_cap.min_fragment_size;
            switch (get_compressed_format(compr_codec)) {
-           case FORMAT_MP3:
-               compr_params.codec.id = compr_cap.codecs[FORMAT_MP3];
+           case SND_AUDIOCODEC_MP3:
+               compr_params.codec.id = SND_AUDIOCODEC_MP3;
                break;
-           case FORMAT_AC3_PASS_THROUGH:
-               compr_params.codec.id = compr_cap.codecs[FORMAT_AC3_PASS_THROUGH];
-               printf("codec -d = %x\n", compr_params.codec.id);
+           case SND_AUDIOCODEC_AC3_PASS_THROUGH:
+               compr_params.codec.id = SND_AUDIOCODEC_AC3_PASS_THROUGH;
+               printf("codec -d = %x\n", SND_AUDIOCODEC_AC3_PASS_THROUGH);
+               break;
+           case SND_AUDIOCODEC_AAC:
+               compr_params.codec.id = SND_AUDIOCODEC_AAC;
+               printf("codec -d = %x\n", SND_AUDIOCODEC_AAC);
                break;
            default:
                break;
@@ -229,8 +291,12 @@
           pcm_close(pcm);
           return -errno;
        }
+       outputMetadataLength = sizeof(struct output_metadata_handle_t);
+    } else if (channels > 2) {
+        if(set_channel_map) {
+            send_channel_map_driver(pcm);
+        }
     }
-#endif
     pcm->channels = channels;
     pcm->rate = rate;
     pcm->flags = flags;
@@ -278,7 +344,7 @@
         pfd[0].fd = pcm->timer_fd;
         pfd[0].events = POLLIN;
 
-        frames = (pcm->flags & PCM_MONO) ? (bufsize / 2) : (bufsize / 4);
+        frames = bufsize / (2*channels);
         for (;;) {
              if (!pcm->running) {
                   if (pcm_prepare(pcm)) {
@@ -338,16 +404,23 @@
              if (data_sz && !piped) {
                  if (remainingData < bufsize) {
                      bufsize = remainingData;
-                     frames = (pcm->flags & PCM_MONO) ? (remainingData / 2) : (remainingData / 4);
+                     frames = remainingData / (2*channels);
                  }
              }
+             fprintf(stderr, "addr = %d, size = %d \n", (dst_addr + outputMetadataLength),(bufsize - outputMetadataLength));
+             err = read(fd, (dst_addr + outputMetadataLength) , (bufsize - outputMetadataLength));
+             if(compressed) {
+                 updateMetaData(err);
+                 memcpy(dst_addr, &outputMetadataTunnel, outputMetadataLength);
+             }
 
-             err = read(fd, dst_addr , bufsize);
              if (debug)
                  fprintf(stderr, "read %d bytes from file\n", err);
-             if (err <= 0)
+             if (err <= 0 ) {
+                 fprintf(stderr," EOS set\n ");
+                 eosSet = 1;
                  break;
-
+             }
              if (data_sz && !piped) {
                  remainingData -= bufsize;
                  if (remainingData <= 0)
@@ -374,15 +447,13 @@
                  fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld  sync_ptr->c.control.appl_ptr %ld\n",
                             pcm->sync_ptr->s.status.hw_ptr,
                             pcm->sync_ptr->c.control.appl_ptr);
-#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
                  if (compressed && start) {
                     struct snd_compr_tstamp tstamp;
-		    if (ioctl(pcm->fd, SNDRV_COMPRESS_TSTAMP, &tstamp))
-			fprintf(stderr, "Aplay: failed SNDRV_COMPRESS_TSTAMP\n");
+        if (ioctl(pcm->fd, SNDRV_COMPRESS_TSTAMP, &tstamp))
+      fprintf(stderr, "Aplay: failed SNDRV_COMPRESS_TSTAMP\n");
                     else
-	                fprintf(stderr, "timestamp = %lld\n", tstamp.timestamp);
-		}
-#endif
+                  fprintf(stderr, "timestamp = %lld\n", tstamp.timestamp);
+    }
              }
              /*
               * If we have reached start threshold of buffer prefill,
@@ -409,6 +480,7 @@
 start_done:
                 offset += frames;
         }
+
         while(1) {
             pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;//SNDRV_PCM_SYNC_PTR_HWSYNC;
             sync_ptr(pcm);
@@ -420,6 +492,14 @@
                 fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld  sync_ptr->c.control.appl_ptr %ld\n",
                            pcm->sync_ptr->s.status.hw_ptr,
                            pcm->sync_ptr->c.control.appl_ptr);
+
+                if(compressed && eosSet) {
+                    fprintf(stderr,"Audio Drain DONE ++\n");
+                    if ( ioctl(pcm->fd, SNDRV_COMPRESS_DRAIN) < 0 ) {
+                        fprintf(stderr,"Audio Drain failed\n");
+                    }
+                    fprintf(stderr,"Audio Drain DONE --\n");
+                }
                 break;
             } else
                 poll(pfd, nfds, TIMEOUT_INFINITE);
@@ -491,7 +571,7 @@
         flag = PCM_NMMAP;
 
     fprintf(stderr, "aplay: Playing '%s': format %s ch = %d\n",
-		    fn, get_format_desc(format), ch );
+        fn, get_format_desc(format), ch );
     return play_file(rate, ch, fd, flag, device, 0);
 }
 
@@ -556,6 +636,45 @@
     return play_file(hdr.sample_rate, hdr.num_channels, fd, flag, device, hdr.data_sz);
 }
 
+char get_channel_map_val(char *string)
+{
+    char retval = 0;
+    if( !strncmp(string, "RRC", sizeof(string)) )
+        retval = 16;
+    else if( !strncmp(string, "RLC", sizeof(string)) )
+        retval = 15;
+    else if( !strncmp(string, "FRC", sizeof(string)) )
+        retval = 14;
+    else if( !strncmp(string, "FLC", sizeof(string)) )
+        retval = 13;
+    else if( !strncmp(string, "MS", sizeof(string)) )
+        retval = 12;
+    else if( !strncmp(string, "CVH", sizeof(string)) )
+        retval = 11;
+    else if( !strncmp(string, "TS", sizeof(string)) )
+        retval = 10;
+    else if( !strncmp(string, "RB", sizeof(string)) )
+        retval = 9;
+    else if( !strncmp(string, "LB", sizeof(string)) )
+        retval = 8;
+    else if( !strncmp(string, "CS", sizeof(string)) )
+        retval = 7;
+    else if( !strncmp(string, "LFE", sizeof(string)) )
+        retval = 6;
+    else if( !strncmp(string, "RS", sizeof(string)) )
+        retval = 5;
+    else if( !strncmp(string, "LS", sizeof(string)) )
+        retval = 4;
+    else if( !strncmp(string, "FC", sizeof(string)) )
+        retval = 3;
+    else if( !strncmp(string, "FR", sizeof(string)) )
+        retval = 2;
+    else if( !strncmp(string, "FL", sizeof(string)) )
+        retval = 1;
+
+    return retval;
+}
+
 int main(int argc, char **argv)
 {
     int option_index = 0;
@@ -565,20 +684,25 @@
     char *mmap = "N";
     char *device = "hw:0,0";
     char *filename;
+    char *ptr;
     int rc = 0;
 
     if (argc <2) {
           printf("\nUsage: aplay [options] <file>\n"
                 "options:\n"
-                "-D <hw:C,D>	-- Alsa PCM by name\n"
-                "-M		-- Mmap stream\n"
-                "-P		-- Hostless steam[No PCM]\n"
-		"-C             -- Channels\n"
-		"-R             -- Rate\n"
-                "-V		-- verbose\n"
-		"-F             -- Format\n"
+                "-D <hw:C,D>  -- Alsa PCM by name\n"
+                "-M   -- Mmap stream\n"
+                "-P   -- Hostless steam[No PCM]\n"
+    "-C             -- Channels\n"
+    "-R             -- Rate\n"
+                "-V   -- verbose\n"
+    "-F             -- Format\n"
                 "-B             -- Period\n"
                 "-T <MP3, AAC, AC3_PASS_THROUGH>  -- Compressed\n"
+                "-X <\"FL,FR,FC,Ls,Rs,LFE\" for 5.1 configuration\n"
+                "     supported channels: \n"
+                "     FL, FR, FC, LS, RS, LFE, CS, TS \n"
+                "     LB, RB, FLC, FRC, RLC, RRC, CVH, MS\n"
                 "<file> \n");
            fprintf(stderr, "Formats Supported:\n");
            for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; ++i)
@@ -587,7 +711,7 @@
            fprintf(stderr, "\nSome of these may not be available on selected hardware\n");
            return 0;
      }
-     while ((c = getopt_long(argc, argv, "PVMD:R:C:F:B:T:", long_options, &option_index)) != -1) {
+     while ((c = getopt_long(argc, argv, "PVMD:R:C:F:B:T:X:", long_options, &option_index)) != -1) {
        switch (c) {
        case 'P':
           pcm_flag = 0;
@@ -619,18 +743,35 @@
           printf("compressed codec type requested = %s\n", optarg);
           compr_codec = optarg;
           break;
+       case 'X':
+          set_channel_map = 1; i = 0;
+          memset(channel_map, 0, sizeof(channel_map));
+          ptr = strtok(optarg, ",");
+          while((ptr != NULL) && (i < sizeof(channel_map))) {
+              channel_map[i] = get_channel_map_val(ptr);
+              if (channel_map[i] < 0 || channel_map[i] > 16) {
+                  set_channel_map = 0;
+                  break;
+              }
+              ptr = strtok(NULL,","); i++;
+          }
+          break;
        default:
           printf("\nUsage: aplay [options] <file>\n"
                 "options:\n"
-                "-D <hw:C,D>	-- Alsa PCM by name\n"
-                "-M		-- Mmap stream\n"
-                "-P		-- Hostless steam[No PCM]\n"
-                "-V		-- verbose\n"
-                "-C		-- Channels\n"
-		"-R             -- Rate\n"
-		"-F             -- Format\n"
+                "-D <hw:C,D>  -- Alsa PCM by name\n"
+                "-M   -- Mmap stream\n"
+                "-P   -- Hostless steam[No PCM]\n"
+                "-V   -- verbose\n"
+                "-C   -- Channels\n"
+    "-R             -- Rate\n"
+    "-F             -- Format\n"
                 "-B             -- Period\n"
                 "-T             -- Compressed\n"
+                "-X <\"FL,FR,FC,Ls,Rs,LFE\" for 5.1 configuration\n"
+                "     supported channels: \n"
+                "     FL, FR, FC, LS, RS, LFE, CS, TS \n"
+                "     LB, RB, FLC, FRC, RLC, RRC, CVH, MS\n"
                 "<file> \n");
            fprintf(stderr, "Formats Supported:\n");
            for (i = 0; i < SNDRV_PCM_FORMAT_LAST; ++i)
@@ -654,7 +795,7 @@
     }
 
     if (pcm_flag) {
-	 if (format == SNDRV_PCM_FORMAT_S16_LE) 
+   if (format == SNDRV_PCM_FORMAT_S16_LE)
              rc = play_wav(mmap, rate, ch, device, filename);
          else
              rc = play_raw(mmap, rate, ch, device, filename);
diff --git a/libalsa-intf/arec.c b/libalsa-intf/arec.c
index cab88f1..8f74fe8 100644
--- a/libalsa-intf/arec.c
+++ b/libalsa-intf/arec.c
@@ -28,6 +28,12 @@
 #include <getopt.h>
 #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"
 
 #define ID_RIFF 0x46464952
@@ -42,17 +48,20 @@
 #define strlcpy g_strlcpy
 #endif
 
+#define COMPR_META_DATA_SIZE	64
 static struct wav_header hdr;
 static int fd;
 static struct pcm *pcm;
-static int debug = 0;
-static int pcm_flag = 1;
-static int duration = 0;
+static debug = 0;
+static pcm_flag = 1;
+static duration = 0;
 static char *filename;
 static char *data;
 static int format = SNDRV_PCM_FORMAT_S16_LE;
 static int period = 0;
 static int piped = 0;
+static int compressed = 0;
+static char *compr_codec;
 
 static struct option long_options[] =
 {
@@ -65,6 +74,7 @@
     {"duration", 1, 0, 'T'},
     {"format", 1, 0, 'F'},
     {"period", 1, 0, 'B'},
+    {"compressed", 1, 0, 'K'},
     {0, 0, 0, 0}
 };
 
@@ -177,7 +187,7 @@
 
 int record_file(unsigned rate, unsigned channels, int fd, unsigned count,  unsigned flags, const char *device)
 {
-    unsigned xfer, bufsize;
+    unsigned xfer, bufsize, framesize;
     int r, avail;
     int nfds = 1;
     static int start = 0;
@@ -187,7 +197,7 @@
     int err;
     struct pollfd pfd[1];
     int rec_size = 0;
-
+    framesize = 0;
     flags |= PCM_IN;
 
     if (channels == 1)
@@ -204,6 +214,41 @@
         pcm_close(pcm);
         goto fail;
     }
+
+    if (compressed) {
+       struct snd_compr_caps compr_cap;
+       struct snd_compr_params compr_params;
+       printf("SNDRV_COMPRESS_GET_CAPS= 0x%X\n", SNDRV_COMPRESS_GET_CAPS);
+       if (ioctl(pcm->fd, SNDRV_COMPRESS_GET_CAPS, &compr_cap)) {
+          fprintf(stderr, "AREC: SNDRV_COMPRESS_GET_CAPS, failed Error no %d \n", errno);
+          pcm_close(pcm);
+          return -errno;
+       }
+       if (!period)
+           period = compr_cap.min_fragment_size;
+           switch (get_compressed_format(compr_codec)) {
+           case SND_AUDIOCODEC_MP3:
+               compr_params.codec.id = SND_AUDIOCODEC_MP3;
+               break;
+           case SND_AUDIOCODEC_AC3_PASS_THROUGH:
+               compr_params.codec.id = SND_AUDIOCODEC_AC3_PASS_THROUGH;
+               printf("codec -d = %x\n", compr_params.codec.id);
+               break;
+           case SND_AUDIOCODEC_AMRWB:
+               compr_params.codec.id = SND_AUDIOCODEC_AMRWB;
+               compr_params.codec.options.generic.reserved[0] = 8; /*band mode - 23.85 kbps*/
+               compr_params.codec.options.generic.reserved[1] = 0; /*dtx mode - disable*/
+               printf("codec -d = %x\n", compr_params.codec.id);
+               break;
+           default:
+               break;
+           }
+       if (ioctl(pcm->fd, SNDRV_COMPRESS_SET_PARAMS, &compr_params)) {
+          fprintf(stderr, "AREC: SNDRV_COMPRESS_SET_PARAMS,failed Error no %d \n", errno);
+          pcm_close(pcm);
+          return -errno;
+       }
+    }
     pcm->channels = channels;
     pcm->rate = rate;
     pcm->flags = flags;
@@ -248,17 +293,18 @@
         }
 
         bufsize = pcm->period_size;
+
         if (debug)
-	    fprintf(stderr, "Arec:bufsize = %d\n", bufsize);
+            fprintf(stderr, "Arec:bufsize = %d\n", bufsize);
         if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) {
-		if (errno == EPIPE) {
+            if (errno == EPIPE) {
 			fprintf(stderr, "Arec:Failed in SNDRV_PCM_IOCTL_START\n");
 			/* we failed to make our window -- try to restart */
 			pcm->running = 0;
-		} else {
-			fprintf(stderr, "Arec:Error no %d \n", errno);
-			return -errno;
-		}
+            } else {
+                fprintf(stderr, "Arec:Error no %d \n", errno);
+                return -errno;
+            }
         }
 
         pfd[0].fd = pcm->fd;
@@ -276,20 +322,20 @@
         }
         x.frames = frames;
         for(;;) {
-		if (!pcm->running) {
-                    if (pcm_prepare(pcm))
-                        return --errno;
-                    start = 0;
-                }
-                /* Sync the current Application pointer from the kernel */
-		pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;//SNDRV_PCM_SYNC_PTR_HWSYNC;
-                err = sync_ptr(pcm);
-                if (err == EPIPE) {
-                     fprintf(stderr, "Arec:Failed in sync_ptr \n");
-                     /* we failed to make our window -- try to restart */
-                     //pcm->overruns++;
-                     pcm->running = 0;
-                     continue;
+            if (!pcm->running) {
+                if (pcm_prepare(pcm))
+                    return --errno;
+                start = 0;
+            }
+            /* Sync the current Application pointer from the kernel */
+            pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;/*SNDRV_PCM_SYNC_PTR_HWSYNC;*/
+            err = sync_ptr(pcm);
+            if (err == EPIPE) {
+                fprintf(stderr, "Arec:Failed in sync_ptr \n");
+                /* we failed to make our window -- try to restart */
+                //pcm->overruns++;
+                pcm->running = 0;
+                continue;
                 }
                /*
                 * Check for the available data in driver. If available data is
@@ -297,14 +343,16 @@
                 */
                 avail = pcm_avail(pcm);
                 if (debug)
-                     fprintf(stderr, "Arec:avail 1 = %d frames = %ld\n",avail, frames);
+                     fprintf(stderr, "Arec:avail 1 = %d frames = %ld, avail_min = %d,"
+                             "x.frames = %d, bufsize = %d, dst_addr = %p\n",avail, frames,
+                             (int)pcm->sw_p->avail_min, (int)x.frames, bufsize, dst_addr);
                 if (avail < 0)
                         return avail;
                 if (avail < pcm->sw_p->avail_min) {
                         poll(pfd, nfds, TIMEOUT_INFINITE);
                         continue;
                 }
-	 	if (x.frames > avail)
+                if (x.frames > avail)
                         frames = avail;
                /*
                 * Now that we have data size greater than avail_min available to
@@ -312,18 +360,31 @@
                 * start reading from.
                 */
                 dst_addr = dst_address(pcm);
+                if (compressed) {
+                    framesize =  (unsigned)(dst_addr[3] << 24) + (unsigned)(dst_addr[2] << 16) +
+                        (unsigned) (dst_addr[1] << 8) + (unsigned)dst_addr[0];
+                    if (debug)
+                        fprintf(stderr, "Arec:dst_addr[0] = %d, dst_addr[1] = %d,"
+                            "dst_addr[2] = %d, dst_addr[3] = %d, dst_addr[4] = %d,"
+                            "dst_addr[5] = %d, dst_addr = %p, bufsize = %d, framesize = %d\n",
+                            dst_addr[0], dst_addr[1], dst_addr[2], dst_addr[3], dst_addr[4],
+                            dst_addr[5],dst_addr,  bufsize, framesize);
+                    dst_addr += COMPR_META_DATA_SIZE;
+                } else {
+                    framesize = bufsize;
+                }
 
                /*
                 * Write to the file at the destination address from kernel mmaped buffer
                 * This reduces a extra copy of intermediate buffer.
                 */
-                if (write(fd, dst_addr, bufsize) != bufsize) {
-                    fprintf(stderr, "Arec:could not write %d bytes\n", bufsize);
+                if (write(fd, dst_addr, framesize) != framesize) {
+                    fprintf(stderr, "Arec:could not write %d bytes\n", framesize);
                     return -errno;
                 }
                 x.frames -= frames;
                 pcm->sync_ptr->c.control.appl_ptr += frames;
-		pcm->sync_ptr->flags = 0;
+                pcm->sync_ptr->flags = 0;
                 err = sync_ptr(pcm);
                 if (err == EPIPE) {
                      fprintf(stderr, "Arec:Failed in sync_ptr \n");
@@ -332,12 +393,14 @@
                      continue;
                 }
                 rec_size += bufsize;
-                hdr.data_sz += bufsize;
-                hdr.riff_sz = hdr.data_sz + 44 - 8;
-                if (!piped) {
-                    lseek(fd, 0, SEEK_SET);
-                    write(fd, &hdr, sizeof(hdr));
-                    lseek(fd, 0, SEEK_END);
+                if (!compressed) {
+                    hdr.data_sz += bufsize;
+                    hdr.riff_sz = hdr.data_sz + 44 - 8;
+                    if (!piped) {
+                        lseek(fd, 0, SEEK_SET);
+                        write(fd, &hdr, sizeof(hdr));
+                        lseek(fd, 0, SEEK_END);
+                    }
                 }
                 if (rec_size >= count)
                       break;
@@ -391,7 +454,7 @@
     uint32_t rec_max_sz = 2147483648LL;
     uint32_t count;
     int i = 0;
-
+    printf("rec_raw-> pcm_flag = %d\n", pcm_flag);
     if (!fn) {
         fd = fileno(stdout);
         piped = 1;
@@ -427,53 +490,60 @@
     uint32_t rec_max_sz = 2147483648LL;
     uint32_t count = 0;
     int i = 0;
-
+    printf("rec_wav-> pcm_flag = %d\n", pcm_flag);
     if (pcm_flag) {
-            if (!fn) {
-              fd = fileno(stdout);
-              piped = 1;
-            } else {
-	       fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
-	       if (fd < 0) {
-	            fprintf(stderr, "Arec:arec: cannot open '%s'\n", fn);
-		    return -EBADFD;
-	       }
+        if (!fn) {
+            fd = fileno(stdout);
+            piped = 1;
+        } else {
+            fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
+            if (fd < 0) {
+                fprintf(stderr, "Arec:arec: cannot open '%s'\n", fn);
+                return -EBADFD;
             }
-	    memset(&hdr, 0, sizeof(struct wav_header));
-	    hdr.riff_id = ID_RIFF;
-	    hdr.riff_fmt = ID_WAVE;
-	    hdr.fmt_id = ID_FMT;
-	    hdr.fmt_sz = 16;
-	    hdr.audio_format = FORMAT_PCM;
-	    hdr.num_channels = ch;
-	    hdr.sample_rate = rate;
-            hdr.bits_per_sample = 16;
-            hdr.byte_rate = (rate * ch * hdr.bits_per_sample) / 8;
-            hdr.block_align = ( hdr.bits_per_sample * ch ) / 8;
-	    hdr.data_id = ID_DATA;
-	    hdr.data_sz = 0;
+        }
+        if (compressed) {
 
-            if (duration == 0) {
-                count = rec_max_sz;
-            } else {
-                count = rate * ch * 2;
-                count *= (uint32_t)duration;
-            }
-            hdr.riff_sz = hdr.data_sz + 44 - 8;
-	    if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
-		if (debug)
-		    fprintf(stderr, "arec: cannot write header\n");
-		return -errno;
-	    }
-	    if (debug)
-		fprintf(stderr, "arec: %d ch, %d hz, %d bit, %s\n",
-		    hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample,
-		    hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown");
-    } else {
+            printf("rec_wav-> compressed = %d\n", compressed);
             hdr.sample_rate = rate;
             hdr.num_channels = ch;
+            goto ignore_header;
+        }
+        memset(&hdr, 0, sizeof(struct wav_header));
+        hdr.riff_id = ID_RIFF;
+        hdr.riff_fmt = ID_WAVE;
+        hdr.fmt_id = ID_FMT;
+        hdr.fmt_sz = 16;
+        hdr.audio_format = FORMAT_PCM;
+        hdr.num_channels = ch;
+        hdr.sample_rate = rate;
+        hdr.bits_per_sample = 16;
+        hdr.byte_rate = (rate * ch * hdr.bits_per_sample) / 8;
+        hdr.block_align = ( hdr.bits_per_sample * ch ) / 8;
+        hdr.data_id = ID_DATA;
+        hdr.data_sz = 0;
+        hdr.riff_sz = hdr.data_sz + 44 - 8;
+        if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+            if (debug)
+                fprintf(stderr, "arec: cannot write header\n");
+            return -errno;
+        }
+        if (debug)
+            fprintf(stderr, "arec: %d ch, %d hz, %d bit, %s\n",
+                    hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample,
+                    hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown");
+    } else {
+        hdr.sample_rate = rate;
+        hdr.num_channels = ch;
     }
+ignore_header:
 
+   if (duration == 0) {
+        count = rec_max_sz;
+    } else {
+          count = rate * ch * 2;
+          count *= (uint32_t)duration;
+    }
     if (!strncmp(fg, "M", sizeof("M"))) {
         flag = PCM_MMAP;
     } else if (!strncmp(fg, "N", sizeof("N"))) {
@@ -521,25 +591,26 @@
     int rc = 0;
 
     if (argc < 2) {
-          printf("\nUsage: arec [options] <file>\n"
-                "options:\n"
-                "-D <hw:C,D>	-- Alsa PCM by name\n"
-                "-M		-- Mmap stream\n"
-                "-P		-- Hostless steam[No PCM]\n"
-                "-V		-- verbose\n"
-                "-C		-- Channels\n"
-                "-R		-- Rate\n"
-                "-T		-- Time in seconds for recording\n"
-		"-F             -- Format\n"
-                "-B             -- Period\n"
-                "<file> \n");
+        printf("\nUsage: arec [options] <file>\n"
+              "options:\n"
+              "-D <hw:C,D>        -- Alsa PCM by name\n"
+              "-M     -- Mmap stream\n"
+              "-P     -- Hostless steam[No PCM]\n"
+              "-V     -- verbose\n"
+              "-C     -- Channels\n"
+              "-R     -- Rate\n"
+              "-T     -- Time in seconds for recording\n"
+              "-F     -- Format\n"
+              "-B     -- Period\n"
+              "-K <AC3,DTS,etc>   -- compressed\n"
+              "<file> \n");
            for (i = 0; i < SNDRV_PCM_FORMAT_LAST; ++i)
                if (get_format_name(i))
                    fprintf(stderr, "%s ", get_format_name(i));
            fprintf(stderr, "\nSome of these may not be available on selected hardware\n");
           return 0;
     }
-    while ((c = getopt_long(argc, argv, "PVMD:R:C:T:F:B:", long_options, &option_index)) != -1) {
+    while ((c = getopt_long(argc, argv, "PVMD:R:C:T:F:B:K:", long_options, &option_index)) != -1) {
        switch (c) {
        case 'P':
           pcm_flag = 0;
@@ -568,18 +639,24 @@
        case 'B':
           period = (int)strtol(optarg, NULL, 0);
           break;
+       case 'K':
+          compressed = 1;
+          printf("compressed codec type requested = %s\n", optarg);
+          compr_codec = optarg;
+          break;
        default:
           printf("\nUsage: arec [options] <file>\n"
                 "options:\n"
-                "-D <hw:C,D>	-- Alsa PCM by name\n"
-                "-M		-- Mmap stream\n"
-                "-P		-- Hostless steam[No PCM]\n"
-                "-V		-- verbose\n"
-                "-C		-- Channels\n"
-                "-R		-- Rate\n"
-                "-T		-- Time in seconds for recording\n"
-		"-F             -- Format\n"
-                "-B             -- Period\n"
+                "-D <hw:C,D>        -- Alsa PCM by name\n"
+                "-M     -- Mmap stream\n"
+                "-P     -- Hostless steam[No PCM]\n"
+                "-V     -- verbose\n"
+                "-C     -- Channels\n"
+                "-R     -- Rate\n"
+                "-T     -- Time in seconds for recording\n"
+                "-F     -- Format\n"
+                "-B     -- Period\n"
+                "-K <AC3,DTS,etc>   -- compressed\n"
                 "<file> \n");
            for (i = 0; i < SNDRV_PCM_FORMAT_LAST; ++i)
                if (get_format_name(i))
diff --git a/libalsa-intf/msm8960_use_cases.h b/libalsa-intf/msm8960_use_cases.h
index ed58d8a..784aa72 100644
--- a/libalsa-intf/msm8960_use_cases.h
+++ b/libalsa-intf/msm8960_use_cases.h
@@ -44,6 +44,7 @@
 #define CAP_VOICE 0x4
 #define DEVICE_HANDSET_RX_ACDB_ID                       7 // HANDSET_SPKR
 #define DEVICE_HANDSET_TX_ACDB_ID                       4 // HANDSET_MIC
+#define DEVICE_SPEAKER_RX_ACDB_ID                       15// SPKR_PHONE_SPKR_STEREO
 #define DEVICE_SPEAKER_MONO_RX_ACDB_ID                  14// SPKR_PHONE_SPKR_MONO
 #define DEVICE_SPEAKER_STEREO_RX_ACDB_ID                15// SPKR_PHONE_SPKR_STEREO
 #define DEVICE_SPEAKER_TX_ACDB_ID                       11// SPKR_PHONE_MIC
@@ -53,6 +54,8 @@
 #define DEVICE_DUALMIC_HANDSET_TX_ENDFIRE_ACDB_ID       6 // HANDSET_MIC_ENDFIRE
 #define DEVICE_DUALMIC_SPEAKER_TX_BROADSIDE_ACDB_ID     12// SPKR_PHONE_MIC_BROADSIDE
 #define DEVICE_DUALMIC_SPEAKER_TX_ENDFIRE_ACDB_ID       13// SPKR_PHONE_MIC_ENDFIRE
+#define DEVICE_DUALMIC_HANDSET_STEREO_ACDB_ID           34
+#define DEVICE_DUALMIC_SPEAKER_PHONE_STEREO_ACDB_ID     35
 #define DEVICE_TTY_HEADSET_MONO_RX_ACDB_ID              17// TTY_HEADSET_SPKR
 #define DEVICE_TTY_HEADSET_MONO_TX_ACDB_ID              16// TTY_HEADSET_MIC
 #define DEVICE_BT_SCO_RX_ACDB_ID                        22// BT_SCO_SPKR
@@ -66,10 +69,10 @@
 #define DEVICE_PROXY_RX_ACDB_ID                         DEVICE_HDMI_STEREO_RX_ACDB_ID
 #define DEVICE_TTY_VCO_HANDSET_TX_ACDB_ID               36// TTY_VCO_HANDSET_MIC
 #define DEVICE_TTY_HCO_HANDSET_RX_ACDB_ID               37// TTY_HCO_HANDSET_SPRK
-#define DEVICE_HANDSET_TX_FV5_ACDB_ID                   50
-#define DEVICE_DUALMIC_HANDSET_TX_ENDFIRE_FV5_ACDB_ID   51
-#define DEVICE_SPEAKER_TX_FV5_ACDB_ID                   52
-#define DEVICE_DUALMIC_SPEAKER_TX_ENDFIRE_FV5_ACDB_ID   53
+#define DEVICE_HANDSET_TX_FV5_ACDB_ID                   40
+#define DEVICE_DUALMIC_HANDSET_TX_ENDFIRE_FV5_ACDB_ID   41
+#define DEVICE_SPEAKER_TX_FV5_ACDB_ID                   42
+#define DEVICE_DUALMIC_SPEAKER_TX_ENDFIRE_FV5_ACDB_ID   43
 #define DEVICE_INCALL_VOICE_RECORD_STEREO_ACDB_ID       45
 #define DEVICE_INCALL_MUSIC_DELIVERY_MONO_ACDB_ID       46
 #define DEVICE_INCALL_VOICE_RECORD_MONO_ACDB_ID         47
@@ -117,6 +120,7 @@
     int acdb_id;
     int capability;
     char *effects_mixer_ctl;
+    char *ec_ref_rx_mixer_ctl;
 }card_mctrl_t;
 
 /* identifier node structure for identifier list*/
@@ -168,7 +172,6 @@
     int current_rx_device;
     card_ctxt_t *card_ctxt_ptr;
     pthread_t thr;
-    void *acdb_handle;
 };
 
 #define MAX_NUM_CARDS (sizeof(card_list)/sizeof(char *))
@@ -177,8 +180,16 @@
 static const char *card_list[] = {
     "snd_soc_msm",
     "snd_soc_msm_2x",
+    "snd_soc_msm_2x_mpq",
     "snd_soc_msm_2x_Fusion3",
     "snd_soc_msm_Sitar",
+    "snd_soc_msm_I2S",
+    "snd_soc_msm_Taiko",
+    "snd_soc_msm_Taiko_CDP",
+    "snd_soc_msm_Taiko_Fluid",
+    "snd_soc_msm_Taiko_liquid",
+    "snd_soc_msm_I2SFusion",
+    "us_soc_msm",
 };
 
 typedef struct card_mapping {
@@ -190,8 +201,16 @@
 static card_mapping_t card_mapping_list[] = {
     {"snd_soc_msm", 0},
     {"snd_soc_msm_2x", 0},
+    {"snd_soc_msm_2x_mpq", 0},
     {"snd_soc_msm_2x_Fusion3", 0},
     {"snd_soc_msm_Sitar", 0},
+    {"snd_soc_msm_I2S", 0},
+    {"snd_soc_msm_Taiko", 0},
+    {"snd_soc_msm_Taiko_CDP", 0},
+    {"snd_soc_msm_Taiko_Fluid", 0},
+    {"snd_soc_msm_Taiko_liquid", 0},
+    {"snd_soc_msm_I2SFusion", 0},
+    {"us_soc_msm", 0},
 };
 
 /* New use cases, devices and modifiers added
@@ -203,6 +222,8 @@
 #define SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC       "HiFi Lowlatency Rec"
 #define SND_USE_CASE_VERB_DL_REC	 "DL REC"
 #define SND_USE_CASE_VERB_UL_DL_REC      "UL DL REC"
+#define SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL	 "Compressed DL REC"
+#define SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL      "Compressed UL DL REC"
 #define SND_USE_CASE_VERB_HIFI_TUNNEL    "HiFi Tunnel"
 #define SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC    "HiFi Lowlatency"
 #define SND_USE_CASE_VERB_HIFI2       "HiFi2"
@@ -210,6 +231,11 @@
 #define SND_USE_CASE_VERB_MI2S        "MI2S"
 #define SND_USE_CASE_VERB_VOLTE    "VoLTE"
 #define SND_USE_CASE_VERB_ADSP_TESTFWK "ADSP testfwk"
+#define SND_USE_CASE_VERB_HIFI_REC2       "HiFi Rec2"
+#define SND_USE_CASE_VERB_HIFI_REC_COMPRESSED    "HiFi Rec Compressed"
+#define SND_USE_CASE_VERB_HIFI3       "HiFi3"
+#define SND_USE_CASE_VERB_HIFI_TUNNEL2    "HiFi Tunnel2"
+#define SND_USE_CASE_VERB_HIFI_PSEUDO_TUNNEL    "HiFi Pseudo Tunnel"
 
 #define SND_USE_CASE_DEV_FM_TX           "FM Tx"
 #define SND_USE_CASE_DEV_ANC_HEADSET     "ANC Headset"
@@ -229,16 +255,25 @@
 #define SND_USE_CASE_DEV_TTY_HANDSET_ANALOG_TX  "TTY Handset Analog Tx"
 #define SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE "DMIC Broadside"
 #define SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE "DMIC Endfire"
+#define SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_SGLTE "DMIC Endfire SGLTE"
+#define SND_USE_CASE_DEV_DUAL_MIC_HANDSET_STEREO "Handset DMIC Stereo"
+#define SND_USE_CASE_DEV_DUAL_MIC_HANDSET_STEREO_SGLTE "Handset DMIC Stereo SGLTE"
 #define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_BROADSIDE "Speaker DMIC Broadside"
 #define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE "Speaker DMIC Endfire"
+#define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE_SGLTE "Speaker DMIC Endfire SGLTE"
+#define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_STEREO "Speaker DMIC Stereo"
+#define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_STEREO_SGLTE "Speaker DMIC Stereo SGLTE"
 #define SND_USE_CASE_DEV_HDMI_TX             "HDMI Tx"
 #define SND_USE_CASE_DEV_HDMI_SPDIF          "HDMI SPDIF"
+#define SND_USE_CASE_DEV_HDMI_SPDIF_SPEAKER   "HDMI SPDIF Speaker"
 #define SND_USE_CASE_DEV_QUAD_MIC "QMIC"
 #define SND_USE_CASE_DEV_SSR_QUAD_MIC "SSR QMIC"
 #define SND_USE_CASE_DEV_PROXY_RX     "PROXY Rx"
 #define SND_USE_CASE_DEV_PROXY_TX     "PROXY Tx"
-#define SND_USE_CASE_DEV_HDMI_SPEAKER     "HDMI Speaker"
+#define SND_USE_CASE_DEV_USB_PROXY_RX     "USB PROXY Rx"
+#define SND_USE_CASE_DEV_USB_PROXY_TX     "USB PROXY Tx"
 #define SND_USE_CASE_DEV_SPDIF_SPEAKER     "SPDIF Speaker"
+#define SND_USE_CASE_DEV_HDMI_SPEAKER      "HDMI Speaker"
 #define SND_USE_CASE_DEV_SPDIF_HANDSET     "SPDIF Earpiece"
 #define SND_USE_CASE_DEV_SPDIF_HEADSET     "SPDIF Headphones"
 #define SND_USE_CASE_DEV_SPDIF_ANC_HEADSET     "SPDIF ANC Headset"
@@ -269,11 +304,20 @@
 #define SND_USE_CASE_MOD_CAPTURE_VOIP    "Capture VOIP"
 #define SND_USE_CASE_MOD_CAPTURE_VOICE_DL       "Capture Voice Downlink"
 #define SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL    "Capture Voice Uplink Downlink"
+#define SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL       "Capture Compressed Voice DL"
+#define SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL    "Capture Compressed Voice UL DL"
 #define SND_USE_CASE_MOD_PLAY_TUNNEL     "Play Tunnel"
 #define SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC     "Play Lowlatency Music"
 #define SND_USE_CASE_MOD_PLAY_MUSIC2       "Play Music2"
 #define SND_USE_CASE_MOD_PLAY_MI2S       "Play MI2S"
 #define SND_USE_CASE_MOD_PLAY_VOLTE   "Play VoLTE"
+#define SND_USE_CASE_MOD_CAPTURE_MUSIC2       "Capture Music2"
+#define SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED    "Capture Music Compressed"
+#define SND_USE_CASE_MOD_PLAY_MUSIC3       "Play Music3"
+#define SND_USE_CASE_MOD_PLAY_TUNNEL1     "Play Tunnel1"
+#define SND_USE_CASE_MOD_PLAY_TUNNEL2     "Play Tunnel2"
+#define SND_USE_CASE_MOD_PSEUDO_TUNNEL     "Pseudo Tunnel"
+
 
 /* List utility functions for maintaining enabled devices and modifiers */
 static int snd_ucm_add_ident_to_list(struct snd_ucm_ident_node **head, const char *value);
@@ -302,6 +346,7 @@
 static int snd_ucm_extract_name(char *buf, char **case_name);
 static int snd_ucm_extract_acdb(char *buf, int *id, int *cap);
 static int snd_ucm_extract_effects_mixer_ctl(char *buf, char **mixer_name);
+static int snd_ucm_extract_ec_ref_rx_mixer_ctl(char *buf, char **mixer_name);
 static int snd_ucm_extract_dev_name(char *buf, char **dev_name);
 static int snd_ucm_extract_controls(char *buf, mixer_control_t **mixer_list, int count);
 static int snd_ucm_print(snd_use_case_mgr_t *uc_mgr);