Merge "hal: Avoid double free while closing of VoIP driver"
diff --git a/hal/Android.mk b/hal/Android.mk
index 73ae361..32b9275 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -43,6 +43,8 @@
 
 LOCAL_SRC_FILES += audio_extn/audio_extn.c \
                    audio_extn/utils.c
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
 
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PCM_OFFLOAD)),true)
     LOCAL_CFLAGS += -DPCM_OFFLOAD_ENABLED
@@ -89,8 +91,7 @@
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_MULTI_VOICE_SESSIONS)),true)
     LOCAL_CFLAGS += -DMULTI_VOICE_SESSION_ENABLED
     LOCAL_SRC_FILES += voice_extn/voice_extn.c
-    LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
-    LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_INCALL_MUSIC)),true)
     LOCAL_CFLAGS += -DINCALL_MUSIC_ENABLED
 endif
@@ -108,8 +109,6 @@
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_SPKR_PROTECTION)),true)
     LOCAL_CFLAGS += -DSPKR_PROT_ENABLED
     LOCAL_SRC_FILES += audio_extn/spkr_protection.c
-    LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
-    LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
 endif
 
 ifdef MULTIPLE_HW_VARIANTS_ENABLED
@@ -124,8 +123,6 @@
 
 ifeq ($(strip $(DOLBY_DDP)),true)
     LOCAL_CFLAGS += -DDS1_DOLBY_DDP_ENABLED
-    LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
-    LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
     LOCAL_SRC_FILES += audio_extn/dolby.c
 endif
 
@@ -140,6 +137,15 @@
     LOCAL_CFLAGS += -DMULTIPLE_OFFLOAD_ENABLED
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_FLAC_DECODER)),true)
+    LOCAL_CFLAGS += -DQTI_FLAC_DECODER
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_DEV_ARBI)),true)
+    LOCAL_CFLAGS += -DDEV_ARBI_ENABLED
+    LOCAL_SRC_FILES += audio_extn/dev_arbi.c
+endif
+
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
 	libcutils \
@@ -147,8 +153,7 @@
 	libtinycompress \
 	libaudioroute \
 	libdl \
-	libexpat \
-        libmdmdetect
+	libexpat
 
 LOCAL_C_INCLUDES += \
 	external/tinyalsa/include \
@@ -158,8 +163,7 @@
 	$(call include-path-for, audio-effects) \
 	$(LOCAL_PATH)/$(AUDIO_PLATFORM) \
 	$(LOCAL_PATH)/audio_extn \
-	$(LOCAL_PATH)/voice_extn \
-        $(TARGET_OUT_HEADERS)/libmdmdetect/inc
+	$(LOCAL_PATH)/voice_extn
 
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_LISTEN)),true)
     LOCAL_CFLAGS += -DAUDIO_LISTEN_ENABLED
@@ -171,6 +175,9 @@
     LOCAL_CFLAGS += -DAUXPCM_BT_ENABLED
 endif
 
+LOCAL_COPY_HEADERS_TO   := mm-audio
+LOCAL_COPY_HEADERS      := audio_extn/audio_defs.h
+
 LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM)
 
 LOCAL_MODULE_RELATIVE_PATH := hw
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index a858028..5eb650c 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -51,6 +51,16 @@
 #define AUDIO_DEVICE_IN_FM_RX_A2DP (AUDIO_DEVICE_BIT_IN | 0x10000)
 #endif
 
+#ifndef QTI_FLAC_DECODER
+#define AUDIO_FORMAT_FLAC 0x19000000UL
+#define AUDIO_OFFLOAD_CODEC_FLAC_MIN_BLK_SIZE "music_offload_flac_min_blk_size"
+#define AUDIO_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE "music_offload_flac_max_blk_size"
+#define AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE "music_offload_flac_min_frame_size"
+#define AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE "music_offload_flac_max_frame_size"
+#define PCM_OUTPUT_BIT_WIDTH (CODEC_BACKEND_DEFAULT_BIT_WIDTH)
+#else
+#define PCM_OUTPUT_BIT_WIDTH (config->offload_info.bit_width)
+#endif
 
 #define MAX_LENGTH_MIXER_CONTROL_IN_INT                  (128)
 
@@ -182,7 +192,7 @@
 #define audio_extn_spkr_prot_stop_processing()     (0)
 #define audio_extn_spkr_prot_is_enabled() (false)
 #define audio_extn_spkr_prot_get_acdb_id(snd_device)         (-EINVAL)
-#define audio_extn_get_spkr_prot_snd_device(snd_device) (SND_DEVICE_OUT_SPEAKER)
+#define audio_extn_get_spkr_prot_snd_device(snd_device) (snd_device)
 #else
 void audio_extn_spkr_prot_init(void *adev);
 int audio_extn_spkr_prot_start_processing(snd_device_t snd_device);
@@ -250,6 +260,18 @@
 audio_usecase_t audio_extn_hfp_get_usecase();
 #endif
 
+#ifndef DEV_ARBI_ENABLED
+#define audio_extn_dev_arbi_init()                  (0)
+#define audio_extn_dev_arbi_deinit()                (0)
+#define audio_extn_dev_arbi_acquire(snd_device)     (0)
+#define audio_extn_dev_arbi_release(snd_device)     (0)
+#else
+int audio_extn_dev_arbi_init();
+int audio_extn_dev_arbi_deinit();
+int audio_extn_dev_arbi_acquire(snd_device_t snd_device);
+int audio_extn_dev_arbi_release(snd_device_t snd_device);
+#endif
+
 void audio_extn_utils_update_streams_output_cfg_list(void *platform,
                                   struct mixer *mixer,
                                   struct listnode *streams_output_cfg_list);
diff --git a/hal/audio_extn/dev_arbi.c b/hal/audio_extn/dev_arbi.c
new file mode 100644
index 0000000..d3c01c5
--- /dev/null
+++ b/hal/audio_extn/dev_arbi.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "audio_hw_dev_arbi"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <cutils/log.h>
+#include <fcntl.h>
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/properties.h>
+#include "audio_extn.h"
+
+#ifdef DEV_ARBI_ENABLED
+
+typedef int (init_fn_t)();
+typedef int (deinit_fn_t)();
+typedef int (acquire_fn_t)(audio_devices_t aud_dev);
+typedef int (release_fn_t)(audio_devices_t aud_dev);
+
+typedef struct {
+    snd_device_t snd_device;
+    audio_devices_t aud_device;
+} snd_aud_dev_mapping_t;
+
+static void* lib_handle = NULL;
+
+static init_fn_t *init_fp = NULL;
+static deinit_fn_t *deinit_fp = NULL;
+static acquire_fn_t *acquire_fp = NULL;
+static release_fn_t *release_fp = NULL;
+
+static int load_dev_arbi_lib()
+{
+    int rc = -EINVAL;
+
+    if (lib_handle != NULL) {
+        ALOGE("%s: library already loaded", __func__);
+        return rc;
+    }
+
+    lib_handle = dlopen("libaudiodevarb.so", RTLD_NOW);
+    if (lib_handle != NULL) {
+        init_fp = (init_fn_t*)dlsym(lib_handle, "aud_dev_arbi_server_init");
+        deinit_fp = (deinit_fn_t*)dlsym(lib_handle, "aud_dev_arbi_server_deinit");
+        acquire_fp = (acquire_fn_t*)dlsym(lib_handle, "aud_dev_arbi_server_acquire");
+        release_fp = (release_fn_t*)dlsym(lib_handle, "aud_dev_arbi_server_release");
+
+        if ((init_fp == NULL) ||
+            (deinit_fp == NULL) ||
+            (acquire_fp == NULL) ||
+            (release_fp == NULL)) {
+
+            ALOGE("%s: error loading symbols from library", __func__);
+
+            init_fp = NULL;
+            deinit_fp = NULL;
+            acquire_fp = NULL;
+            release_fp = NULL;
+        } else
+            return 0;
+    }
+
+    return rc;
+}
+
+int audio_extn_dev_arbi_init()
+{
+    int rc = load_dev_arbi_lib();
+    if (!rc)
+        rc = init_fp();
+
+    return rc;
+}
+
+int audio_extn_dev_arbi_deinit()
+{
+    int rc = -EINVAL;
+
+    if(deinit_fp != NULL) {
+        rc = deinit_fp();
+
+        init_fp = NULL;
+        deinit_fp = NULL;
+        acquire_fp = NULL;
+        release_fp = NULL;
+
+        dlclose(lib_handle);
+        lib_handle = NULL;
+    }
+
+    return rc;
+}
+
+static audio_devices_t get_audio_device(snd_device_t snd_device)
+{
+    static snd_aud_dev_mapping_t snd_aud_dev_map[] = {
+        {SND_DEVICE_OUT_HANDSET, AUDIO_DEVICE_OUT_EARPIECE},
+        {SND_DEVICE_OUT_VOICE_HANDSET, AUDIO_DEVICE_OUT_EARPIECE}
+    };
+
+    audio_devices_t aud_device = AUDIO_DEVICE_NONE;
+    uint32_t ind = 0;
+
+    for (ind = 0; ind < ARRAY_SIZE(snd_aud_dev_map); ++ind) {
+        if (snd_device == snd_aud_dev_map[ind].snd_device) {
+            aud_device = snd_aud_dev_map[ind].aud_device;
+            break;
+        }
+    }
+
+    return aud_device;
+}
+
+int audio_extn_dev_arbi_acquire(snd_device_t snd_device)
+{
+    int rc = -EINVAL;
+    audio_devices_t audio_device = get_audio_device(snd_device);
+
+    if ((acquire_fp != NULL) && (audio_device != AUDIO_DEVICE_NONE))
+        rc = acquire_fp(audio_device);
+
+    return rc;
+}
+
+int audio_extn_dev_arbi_release(snd_device_t snd_device)
+{
+    int rc = -EINVAL;
+    audio_devices_t audio_device = get_audio_device(snd_device);
+
+    if ((release_fp != NULL) && (audio_device != AUDIO_DEVICE_NONE))
+        rc = release_fp(audio_device);
+
+    return rc;
+}
+
+#endif /*DEV_ARBI_ENABLED*/
diff --git a/hal/audio_extn/fm.c b/hal/audio_extn/fm.c
index 1d1613a..b6f8689 100644
--- a/hal/audio_extn/fm.c
+++ b/hal/audio_extn/fm.c
@@ -148,6 +148,10 @@
     ALOGD("%s: enter", __func__);
 
     uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+
+    if (!uc_info)
+        return -ENOMEM;
+
     uc_info->id = USECASE_AUDIO_PLAYBACK_FM;
     uc_info->type = PCM_PLAYBACK;
     uc_info->stream.out = adev->primary_output;
diff --git a/hal/audio_extn/hfp.c b/hal/audio_extn/hfp.c
index 239c975..c94cc14 100644
--- a/hal/audio_extn/hfp.c
+++ b/hal/audio_extn/hfp.c
@@ -136,6 +136,10 @@
     ALOGD("%s: enter", __func__);
 
     uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+
+    if (!uc_info)
+        return -ENOMEM;
+
     uc_info->id = hfpmod.ucid;
     uc_info->type = PCM_HFP_CALL;
     uc_info->stream.out = adev->primary_output;
@@ -200,10 +204,26 @@
         ret = -EIO;
         goto exit;
     }
-    pcm_start(hfpmod.hfp_sco_rx);
-    pcm_start(hfpmod.hfp_sco_tx);
-    pcm_start(hfpmod.hfp_pcm_rx);
-    pcm_start(hfpmod.hfp_pcm_tx);
+    if (pcm_start(hfpmod.hfp_sco_rx) < 0) {
+        ALOGE("%s: pcm start for hfp sco rx failed", __func__);
+        ret = -EINVAL;
+        goto exit;
+    }
+    if (pcm_start(hfpmod.hfp_sco_tx) < 0) {
+        ALOGE("%s: pcm start for hfp sco tx failed", __func__);
+        ret = -EINVAL;
+        goto exit;
+    }
+    if (pcm_start(hfpmod.hfp_pcm_rx) < 0) {
+        ALOGE("%s: pcm start for hfp pcm rx failed", __func__);
+        ret = -EINVAL;
+        goto exit;
+    }
+    if (pcm_start(hfpmod.hfp_pcm_tx) < 0) {
+        ALOGE("%s: pcm start for hfp pcm tx failed", __func__);
+        ret = -EINVAL;
+        goto exit;
+    }
 
     hfpmod.is_hfp_running = true;
     hfp_set_volume(adev, hfpmod.hfp_volume);
diff --git a/hal/audio_extn/listen.c b/hal/audio_extn/listen.c
index b1ed105..4cb2d2d 100644
--- a/hal/audio_extn/listen.c
+++ b/hal/audio_extn/listen.c
@@ -200,6 +200,11 @@
         listen_dev = (struct listen_audio_device*)
             calloc(1, sizeof(struct listen_audio_device));
 
+        if (!listen_dev) {
+            ALOGE("failed to allocate listen_dev mem");
+            return -ENOMEM;
+        }
+
         listen_dev->lib_handle = lib_handle;
         listen_dev->adev = adev;
 
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index 7ab65c6..951dadc 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -668,6 +668,15 @@
         handle.thermal_handle = NULL;
         handle.spkr_prot_enable = false;
     }
+
+    if (handle.spkr_prot_enable) {
+        char platform[PROPERTY_VALUE_MAX];
+        property_get("ro.board.platform", platform, "");
+        if (!strncmp("apq8084", platform, sizeof("apq8084"))) {
+            platform_set_snd_device_backend(SND_DEVICE_OUT_VOICE_SPEAKER,
+                                            "speaker-protected");
+        }
+    }
 }
 
 int audio_extn_spkr_prot_get_acdb_id(snd_device_t snd_device)
diff --git a/hal/audio_extn/ssr.c b/hal/audio_extn/ssr.c
index ac6da8b..f32d217 100644
--- a/hal/audio_extn/ssr.c
+++ b/hal/audio_extn/ssr.c
@@ -294,8 +294,8 @@
     if ( ret > 0 ) {
         ALOGV("%s: Allocating surroundObj size is %d", __func__, ret);
         ssrmod.surround_obj = (void *)malloc(ret);
-        memset(ssrmod.surround_obj,0,ret);
         if (NULL != ssrmod.surround_obj) {
+            memset(ssrmod.surround_obj,0,ret);
             /* initialize after allocating the memory for surround_obj */
             ret = ssrmod.surround_filters_init(ssrmod.surround_obj,
                         6,
diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c
index bc83709..a4ea134 100644
--- a/hal/audio_extn/usb.c
+++ b/hal/audio_extn/usb.c
@@ -159,12 +159,16 @@
     char *buffer;
     int32_t err = 1;
     int32_t size = 0;
-    int32_t fd, i, channels_playback;
-    char *read_buf, *str_start, *channel_start, *rates_str, *rates_str_for_val,
-    *rates_str_start, *next_sr_str, *test, *next_sr_string, *temp_ptr;
+    int32_t fd=-1, i, channels_playback;
+    char *str_start, *channel_start, *rates_str_start, *next_sr_str,
+         *next_sr_string, *temp_ptr;
     struct stat st;
-    int *rates_supported;
+    char *read_buf = NULL;
+    char *rates_str = NULL;
+    char *rates_str_for_val = NULL;
+    int  *rates_supported = NULL;
     char path[128];
+    int ret = 0;
 
     memset(&st, 0x0, sizeof(struct stat));
     *sample_rate = 0;
@@ -175,45 +179,49 @@
     if (fd <0) {
         ALOGE("%s: error failed to open config file %s error: %d\n",
               __func__, path, errno);
-        close(fd);
-        return -EINVAL;
+        ret = -EINVAL;
+        goto done;
     }
 
     if (fstat(fd, &st) < 0) {
         ALOGE("%s: error failed to stat %s error %d\n",
              __func__, path, errno);
-        close(fd);
-        return -EINVAL;
+        ret = -EINVAL;
+        goto done;
     }
 
     file_size = st.st_size;
 
     read_buf = (char *)calloc(1, USB_BUFF_SIZE + 1);
+
+    if (!read_buf) {
+        ALOGE("Failed to create read_buf");
+        ret = -ENOMEM;
+        goto done;
+    }
+
     err = read(fd, read_buf, USB_BUFF_SIZE);
     str_start = strstr(read_buf, type);
     if (str_start == NULL) {
         ALOGE("%s: error %s section not found in usb config file",
                __func__, type);
-        close(fd);
-        free(read_buf);
-        return -EINVAL;
+        ret = -EINVAL;
+        goto done;
     }
 
     channel_start = strstr(str_start, "Channels:");
     if (channel_start == NULL) {
         ALOGE("%s: error could not find Channels information", __func__);
-        close(fd);
-        free(read_buf);
-        return -EINVAL;
+        ret = -EINVAL;
+        goto done;
     }
 
     channel_start = strstr(channel_start, " ");
     if (channel_start == NULL) {
         ALOGE("%s: error channel section not found in usb config file",
                __func__);
-        close(fd);
-        free(read_buf);
-        return -EINVAL;
+        ret = -EINVAL;
+        goto done;
     }
 
     channels_playback = atoi(channel_start);
@@ -227,44 +235,38 @@
     rates_str_start = strstr(str_start, "Rates:");
     if (rates_str_start == NULL) {
         ALOGE("%s: error cant find rates information", __func__);
-        close(fd);
-        free(read_buf);
-        return -EINVAL;
+        ret = -EINVAL;
+        goto done;
     }
 
     rates_str_start = strstr(rates_str_start, " ");
     if (rates_str_start == NULL) {
         ALOGE("%s: error channel section not found in usb config file",
                __func__);
-        close(fd);
-        free(read_buf);
-        return -EINVAL;
+        ret = -EINVAL;
+        goto done;
     }
 
     char *target = strchr(rates_str_start, '\n');
     if (target == NULL) {
         ALOGE("%s: error end of line not found", __func__);
-        close(fd);
-        free(read_buf);
-        return -EINVAL;
+        ret = -EINVAL;
+        goto done;
     }
 
     size = target - rates_str_start;
     if ((rates_str = (char *)malloc(size + 1)) == NULL) {
         ALOGE("%s: error unable to allocate memory to hold sample rate strings",
               __func__);
-        close(fd);
-        free(read_buf);
-        return -ENOMEM;
+        ret = -EINVAL;
+        goto done;
     }
 
     if ((rates_str_for_val = (char *)malloc(size + 1)) == NULL) {
         ALOGE("%s: error unable to allocate memory to hold sample rate string",
                __func__);
-        close(fd);
-        free(rates_str);
-        free(read_buf);
-        return -ENOMEM;
+        ret = -EINVAL;
+        goto done;
     }
 
     memcpy(rates_str, rates_str_start, size);
@@ -275,23 +277,23 @@
     size = usb_get_numof_rates(rates_str);
     if (!size) {
         ALOGE("%s: error could not get rate size, returning", __func__);
-        close(fd);
-        free(rates_str_for_val);
-        free(rates_str);
-        free(read_buf);
-        return -EINVAL;
+        ret = -EINVAL;
+        goto done;
     }
 
     rates_supported = (int *)malloc(sizeof(int) * size);
+
+    if (!rates_supported) {
+        ALOGE("couldn't allocate mem for rates_supported");
+        ret = -EINVAL;
+        goto done;
+    }
+
     next_sr_string = strtok_r(rates_str_for_val, " ,", &temp_ptr);
     if (next_sr_string == NULL) {
         ALOGE("%s: error could not get first rate val", __func__);
-        close(fd);
-        free(rates_str_for_val);
-        free(rates_str);
-        free(rates_supported);
-        free(read_buf);
-        return -EINVAL;
+        ret = -EINVAL;
+        goto done;
     }
 
     rates_supported[0] = atoi(next_sr_string);
@@ -299,6 +301,10 @@
            __func__, rates_supported[0]);
     for (i = 1; i<size; i++) {
         next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
+        if (next_sr_string == NULL) {
+            rates_supported[i] = -1; // fill in an invalid sr for the rest
+            continue;
+        }
         rates_supported[i] = atoi(next_sr_string);
         ALOGD("rates_supported[%d] for playback: %d",i, rates_supported[i]);
     }
@@ -317,12 +323,13 @@
     }
     ALOGD("%s: sample_rate: %d", __func__, *sample_rate);
 
-    close(fd);
-    free(rates_str_for_val);
-    free(rates_str);
-    free(rates_supported);
-    free(read_buf);
-    return 0;
+done:
+    if (fd >= 0) close(fd);
+    if (rates_str_for_val) free(rates_str_for_val);
+    if (rates_str) free(rates_str);
+    if (rates_supported) free(rates_supported);
+    if (read_buf) free(read_buf);
+    return ret;
 }
 
 static int32_t usb_playback_entry(void *adev)
@@ -387,7 +394,6 @@
         if(usbmod->proxy_pcm_playback_handle
             && !pcm_is_ready(usbmod->proxy_pcm_playback_handle)){
                      pcm_close(usbmod->proxy_pcm_playback_handle);
-                     usbmod->proxy_pcm_playback_handle = NULL;
                      proxy_open_retry_count--;
                      usleep(USB_PROXY_OPEN_WAIT_TIME * 1000);
                      ALOGE("%s: pcm_open for proxy failed retrying = %d",
@@ -507,7 +513,6 @@
         if(usbmod->proxy_pcm_record_handle
             && !pcm_is_ready(usbmod->proxy_pcm_record_handle)){
                      pcm_close(usbmod->proxy_pcm_record_handle);
-                     usbmod->proxy_pcm_record_handle = NULL;
                      proxy_open_retry_count--;
                      usleep(USB_PROXY_OPEN_WAIT_TIME * 1000);
                      ALOGE("%s: pcm_open for proxy(recording) failed retrying = %d",
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index aa66360..e7a57c8 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -141,6 +141,9 @@
         ALOGV("%s: format - %d", __func__, format);
         if (format != 0) {
             sf_info = (struct stream_format *)calloc(1, sizeof(struct stream_format));
+            if (sf_info == NULL)
+                break; /* return whatever was parsed */
+
             sf_info->format = format;
             list_add_tail(&so_info->format_list, &sf_info->list);
         }
@@ -192,6 +195,12 @@
 
     ALOGV("%s", __func__);
     so_info = (struct streams_output_cfg *)calloc(1, sizeof(struct streams_output_cfg));
+
+    if (!so_info) {
+        ALOGE("failed to allocate mem for so_info list element");
+        return;
+    }
+
     while (node) {
         if (strcmp(node->name, FLAGS_TAG) == 0) {
             so_info->flags = parse_flag_names((char *)node->value);
@@ -298,6 +307,11 @@
     }
 
     root = config_node("", "");
+    if (root == NULL) {
+        ALOGE("cfg_list, NULL config root");
+        return;
+    }
+
     config_load(root, data);
     load_output(root, platform, streams_output_cfg_list);
 
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 9171d04..4d8925d 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -125,7 +125,7 @@
     [USECASE_AUDIO_HFP_SCO] = "hfp-sco",
     [USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb",
     [USECASE_VOICE_CALL] = "voice-call",
-    
+
     [USECASE_VOICE2_CALL] = "voice2-call",
     [USECASE_VOLTE_CALL] = "volte-call",
     [USECASE_QCHAT_CALL] = "qchat-call",
@@ -209,7 +209,8 @@
     if (format == AUDIO_FORMAT_MP3 ||
         format == AUDIO_FORMAT_AAC ||
         format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD ||
-        format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD)
+        format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD ||
+        format == AUDIO_FORMAT_FLAC)
            return true;
 
     return false;
@@ -230,6 +231,9 @@
     case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD:
         id = SND_AUDIOCODEC_PCM;
         break;
+    case AUDIO_FORMAT_FLAC:
+        id = SND_AUDIOCODEC_FLAC;
+        break;
     default:
         ALOGE("%s: Unsupported audio format :%x", __func__, format);
     }
@@ -375,6 +379,7 @@
                                         LISTEN_EVENT_SND_DEVICE_FREE);
             return -EINVAL;
         }
+        audio_extn_dev_arbi_acquire(snd_device);
         audio_route_apply_and_update_path(adev->audio_route, device_name);
     }
     return 0;
@@ -418,9 +423,10 @@
             snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) &&
             audio_extn_spkr_prot_is_enabled()) {
             audio_extn_spkr_prot_stop_processing();
-        } else
+        } else {
             audio_route_reset_and_update_path(adev->audio_route, device_name);
-
+            audio_extn_dev_arbi_release(snd_device);
+        }
         audio_extn_listen_update_device_status(snd_device,
                                         LISTEN_EVENT_SND_DEVICE_FREE);
     }
@@ -447,6 +453,15 @@
      * because of the limitation that both the devices cannot be enabled
      * at the same time as they share the same backend.
      */
+    /*
+     * This call is to check if we need to force routing for a particular stream
+     * If there is a backend configuration change for the device when a
+     * new stream starts, then ADM needs to be closed and re-opened with the new
+     * configuraion. This call check if we need to re-route all the streams
+     * associated with the backend. Touch tone + 24 bit playback.
+     */
+    bool force_routing = platform_check_and_set_codec_backend_cfg(adev, uc_info);
+
     /* Disable all the usecases on the shared backend other than the
        specified usecase */
     for (i = 0; i < AUDIO_USECASE_MAX; i++)
@@ -456,7 +471,7 @@
         usecase = node_to_item(node, struct audio_usecase, list);
         if (usecase->type != PCM_CAPTURE &&
                 usecase != uc_info &&
-                usecase->out_snd_device != snd_device &&
+                (usecase->out_snd_device != snd_device || force_routing)  &&
                 usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
             ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
                   __func__, use_case_table[usecase->id],
@@ -657,26 +672,26 @@
          * usecase. This is to avoid switching devices for voice call when
          * check_usecases_codec_backend() is called below.
          */
-        if (voice_is_in_call(adev)) {
+        if (adev->voice.in_call && adev->mode == AUDIO_MODE_IN_CALL) {
             vc_usecase = get_usecase_from_list(adev,
                                                get_voice_usecase_id_from_list(adev));
-            if ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
-                (usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL)) {
+            if ((vc_usecase) && ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
+                (usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL))) {
                 in_snd_device = vc_usecase->in_snd_device;
                 out_snd_device = vc_usecase->out_snd_device;
             }
         } else if (voice_extn_compress_voip_is_active(adev)) {
             voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
-            if ((voip_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
+            if ((voip_usecase) && ((voip_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
                 (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
-                 (voip_usecase->stream.out != adev->primary_output)) {
+                 (voip_usecase->stream.out != adev->primary_output))) {
                     in_snd_device = voip_usecase->in_snd_device;
                     out_snd_device = voip_usecase->out_snd_device;
             }
         } else if (audio_extn_hfp_is_active(adev)) {
             hfp_ucid = audio_extn_hfp_get_usecase();
             hfp_usecase = get_usecase_from_list(adev, hfp_ucid);
-            if (hfp_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
+            if ((hfp_usecase) && (hfp_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)) {
                    in_snd_device = hfp_usecase->in_snd_device;
                    out_snd_device = hfp_usecase->out_snd_device;
             }
@@ -723,7 +738,9 @@
      * and enable both RX and TX devices though one of them is same as current
      * device.
      */
-    if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
+    if ((usecase->type == VOICE_CALL) &&
+        (usecase->in_snd_device != SND_DEVICE_NONE) &&
+        (usecase->out_snd_device != SND_DEVICE_NONE)) {
         status = platform_switch_voice_call_device_pre(adev->platform);
     }
 
@@ -742,10 +759,13 @@
      * New device information should be sent to modem before enabling
      * the devices to reduce in-call device switch time.
      */
-    if (usecase->type == VOICE_CALL)
+    if ((usecase->type == VOICE_CALL) &&
+        (usecase->in_snd_device != SND_DEVICE_NONE) &&
+        (usecase->out_snd_device != SND_DEVICE_NONE)) {
         status = platform_switch_voice_call_enable_device_config(adev->platform,
                                                                  out_snd_device,
                                                                  in_snd_device);
+    }
 
     /* Enable new sound devices */
     if (out_snd_device != SND_DEVICE_NONE) {
@@ -777,7 +797,6 @@
         status = platform_switch_voice_call_usecase_route_post(adev->platform,
                                                                out_snd_device,
                                                                in_snd_device);
-
     ALOGD("%s: done",__func__);
 
     return status;
@@ -852,6 +871,12 @@
 
     adev->active_input = in;
     uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+
+    if (!uc_info) {
+        ret = -ENOMEM;
+        goto error_config;
+    }
+
     uc_info->id = in->usecase;
     uc_info->type = PCM_CAPTURE;
     uc_info->stream.in = in;
@@ -893,6 +918,11 @@
 {
     struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
 
+    if (!cmd) {
+        ALOGE("failed to allocate mem for command 0x%x", command);
+        return -ENOMEM;
+    }
+
     ALOGVV("%s %d", __func__, command);
 
     cmd->cmd = command;
@@ -1213,6 +1243,11 @@
     struct audio_device *adev = out->dev;
     int snd_card_status = get_snd_card_state(adev);
 
+    if ((out->usecase < 0) || (out->usecase >= AUDIO_USECASE_MAX)) {
+        ret = -EINVAL;
+        goto error_config;
+    }
+
     ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x)",
           __func__, &out->stream, out->usecase, use_case_table[out->usecase],
           out->devices);
@@ -1232,6 +1267,12 @@
     }
 
     uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+
+    if (!uc_info) {
+        ret = -ENOMEM;
+        goto error_config;
+    }
+
     uc_info->id = out->usecase;
     uc_info->type = PCM_PLAYBACK;
     uc_info->stream.out = out;
@@ -1475,6 +1516,29 @@
         out->send_new_metadata = 1;
     }
 
+    if (out->format == AUDIO_FORMAT_FLAC) {
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_BLK_SIZE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.flac_dec.min_blk_size = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.flac_dec.max_blk_size = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.flac_dec.min_frame_size = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.flac_dec.max_frame_size = atoi(value);
+            out->send_new_metadata = 1;
+        }
+    }
+
     ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_SAMPLE_RATE, value, sizeof(value));
     if(ret >= 0)
         is_meta_data_params = true;
@@ -1566,17 +1630,18 @@
                 select_devices(adev, out->usecase);
 
             if ((adev->mode == AUDIO_MODE_IN_CALL) &&
-                    !voice_is_in_call(adev) &&
-                    (out == adev->primary_output)) {
+                !adev->voice.in_call &&
+                (out == adev->primary_output)) {
                 ret = voice_start_call(adev);
-            } else if (voice_is_in_call(adev) &&
-                            (out == adev->primary_output)) {
+            } else if ((adev->mode == AUDIO_MODE_IN_CALL) &&
+                       adev->voice.in_call &&
+                       (out == adev->primary_output)) {
                 voice_update_devices_for_all_voice_usecases(adev);
             }
         }
 
         if ((adev->mode == AUDIO_MODE_NORMAL) &&
-                voice_is_in_call(adev) &&
+                adev->voice.in_call &&
                 (out == adev->primary_output)) {
             ret = voice_stop_call(adev);
         }
@@ -1611,6 +1676,12 @@
     size_t i, j;
     int ret;
     bool first = true;
+
+    if (!query || !reply) {
+        ALOGE("out_get_parameters: failed to allocate mem for query or reply");
+        return NULL;
+    }
+
     ALOGV("%s: enter: keys - %s", __func__, keys);
     ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value));
     if (ret >= 0) {
@@ -1796,9 +1867,9 @@
                                    uint32_t *dsp_frames)
 {
     struct stream_out *out = (struct stream_out *)stream;
-    *dsp_frames = 0;
     if (is_offload_usecase(out->usecase) && (dsp_frames != NULL)) {
         ssize_t ret =  -EINVAL;
+        *dsp_frames = 0;
         pthread_mutex_lock(&out->lock);
         if (out->compr != NULL) {
             ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
@@ -2116,6 +2187,12 @@
     char *str;
     char value[256];
     struct str_parms *reply = str_parms_create();
+
+    if (!query || !reply) {
+        ALOGE("in_get_parameters: failed to create query or reply");
+        return NULL;
+    }
+
     ALOGV("%s: enter: keys - %s", __func__, keys);
 
     voice_extn_in_get_parameters(in, query, reply);
@@ -2301,6 +2378,7 @@
     out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
     out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
     out->handle = handle;
+    out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
 
     /* Init use case and pcm_config */
     if ((out->flags == AUDIO_OUTPUT_FLAG_DIRECT) &&
@@ -2355,6 +2433,11 @@
         out->compr_config.codec = (struct snd_codec *)
                                     calloc(1, sizeof(struct snd_codec));
 
+        if (!out->compr_config.codec) {
+            ret = -ENOMEM;
+            goto error_open;
+        }
+
         out->usecase = get_offload_usecase(adev);
         if (config->offload_info.channel_mask)
             out->channel_mask = config->offload_info.channel_mask;
@@ -2370,6 +2453,7 @@
         out->stream.resume = out_resume;
         out->stream.drain = out_drain;
         out->stream.flush = out_flush;
+        out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
 
         if (audio_extn_is_dolby_format(config->offload_info.format))
             out->compr_config.codec->id =
@@ -2393,13 +2477,26 @@
         out->compr_config.codec->ch_in =
                     popcount(config->channel_mask);
         out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
-        out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
+        out->bit_width = PCM_OUTPUT_BIT_WIDTH;
 
+        if (config->offload_info.format == AUDIO_FORMAT_AAC)
+            out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
         if (config->offload_info.format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD)
             out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE;
-        else if(config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD)
+        if(config->offload_info.format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD)
             out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE;
 
+        if (out->bit_width == 24) {
+            out->compr_config.codec->format = SNDRV_PCM_FORMAT_S24_LE;
+        }
+
+        if (out->bit_width == 24 && !platform_check_24_bit_support()) {
+            ALOGW("24 bit support is not enabled, using 16 bit backend");
+            out->compr_config.codec->format = SNDRV_PCM_FORMAT_S16_LE;
+        }
+
+        out->compr_config.codec->options.flac_dec.sample_size = out->bit_width;
+
         if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
             out->non_blocking = 1;
 
@@ -2659,6 +2756,11 @@
     char value[256] = {0};
     int ret = 0;
 
+    if (!query || !reply) {
+        ALOGE("adev_get_parameters: failed to create query or reply");
+        return NULL;
+    }
+
     ret = str_parms_get_str(query, "SND_CARD_STATUS", value,
                             sizeof(value));
     if (ret >=0) {
@@ -2778,6 +2880,12 @@
         return -EINVAL;
 
     in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
+
+    if (!in) {
+        ALOGE("failed to allocate input stream");
+        return -ENOMEM;
+    }
+
     ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x)\
         stream_handle(%p)",__func__, config->sample_rate, config->channel_mask,
         devices, &in->stream);
@@ -2923,6 +3031,11 @@
 
     adev = calloc(1, sizeof(struct audio_device));
 
+    if (!adev) {
+        pthread_mutex_unlock(&adev_init_lock);
+        return -ENOMEM;
+    }
+
     pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL);
 
     adev->device.common.tag = HARDWARE_DEVICE_TAG;
@@ -2956,6 +3069,8 @@
     adev->bluetooth_nrec = true;
     adev->acdb_settings = TTY_MODE_OFF;
     /* adev->cur_hdmi_channels = 0;  by calloc() */
+    adev->cur_codec_backend_samplerate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    adev->cur_codec_backend_bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
     adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int));
     voice_init(adev);
     list_init(&adev->usecase_list);
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index e537377..f1ceedc 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -188,6 +188,7 @@
     void *offload_cookie;
     struct compr_gapless_mdata gapless_mdata;
     int send_new_metadata;
+    unsigned int bit_width;
 
     struct audio_device *dev;
 };
@@ -272,6 +273,8 @@
     bool bt_wb_speech_enabled;
 
     int snd_card;
+    unsigned int cur_codec_backend_samplerate;
+    unsigned int cur_codec_backend_bit_width;
     void *platform;
     unsigned int offload_usecases_state;
     void *visualizer_lib;
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 4360967..6cf0f65 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -23,6 +23,7 @@
 
 #include <stdlib.h>
 #include <dlfcn.h>
+#include <sys/ioctl.h>
 #include <cutils/log.h>
 #include <cutils/properties.h>
 #include <cutils/str_parms.h>
@@ -116,6 +117,7 @@
     bool fluence_in_audio_rec;
     int  fluence_type;
     char fluence_cap[PROPERTY_VALUE_MAX];
+    int  fluence_mode;
     bool slowtalk;
     /* Audio calibration related functions */
     void                       *acdb_handle;
@@ -248,6 +250,11 @@
     [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = "handset-stereo-dmic-ef",
     [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = "speaker-stereo-dmic-ef",
     [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = "vi-feedback",
+    [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE] = "voice-speaker-dmic-broadside",
+    [SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE] = "speaker-dmic-broadside",
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE] = "speaker-dmic-broadside",
+    [SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE] = "speaker-dmic-broadside",
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE] = "speaker-dmic-broadside",
 };
 
 /* ACDB IDs (audio DSP path configuration IDs) for each sound device */
@@ -321,6 +328,11 @@
     [SND_DEVICE_IN_HANDSET_STEREO_DMIC] = 34,
     [SND_DEVICE_IN_SPEAKER_STEREO_DMIC] = 35,
     [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = 102,
+    [SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE] = 12,
+    [SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE] = 12,
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE] = 119,
+    [SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE] = 121,
+    [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE] = 120,
 };
 
 struct snd_device_index {
@@ -549,6 +561,14 @@
                   __func__, dlerror());
             goto error;
         }
+        csd->set_lch = (set_lch_t)dlsym(csd->csd_client, "csd_client_set_lch");
+        if (csd->set_lch == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_set_lch",
+                  __func__, dlerror());
+            /* Ignore the error as this is not mandatory function for
+             * basic voice call to work.
+             */
+        }
         csd->start_record = (start_record_t)dlsym(csd->csd_client,
                                              "csd_client_start_record");
         if (csd->start_record == NULL) {
@@ -661,6 +681,7 @@
     my_data->fluence_in_voice_rec = false;
     my_data->fluence_in_audio_rec = false;
     my_data->fluence_type = FLUENCE_NONE;
+    my_data->fluence_mode = FLUENCE_ENDFIRE;
 
     property_get("ro.qc.sdk.audio.fluencetype", my_data->fluence_cap, "");
     if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro"))) {
@@ -691,6 +712,11 @@
         if (!strncmp("true", value, sizeof("true"))) {
             my_data->fluence_in_spkr_mode = true;
         }
+
+        property_get("persist.audio.fluence.mode",value,"");
+        if (!strncmp("broadside", value, sizeof("broadside"))) {
+            my_data->fluence_mode = FLUENCE_BROADSIDE;
+        }
     }
 
     my_data->voice_feature_set = VOICE_FEATURE_SET_DEFAULT;
@@ -1415,7 +1441,10 @@
                     snd_device = SND_DEVICE_IN_VOICE_SPEAKER_QMIC;
                 } else {
                     adev->acdb_settings |= DMIC_FLAG;
-                    snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC;
+                    if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                       snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE;
+                    else
+                       snd_device = SND_DEVICE_IN_VOICE_SPEAKER_DMIC;
                 }
             } else {
                 snd_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
@@ -1455,7 +1484,10 @@
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
                     if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
                        my_data->fluence_in_spkr_mode) {
-                        snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
+                        if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE;
+                        else
+                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
                         adev->acdb_settings |= DMIC_FLAG;
                     } else
                         snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
@@ -1471,8 +1503,12 @@
                 set_echo_reference(adev->mixer, EC_REF_RX);
             } else if (adev->active_input->enable_aec) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
-                    if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
-                        snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC;
+                    if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
+                        my_data->fluence_in_spkr_mode) {
+                        if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE;
+                        else
+                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC;
                         adev->acdb_settings |= DMIC_FLAG;
                     } else
                         snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC;
@@ -1488,8 +1524,12 @@
                 set_echo_reference(adev->mixer, EC_REF_RX);
             } else if (adev->active_input->enable_ns) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
-                    if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
-                        snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS;
+                    if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
+                        my_data->fluence_in_spkr_mode) {
+                        if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE;
+                        else
+                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS;
                         adev->acdb_settings |= DMIC_FLAG;
                     } else
                         snd_device = SND_DEVICE_IN_SPEAKER_MIC_NS;
@@ -1840,6 +1880,20 @@
     return ret;
 }
 
+int platform_update_lch(void *platform, struct voice_session *session,
+                        enum voice_lch_mode lch_mode)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if ((my_data->csd != NULL) && (my_data->csd->set_lch != NULL))
+        ret = my_data->csd->set_lch(session->vsid, lch_mode);
+    else
+        ret = pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode);
+
+    return ret;
+}
+
 void platform_get_parameters(void *platform,
                             struct str_parms *query,
                             struct str_parms *reply)
@@ -2018,3 +2072,28 @@
     return fragment_size;
 }
 
+bool platform_check_24_bit_support() {
+    return false;
+}
+
+bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase) {
+    return false;
+}
+
+int platform_get_usecase_index(const char * usecase __unused)
+{
+    return -ENOSYS;
+}
+
+int platform_set_usecase_pcm_id(audio_usecase_t usecase __unused, int32_t type __unused,
+                                int32_t pcm_id __unused)
+{
+    return -ENOSYS;
+}
+
+int platform_set_snd_device_backend(snd_device_t snd_device __unused,
+                                    const char * backend __unused)
+{
+    return -ENOSYS;
+}
+
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index f12697c..3fc8fbf 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -19,6 +19,7 @@
 
 #ifndef QCOM_AUDIO_PLATFORM_H
 #define QCOM_AUDIO_PLATFORM_H
+#include <sound/voice_params.h>
 
 enum {
     FLUENCE_NONE,
@@ -26,6 +27,11 @@
     FLUENCE_QUAD_MIC = 0x2,
 };
 
+enum {
+    FLUENCE_ENDFIRE = 0x1,
+    FLUENCE_BROADSIDE = 0x2,
+};
+
 /*
  * Below are the devices for which is back end is same, SLIMBUS_0_RX.
  * All these devices are handled by the internal HW codec. We can
@@ -120,6 +126,11 @@
     SND_DEVICE_IN_HANDSET_STEREO_DMIC,
     SND_DEVICE_IN_SPEAKER_STEREO_DMIC,
     SND_DEVICE_IN_CAPTURE_VI_FEEDBACK,
+    SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE,
+    SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE,
+    SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE,
+    SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE,
+    SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE,
     SND_DEVICE_IN_END,
 
     SND_DEVICE_MAX = SND_DEVICE_IN_END,
@@ -205,6 +216,7 @@
 typedef int (*stop_voice_t)(uint32_t);
 typedef int (*start_playback_t)(uint32_t);
 typedef int (*stop_playback_t)(uint32_t);
+typedef int (*set_lch_t)(uint32_t, enum voice_lch_mode);
 typedef int (*start_record_t)(uint32_t, int);
 typedef int (*stop_record_t)(uint32_t);
 /* CSD Client structure */
@@ -222,6 +234,7 @@
     stop_voice_t stop_voice;
     start_playback_t start_playback;
     stop_playback_t stop_playback;
+    set_lch_t set_lch;
     start_record_t start_record;
     stop_record_t stop_record;
 };
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 4102be7..d83a93f 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -914,6 +914,14 @@
     return -ENOSYS;
 }
 
+int platform_update_lch(void *platform __unused,
+                        struct voice_session *session __unused,
+                        enum voice_lch_mode lch_mode __unused)
+{
+    LOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
 /* Delay in Us */
 int64_t platform_render_latency(audio_usecase_t usecase)
 {
@@ -942,3 +950,28 @@
 {
     return false;
 }
+
+bool platform_check_24_bit_support() {
+    return false;
+}
+
+bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase) {
+    return false;
+}
+
+int platform_get_usecase_index(const char * usecase __unused)
+{
+    return -ENOSYS;
+}
+
+int platform_set_usecase_pcm_id(audio_usecase_t usecase __unused, int32_t type __unused,
+                                int32_t pcm_id __unused)
+{
+    return -ENOSYS;
+}
+
+int platform_set_snd_device_backend(snd_device_t snd_device __unused,
+                                    const char * backend __unused)
+{
+    return -ENOSYS;
+}
diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c
index 7ac5ce7..f7d19f4 100644
--- a/hal/msm8974/hw_info.c
+++ b/hal/msm8974/hw_info.c
@@ -329,6 +329,11 @@
     struct hardware_info *hw_info;
 
     hw_info = malloc(sizeof(struct hardware_info));
+    if (!hw_info) {
+        ALOGE("failed to allocate mem for hardware info");
+        return NULL;
+    }
+
     hw_info->snd_devices = NULL;
     hw_info->num_snd_devices = 0;
     strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index f853506..88a09b8 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -23,6 +23,7 @@
 
 #include <stdlib.h>
 #include <dlfcn.h>
+#include <sys/ioctl.h>
 #include <cutils/log.h>
 #include <cutils/properties.h>
 #include <cutils/str_parms.h>
@@ -32,7 +33,6 @@
 #include "audio_extn.h"
 #include "voice_extn.h"
 #include "sound/compress_params.h"
-#include "mdm_detect.h"
 
 #define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
 #define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
@@ -43,6 +43,7 @@
 
 #define LIB_ACDB_LOADER "libacdbloader.so"
 #define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID"
+#define CVD_VERSION_MIXER_CTL "CVD Version"
 
 #define MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE (256 * 1024)
 #define MIN_COMPRESS_OFFLOAD_FRAGMENT_SIZE (2 * 1024)
@@ -71,6 +72,8 @@
 #define MAX_SAD_BLOCKS      10
 #define SAD_BLOCK_SIZE      3
 
+#define MAX_CVD_VERSION_STRING_SIZE    100
+
 /* EDID format ID for LPCM audio */
 #define EDID_FORMAT_LPCM    1
 
@@ -108,7 +111,7 @@
 
 /* Audio calibration related functions */
 typedef void (*acdb_deallocate_t)();
-typedef int  (*acdb_init_t)(char *);
+typedef int  (*acdb_init_t)(char *, char *);
 typedef void (*acdb_send_audio_cal_t)(int, int, int , int);
 typedef void (*acdb_send_voice_cal_t)(int, int);
 typedef int (*acdb_reload_vocvoltable_t)(int);
@@ -142,7 +145,7 @@
     struct csd_data *csd;
 };
 
-static const int pcm_device_table[AUDIO_USECASE_MAX][2] = {
+static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
     [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE,
                                             DEEP_BUFFER_PCM_DEVICE},
     [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
@@ -372,7 +375,7 @@
     [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE] = 120,
 };
 
-struct snd_device_index {
+struct name_to_index {
     char name[100];
     unsigned int index;
 };
@@ -380,7 +383,7 @@
 #define TO_NAME_INDEX(X)   #X, X
 
 /* Used to get index from parsed sting */
-struct snd_device_index snd_device_name_index[SND_DEVICE_MAX] = {
+static struct name_to_index snd_device_name_index[SND_DEVICE_MAX] = {
     {TO_NAME_INDEX(SND_DEVICE_OUT_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_EXTERNAL_1)},
@@ -460,6 +463,26 @@
     {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE)},
 };
 
+static char * backend_table[SND_DEVICE_MAX] = {0};
+
+static struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = {
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_DEEP_BUFFER)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_LOW_LATENCY)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MULTI_CH)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD)},
+    {TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
+    {TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)},
+    {TO_NAME_INDEX(USECASE_VOICE_CALL)},
+    {TO_NAME_INDEX(USECASE_VOICE2_CALL)},
+    {TO_NAME_INDEX(USECASE_VOLTE_CALL)},
+    {TO_NAME_INDEX(USECASE_QCHAT_CALL)},
+    {TO_NAME_INDEX(USECASE_VOWLAN_CALL)},
+    {TO_NAME_INDEX(USECASE_INCALL_REC_UPLINK)},
+    {TO_NAME_INDEX(USECASE_INCALL_REC_DOWNLINK)},
+    {TO_NAME_INDEX(USECASE_INCALL_REC_UPLINK_AND_DOWNLINK)},
+    {TO_NAME_INDEX(USECASE_AUDIO_HFP_SCO)},
+};
+
 #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
 #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
 
@@ -477,6 +500,11 @@
 {
     struct csd_data *csd = calloc(1, sizeof(struct csd_data));
 
+    if (!csd) {
+        ALOGE("failed to allocate csd_data mem");
+        return NULL;
+    }
+
     csd->csd_client = dlopen(LIB_CSD_CLIENT, RTLD_NOW);
     if (csd->csd_client == NULL) {
         ALOGE("%s: DLOPEN failed for %s", __func__, LIB_CSD_CLIENT);
@@ -561,6 +589,14 @@
                   __func__, dlerror());
             goto error;
         }
+        csd->set_lch = (set_lch_t)dlsym(csd->csd_client, "csd_client_set_lch");
+        if (csd->set_lch == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_set_lch",
+                  __func__, dlerror());
+            /* Ignore the error as this is not mandatory function for
+             * basic voice call to work.
+             */
+        }
         csd->start_record = (start_record_t)dlsym(csd->csd_client,
                                              "csd_client_start_record");
         if (csd->start_record == NULL) {
@@ -613,26 +649,6 @@
     }
 }
 
-static void platform_csd_init(struct platform_data *plat_data)
-{
-    struct dev_info mdm_detect_info;
-    int ret = 0;
-
-    /* Call ESOC API to get the number of modems.
-     * If the number of modems is not zero, load CSD Client specific
-     * symbols. Voice call is handled by MDM and apps processor talks to
-     * MDM through CSD Client
-     */
-    ret = get_system_info(&mdm_detect_info);
-    if (ret > 0) {
-        ALOGE("%s: Failed to get system info, ret %d", __func__, ret);
-    }
-    ALOGD("%s: num_modems %d\n", __func__, mdm_detect_info.num_modems);
-
-    if (mdm_detect_info.num_modems > 0)
-        plat_data->csd = open_csd_client(plat_data->is_i2s_ext_modem);
-}
-
 static bool platform_is_i2s_ext_modem(const char *snd_card_name,
                                       struct platform_data *plat_data)
 {
@@ -649,15 +665,74 @@
     return plat_data->is_i2s_ext_modem;
 }
 
+static void set_platform_defaults(struct platform_data * my_data)
+{
+    int32_t dev;
+    for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
+        backend_table[dev] = NULL;
+    }
+
+    // TBD - do these go to the platform-info.xml file.
+    // will help in avoiding strdups here
+    backend_table[SND_DEVICE_IN_BT_SCO_MIC] = strdup("bt-sco");
+    backend_table[SND_DEVICE_IN_BT_SCO_MIC_WB] = strdup("bt-sco-wb");
+    backend_table[SND_DEVICE_OUT_BT_SCO] = strdup("bt-sco");
+    backend_table[SND_DEVICE_OUT_BT_SCO_WB] = strdup("bt-sco-wb");
+    backend_table[SND_DEVICE_OUT_HDMI] = strdup("hdmi");
+    backend_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = strdup("speaker-and-hdmi");
+    backend_table[SND_DEVICE_OUT_AFE_PROXY] = strdup("afe-proxy");
+    backend_table[SND_DEVICE_OUT_USB_HEADSET] = strdup("usb-headphones");
+    backend_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] =
+        strdup("speaker-and-usb-headphones");
+    backend_table[SND_DEVICE_IN_USB_HEADSET_MIC] = strdup("usb-headset-mic");
+    backend_table[SND_DEVICE_IN_CAPTURE_FM] = strdup("capture-fm");
+    backend_table[SND_DEVICE_OUT_TRANSMISSION_FM] = strdup("transmission-fm");
+}
+
+void get_cvd_version(char *cvd_version, struct audio_device *adev)
+{
+    struct mixer_ctl *ctl;
+    int count;
+    int ret = 0;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, CVD_VERSION_MIXER_CTL);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",  __func__, CVD_VERSION_MIXER_CTL);
+        goto done;
+    }
+    mixer_ctl_update(ctl);
+
+    count = mixer_ctl_get_num_values(ctl);
+    if (count > MAX_CVD_VERSION_STRING_SIZE)
+        count = MAX_CVD_VERSION_STRING_SIZE;
+
+    ret = mixer_ctl_get_array(ctl, cvd_version, count);
+    if (ret != 0) {
+        ALOGE("%s: ERROR! mixer_ctl_get_array() failed to get CVD Version", __func__);
+        goto done;
+    }
+
+done:
+    return;
+}
+
 void *platform_init(struct audio_device *adev)
 {
+    char platform[PROPERTY_VALUE_MAX];
+    char baseband[PROPERTY_VALUE_MAX];
     char value[PROPERTY_VALUE_MAX];
     struct platform_data *my_data = NULL;
     int retry_num = 0, snd_card_num = 0;
     const char *snd_card_name;
+    char *cvd_version = NULL;
 
     my_data = calloc(1, sizeof(struct platform_data));
 
+    if (!my_data) {
+        ALOGE("failed to allocate platform data");
+        return NULL;
+    }
+
     while (snd_card_num < MAX_SND_CARD) {
         adev->mixer = mixer_open(snd_card_num);
 
@@ -798,20 +873,44 @@
 
         my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_init_v2");
-        if (my_data->acdb_init == NULL)
+        if (my_data->acdb_init == NULL) {
             ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__, dlerror());
+            goto acdb_init_fail;
+        }
+
+        cvd_version = calloc(1, MAX_CVD_VERSION_STRING_SIZE);
+        if (!cvd_version)
+            ALOGE("failed to allocate cvd_version");
         else
-            my_data->acdb_init(snd_card_name);
+            get_cvd_version(cvd_version, adev);
+
+        my_data->acdb_init(snd_card_name, cvd_version);
+        if (cvd_version)
+            free(cvd_version);
     }
 
+acdb_init_fail:
+
+    set_platform_defaults(my_data);
+
     /* Initialize ACDB ID's */
     if (my_data->is_i2s_ext_modem)
         platform_info_init(PLATFORM_INFO_XML_PATH_I2S);
     else
         platform_info_init(PLATFORM_INFO_XML_PATH);
 
-    /* load csd client */
-    platform_csd_init(my_data);
+    /* If platform is apq8084 and baseband is MDM, load CSD Client specific
+     * symbols. Voice call is handled by MDM and apps processor talks to
+     * MDM through CSD Client
+     */
+    property_get("ro.board.platform", platform, "");
+    property_get("ro.baseband", baseband, "");
+    if (!strncmp("apq8084", platform, sizeof("apq8084")) &&
+        !strncmp("mdm", baseband, (sizeof("mdm")-1))) {
+         my_data->csd = open_csd_client(my_data->is_i2s_ext_modem);
+    } else {
+         my_data->csd = NULL;
+    }
 
     /* init usb */
     audio_extn_usb_init(adev);
@@ -824,6 +923,9 @@
 
     audio_extn_dolby_set_license(adev);
 
+    /* init audio device arbitration */
+    audio_extn_dev_arbi_init();
+
     return my_data;
 }
 
@@ -834,6 +936,17 @@
     hw_info_deinit(my_data->hw_info);
     close_csd_client(my_data->csd);
 
+    int32_t dev;
+    for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
+        if (backend_table[dev]) {
+            free(backend_table[dev]);
+            backend_table[dev]= NULL;
+        }
+    }
+
+    /* deinit audio device arbitration */
+    audio_extn_dev_arbi_deinit();
+
     free(platform);
     /* deinit usb */
     audio_extn_usb_deinit();
@@ -865,37 +978,16 @@
 
 void platform_add_backend_name(char *mixer_path, snd_device_t snd_device)
 {
-    if (snd_device == SND_DEVICE_IN_BT_SCO_MIC)
-        strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB)
-        strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
-    else if(snd_device == SND_DEVICE_OUT_BT_SCO)
-        strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
-    else if(snd_device == SND_DEVICE_OUT_BT_SCO_WB)
-        strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_OUT_HDMI)
-        strlcat(mixer_path, " hdmi", MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI)
-        strcat(mixer_path, " speaker-and-hdmi");
-    else if (snd_device == SND_DEVICE_OUT_AFE_PROXY)
-        strlcat(mixer_path, " afe-proxy", MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_OUT_USB_HEADSET)
-        strlcat(mixer_path, " usb-headphones", MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET)
-        strlcat(mixer_path, " speaker-and-usb-headphones",
-                MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_IN_USB_HEADSET_MIC)
-        strlcat(mixer_path, " usb-headset-mic", MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_IN_CAPTURE_FM)
-        strlcat(mixer_path, " capture-fm", MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_OUT_TRANSMISSION_FM)
-        strlcat(mixer_path, " transmission-fm", MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_OUT_VOICE_SPEAKER &&
-             audio_extn_spkr_prot_is_enabled() ) {
-        char platform[PROPERTY_VALUE_MAX];
-        property_get("ro.board.platform", platform, "");
-        if (!strncmp("apq8084", platform, sizeof("apq8084")))
-            strlcat(mixer_path, " speaker-protected", MIXER_PATH_MAX_LENGTH);
+    if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+        ALOGE("%s: Invalid snd_device = %d", __func__, snd_device);
+        return;
+    }
+
+    const char * suffix = backend_table[snd_device];
+
+    if (suffix != NULL) {
+        strlcat(mixer_path, " ", MIXER_PATH_MAX_LENGTH);
+        strlcat(mixer_path, suffix, MIXER_PATH_MAX_LENGTH);
     }
 }
 
@@ -909,25 +1001,36 @@
     return device_id;
 }
 
-int platform_get_snd_device_index(char *snd_device_index_name)
+static int find_index(struct name_to_index * table, int32_t len, const char * name)
 {
     int ret = 0;
-    int i;
+    int32_t i;
 
-    if (snd_device_index_name == NULL) {
-        ALOGE("%s: snd_device_index_name is NULL", __func__);
+    if (table == NULL) {
+        ALOGE("%s: table is NULL", __func__);
         ret = -ENODEV;
         goto done;
     }
 
-    for (i=0; i < SND_DEVICE_MAX; i++) {
-        if(strcmp(snd_device_name_index[i].name, snd_device_index_name) == 0) {
-            ret = snd_device_name_index[i].index;
+    if (name == NULL) {
+        ALOGE("null key");
+        ret = -ENODEV;
+        goto done;
+    }
+
+    for (i=0; i < len; i++) {
+        const char* tn = table[i].name;
+        int32_t len = strlen(tn);
+        if (strncmp(tn, name, len) == 0) {
+            if (strlen(name) != len) {
+                continue; // substring
+            }
+            ret = table[i].index;
             goto done;
         }
     }
-    ALOGE("%s: Could not find index for snd_device_index_name = %s",
-            __func__, snd_device_index_name);
+    ALOGE("%s: Could not find index for name = %s",
+            __func__, name);
     ret = -ENODEV;
 done:
     return ret;
@@ -990,6 +1093,16 @@
     return ret;
 }
 
+int platform_get_snd_device_index(char *device_name)
+{
+    return find_index(snd_device_name_index, SND_DEVICE_MAX, device_name);
+}
+
+int platform_get_usecase_index(const char *usecase_name)
+{
+    return find_index(usecase_name_index, AUDIO_USECASE_MAX, usecase_name);
+}
+
 int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id)
 {
     int ret = 0;
@@ -1031,7 +1144,7 @@
     struct platform_data *my_data = (struct platform_data *)platform;
     int acdb_dev_id, acdb_dev_type;
 
-    acdb_dev_id = acdb_device_table[snd_device];
+    acdb_dev_id = acdb_device_table[audio_extn_get_spkr_prot_snd_device(snd_device)];
     if (acdb_dev_id < 0) {
         ALOGE("%s: Could not find acdb id for device(%d)",
               __func__, snd_device);
@@ -2035,6 +2148,20 @@
     return ret;
 }
 
+int platform_update_lch(void *platform, struct voice_session *session,
+                        enum voice_lch_mode lch_mode)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if ((my_data->csd != NULL) && (my_data->csd->set_lch != NULL))
+        ret = my_data->csd->set_lch(session->vsid, lch_mode);
+    else
+        ret = pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode);
+
+    return ret;
+}
+
 void platform_get_parameters(void *platform,
                             struct str_parms *query,
                             struct str_parms *reply)
@@ -2121,6 +2248,14 @@
         fragment_size =  atoi(value) * 1024;
     }
 
+    // For FLAC use max size since it is loss less, and has sampling rates
+    // upto 192kHZ
+    if (info != NULL && !info->has_video &&
+        info->format == AUDIO_FORMAT_FLAC) {
+       fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+       ALOGV("FLAC fragment size %d", fragment_size);
+    }
+
     if (info != NULL && info->has_video && info->is_streaming) {
         fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING;
         ALOGV("%s: offload fragment size reduced for AV streaming to %d",
@@ -2180,3 +2315,227 @@
     return fragment_size;
 }
 
+bool platform_check_24_bit_support() {
+
+    char value[PROPERTY_VALUE_MAX] = {0};
+    property_get("audio.offload.24bit.enable", value, "0");
+    if (atoi(value)) {
+        ALOGW("Property audio.offload.24bit.enable is set");
+        return true;
+    }
+    return false;
+}
+
+int platform_set_codec_backend_cfg(struct audio_device* adev,
+                         unsigned int bit_width, unsigned int sample_rate)
+{
+    ALOGV("platform_set_codec_backend_cfg bw %d, sr %d", bit_width, sample_rate);
+
+    int ret = 0;
+    if (bit_width != adev->cur_codec_backend_bit_width) {
+        const char * mixer_ctl_name = "SLIM_0_RX Format";
+        struct  mixer_ctl *ctl;
+        ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+        if (!ctl) {
+            ALOGE("%s: Could not get ctl for mixer command - %s",
+                    __func__, mixer_ctl_name);
+            return -EINVAL;
+        }
+
+        if (bit_width == 24) {
+                mixer_ctl_set_enum_by_string(ctl, "S24_LE");
+        } else {
+            mixer_ctl_set_enum_by_string(ctl, "S16_LE");
+            sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+        }
+        adev->cur_codec_backend_bit_width = bit_width;
+        ALOGE("Backend bit width is set to %d ", bit_width);
+    }
+
+    if ((adev->cur_codec_backend_bit_width == CODEC_BACKEND_DEFAULT_BIT_WIDTH &&
+             adev->cur_codec_backend_samplerate != CODEC_BACKEND_DEFAULT_SAMPLE_RATE) ||
+        (adev->cur_codec_backend_samplerate < sample_rate)) {
+
+            char *rate_str = NULL;
+            const char * mixer_ctl_name = "SLIM_0_RX SampleRate";
+            struct  mixer_ctl *ctl;
+
+            switch (sample_rate) {
+            case 8000:
+                rate_str = "KHZ_8";
+                break;
+            case 11025:
+                rate_str = "KHZ_11_025";
+                break;
+            case 16000:
+                rate_str = "KHZ_16";
+                break;
+            case 22050:
+                rate_str = "KHZ_22_05";
+                break;
+            case 32000:
+                rate_str = "KHZ_32";
+                break;
+            case 44100:
+                rate_str = "KHZ_44_1";
+                break;
+            case 48000:
+                rate_str = "KHZ_48";
+                break;
+            case 64000:
+                rate_str = "KHZ_64";
+                break;
+            case 88200:
+                rate_str = "KHZ_88_2";
+                break;
+            case 96000:
+                rate_str = "KHZ_96";
+                break;
+            case 176400:
+                rate_str = "KHZ_176_4";
+                break;
+            case 192000:
+                rate_str = "KHZ_192";
+                break;
+            default:
+                rate_str = "KHZ_48";
+                break;
+            }
+
+            ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+            if(!ctl) {
+                ALOGE("%s: Could not get ctl for mixer command - %s",
+                    __func__, mixer_ctl_name);
+                return -EINVAL;
+            }
+
+            ALOGV("Set sample rate as rate_str = %s", rate_str);
+            mixer_ctl_set_enum_by_string(ctl, rate_str);
+            adev->cur_codec_backend_samplerate = sample_rate;
+    }
+
+    return ret;
+}
+
+bool platform_check_codec_backend_cfg(struct audio_device* adev,
+                                   struct audio_usecase* usecase,
+                                   unsigned int* new_bit_width,
+                                   unsigned int* new_sample_rate)
+{
+    bool backend_change = false;
+    struct listnode *node;
+    struct stream_out *out = NULL;
+
+    // For voice calls use default configuration
+    // force routing is not required here, caller will do it anyway
+    if (adev->mode == AUDIO_MODE_IN_CALL ||
+        adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
+        ALOGW("%s:Use default bw and sr for voice/voip calls ",__func__);
+        *new_bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+        *new_sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+        backend_change = true;
+    }
+
+
+    if (!backend_change) {
+        // go through all the offload usecases, and
+        // find the max bit width and samplerate
+        list_for_each(node, &adev->usecase_list) {
+            struct audio_usecase *curr_usecase;
+            curr_usecase = node_to_item(node, struct audio_usecase, list);
+            if (curr_usecase->id == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+                struct stream_out *out =
+                           (struct stream_out*) curr_usecase->stream.out;
+                if (out != NULL ) {
+                    ALOGV("Offload playback running bw %d sr %d",
+                              out->bit_width, out->sample_rate);
+                    if (*new_bit_width < out->bit_width) {
+                        *new_bit_width = out->bit_width;
+                    }
+                    if (*new_sample_rate < out->sample_rate) {
+                        *new_sample_rate = out->sample_rate;
+                    }
+                }
+            }
+        }
+    }
+
+    // Force routing if the expected bitwdith or samplerate
+    // is not same as current backend comfiguration
+    if ((*new_bit_width != adev->cur_codec_backend_bit_width) ||
+        (*new_sample_rate != adev->cur_codec_backend_samplerate)) {
+        backend_change = true;
+        ALOGW("Codec backend needs to be updated");
+    }
+
+    return backend_change;
+}
+
+bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase)
+{
+    // check if 24bit configuration is enabled first
+    if (!platform_check_24_bit_support()) {
+        ALOGW("24bit not enable, no need to check for backend change");
+        return false;
+    }
+
+    ALOGV("platform_check_and_set_codec_backend_cfg usecase = %d",usecase->id );
+
+    unsigned int new_bit_width, old_bit_width;
+    unsigned int new_sample_rate, old_sample_rate;
+
+    new_bit_width = old_bit_width = adev->cur_codec_backend_bit_width;
+    new_sample_rate = old_sample_rate = adev->cur_codec_backend_samplerate;
+
+    ALOGW("Codec backend bitwidth %d, samplerate %d", old_bit_width, old_sample_rate);
+    if (platform_check_codec_backend_cfg(adev, usecase,
+                                      &new_bit_width, &new_sample_rate)) {
+        platform_set_codec_backend_cfg(adev, new_bit_width, new_sample_rate);
+    }
+
+    if (old_bit_width != adev->cur_codec_backend_bit_width ||
+        old_sample_rate != adev->cur_codec_backend_samplerate) {
+        ALOGW("New codec backend bit width %d, sample rate %d",
+                    adev->cur_codec_backend_bit_width, adev->cur_codec_backend_samplerate);
+        return true;
+    }
+
+    return false;
+}
+
+int platform_set_snd_device_backend(snd_device_t device, const char *backend)
+{
+    int ret = 0;
+
+    if ((device < SND_DEVICE_MIN) || (device >= SND_DEVICE_MAX)) {
+        ALOGE("%s: Invalid snd_device = %d",
+            __func__, device);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    if (backend_table[device]) {
+        free(backend_table[device]);
+    }
+    backend_table[device] = strdup(backend);
+done:
+    return ret;
+}
+
+int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id)
+{
+    int ret = 0;
+    if ((usecase <= USECASE_INVALID) || (usecase >= AUDIO_USECASE_MAX)) {
+        ALOGE("%s: invalid usecase case idx %d", __func__, usecase);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    if ((type != 0) && (type != 1)) {
+        ALOGE("%s: invalid usecase type", __func__);
+        ret = -EINVAL;
+    }
+    pcm_device_table[usecase][type] = pcm_id;
+done:
+    return ret;
+}
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 956e395..19f37c7 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -19,6 +19,7 @@
 
 #ifndef QCOM_AUDIO_PLATFORM_H
 #define QCOM_AUDIO_PLATFORM_H
+#include <sound/voice_params.h>
 
 enum {
     FLUENCE_NONE,
@@ -190,13 +191,15 @@
 #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 14
 #elif PLATFORM_MSM8x26
 #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16
+#elif PLATFORM_APQ8084
+#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 34
 #else
 #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 35
 #endif
 
 #define SPKR_PROT_CALIB_RX_PCM_DEVICE 5
 #ifdef PLATFORM_APQ8084
-#define SPKR_PROT_CALIB_TX_PCM_DEVICE 33
+#define SPKR_PROT_CALIB_TX_PCM_DEVICE 35
 #else
 #define SPKR_PROT_CALIB_TX_PCM_DEVICE 25
 #endif
@@ -302,6 +305,7 @@
 typedef int (*stop_voice_t)(uint32_t);
 typedef int (*start_playback_t)(uint32_t);
 typedef int (*stop_playback_t)(uint32_t);
+typedef int (*set_lch_t)(uint32_t, enum voice_lch_mode);
 typedef int (*start_record_t)(uint32_t, int);
 typedef int (*stop_record_t)(uint32_t);
 typedef int (*get_sample_rate_t)(uint32_t *);
@@ -320,6 +324,7 @@
     stop_voice_t stop_voice;
     start_playback_t start_playback;
     stop_playback_t stop_playback;
+    set_lch_t set_lch;
     start_record_t start_record;
     stop_record_t stop_record;
     get_sample_rate_t get_sample_rate;
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 66b090e..85b3c4f 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -19,6 +19,10 @@
 
 #ifndef AUDIO_PLATFORM_API_H
 #define AUDIO_PLATFORM_API_H
+#include <sound/voice_params.h>
+
+#define CODEC_BACKEND_DEFAULT_BIT_WIDTH 16
+#define CODEC_BACKEND_DEFAULT_SAMPLE_RATE 48000
 
 void *platform_init(struct audio_device *adev);
 void platform_deinit(void *platform);
@@ -63,6 +67,8 @@
 int platform_stop_incall_recording_usecase(void *platform);
 int platform_start_incall_music_usecase(void *platform);
 int platform_stop_incall_music_usecase(void *platform);
+int platform_update_lch(void *platform, struct voice_session *session,
+                        enum voice_lch_mode lch_mode);
 /* returns the latency for a usecase in Us */
 int64_t platform_render_latency(audio_usecase_t usecase);
 int platform_update_usecase_from_source(int source, audio_usecase_t usecase);
@@ -70,6 +76,8 @@
 bool platform_listen_device_needs_event(snd_device_t snd_device);
 bool platform_listen_usecase_needs_event(audio_usecase_t uc_id);
 
+int platform_set_snd_device_backend(snd_device_t snd_device, const char * backend);
+
 /* From platform_info_parser.c */
 int platform_info_init(const char *filename);
 
@@ -77,4 +85,9 @@
 uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info);
 uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info);
 
+bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase);
+bool platform_check_24_bit_support();
+int platform_get_usecase_index(const char * usecase);
+int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id);
+
 #endif // AUDIO_PLATFORM_API_H
diff --git a/hal/platform_info.c b/hal/platform_info.c
index 85a05eb..615b9f3 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -40,7 +40,137 @@
 
 #define BUF_SIZE                    1024
 
-static void process_device(const XML_Char **attr)
+typedef enum {
+    ROOT,
+    ACDB,
+    PCM_ID,
+    BACKEND_NAME,
+} section_t;
+
+typedef void (* section_process_fn)(const XML_Char **attr);
+
+static void process_acdb_id(const XML_Char **attr);
+static void process_pcm_id(const XML_Char **attr);
+static void process_backend_name(const XML_Char **attr);
+static void process_root(const XML_Char **attr);
+
+static section_process_fn section_table[] = {
+    [ROOT] = process_root,
+    [ACDB] = process_acdb_id,
+    [PCM_ID] = process_pcm_id,
+    [BACKEND_NAME] = process_backend_name,
+};
+
+static section_t section;
+
+/*
+ * <audio_platform_info>
+ * <acdb_ids>
+ * <device name="???" acdb_id="???"/>
+ * ...
+ * ...
+ * </acdb_ids>
+ * <backend_names>
+ * <device name="???" backend="???"/>
+ * ...
+ * ...
+ * </backend_names>
+ * <pcm_ids>
+ * <usecase name="???" type="in/out" id="???"/>
+ * ...
+ * ...
+ * </pcm_ids>
+ * </audio_platform_info>
+ */
+
+static void process_root(const XML_Char **attr __unused)
+{
+}
+
+/* mapping from usecase to pcm dev id */
+static void process_pcm_id(const XML_Char **attr)
+{
+    int index;
+
+    if (strcmp(attr[0], "name") != 0) {
+        ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
+        goto done;
+    }
+
+    index = platform_get_usecase_index((char *)attr[1]);
+    if (index < 0) {
+        ALOGE("%s: usecase %s not found!",
+              __func__, attr[1]);
+        goto done;
+    }
+
+    if (strcmp(attr[2], "type") != 0) {
+        ALOGE("%s: usecase type not mentioned", __func__);
+        goto done;
+    }
+
+    int type = -1;
+
+    if (!strcasecmp((char *)attr[3], "in")) {
+        type = 1;
+    } else if (!strcasecmp((char *)attr[3], "out")) {
+        type = 0;
+    } else {
+        ALOGE("%s: type must be IN or OUT", __func__);
+        goto done;
+    }
+
+    if (strcmp(attr[4], "id") != 0) {
+        ALOGE("%s: usecase id not mentioned", __func__);
+        goto done;
+    }
+
+    int id = atoi((char *)attr[5]);
+
+    if (platform_set_usecase_pcm_id(index, type, id) < 0) {
+        ALOGE("%s: usecase %s type %d id %d was not set!",
+              __func__, attr[1], type, id);
+        goto done;
+    }
+
+done:
+    return;
+}
+
+/* backend to be used for a device */
+static void process_backend_name(const XML_Char **attr)
+{
+    int index;
+
+    if (strcmp(attr[0], "name") != 0) {
+        ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
+        goto done;
+    }
+
+    index = platform_get_snd_device_index((char *)attr[1]);
+    if (index < 0) {
+        ALOGE("%s: Device %s not found, no ACDB ID set!",
+              __func__, attr[1]);
+        goto done;
+    }
+
+    if (strcmp(attr[2], "backend") != 0) {
+        ALOGE("%s: Device %s has no backend set!",
+              __func__, attr[1]);
+        goto done;
+    }
+
+    if (platform_set_snd_device_backend(index, attr[3]) < 0) {
+        ALOGE("%s: Device %s backend %s was not set!",
+              __func__, attr[1], attr[3]);
+        goto done;
+    }
+
+done:
+    return;
+}
+
+static void process_acdb_id(const XML_Char **attr)
 {
     int index;
 
@@ -62,8 +192,8 @@
         goto done;
     }
 
-    if(platform_set_snd_device_acdb_id(index, atoi((char *)attr[3])) < 0) {
-        ALOGE("%s: Device %s in platform info xml ACDB ID %d was not set!",
+    if (platform_set_snd_device_acdb_id(index, atoi((char *)attr[3])) < 0) {
+        ALOGE("%s: Device %s, ACDB ID %d was not set!",
               __func__, attr[1], atoi((char *)attr[3]));
         goto done;
     }
@@ -72,22 +202,50 @@
     return;
 }
 
-static void start_tag(void *userdata, const XML_Char *tag_name,
+static void start_tag(void *userdata __unused, const XML_Char *tag_name,
                       const XML_Char **attr)
 {
     const XML_Char              *attr_name = NULL;
     const XML_Char              *attr_value = NULL;
     unsigned int                i;
 
-    if (strcmp(tag_name, "device") == 0)
-        process_device(attr);
+    if (strcmp(tag_name, "acdb_ids") == 0) {
+        section = ACDB;
+    } else if (strcmp(tag_name, "pcm_ids") == 0) {
+        section = PCM_ID;
+    } else if (strcmp(tag_name, "backend_names") == 0) {
+        section = BACKEND_NAME;
+    } else if (strcmp(tag_name, "device") == 0) {
+        if ((section != ACDB) && (section != BACKEND_NAME)) {
+            ALOGE("device tag only supported for acdb/backend names");
+            return;
+        }
+
+        /* call into process function for the current section */
+        section_process_fn fn = section_table[section];
+        fn(attr);
+    } else if (strcmp(tag_name, "usecase") == 0) {
+        if (section != PCM_ID) {
+            ALOGE("usecase tag only supported with PCM_ID section");
+            return;
+        }
+
+        section_process_fn fn = section_table[PCM_ID];
+        fn(attr);
+    }
 
     return;
 }
 
-static void end_tag(void *userdata, const XML_Char *tag_name)
+static void end_tag(void *userdata __unused, const XML_Char *tag_name)
 {
-
+    if (strcmp(tag_name, "acdb_ids") == 0) {
+        section = ROOT;
+    } else if (strcmp(tag_name, "pcm_ids") == 0) {
+        section = ROOT;
+    } else if (strcmp(tag_name, "backend_names") == 0) {
+        section = ROOT;
+    }
 }
 
 int platform_info_init(const char *filename)
@@ -99,6 +257,8 @@
     void            *buf;
 
     file = fopen(filename, "r");
+    section = ROOT;
+
     if (!file) {
         ALOGD("%s: Failed to open %s, using defaults.",
             __func__, filename);
diff --git a/hal/voice.c b/hal/voice.c
index 449c0c2..a5826e6 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -66,6 +66,11 @@
     ALOGD("%s: enter usecase:%s", __func__, use_case_table[usecase_id]);
 
     session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id);
+    if (!session) {
+        ALOGE("stop_call: couldn't find voice session");
+        return -EINVAL;
+    }
+
     session->state.current = CALL_INACTIVE;
     if (adev->mode == AUDIO_MODE_NORMAL)
         adev->voice.is_in_call = false;
@@ -115,7 +120,17 @@
     ALOGD("%s: enter usecase:%s", __func__, use_case_table[usecase_id]);
 
     session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id);
+    if (!session) {
+        ALOGE("start_call: couldn't find voice session");
+        return -EINVAL;
+    }
+
     uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+    if (!uc_info) {
+        ALOGE("start_call: couldn't allocate mem for audio_usecase");
+        return -ENOMEM;
+    }
+
     uc_info->id = usecase_id;
     uc_info->type = VOICE_CALL;
     uc_info->stream.out = adev->primary_output;
@@ -177,26 +192,27 @@
     }
 
     session->state.current = CALL_ACTIVE;
-    return 0;
+    goto done;
 
 error_start_voice:
     stop_call(adev, usecase_id);
 
+done:
     ALOGD("%s: exit: status(%d)", __func__, ret);
     return ret;
 }
 
-bool voice_is_in_call(struct audio_device *adev)
+bool voice_is_call_state_active(struct audio_device *adev)
 {
-    bool in_call = false;
+    bool call_state = false;
     int ret = 0;
 
-    ret = voice_extn_is_in_call(adev, &in_call);
+    ret = voice_extn_is_call_state_active(adev, &call_state);
     if (ret == -ENOSYS) {
-        in_call = (adev->voice.session[VOICE_SESS_IDX].state.current == CALL_ACTIVE) ? true : false;
+        call_state = (adev->voice.session[VOICE_SESS_IDX].state.current == CALL_ACTIVE) ? true : false;
     }
 
-    return in_call;
+    return call_state;
 }
 
 bool voice_is_in_call_rec_stream(struct stream_in *in)
@@ -232,7 +248,7 @@
     int usecase_id;
     int rec_mode = INCALL_REC_NONE;
 
-    if (voice_is_in_call(adev)) {
+    if (voice_is_call_state_active(adev)) {
         switch (in->source) {
         case AUDIO_SOURCE_VOICE_UPLINK:
             if (audio_extn_compr_cap_enabled() &&
@@ -358,6 +374,7 @@
     if (ret == -ENOSYS) {
         ret = start_call(adev, USECASE_VOICE_CALL);
     }
+    adev->voice.in_call = true;
 
     return ret;
 }
@@ -366,6 +383,7 @@
 {
     int ret = 0;
 
+    adev->voice.in_call = false;
     ret = voice_extn_stop_call(adev);
     if (ret == -ENOSYS) {
         ret = stop_call(adev, USECASE_VOICE_CALL);
@@ -392,12 +410,20 @@
     ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
 
     ret = voice_extn_set_parameters(adev, parms);
-    if (ret != 0)
-        goto done;
+    if (ret != 0) {
+        if (ret == -ENOSYS)
+            ret = 0;
+        else
+            goto done;
+    }
 
     ret = voice_extn_compress_voip_set_parameters(adev, parms);
-    if (ret != 0)
-        goto done;
+    if (ret != 0) {
+        if (ret == -ENOSYS)
+            ret = 0;
+        else
+            goto done;
+    }
 
     err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_TTY_MODE, value, sizeof(value));
     if (err >= 0) {
@@ -419,7 +445,7 @@
         if (tty_mode != adev->voice.tty_mode) {
             adev->voice.tty_mode = tty_mode;
             adev->acdb_settings = (adev->acdb_settings & TTY_MODE_CLEAR) | tty_mode;
-            if (voice_is_in_call(adev))
+            if (voice_is_call_state_active(adev))
                voice_update_devices_for_all_voice_usecases(adev);
         }
     }
@@ -432,7 +458,7 @@
             platform_start_incall_music_usecase(adev->platform);
         else
             platform_stop_incall_music_usecase(adev->platform);
-     }
+    }
 
 done:
     ALOGV("%s: exit with code(%d)", __func__, ret);
@@ -448,7 +474,7 @@
     adev->voice.tty_mode = TTY_MODE_OFF;
     adev->voice.volume = 1.0f;
     adev->voice.mic_mute = false;
-    adev->voice.voice_device_set = false;
+    adev->voice.in_call = false;
     for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
         adev->voice.session[i].pcm_rx = NULL;
         adev->voice.session[i].pcm_tx = NULL;
diff --git a/hal/voice.h b/hal/voice.h
index 4df2d6a..5d1ae40 100644
--- a/hal/voice.h
+++ b/hal/voice.h
@@ -60,8 +60,8 @@
     int tty_mode;
     bool mic_mute;
     float volume;
-    bool voice_device_set;
     bool is_in_call;
+    bool in_call;
 };
 
 enum {
@@ -77,8 +77,8 @@
 void voice_get_parameters(struct audio_device *adev, struct str_parms *query,
                           struct str_parms *reply);
 void voice_init(struct audio_device *adev);
-bool voice_is_in_call(struct audio_device *adev);
 bool voice_is_in_call_rec_stream(struct stream_in *in);
+bool voice_is_call_state_active(struct audio_device *adev);
 int voice_set_mic_mute(struct audio_device *dev, bool state);
 bool voice_get_mic_mute(struct audio_device *dev);
 int voice_set_volume(struct audio_device *adev, float volume);
diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c
index 841f866..46aab7d 100644
--- a/hal/voice_extn/compress_voip.c
+++ b/hal/voice_extn/compress_voip.c
@@ -335,6 +335,12 @@
     if (uc_info == NULL) {
         ALOGV("%s: voip usecase is added to the list", __func__);
         uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
+
+        if (!uc_info) {
+            ALOGE("failed to allocate voip usecase mem");
+            return -ENOMEM;
+        }
+
         uc_info->id = USECASE_COMPRESS_VOIP_CALL;
         uc_info->type = VOIP_CALL;
         if (voip_data.out_stream)
@@ -574,8 +580,14 @@
     ret = voip_start_call(adev, &out->config);
     out->pcm = voip_data.pcm_rx;
     uc_info = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
-    uc_info->stream.out = out;
-    uc_info->devices = out->devices;
+    if (uc_info) {
+        uc_info->stream.out = out;
+        uc_info->devices = out->devices;
+    } else {
+        ret = -EINVAL;
+        ALOGE("%s: exit(%d): failed to get use case info", __func__, ret);
+        goto error;
+    }
 
 error:
     ALOGV("%s: exit: status(%d)", __func__, ret);
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
index ea25a4b..89abc3a 100644
--- a/hal/voice_extn/voice_extn.c
+++ b/hal/voice_extn/voice_extn.c
@@ -73,7 +73,7 @@
 
 extern int start_call(struct audio_device *adev, audio_usecase_t usecase_id);
 extern int stop_call(struct audio_device *adev, audio_usecase_t usecase_id);
-int voice_extn_is_in_call(struct audio_device *adev, bool *in_call);
+int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active);
 
 static bool is_valid_call_state(int call_state)
 {
@@ -153,7 +153,6 @@
     struct voice_session *session = NULL;
     int fd = 0;
     int ret = 0;
-    bool is_in_call = false;
 
     ALOGD("%s: enter:", __func__);
 
@@ -187,11 +186,11 @@
             case CALL_LOCAL_HOLD:
                 ALOGD("%s: LOCAL_HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
                 lch_mode = VOICE_LCH_STOP;
-                if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
-                    ALOGE("LOCAL_HOLD -> ACTIVE failed");
-                } else {
+                ret = platform_update_lch(adev->platform, session, lch_mode);
+                if (ret < 0)
+                    ALOGE("%s: lch mode update failed, ret = %d", __func__, ret);
+                else
                     session->state.current = session->state.new;
-                }
                 break;
 
             default:
@@ -213,10 +212,6 @@
                     ALOGE("%s: voice_end_call() failed for usecase: %d\n",
                           __func__, usecase_id);
                 } else {
-                    voice_extn_is_in_call(adev, &is_in_call);
-                    if (!is_in_call) {
-                        adev->voice.voice_device_set = false;
-                    }
                     session->state.current = session->state.new;
                 }
                 break;
@@ -239,11 +234,11 @@
             case CALL_LOCAL_HOLD:
                 ALOGD("%s: CALL_LOCAL_HOLD -> HOLD vsid:%x", __func__, session->vsid);
                 lch_mode = VOICE_LCH_STOP;
-                if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
-                    ALOGE("LOCAL_HOLD -> HOLD failed");
-                } else {
+                ret = platform_update_lch(adev->platform, session, lch_mode);
+                if (ret < 0)
+                    ALOGE("%s: lch mode update failed, ret = %d", __func__, ret);
+                else
                     session->state.current = session->state.new;
-                }
                 break;
 
             default:
@@ -261,11 +256,11 @@
                 ALOGD("%s: ACTIVE/CALL_HOLD -> LOCAL_HOLD vsid:%x", __func__,
                       session->vsid);
                 lch_mode = VOICE_LCH_START;
-                if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
-                    ALOGE("LOCAL_HOLD -> HOLD failed");
-                } else {
+                ret = platform_update_lch(adev->platform, session, lch_mode);
+                if (ret < 0)
+                    ALOGE("%s: lch mode update failed, ret = %d", __func__, ret);
+                else
                     session->state.current = session->state.new;
-                }
                 break;
 
             default:
@@ -288,8 +283,7 @@
 {
     struct voice_session *session = NULL;
     int i = 0;
-    bool is_in_call;
-    int no_of_calls_active = 0;
+    bool is_call_active;
 
     for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
         if (vsid == adev->voice.session[i].vsid) {
@@ -298,21 +292,16 @@
         }
     }
 
-    for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
-        if (CALL_INACTIVE != adev->voice.session[i].state.current)
-            no_of_calls_active++;
-    }
-
     if (session) {
         session->state.new = call_state;
-        voice_extn_is_in_call(adev, &is_in_call);
-        ALOGD("%s is_in_call:%d voice_device_set:%d, mode:%d\n",
-              __func__, is_in_call, adev->voice.voice_device_set, adev->mode);
+        voice_extn_is_call_state_active(adev, &is_call_active);
+        ALOGD("%s is_call_active:%d in_call:%d, mode:%d\n",
+              __func__, is_call_active, adev->voice.in_call, adev->mode);
         /* Dont start voice call before device routing for voice usescases has
          * occured, otherwise voice calls will be started unintendedly on
          * speaker.
          */
-        if (is_in_call || adev->voice.voice_device_set) {
+        if (is_call_active || adev->voice.in_call) {
             /* Device routing is not triggered for voice calls on the subsequent
              * subs, Hence update the call states if voice call is already
              * active on other sub.
@@ -334,16 +323,16 @@
     return 0;
 }
 
-int voice_extn_is_in_call(struct audio_device *adev, bool *in_call)
+int voice_extn_is_call_state_active(struct audio_device *adev, bool *is_call_active)
 {
     struct voice_session *session = NULL;
     int i = 0;
-    *in_call = false;
+    *is_call_active = false;
 
     for (i = 0; i < MAX_VOICE_SESSIONS; i++) {
         session = &adev->voice.session[i];
         if(session->state.current != CALL_INACTIVE){
-            *in_call = true;
+            *is_call_active = true;
             break;
         }
     }
@@ -415,7 +404,6 @@
      * udpated.
      */
     ALOGV("%s: enter:", __func__);
-    adev->voice.voice_device_set = true;
     return update_calls(adev);
 }
 
@@ -462,6 +450,7 @@
         err = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_CALL_STATE, &value);
         if (err >= 0) {
             call_state = value;
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_CALL_STATE);
         } else {
             ALOGE("%s: call_state key not found", __func__);
             ret = -EINVAL;
diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h
index 4a9c610..73da18a 100644
--- a/hal/voice_extn/voice_extn.h
+++ b/hal/voice_extn/voice_extn.h
@@ -32,8 +32,9 @@
 void voice_extn_get_parameters(const struct audio_device *adev,
                                struct str_parms *query,
                                struct str_parms *reply);
-int voice_extn_is_in_call(struct audio_device *adev, bool *in_call);
 int voice_extn_is_in_call_rec_stream(struct stream_in *in, bool *in_call_rec);
+int voice_extn_is_call_state_active(struct audio_device *adev,
+                                    bool *is_call_active);
 int voice_extn_get_active_session_id(struct audio_device *adev,
                                      uint32_t *session_id);
 void voice_extn_in_get_parameters(struct stream_in *in,
@@ -76,7 +77,8 @@
 {
 }
 
-static int voice_extn_is_in_call(struct audio_device *adev, bool *in_call)
+static int voice_extn_is_call_state_active(struct audio_device *adev,
+                                           bool *is_call_active)
 {
     return -ENOSYS;
 }
diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c
index 1c96280..e2c6d9a 100644
--- a/post_proc/bass_boost.c
+++ b/post_proc/bass_boost.c
@@ -158,24 +158,27 @@
        (device == AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
        (device == AUDIO_DEVICE_OUT_USB_ACCESSORY) ||
        (device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET)) {
-        if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) {
-            offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false);
+        if (!bass_ctxt->temp_disabled) {
+            if (effect_is_active(&bass_ctxt->common)) {
+                offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false);
+                if (bass_ctxt->ctl)
+                    offload_bassboost_send_params(bass_ctxt->ctl,
+                                                  bass_ctxt->offload_bass,
+                                                  OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+            }
             bass_ctxt->temp_disabled = true;
-            if (bass_ctxt->ctl)
-                offload_bassboost_send_params(bass_ctxt->ctl,
-                                              bass_ctxt->offload_bass,
-                                              OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
-            ALOGI("%s: ctxt %p, disabled based on device", __func__, bass_ctxt);
         }
+        ALOGI("%s: ctxt %p, disabled based on device", __func__, bass_ctxt);
     } else {
-        if (!offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)) &&
-            bass_ctxt->temp_disabled) {
-            offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true);
+        if (bass_ctxt->temp_disabled) {
+            if (effect_is_active(&bass_ctxt->common)) {
+                offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true);
+                if (bass_ctxt->ctl)
+                    offload_bassboost_send_params(bass_ctxt->ctl,
+                                                  bass_ctxt->offload_bass,
+                                                  OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+            }
             bass_ctxt->temp_disabled = false;
-            if (bass_ctxt->ctl)
-                offload_bassboost_send_params(bass_ctxt->ctl,
-                                              bass_ctxt->offload_bass,
-                                              OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
         }
     }
     offload_bassboost_set_device(&(bass_ctxt->offload_bass), device);
diff --git a/post_proc/bundle.c b/post_proc/bundle.c
index a0d9fcb..0db2e37 100644
--- a/post_proc/bundle.c
+++ b/post_proc/bundle.c
@@ -186,6 +186,7 @@
     int ret = 0;
     struct listnode *node;
     char mixer_string[128];
+    output_context_t * out_ctxt = NULL;
 
     ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
 
@@ -199,7 +200,7 @@
         goto exit;
     }
 
-    output_context_t *out_ctxt = (output_context_t *)
+    out_ctxt = (output_context_t *)
                                  malloc(sizeof(output_context_t));
     if (!out_ctxt) {
         ALOGE("%s fail to allocate for output context", __func__);
@@ -217,6 +218,7 @@
         ALOGE("Failed to open mixer");
         out_ctxt->ctl = NULL;
         ret = -EINVAL;
+        free(out_ctxt);
         goto exit;
     } else {
         out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string);
@@ -225,6 +227,7 @@
             mixer_close(out_ctxt->mixer);
             out_ctxt->mixer = NULL;
             ret = -EINVAL;
+            free(out_ctxt);
             goto exit;
         }
     }
@@ -535,12 +538,12 @@
 
     pthread_mutex_lock(&lock);
     if (!effect_exists(context)) {
-        status = -EINVAL;
+        status = -ENOSYS;
         goto exit;
     }
 
     if (context->state != EFFECT_STATE_ACTIVE) {
-        status = -EINVAL;
+        status = -ENODATA;
         goto exit;
     }
 
@@ -560,13 +563,13 @@
     pthread_mutex_lock(&lock);
 
     if (!effect_exists(context)) {
-        status = -EINVAL;
+        status = -ENOSYS;
         goto exit;
     }
 
     ALOGV("%s: ctxt %p, cmd %d", __func__, context, cmdCode);
     if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
-        status = -EINVAL;
+        status = -ENOSYS;
         goto exit;
     }
 
@@ -752,6 +755,9 @@
     return 0;
 }
 
+bool effect_is_active(effect_context_t * ctxt) {
+    return ctxt->state == EFFECT_STATE_ACTIVE;
+}
 
 /* effect_handle_t interface implementation for offload effects */
 const struct effect_interface_s effect_interface = {
diff --git a/post_proc/bundle.h b/post_proc/bundle.h
index 7ebea92..cbe7dba 100644
--- a/post_proc/bundle.h
+++ b/post_proc/bundle.h
@@ -87,4 +87,6 @@
 
 int set_config(effect_context_t *context, effect_config_t *config);
 
+bool effect_is_active(effect_context_t *context);
+
 #endif /* OFFLOAD_EFFECT_BUNDLE_H */
diff --git a/post_proc/reverb.c b/post_proc/reverb.c
index 81bcb97..77ae303 100644
--- a/post_proc/reverb.c
+++ b/post_proc/reverb.c
@@ -229,7 +229,7 @@
 
 void reverb_set_density(reverb_context_t *context, int16_t density)
 {
-    ALOGV("%s: ctxt %p, density: %d", __func__, density, density);
+    ALOGV("%s: ctxt %p, density: %d", __func__, context, density);
     context->reverb_settings.density = density;
     offload_reverb_set_density(&(context->offload_reverb), density);
     if (context->ctl)
diff --git a/post_proc/virtualizer.c b/post_proc/virtualizer.c
index 96828a0..9ed1ac5 100644
--- a/post_proc/virtualizer.c
+++ b/post_proc/virtualizer.c
@@ -157,24 +157,27 @@
        (device == AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
        (device == AUDIO_DEVICE_OUT_USB_ACCESSORY) ||
        (device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET)) {
-        if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) {
-            offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
+        if (!virt_ctxt->temp_disabled) {
+            if (effect_is_active(&virt_ctxt->common)) {
+                offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
+                if (virt_ctxt->ctl)
+                    offload_virtualizer_send_params(virt_ctxt->ctl,
+                                                    virt_ctxt->offload_virt,
+                                                    OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+            }
             virt_ctxt->temp_disabled = true;
-            if (virt_ctxt->ctl)
-                offload_virtualizer_send_params(virt_ctxt->ctl,
-                                              virt_ctxt->offload_virt,
-                                              OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
             ALOGI("%s: ctxt %p, disabled based on device", __func__, virt_ctxt);
         }
     } else {
-        if (!offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)) &&
-            virt_ctxt->temp_disabled) {
-            offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
+        if (virt_ctxt->temp_disabled) {
+            if (effect_is_active(&virt_ctxt->common)) {
+                offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
+                if (virt_ctxt->ctl)
+                    offload_virtualizer_send_params(virt_ctxt->ctl,
+                                                    virt_ctxt->offload_virt,
+                                                    OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+            }
             virt_ctxt->temp_disabled = false;
-            if (virt_ctxt->ctl)
-                offload_virtualizer_send_params(virt_ctxt->ctl,
-                                              virt_ctxt->offload_virt,
-                                              OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
         }
     }
     offload_virtualizer_set_device(&(virt_ctxt->offload_virt), device);
@@ -212,6 +215,7 @@
 
     set_config(context, &context->config);
 
+    virt_ctxt->temp_disabled = false;
     memset(&(virt_ctxt->offload_virt), 0, sizeof(struct virtualizer_params));
 
     return 0;