Merge AU_LINUX_ANDROID_LA.BR.1.3.2_RB3.05.01.01.156.017 on remote branch

Change-Id: I8ad8a722bb667715cfb13f4927c00efeeec1d436
diff --git a/hal/Android.mk b/hal/Android.mk
index e0149f9..8c6eb61 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -54,6 +54,7 @@
 
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HDMI_EDID)),true)
     LOCAL_SRC_FILES += edid.c
+    LOCAL_CFLAGS := -DHDMI_EDID_ENABLED
 endif
 
 ifeq ($(strip $(AUDIO_USE_LL_AS_PRIMARY_OUTPUT)),true)
@@ -68,6 +69,10 @@
     LOCAL_CFLAGS += -DANC_HEADSET_ENABLED
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_VBAT_MONITOR)),true)
+    LOCAL_CFLAGS += -DVBAT_MONITOR_ENABLED
+endif
+
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FLUENCE)),true)
     LOCAL_CFLAGS += -DFLUENCE_ENABLED
 endif
@@ -251,6 +256,12 @@
     LOCAL_SRC_FILES += audio_extn/listen.c
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXT_HDMI)),true)
+    LOCAL_CFLAGS += -DAUDIO_EXTERNAL_HDMI_ENABLED
+    LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-parsers
+    LOCAL_SHARED_LIBRARIES += libaudioparsers
+endif
+
 ifeq ($(strip $(BOARD_SUPPORTS_SOUND_TRIGGER)),true)
     LOCAL_CFLAGS += -DSOUND_TRIGGER_ENABLED
     LOCAL_CFLAGS += -DSOUND_TRIGGER_PLATFORM_NAME=$(TARGET_BOARD_PLATFORM)
diff --git a/hal/audio_extn/audio_defs.h b/hal/audio_extn/audio_defs.h
index 96b0a8b..9d80112 100644
--- a/hal/audio_extn/audio_defs.h
+++ b/hal/audio_extn/audio_defs.h
@@ -72,6 +72,8 @@
 #define AUDIO_OFFLOAD_CODEC_APE_SAMPLE_RATE "music_offload_ape_sample_rate"
 #define AUDIO_OFFLOAD_CODEC_APE_SEEK_TABLE_PRESENT "music_offload_seek_table_present"
 
+#define AUDIO_OFFLOAD_CODEC_VORBIS_BITSTREAM_FMT "music_offload_vorbis_bitstream_fmt"
+
 /* Query handle fm parameter*/
 #define AUDIO_PARAMETER_KEY_HANDLE_FM "handle_fm"
 
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 67d30ca..72842b6 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -62,6 +62,7 @@
     bool custom_stereo_enabled;
     uint32_t proxy_channel_num;
     bool hpx_enabled;
+    bool vbat_enabled;
 };
 
 static struct audio_extn_module aextnmod = {
@@ -70,6 +71,7 @@
     .custom_stereo_enabled = 0,
     .proxy_channel_num = 2,
     .hpx_enabled = 0,
+    .vbat_enabled = 0,
 };
 
 #define AUDIO_PARAMETER_KEY_ANC        "anc_enabled"
@@ -216,6 +218,27 @@
 }
 #endif
 
+#ifdef VBAT_MONITOR_ENABLED
+bool audio_extn_is_vbat_enabled(void)
+{
+    ALOGD("%s: status: %d", __func__, aextnmod.vbat_enabled);
+    return (aextnmod.vbat_enabled ? true: false);
+}
+
+bool audio_extn_can_use_vbat(void)
+{
+    char prop_vbat_enabled[PROPERTY_VALUE_MAX] = "false";
+
+    property_get("persist.audio.vbat.enabled", prop_vbat_enabled, "0");
+    if (!strncmp("true", prop_vbat_enabled, 4)) {
+        aextnmod.vbat_enabled = 1;
+    }
+
+    ALOGD("%s: vbat.enabled property is set to %s", __func__, prop_vbat_enabled);
+    return (aextnmod.vbat_enabled ? true: false);
+}
+#endif
+
 #ifndef ANC_HEADSET_ENABLED
 #define audio_extn_set_anc_parameters(adev, parms)       (0)
 #else
@@ -682,25 +705,23 @@
     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->gapless_mdata.min_blk_size =
             out->compr_config.codec->options.flac_dec.min_blk_size = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE, value, sizeof(value));
         if (ret >= 0) {
-            out->gapless_mdata.max_blk_size =
             out->compr_config.codec->options.flac_dec.max_blk_size = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         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;
+            out->is_compr_metadata_avail = true;
         }
         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;
+            out->is_compr_metadata_avail = true;
         }
         ALOGV("FLAC metadata: min_blk_size %d, max_blk_size %d min_frame_size %d max_frame_size %d",
               out->compr_config.codec->options.flac_dec.min_blk_size,
@@ -713,63 +734,63 @@
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_FRAME_LENGTH, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.frame_length = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_COMPATIBLE_VERSION, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.compatible_version = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_BIT_DEPTH, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.bit_depth = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_PB, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.pb = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_MB, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.mb = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
 
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_KB, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.kb = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_NUM_CHANNELS, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.num_channels = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_MAX_RUN, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.max_run = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_MAX_FRAME_BYTES, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.max_frame_bytes = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_AVG_BIT_RATE, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.avg_bit_rate = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_SAMPLING_RATE, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.sample_rate = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_ALAC_CHANNEL_LAYOUT_TAG, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.alac.channel_layout_tag = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ALOGV("ALAC CSD values: frameLength %d bitDepth %d numChannels %d"
                 " maxFrameBytes %d, avgBitRate %d, sampleRate %d",
@@ -785,52 +806,52 @@
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_COMPATIBLE_VERSION, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.compatible_version = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_COMPRESSION_LEVEL, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.compression_level = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_FORMAT_FLAGS, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.format_flags = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_BLOCKS_PER_FRAME, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.blocks_per_frame = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_FINAL_FRAME_BLOCKS, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.final_frame_blocks = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_TOTAL_FRAMES, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.total_frames = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_BITS_PER_SAMPLE, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.bits_per_sample = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_NUM_CHANNELS, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.num_channels = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_SAMPLE_RATE, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.sample_rate = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_APE_SEEK_TABLE_PRESENT, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.ape.seek_table_present = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ALOGV("APE CSD values: compatibleVersion %d compressionLevel %d"
                 " formatFlags %d blocksPerFrame %d finalFrameBlocks %d"
@@ -849,49 +870,59 @@
     }
 
     else if (out->format == AUDIO_FORMAT_VORBIS) {
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_VORBIS_BITSTREAM_FMT, value, sizeof(value));
+        if (ret >= 0) {
         // transcoded bitstream mode
-        out->compr_config.codec->options.vorbis_dec.bit_stream_fmt = 1;
-        out->send_new_metadata = 1;
+            out->compr_config.codec->options.vorbis_dec.bit_stream_fmt = (atoi(value) > 0) ? 1 : 0;
+            out->is_compr_metadata_avail = true;
+        }
     }
 
     else if (out->format == AUDIO_FORMAT_WMA || out->format == AUDIO_FORMAT_WMA_PRO) {
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_FORMAT_TAG, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->format = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.wma.avg_bit_rate = atoi(value);
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BLOCK_ALIGN, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.wma.super_block_align = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_BIT_PER_SAMPLE, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.wma.bits_per_sample = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_CHANNEL_MASK, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.wma.channelmask = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.wma.encodeopt = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION1, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.wma.encodeopt1 = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
         ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_WMA_ENCODE_OPTION2, value, sizeof(value));
         if (ret >= 0) {
             out->compr_config.codec->options.wma.encodeopt2 = atoi(value);
-            out->send_new_metadata = 1;
+            out->is_compr_metadata_avail = true;
         }
-        ALOGV("WMA params: fmt %x, balgn %x, sr %d, chmsk %x, encop %x, op1 %x, op2 %x",
+        ALOGV("WMA params: fmt %x, bit rate %x, balgn %x, sr %d, chmsk %x"
+                " encop %x, op1 %x, op2 %x",
                 out->compr_config.codec->format,
+                out->compr_config.codec->options.wma.avg_bit_rate,
                 out->compr_config.codec->options.wma.super_block_align,
                 out->compr_config.codec->options.wma.bits_per_sample,
                 out->compr_config.codec->options.wma.channelmask,
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index c0b6de1..5028b87 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -118,6 +118,14 @@
 bool audio_extn_should_use_handset_anc(int in_channels);
 #endif
 
+#ifndef VBAT_MONITOR_ENABLED
+#define audio_extn_is_vbat_enabled()                     (0)
+#define audio_extn_can_use_vbat()                        (0)
+#else
+bool audio_extn_is_vbat_enabled(void);
+bool audio_extn_can_use_vbat(void);
+#endif
+
 #ifndef FLUENCE_ENABLED
 #define audio_extn_set_fluence_parameters(adev, parms) (0)
 #define audio_extn_get_fluence_parameters(adev, query, reply) (0)
@@ -221,6 +229,7 @@
 #define audio_extn_sound_trigger_set_parameters(adev, parms)           (0)
 #define audio_extn_sound_trigger_check_and_get_session(in)             (0)
 #define audio_extn_sound_trigger_stop_lab(in)                          (0)
+#define audio_extn_sound_trigger_read(in, buffer, bytes)               (0)
 #else
 
 enum st_event_type {
@@ -241,6 +250,8 @@
                                              struct str_parms *parms);
 void audio_extn_sound_trigger_check_and_get_session(struct stream_in *in);
 void audio_extn_sound_trigger_stop_lab(struct stream_in *in);
+int audio_extn_sound_trigger_read(struct stream_in *in, void *buffer,
+                                  size_t bytes);
 #endif
 
 #ifndef AUXPCM_BT_ENABLED
@@ -467,6 +478,7 @@
 
 int b64decode(char *inp, int ilen, uint8_t* outp);
 int b64encode(uint8_t *inp, int ilen, char* outp);
+int read_line_from_file(const char *path, char *buf, size_t count);
 
 #ifndef KPI_OPTIMIZE_ENABLED
 #define audio_extn_perf_lock_init() (0)
@@ -477,4 +489,10 @@
 void audio_extn_perf_lock_acquire(void);
 void audio_extn_perf_lock_release(void);
 #endif /* KPI_OPTIMIZE_ENABLED */
+
+#ifndef AUDIO_EXTERNAL_HDMI_ENABLED
+#define setChannelStatus(out, buffer, bytes) (0)
+#else
+void setChannelStatus(struct stream_out *out, char * buffer, size_t bytes);
+#endif
 #endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/fm.c b/hal/audio_extn/fm.c
index efc2307..0ef7c7e 100644
--- a/hal/audio_extn/fm.c
+++ b/hal/audio_extn/fm.c
@@ -251,7 +251,7 @@
                  * Currently, platform_get_wsa_mode will directly return
                  * 1 when wsa is in analog mode.
                  */
-                if (platform_get_wsa_mode(adev->platform) == 1) {
+                if (platform_get_wsa_mode(adev) == 1) {
                     fm_stop(adev);
                     fm_start(adev);
                 } else {
diff --git a/hal/audio_extn/soundtrigger.c b/hal/audio_extn/soundtrigger.c
index 9051334..c13c2f3 100644
--- a/hal/audio_extn/soundtrigger.c
+++ b/hal/audio_extn/soundtrigger.c
@@ -30,6 +30,7 @@
 /* #define LOG_NDEBUG 0 */
 #define LOG_NDDEBUG 0
 
+#include <errno.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <dlfcn.h>
@@ -64,7 +65,7 @@
 {
     struct sound_trigger_info  *st_ses_info = NULL;
     struct listnode *node;
-    ALOGD("%s: list %d capture_handle %d", __func__,
+    ALOGV("%s: list empty %d capture_handle %d", __func__,
            list_empty(&st_dev->st_ses_list), capture_handle);
     list_for_each(node, &st_dev->st_ses_list) {
         st_ses_info = node_to_item(node, struct sound_trigger_info , list);
@@ -128,6 +129,45 @@
     return status;
 }
 
+int audio_extn_sound_trigger_read(struct stream_in *in, void *buffer,
+                       size_t bytes)
+{
+    int ret = -1;
+    struct sound_trigger_info  *st_info = NULL;
+    audio_event_info_t event;
+
+    if (!st_dev)
+       return ret;
+
+    if (!in->is_st_session_active) {
+        ALOGE(" %s: Sound trigger is not active", __func__);
+        goto exit;
+    }
+    if(in->standby)
+        in->standby = false;
+
+    pthread_mutex_lock(&st_dev->lock);
+    st_info = get_sound_trigger_info(in->capture_handle);
+    pthread_mutex_unlock(&st_dev->lock);
+    if (st_info) {
+        event.u.aud_info.ses_info = &st_info->st_ses;
+        event.u.aud_info.buf = buffer;
+        event.u.aud_info.num_bytes = bytes;
+        ret = st_dev->st_callback(AUDIO_EVENT_READ_SAMPLES, &event);
+    }
+
+exit:
+    if (ret) {
+        if (-ENETRESET == ret)
+            in->is_st_session_active = false;
+        memset(buffer, 0, bytes);
+        ALOGV("%s: read failed status %d - sleep", __func__, ret);
+        usleep((bytes * 1000000) / (audio_stream_in_frame_size((struct audio_stream_in *)in) *
+                                   in->config.rate));
+    }
+    return ret;
+}
+
 void audio_extn_sound_trigger_stop_lab(struct stream_in *in)
 {
     int status = 0;
@@ -294,6 +334,18 @@
         event.u.value = val;
         st_dev->st_callback(AUDIO_EVENT_NUM_ST_SESSIONS, &event);
     }
+
+    ret = str_parms_get_int(params, AUDIO_PARAMETER_DEVICE_CONNECT, &val);
+    if ((ret >= 0) && audio_is_input_device(val)) {
+        event.u.value = val;
+        st_dev->st_callback(AUDIO_EVENT_DEVICE_CONNECT, &event);
+    }
+
+    ret = str_parms_get_int(params, AUDIO_PARAMETER_DEVICE_DISCONNECT, &val);
+    if ((ret >= 0) && audio_is_input_device(val)) {
+        event.u.value = val;
+        st_dev->st_callback(AUDIO_EVENT_DEVICE_DISCONNECT, &event);
+    }
 }
 
 int audio_extn_sound_trigger_init(struct audio_device *adev)
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index e5201cc..858a00e 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -58,6 +58,10 @@
 #define SAFE_SPKR_TEMP 40
 #define SAFE_SPKR_TEMP_Q6 (SAFE_SPKR_TEMP * (1 << 6))
 
+/*Bongo Spkr temp range*/
+#define TZ_TEMP_MIN_THRESHOLD    (5)
+#define TZ_TEMP_MAX_THRESHOLD    (45)
+
 /*Range of resistance values 2ohms to 40 ohms*/
 #define MIN_RESISTANCE_SPKR_Q24 (2 * (1 << 24))
 #define MAX_RESISTANCE_SPKR_Q24 (40 * (1 << 24))
@@ -90,6 +94,11 @@
 #define SPKR_PROCESSING_IN_PROGRESS 1
 #define SPKR_PROCESSING_IN_IDLE 0
 
+#ifdef PLATFORM_MSM8916
+#define ACDB_DEVICE_SPKR_PROT_WSA_ANALOG 136
+#define ACDB_DEVICE_VI_FEEDBACK_WSA_ANALOG 137
+#endif
+
 #define MAX_PATH             (256)
 #define THERMAL_SYSFS "/sys/class/thermal"
 #define TZ_TYPE "/sys/class/thermal/thermal_zone%d/type"
@@ -147,27 +156,6 @@
 static struct speaker_prot_session handle;
 static int vi_feed_no_channels;
 
-int read_line_from_file(const char *path, char *buf, size_t count)
-{
-    char * fgets_ret;
-    FILE * fd;
-    int rv;
-
-    fd = fopen(path, "r");
-    if (fd == NULL)
-        return -1;
-
-    fgets_ret = fgets(buf, (int)count, fd);
-    if (NULL != fgets_ret) {
-        rv = (int)strlen(buf);
-    } else {
-        rv = ferror(fd);
-    }
-    fclose(fd);
-
-   return rv;
-}
-
 /*===========================================================================
 FUNCTION get_tzn
 
@@ -214,7 +202,8 @@
             snprintf(name, MAX_PATH, TZ_TYPE, tzn);
             ALOGD("Opening %s\n", name);
             read_line_from_file(name, buf, sizeof(buf));
-            buf[strlen(sensor_name)] = '\0';
+            if (strlen(buf) > 0)
+                buf[strlen(buf) - 1] = '\0';
             if (!strcmp(buf, sensor_name)) {
                 found = 1;
                 break;
@@ -445,10 +434,16 @@
     uc_info_rx->type = PCM_PLAYBACK;
     uc_info_rx->in_snd_device = SND_DEVICE_NONE;
     uc_info_rx->stream.out = adev->primary_output;
-    uc_info_rx->out_snd_device = SND_DEVICE_OUT_SPEAKER_PROTECTED;
+    if (audio_extn_is_vbat_enabled())
+        uc_info_rx->out_snd_device = SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT;
+    else
+        uc_info_rx->out_snd_device = SND_DEVICE_OUT_SPEAKER_PROTECTED;
     disable_rx = true;
     list_add_tail(&adev->usecase_list, &uc_info_rx->list);
-    enable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED);
+    if (audio_extn_is_vbat_enabled())
+         enable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT);
+    else
+         enable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED);
     enable_audio_route(adev, uc_info_rx);
 
     pcm_dev_rx_id = platform_get_pcm_device_id(uc_info_rx->id, PCM_PLAYBACK);
@@ -485,6 +480,7 @@
     enable_audio_route(adev, uc_info_tx);
 
     pcm_dev_tx_id = platform_get_pcm_device_id(uc_info_tx->id, PCM_CAPTURE);
+    ALOGV("%s: pcm device id %d", __func__, pcm_dev_tx_id);
     if (pcm_dev_tx_id < 0) {
         ALOGE("%s: Invalid pcm device for usecase (%d)",
               __func__, uc_info_tx->id);
@@ -606,7 +602,10 @@
         }
         if (disable_rx) {
             list_remove(&uc_info_rx->list);
-            disable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED);
+            if (audio_extn_is_vbat_enabled())
+                disable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT);
+            else
+                disable_snd_device(adev, SND_DEVICE_OUT_SPEAKER_PROTECTED);
             disable_audio_route(adev, uc_info_rx);
         }
         if (disable_tx) {
@@ -647,6 +646,7 @@
     char wsa_path[MAX_PATH] = {0};
     int spk_1_tzn, spk_2_tzn;
     char buf[32] = {0};
+    int ret;
 
     /* If the value of this persist.spkr.cal.duration is 0
      * then it means it will take 30min to calibrate
@@ -724,24 +724,23 @@
         close(acdb_fd);
     }
 
+    ALOGV("%s: start calibration", __func__);
     while (1) {
-        ALOGV("%s: start calibration", __func__);
         if (handle.wsa_found) {
             spk_1_tzn = handle.spkr_1_tzn;
             spk_2_tzn = handle.spkr_2_tzn;
             goahead = false;
             pthread_mutex_lock(&adev->lock);
             if (is_speaker_in_use(&sec)) {
-                ALOGD("%s: WSA Speaker in use retry calibration", __func__);
+                ALOGV("%s: WSA Speaker in use retry calibration", __func__);
                 pthread_mutex_unlock(&adev->lock);
                 continue;
             } else {
-                ALOGD("%s: wsa speaker idle %ld min time %ld", __func__, sec, min_idle_time);
                 if (sec < min_idle_time) {
-                    ALOGD("%s: speaker idle is less retry", __func__);
                     pthread_mutex_unlock(&adev->lock);
                     continue;
                }
+               ALOGV("%s: wsa speaker idle %ld min time %ld", __func__, sec, min_idle_time);
                goahead = true;
            }
            if (!list_empty(&adev->usecase_list)) {
@@ -751,18 +750,22 @@
            if (goahead) {
                if (spk_1_tzn > 0) {
                    snprintf(wsa_path, MAX_PATH, TZ_WSA, spk_1_tzn);
-                   ALOGD("%s: wsa_path: %s\n", __func__, wsa_path);
+                   ALOGV("%s: wsa_path: %s\n", __func__, wsa_path);
                    thermal_fd = -1;
                    thermal_fd = open(wsa_path, O_RDONLY);
                    if (thermal_fd > 0) {
                        for (i = 0; i < NUM_ATTEMPTS; i++) {
-                            if (read(thermal_fd, buf, sizeof(buf))) {
+                            if ((ret = read(thermal_fd, buf, sizeof(buf))) >= 0) {
                                 t0_spk_1 = atoi(buf);
-                                if (i > 0 && (t0_spk_1 != t0_spk_prior))
+                                if (i > 0 && (t0_spk_1 != t0_spk_prior)) {
+                                    ALOGE("%s: spkr1 curr temp: %d, prev temp: %d\n",
+                                          __func__, t0_spk_1, t0_spk_prior);
                                     break;
+                                }
                                 t0_spk_prior = t0_spk_1;
+                                sleep(1);
                             } else {
-                               ALOGE("%s: read fail for %s\n", __func__, wsa_path);
+                               ALOGE("%s: read fail for %s err:%d\n", __func__, wsa_path, ret);
                                break;
                             }
                         }
@@ -771,28 +774,38 @@
                        ALOGE("%s: fd for %s is NULL\n", __func__, wsa_path);
                    }
                    if (i == NUM_ATTEMPTS) {
+                       if (t0_spk_1 < TZ_TEMP_MIN_THRESHOLD ||
+                           t0_spk_1 > TZ_TEMP_MAX_THRESHOLD) {
+                           pthread_mutex_unlock(&adev->lock);
+                           continue;
+                       }
                        /*Convert temp into q6 format*/
                        t0_spk_1 = (t0_spk_1 * (1 << 6));
-                       ALOGE("%s: temp T0 for spkr1 %d\n", __func__, t0_spk_1);
+                       ALOGD("%s: temp T0 for spkr1 %d\n", __func__, t0_spk_1);
                    } else {
-                       ALOGE("%s: thermal equilibrium failed for spkr1 in %d readings\n",
-                                                __func__, NUM_ATTEMPTS);
-                       t0_spk_1 = SAFE_SPKR_TEMP_Q6;
+                       ALOGV("%s: thermal equilibrium failed for spkr1 in %d/%d readings\n",
+                                                __func__, i, NUM_ATTEMPTS);
+                       pthread_mutex_unlock(&adev->lock);
+                       continue;
                    }
                }
                if (spk_2_tzn > 0) {
                    snprintf(wsa_path, MAX_PATH, TZ_WSA, spk_2_tzn);
-                   ALOGE("%s: wsa_path: %s\n", __func__, wsa_path);
+                   ALOGV("%s: wsa_path: %s\n", __func__, wsa_path);
                    thermal_fd = open(wsa_path, O_RDONLY);
                    if (thermal_fd > 0) {
                        for (i = 0; i < NUM_ATTEMPTS; i++) {
-                            if (read(thermal_fd, buf, sizeof(buf))) {
+                            if ((ret = read(thermal_fd, buf, sizeof(buf))) >= 0) {
                                 t0_spk_2 = atoi(buf);
-                                if (i > 0 && (t0_spk_2 != t0_spk_prior))
+                                if (i > 0 && (t0_spk_2 != t0_spk_prior)) {
+                                    ALOGE("%s: spkr2 curr temp: %d, prev temp: %d\n",
+                                          __func__, t0_spk_2, t0_spk_prior);
                                     break;
+                                }
                                 t0_spk_prior = t0_spk_2;
+                                sleep(1);
                             } else {
-                               ALOGE("%s: read fail for %s\n", __func__, wsa_path);
+                               ALOGE("%s: read fail for %s err:%d\n", __func__, wsa_path, ret);
                                break;
                             }
                         }
@@ -801,13 +814,19 @@
                        ALOGE("%s: fd for %s is NULL\n", __func__, wsa_path);
                    }
                    if (i == NUM_ATTEMPTS) {
+                       if (t0_spk_2 < TZ_TEMP_MIN_THRESHOLD ||
+                           t0_spk_2 > TZ_TEMP_MAX_THRESHOLD) {
+                           pthread_mutex_unlock(&adev->lock);
+                           continue;
+                       }
                        /*Convert temp into q6 format*/
                        t0_spk_2 = (t0_spk_2 * (1 << 6));
-                       ALOGE("%s: temp T0 for spkr2 %d\n", __func__, t0_spk_2);
+                       ALOGD("%s: temp T0 for spkr2 %d\n", __func__, t0_spk_2);
                    } else {
-                       ALOGE("%s: thermal equilibrium failed for spkr2 in %d readings\n",
-                                                __func__, NUM_ATTEMPTS);
-                       t0_spk_2 = SAFE_SPKR_TEMP_Q6;
+                       ALOGV("%s: thermal equilibrium failed for spkr2 in %d/%d readings\n",
+                                                __func__, i, NUM_ATTEMPTS);
+                       pthread_mutex_unlock(&adev->lock);
+                       continue;
                    }
                }
            }
@@ -838,16 +857,15 @@
         goahead = false;
         pthread_mutex_lock(&adev->lock);
         if (is_speaker_in_use(&sec)) {
-            ALOGD("%s: Speaker in use retry calibration", __func__);
+            ALOGV("%s: Speaker in use retry calibration", __func__);
             pthread_mutex_unlock(&adev->lock);
             continue;
         } else {
-            ALOGD("%s: speaker idle %ld min time %ld", __func__, sec, min_idle_time);
             if (sec < min_idle_time) {
-                ALOGD("%s: speaker idle is less retry", __func__);
                 pthread_mutex_unlock(&adev->lock);
                 continue;
             }
+            ALOGD("%s: speaker idle %ld min time %ld", __func__, sec, min_idle_time);
             goahead = true;
         }
         if (!list_empty(&adev->usecase_list)) {
@@ -925,6 +943,24 @@
     handle.spkr_prot_t0 = -1;
 
     if (is_wsa_present()) {
+#ifdef PLATFORM_MSM8916
+        if (platform_get_wsa_mode(adev) == 1) {
+            ALOGD("%s: WSA analog mode", __func__);
+            platform_set_snd_device_backend(SND_DEVICE_OUT_VOICE_SPEAKER_WSA,
+                                            "speaker-protected");
+            platform_set_snd_device_acdb_id(SND_DEVICE_OUT_SPEAKER_PROTECTED,
+                                            ACDB_DEVICE_SPKR_PROT_WSA_ANALOG);
+            platform_set_snd_device_acdb_id(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED,
+                                            ACDB_DEVICE_SPKR_PROT_WSA_ANALOG);
+            platform_set_snd_device_acdb_id(SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT,
+                                            ACDB_DEVICE_SPKR_PROT_WSA_ANALOG);
+            platform_set_snd_device_acdb_id(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT,
+                                            ACDB_DEVICE_SPKR_PROT_WSA_ANALOG);
+	    platform_set_snd_device_acdb_id(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK,
+                                            ACDB_DEVICE_VI_FEEDBACK_WSA_ANALOG);
+            pcm_config_skr_prot.channels = 2;
+        }
+#endif
         pthread_cond_init(&handle.spkr_calib_cancel, NULL);
         pthread_cond_init(&handle.spkr_calibcancel_ack, NULL);
         pthread_mutex_init(&handle.mutex_spkr_prot, NULL);
@@ -999,9 +1035,21 @@
 
     switch(snd_device) {
     case SND_DEVICE_OUT_SPEAKER:
+#ifdef PLATFORM_MSM8916
+    case SND_DEVICE_OUT_SPEAKER_WSA:
+#endif
         acdb_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_SPEAKER_PROTECTED);
         break;
+    case SND_DEVICE_OUT_SPEAKER_VBAT:
+        acdb_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT);
+        break;
+    case SND_DEVICE_OUT_VOICE_SPEAKER_VBAT:
+        acdb_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT);
+        break;
     case SND_DEVICE_OUT_VOICE_SPEAKER:
+#ifdef PLATFORM_MSM8916
+    case SND_DEVICE_OUT_VOICE_SPEAKER_WSA:
+#endif
         acdb_id = platform_get_snd_device_acdb_id(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED);
         break;
     default:
@@ -1018,8 +1066,18 @@
 
     switch(snd_device) {
     case SND_DEVICE_OUT_SPEAKER:
+#ifdef PLATFORM_MSM8916
+    case SND_DEVICE_OUT_SPEAKER_WSA:
+#endif
         return SND_DEVICE_OUT_SPEAKER_PROTECTED;
+    case SND_DEVICE_OUT_SPEAKER_VBAT:
+        return SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT;
+    case SND_DEVICE_OUT_VOICE_SPEAKER_VBAT:
+        return SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT;
     case SND_DEVICE_OUT_VOICE_SPEAKER:
+#ifdef PLATFORM_MSM8916
+    case SND_DEVICE_OUT_VOICE_SPEAKER_WSA:
+#endif
         return SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED;
     default:
         return snd_device;
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 75bb336..644300a 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -35,6 +35,10 @@
 #include "audio_extn.h"
 #include "voice.h"
 
+#ifdef AUDIO_EXTERNAL_HDMI_ENABLED
+#include "audio_parsers.h"
+#endif
+
 #define AUDIO_OUTPUT_POLICY_VENDOR_CONFIG_FILE "/vendor/etc/audio_output_policy.conf"
 
 #define OUTPUTS_TAG "outputs"
@@ -52,6 +56,21 @@
 #define BASE_TABLE_SIZE 64
 #define MAX_BASEINDEX_LEN 256
 
+#ifdef AUDIO_EXTERNAL_HDMI_ENABLED
+#define PROFESSIONAL        (1<<0)	/* 0 = consumer, 1 = professional */
+#define NON_LPCM	    (1<<1)	/* 0 = audio, 1 = non-audio */
+#define SR_44100	    (0<<0)	/* 44.1kHz */
+#define SR_NOTID	    (1<<0)	/* non indicated */
+#define SR_48000	    (2<<0)	/* 48kHz */
+#define SR_32000	    (3<<0)	/* 32kHz */
+#define SR_22050	    (4<<0)	/* 22.05kHz */
+#define SR_24000	    (6<<0)	/* 24kHz */
+#define SR_88200	    (8<<0)	/* 88.2kHz */
+#define SR_96000	    (10<<0)	/* 96kHz */
+#define SR_176400	    (12<<0)	/* 176.4kHz */
+#define SR_192000	    (14<<0)	/* 192kHz */
+
+#endif
 struct string_to_enum {
     const char *name;
     uint32_t value;
@@ -586,6 +605,27 @@
     return rc;
 }
 
+int read_line_from_file(const char *path, char *buf, size_t count)
+{
+    char * fgets_ret;
+    FILE * fd;
+    int rv;
+
+    fd = fopen(path, "r");
+    if (fd == NULL)
+        return -1;
+
+    fgets_ret = fgets(buf, (int)count, fd);
+    if (NULL != fgets_ret) {
+        rv = (int)strlen(buf);
+    } else {
+        rv = ferror(fd);
+    }
+    fclose(fd);
+
+   return rv;
+}
+
 void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
                                              struct audio_usecase *usecase)
 {
@@ -750,3 +790,130 @@
     outp[k] = '\0';
     return k;
 }
+
+#ifdef AUDIO_EXTERNAL_HDMI_ENABLED
+
+void get_default_compressed_channel_status(
+                                  unsigned char *channel_status)
+{
+     int32_t status = 0;
+     unsigned char bit_index;
+     memset(channel_status,0,24);
+
+     /* block start bit in preamble bit 3 */
+     channel_status[0] |= PROFESSIONAL;
+     //compre out
+     channel_status[0] |= NON_LPCM;
+     // sample rate; fixed 48K for default/transcode
+     channel_status[3] |= SR_48000;
+}
+
+int32_t get_compressed_channel_status(void *audio_stream_data,
+                                                   uint32_t audio_frame_size,
+                                                   unsigned char *channel_status,
+                                                   enum audio_parser_code_type codec_type)
+                                                   // codec_type - AUDIO_PARSER_CODEC_AC3
+                                                   //            - AUDIO_PARSER_CODEC_DTS
+{
+     unsigned char *streamPtr;
+     int ret = 0;
+     streamPtr = (unsigned char *)audio_stream_data;
+
+     if (audio_stream_data == NULL || audio_frame_size == 0) {
+         ALOGW("no buffer to get channel status, return default for compress");
+         get_default_compressed_channel_status(channel_status);
+         return ret;
+     }
+
+     memset(channel_status,0,24);
+     if(init_audio_parser(streamPtr, audio_frame_size, codec_type) == -1)
+     {
+         ALOGE("init audio parser failed");
+         return -1;
+     }
+     ret = get_channel_status(channel_status, codec_type);
+     return ret;
+
+}
+
+void get_linearpcm_channel_status(uint32_t sampleRate,
+                                                  unsigned char *channel_status)
+{
+     int32_t status = 0;
+     unsigned char bit_index;
+     memset(channel_status,0,24);
+     /* block start bit in preamble bit 3 */
+     channel_status[0] |= PROFESSIONAL;
+     //LPCM OUT
+     channel_status[0] &= ~NON_LPCM;
+
+     switch (sampleRate) {
+         case 8000:
+         case 11025:
+         case 12000:
+         case 16000:
+         case 22050:
+             channel_status[3] |= SR_NOTID;
+         case 24000:
+             channel_status[3] |= SR_24000;
+             break;
+         case 32000:
+             channel_status[3] |= SR_32000;
+             break;
+         case 44100:
+             channel_status[3] |= SR_44100;
+             break;
+         case 48000:
+             channel_status[3] |= SR_48000;
+             break;
+         case 88200:
+             channel_status[3] |= SR_88200;
+             break;
+         case 96000:
+             channel_status[3] |= SR_96000;
+             break;
+         case 176400:
+             channel_status[3] |= SR_176400;
+             break;
+         case 192000:
+            channel_status[3] |= SR_192000;
+             break;
+         default:
+             ALOGV("Invalid sample_rate %u\n", sampleRate);
+             status = -1;
+             break;
+     }
+}
+
+void setChannelStatus(struct stream_out *out, char * buffer, size_t bytes)
+{
+    unsigned char channel_status[24]={0};
+    struct snd_aes_iec958 iec958;
+    const char *mixer_ctl_name = "IEC958 Playback PCM Stream";
+    struct mixer_ctl *ctl;
+    int i=0;
+    if (audio_extn_is_dolby_format(out->format) &&
+        /*TODO:Extend code to support DTS passthrough*/
+        /*set compressed channel status bits*/
+        audio_extn_dolby_is_passthrough_stream(out->flags)){
+        get_compressed_channel_status(buffer, bytes, channel_status, AUDIO_PARSER_CODEC_AC3);
+    } else {
+        /*set channel status bit for LPCM*/
+        get_linearpcm_channel_status(out->sample_rate, channel_status);
+    }
+
+    memcpy(iec958.status, channel_status,sizeof(iec958.status));
+    ctl = mixer_get_ctl_by_name(out->dev->mixer, mixer_ctl_name);
+    if (!ctl) {
+            ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                  __func__, mixer_ctl_name);
+            return;
+    }
+    if (mixer_ctl_set_array(ctl, &iec958, sizeof(iec958)) < 0) {
+        ALOGE("%s: Could not set channel status for ext HDMI ",
+              __func__);
+        return;
+    }
+
+}
+#endif
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 2c18128..1a55750 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -421,7 +421,7 @@
     audio_extn_utils_send_audio_calibration(adev, usecase);
     audio_extn_utils_send_app_type_cfg(usecase);
     strlcpy(mixer_path, use_case_table[usecase->id], MIXER_PATH_MAX_LENGTH);
-    platform_add_backend_name(mixer_path, snd_device);
+    platform_add_backend_name(mixer_path, snd_device, usecase);
     ALOGV("%s: apply mixer and update path: %s", __func__, mixer_path);
     audio_route_apply_and_update_path(adev->audio_route, mixer_path);
     ALOGV("%s: exit", __func__);
@@ -443,7 +443,7 @@
     else
         snd_device = usecase->out_snd_device;
     strlcpy(mixer_path, use_case_table[usecase->id], MIXER_PATH_MAX_LENGTH);
-    platform_add_backend_name(mixer_path, snd_device);
+    platform_add_backend_name(mixer_path, snd_device, usecase);
     ALOGV("%s: reset and update mixer path: %s", __func__, mixer_path);
     audio_route_reset_and_update_path(adev->audio_route, mixer_path);
     audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_FREE);
@@ -486,7 +486,8 @@
     if(SND_DEVICE_IN_USB_HEADSET_MIC == snd_device)
        audio_extn_usb_start_capture(adev);
 
-    if ((snd_device == SND_DEVICE_OUT_SPEAKER ||
+    if ((snd_device == SND_DEVICE_OUT_SPEAKER || snd_device == SND_DEVICE_OUT_SPEAKER_WSA ||
+        snd_device == SND_DEVICE_OUT_SPEAKER_VBAT || snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT ||
         snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) &&
         audio_extn_spkr_prot_is_enabled()) {
        if (audio_extn_spkr_prot_get_acdb_id(snd_device) < 0) {
@@ -556,7 +557,8 @@
         if(SND_DEVICE_IN_USB_HEADSET_MIC == snd_device)
             audio_extn_usb_stop_capture();
 
-        if ((snd_device == SND_DEVICE_OUT_SPEAKER ||
+        if ((snd_device == SND_DEVICE_OUT_SPEAKER || snd_device == SND_DEVICE_OUT_SPEAKER_WSA ||
+            snd_device == SND_DEVICE_OUT_SPEAKER_VBAT || snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT ||
             snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) &&
             audio_extn_spkr_prot_is_enabled()) {
             audio_extn_spkr_prot_stop_processing(snd_device);
@@ -564,6 +566,9 @@
             audio_route_reset_and_update_path(adev->audio_route, device_name);
         }
 
+        if (snd_device == SND_DEVICE_OUT_HDMI)
+            adev->mChannelStatusSet = false;
+
         audio_extn_dev_arbi_release(snd_device);
         audio_extn_sound_trigger_update_device_status(snd_device,
                                         ST_EVENT_SND_DEVICE_FREE);
@@ -658,10 +663,9 @@
            specified usecase to new snd devices */
         list_for_each(node, &adev->usecase_list) {
             usecase = node_to_item(node, struct audio_usecase, list);
-            /* Update the out_snd_device only before enabling the audio route */
-            if (switch_device[usecase->id] ) {
-                usecase->out_snd_device = snd_device;
-                if (usecase->type != VOICE_CALL)
+            /* Update the out_snd_device only for the usecases that are enabled here */
+            if (switch_device[usecase->id] && (usecase->type != VOICE_CALL)) {
+                    usecase->out_snd_device = snd_device;
                     enable_audio_route(adev, usecase);
             }
         }
@@ -695,7 +699,8 @@
         if (usecase->type != PCM_PLAYBACK &&
                 usecase != uc_info &&
                 usecase->in_snd_device != snd_device &&
-                (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
+                ((uc_info->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) &&
+                ((usecase->devices & ~AUDIO_DEVICE_BIT_IN) & AUDIO_DEVICE_IN_ALL_CODEC_BACKEND)) &&
                 (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
             ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
                   __func__, use_case_table[usecase->id],
@@ -870,7 +875,6 @@
                                             usecase->stream.out);
                 if (usecase->stream.out == adev->primary_output &&
                         adev->active_input &&
-                        adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
                         out_snd_device != usecase->out_snd_device) {
                     select_devices(adev, adev->active_input->usecase);
                 }
@@ -1271,6 +1275,10 @@
                 ALOGE("%s: Next track returned error %d",__func__, ret);
             if (ret != -ENETRESET) {
                 send_callback = true;
+                pthread_mutex_lock(&out->lock);
+                out->send_new_metadata = 1;
+                out->send_next_track_params = true;
+                pthread_mutex_unlock(&out->lock);
                 event = STREAM_CBK_EVENT_DRAIN_READY;
                 ALOGV("copl(%p):send drain callback, ret %d", out, ret);
             } else
@@ -1594,6 +1602,9 @@
             ret = -EIO;
             goto error_open;
         }
+        /* compress_open sends params of the track, so reset the flag here */
+        out->is_compr_metadata_avail = false;
+
         if (out->offload_callback)
             compress_nonblock(out->compr, out->non_blocking);
 
@@ -1768,6 +1779,8 @@
         } else {
             ALOGD("copl(%p):standby", out);
             stop_compressed_output_l(out);
+            out->send_next_track_params = false;
+            out->is_compr_metadata_avail = false;
             out->gapless_mdata.encoder_delay = 0;
             out->gapless_mdata.encoder_padding = 0;
             if (out->compr != NULL) {
@@ -1793,7 +1806,6 @@
 {
     int ret = 0;
     char value[32];
-    bool is_meta_data_params = false;
 
     if (!out || !parms) {
         ALOGE("%s: return invalid ",__func__);
@@ -1806,36 +1818,19 @@
             out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_MP4ADTS;
             ALOGV("ADTS format is set in offload mode");
         }
-        out->send_new_metadata = 1;
     }
 
     ret = audio_extn_parse_compress_metadata(out, parms);
 
-    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_SAMPLE_RATE, value, sizeof(value));
-    if(ret >= 0)
-        is_meta_data_params = true;
-    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_NUM_CHANNEL, value, sizeof(value));
-    if(ret >= 0)
-        is_meta_data_params = true;
-    ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE, value, sizeof(value));
-    if(ret >= 0)
-        is_meta_data_params = true;
     ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value));
     if (ret >= 0) {
-        is_meta_data_params = true;
         out->gapless_mdata.encoder_delay = atoi(value); //whats a good limit check?
     }
     ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value));
     if (ret >= 0) {
-        is_meta_data_params = true;
         out->gapless_mdata.encoder_padding = atoi(value);
     }
 
-    if(!is_meta_data_params) {
-        ALOGV("%s: Not gapless meta data params", __func__);
-        return 0;
-    }
-    out->send_new_metadata = 1;
     ALOGV("%s new encoder delay %u and padding %u", __func__,
           out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding);
 
@@ -2121,12 +2116,23 @@
         }
     }
 
+    if (adev->mChannelStatusSet == false && (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)){
+        setChannelStatus(out, buffer, bytes);
+        adev->mChannelStatusSet = true;
+    }
+
     if (is_offload_usecase(out->usecase)) {
         ALOGVV("copl(%p): writing buffer (%zu bytes) to compress device", out, bytes);
         if (out->send_new_metadata) {
             ALOGD("copl(%p):send new gapless metadata", out);
             compress_set_gapless_metadata(out->compr, &out->gapless_mdata);
             out->send_new_metadata = 0;
+            if (out->send_next_track_params && out->is_compr_metadata_avail) {
+                ALOGD("copl(%p):send next track params in gapless", out);
+                compress_set_next_track_param(out->compr, &(out->compr_config.codec->options));
+                out->send_next_track_params = false;
+                out->is_compr_metadata_avail = false;
+            }
         }
 
         ret = compress_write(out->compr, buffer, bytes);
@@ -2603,31 +2609,29 @@
 
     pthread_mutex_lock(&in->lock);
 
-    if (in->pcm) {
-        if(SND_CARD_STATE_OFFLINE == snd_scard_state) {
-            ALOGD(" %s: sound card is not active/SSR state", __func__);
-            ret= -EIO;;
-            goto exit;
-        } else {
-            if (in->is_st_session &&  !in->is_st_session_active) {
-                ALOGD(" %s: Sound trigger is not active/SSR", __func__);
-                ret= -EIO;;
-                goto exit;
-            }
-        }
+    if (in->is_st_session) {
+        ALOGVV(" %s: reading on st session bytes=%zu", __func__, bytes);
+        /* Read from sound trigger HAL */
+        audio_extn_sound_trigger_read(in, buffer, bytes);
+        pthread_mutex_unlock(&in->lock);
+        return bytes;
+    }
+
+    if (in->pcm && (SND_CARD_STATE_OFFLINE == snd_scard_state)) {
+        ALOGD(" %s: sound card is not active/SSR state", __func__);
+        ret= -EIO;;
+        goto exit;
     }
 
     if (in->standby) {
-        if (!in->is_st_session) {
-            pthread_mutex_lock(&adev->lock);
-            if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
-                ret = voice_extn_compress_voip_start_input_stream(in);
-            else
-                ret = start_input_stream(in);
-            pthread_mutex_unlock(&adev->lock);
-            if (ret != 0) {
-                goto exit;
-            }
+        pthread_mutex_lock(&adev->lock);
+        if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
+            ret = voice_extn_compress_voip_start_input_stream(in);
+        else
+            ret = start_input_stream(in);
+        pthread_mutex_unlock(&adev->lock);
+        if (ret != 0) {
+            goto exit;
         }
         in->standby = 0;
     }
@@ -2657,17 +2661,9 @@
 exit:
     /* ToDo: There may be a corner case when SSR happens back to back during
        start/stop. Need to post different error to handle that. */
-    if (-ENETRESET == ret) {
-        /* CPE SSR results in kernel returning ENETRESET for sound trigger
-          session reading on LAB data. In this case do not set sound card state
-          offline, instead mark this sound trigger session inactive to avoid
-          further reading of LAB data from CPE driver. Marking the session
-          inactive handles both CPE and ADSP SSR for sound trigger session */
-        if (!in->is_st_session)
-            set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
-        else
-            in->is_st_session_active = false;
-    }
+    if (-ENETRESET == ret)
+        set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
+
     pthread_mutex_unlock(&in->lock);
 
     if (ret != 0) {
@@ -2787,9 +2783,9 @@
     out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
     out->non_blocking = 0;
     out->use_small_bufs = false;
-
     /* Init use case and pcm_config */
-    if ((out->flags == AUDIO_OUTPUT_FLAG_DIRECT) &&
+    if ((out->flags & AUDIO_OUTPUT_FLAG_DIRECT) &&
+        !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
         (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL ||
         out->devices & AUDIO_DEVICE_OUT_PROXY)) {
 
@@ -2894,7 +2890,7 @@
         }
         out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
         out->compr_config.codec->sample_rate =
-                    compress_get_alsa_rate(config->offload_info.sample_rate);
+                    config->offload_info.sample_rate;
         out->compr_config.codec->bit_rate =
                     config->offload_info.bit_rate;
         out->compr_config.codec->ch_in =
@@ -2931,6 +2927,8 @@
         }
 
         out->send_new_metadata = 1;
+        out->send_next_track_params = false;
+        out->is_compr_metadata_avail = false;
         out->offload_state = OFFLOAD_STATE_IDLE;
         out->playback_started = 0;
 
@@ -3351,6 +3349,7 @@
         if ((mode == AUDIO_MODE_NORMAL || mode == AUDIO_MODE_IN_COMMUNICATION) &&
                 voice_is_in_call(adev)) {
             voice_stop_call(adev);
+            platform_set_gsm_mode(adev->platform, false);
             adev->current_call_output = NULL;
         }
     }
@@ -3386,7 +3385,7 @@
 }
 
 static int adev_open_input_stream(struct audio_hw_device *dev,
-                                  audio_io_handle_t handle __unused,
+                                  audio_io_handle_t handle,
                                   audio_devices_t devices,
                                   struct audio_config *config,
                                   struct audio_stream_in **stream_in,
@@ -3668,6 +3667,7 @@
     list_init(&adev->usecase_list);
     adev->cur_wfd_channels = 2;
     adev->offload_usecases_state = 0;
+    adev->mChannelStatusSet = false;
 
     pthread_mutex_init(&adev->snd_card_status.lock, (const pthread_mutexattr_t *) NULL);
     adev->snd_card_status.state = SND_CARD_STATE_OFFLINE;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 67f5279..dc11e99 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -213,6 +213,8 @@
     void *offload_cookie;
     struct compr_gapless_mdata gapless_mdata;
     int send_new_metadata;
+    bool send_next_track_params;
+    bool is_compr_metadata_avail;
     unsigned int bit_width;
 
     struct audio_device *dev;
@@ -311,6 +313,7 @@
     int snd_card;
     unsigned int cur_codec_backend_samplerate;
     unsigned int cur_codec_backend_bit_width;
+    bool mChannelStatusSet;
     void *platform;
     unsigned int offload_usecases_state;
     void *visualizer_lib;
diff --git a/hal/msm8916/hw_info.c b/hal/msm8916/hw_info.c
index fb36a95..613c1a7 100644
--- a/hal/msm8916/hw_info.c
+++ b/hal/msm8916/hw_info.c
@@ -257,6 +257,12 @@
         hw_info->snd_devices = NULL;
         hw_info->num_snd_devices = 0;
         strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+    }  else if (!strcmp(snd_card_name, "msm8976-skun-snd-card")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8976", sizeof(hw_info->name));
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
     } else {
         ALOGW("%s: Not an  8x16/8939/8909/8952 device", __func__);
     }
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index c9dc59c..94967c8 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -52,6 +52,7 @@
 #define MIXER_XML_PATH_SKUE "/system/etc/mixer_paths_skue.xml"
 #define MIXER_XML_PATH_SKUL "/system/etc/mixer_paths_skul.xml"
 #define MIXER_XML_PATH_SKUM "/system/etc/mixer_paths_qrd_skum.xml"
+#define MIXER_XML_PATH_SKUN_CAJON "/system/etc/mixer_paths_qrd_skun_cajon.xml"
 #define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
 #define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
 #define MIXER_XML_PATH_I2S "/system/etc/mixer_paths_i2s.xml"
@@ -137,6 +138,7 @@
 char cal_name_info[WCD9XXX_MAX_CAL][MAX_CAL_NAME] = {
         [WCD9XXX_ANC_CAL] = "anc_cal",
         [WCD9XXX_MBHC_CAL] = "mbhc_cal",
+        [WCD9XXX_VBAT_CAL] = "vbat_cal",
 };
 
 #define AUDIO_PARAMETER_KEY_REC_PLAY_CONC "rec_play_conc_on"
@@ -189,6 +191,7 @@
 acdb_loader_get_calibration_t acdb_loader_get_calibration;
 typedef int (*acdb_set_audio_cal_t) (void *, void *, uint32_t);
 typedef int (*acdb_get_audio_cal_t) (void *, void *, uint32_t*);
+typedef int (*acdb_set_codec_data_t) (void *, char *);
 
 typedef struct codec_backend_cfg {
     uint32_t sample_rate;
@@ -221,6 +224,9 @@
     bool ec_ref_enabled;
     bool is_wsa_speaker;
     bool is_acdb_initialized;
+    /* Vbat monitor related flags */
+    bool is_vbat_speaker;
+    bool gsm_mode_enabled;
     /* Audio calibration related functions */
     void                       *acdb_handle;
     int                        voice_feature_set;
@@ -232,6 +238,7 @@
     acdb_send_voice_cal_t      acdb_send_voice_cal;
     acdb_reload_vocvoltable_t  acdb_reload_vocvoltable;
     acdb_get_default_app_type_t acdb_get_default_app_type;
+    acdb_set_codec_data_t      acdb_set_codec_data;
 #ifdef RECORD_PLAY_CONCURRENCY
     bool rec_play_conc_set;
 #endif
@@ -323,6 +330,7 @@
     [SND_DEVICE_OUT_SPEAKER_EXTERNAL_1] = "speaker-ext-1",
     [SND_DEVICE_OUT_SPEAKER_EXTERNAL_2] = "speaker-ext-2",
     [SND_DEVICE_OUT_SPEAKER_WSA] = "wsa-speaker",
+    [SND_DEVICE_OUT_SPEAKER_VBAT] = "vbat-speaker",
     [SND_DEVICE_OUT_SPEAKER_REVERSE] = "speaker-reverse",
     [SND_DEVICE_OUT_HEADPHONES] = "headphones",
     [SND_DEVICE_OUT_HEADPHONES_44_1] = "headphones-44.1",
@@ -332,6 +340,7 @@
     [SND_DEVICE_OUT_VOICE_HANDSET] = "voice-handset",
     [SND_DEVICE_OUT_VOICE_SPEAKER] = "voice-speaker",
     [SND_DEVICE_OUT_VOICE_SPEAKER_WSA] = "wsa-voice-speaker",
+    [SND_DEVICE_OUT_VOICE_SPEAKER_VBAT] = "vbat-voice-speaker",
     [SND_DEVICE_OUT_VOICE_HEADPHONES] = "voice-headphones",
     [SND_DEVICE_OUT_HDMI] = "hdmi",
     [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi",
@@ -353,6 +362,8 @@
     [SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset",
     [SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected",
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = "voice-speaker-protected",
+    [SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT] = "speaker-protected-vbat",
+    [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT] = "voice-speaker-protected-vbat",
 #ifdef RECORD_PLAY_CONCURRENCY
     [SND_DEVICE_OUT_VOIP_HANDSET] = "voip-handset",
     [SND_DEVICE_OUT_VOIP_SPEAKER] = "voip-speaker",
@@ -428,6 +439,7 @@
     [SND_DEVICE_OUT_SPEAKER_EXTERNAL_1] = 14,
     [SND_DEVICE_OUT_SPEAKER_EXTERNAL_2] = 14,
     [SND_DEVICE_OUT_SPEAKER_WSA] = 135,
+    [SND_DEVICE_OUT_SPEAKER_VBAT] = 135,
     [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14,
     [SND_DEVICE_OUT_HEADPHONES] = 10,
     [SND_DEVICE_OUT_HEADPHONES_44_1] = 10,
@@ -437,6 +449,7 @@
     [SND_DEVICE_OUT_VOICE_HANDSET] = 7,
     [SND_DEVICE_OUT_VOICE_SPEAKER] = 14,
     [SND_DEVICE_OUT_VOICE_SPEAKER_WSA] = 135,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_VBAT] = 135,
     [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10,
     [SND_DEVICE_OUT_HDMI] = 18,
     [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14,
@@ -458,6 +471,8 @@
     [SND_DEVICE_OUT_ANC_HANDSET] = 103,
     [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 124,
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = 101,
+    [SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT] = 124,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT] = 101,
 #ifdef RECORD_PLAY_CONCURRENCY
     [SND_DEVICE_OUT_VOIP_HANDSET] = 133,
     [SND_DEVICE_OUT_VOIP_SPEAKER] = 132,
@@ -535,6 +550,7 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_EXTERNAL_1)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_EXTERNAL_2)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_WSA)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_VBAT)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_REVERSE)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_HEADPHONES)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_HEADPHONES_44_1)},
@@ -544,6 +560,7 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_WSA)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_VBAT)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_HEADPHONES)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_HDMI)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HDMI)},
@@ -565,6 +582,8 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_ANC_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT)},
 #ifdef RECORD_PLAY_CONCURRENCY
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_SPEAKER)},
@@ -657,6 +676,7 @@
     {TO_NAME_INDEX(USECASE_INCALL_REC_DOWNLINK)},
     {TO_NAME_INDEX(USECASE_INCALL_REC_UPLINK_AND_DOWNLINK)},
     {TO_NAME_INDEX(USECASE_AUDIO_HFP_SCO)},
+    {TO_NAME_INDEX(USECASE_AUDIO_SPKR_CALIB_TX)},
 };
 
 #define NO_COLS 2
@@ -930,7 +950,13 @@
         msm_device_to_be_id = msm_device_to_be_id_internal_codec;
         msm_be_id_array_len  =
             sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
-
+    } else if (!strncmp(snd_card_name, "msm8976-skun-snd-card",
+                 sizeof("msm8976-skun-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_SKUN_CAJON,
+                sizeof(MIXER_XML_PATH_SKUN_CAJON));
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_internal_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
     } else {
         strlcpy(mixer_xml_path, MIXER_XML_PATH,
                 sizeof(MIXER_XML_PATH));
@@ -942,21 +968,43 @@
     }
 }
 
-void platform_set_echo_reference(void *platform, bool enable)
+void platform_set_gsm_mode(void *platform, bool enable)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
     struct audio_device *adev = my_data->adev;
 
+    if (my_data->gsm_mode_enabled) {
+        my_data->gsm_mode_enabled = false;
+        ALOGV("%s: disabling gsm mode", __func__);
+        audio_route_reset_and_update_path(adev->audio_route, "gsm-mode");
+    }
+
+    if (enable) {
+         my_data->gsm_mode_enabled = true;
+         ALOGD("%s: enabling gsm mode", __func__);
+         audio_route_apply_and_update_path(adev->audio_route, "gsm-mode");
+    }
+}
+
+void platform_set_echo_reference(void *platform, bool enable)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    char *mixer_path_name = "echo-reference";
+
+    if(my_data->is_vbat_speaker)
+       mixer_path_name = "vbat-speaker echo-reference";
+
     if (my_data->ec_ref_enabled) {
         my_data->ec_ref_enabled = false;
         ALOGV("%s: disabling echo-reference", __func__);
-        audio_route_reset_and_update_path(adev->audio_route, "echo-reference");
+        audio_route_reset_and_update_path(adev->audio_route, mixer_path_name);
     }
 
     if (enable) {
          my_data->ec_ref_enabled = true;
          ALOGD("%s: enabling echo-reference", __func__);
-         audio_route_apply_and_update_path(adev->audio_route, "echo-reference");
+         audio_route_apply_and_update_path(adev->audio_route, mixer_path_name);
     }
 }
 
@@ -1135,6 +1183,7 @@
     backend_table[SND_DEVICE_IN_CAPTURE_FM] = strdup("capture-fm");
     backend_table[SND_DEVICE_OUT_TRANSMISSION_FM] = strdup("transmission-fm");
     backend_table[SND_DEVICE_OUT_HEADPHONES_44_1] = strdup("headphones-44.1");
+    backend_table[SND_DEVICE_OUT_VOICE_SPEAKER_VBAT] = strdup("vbat-voice-speaker");
 }
 
 void get_cvd_version(char *cvd_version, struct audio_device *adev)
@@ -1190,7 +1239,37 @@
     void   *buff;
 };
 
-static int send_codec_cal(acdb_loader_get_calibration_t acdb_loader_get_calibration, int fd)
+static int send_vbat_adc_data_to_acdb(struct platform_data *plat_data, char *cal_type)
+{
+    int ret = 0;
+    struct mixer_ctl *ctl;
+    uint16_t vbat_adc_data[2];
+    struct platform_data *my_data = plat_data;
+    struct audio_device *adev = my_data->adev;
+
+    const char *mixer_ctl_name = "Vbat ADC data";
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer ctl name - %s",
+               __func__, mixer_ctl_name);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    vbat_adc_data[0] = mixer_ctl_get_value(ctl, 0);
+    vbat_adc_data[1] = mixer_ctl_get_value(ctl, 1);
+
+    ALOGD("%s: Vbat ADC output values: Dcp1: %d , Dcp2: %d",
+           __func__, vbat_adc_data[0], vbat_adc_data[1]);
+
+    ret = my_data->acdb_set_codec_data(&vbat_adc_data[0], cal_type);
+
+done:
+    return ret;
+}
+
+static int send_codec_cal(acdb_loader_get_calibration_t acdb_loader_get_calibration, struct platform_data *plat_data, int fd)
 {
     int ret = 0, type;
 
@@ -1198,6 +1277,12 @@
         struct wcdcal_ioctl_buffer codec_buffer;
         struct param_data calib;
 
+        if((plat_data->is_vbat_speaker) && (WCD9XXX_VBAT_CAL == type)) {
+           ret = send_vbat_adc_data_to_acdb(plat_data, cal_name_info[type]);
+           if (ret < 0)
+               ALOGE("%s error in sending vbat adc data to acdb", __func__);
+	}
+
         calib.get_size = 1;
         ret = acdb_loader_get_calibration(cal_name_info[type], sizeof(struct param_data),
                                                                  &calib);
@@ -1251,16 +1336,34 @@
            dlerror());
         return;
     }
-    if (send_codec_cal(acdb_loader_get_calibration, fd) < 0)
+    if (send_codec_cal(acdb_loader_get_calibration, plat_data, fd) < 0)
         ALOGE("%s: Could not send anc cal", __FUNCTION__);
 }
 
+const char * get_snd_card_name_for_acdb_loader(const char *snd_card_name) {
+
+    if(snd_card_name == NULL)
+        return NULL;
+
+    // Both tasha & tasha-lite uses tasha ACDB files
+    // simulate sound card name for tasha lite, so that
+    // ACDB module loads tasha ACDB files for tasha lite
+    if(!strncmp(snd_card_name, "msm8976-tashalite-snd-card",
+             sizeof("msm8976-tashalite-snd-card"))) {
+       ALOGD("using tasha ACDB files for tasha-lite");
+       return "msm8976-tasha-snd-card";
+   } else {
+       return snd_card_name;
+   }
+}
+
+
 int platform_acdb_init(void *platform)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
     char *cvd_version = NULL;
     int key = 0;
-    const char *snd_card_name;
+    const char *snd_card_name, *acdb_snd_card_name;
     int result;
     char value[PROPERTY_VALUE_MAX];
     cvd_version = calloc(1, MAX_CVD_VERSION_STRING_SIZE);
@@ -1272,7 +1375,10 @@
     property_get("audio.ds1.metainfo.key",value,"0");
     key = atoi(value);
     snd_card_name = mixer_get_name(my_data->adev->mixer);
-    result = my_data->acdb_init(snd_card_name, cvd_version, key);
+    acdb_snd_card_name = get_snd_card_name_for_acdb_loader(snd_card_name);
+
+    result = my_data->acdb_init(acdb_snd_card_name, cvd_version, key);
+
     if (cvd_version)
         free(cvd_version);
     if (!result) {
@@ -1286,6 +1392,61 @@
     return result;
 }
 
+#define MAX_PATH             (256)
+#define THERMAL_SYSFS "/sys/class/thermal"
+#define TZ_TYPE "/sys/class/thermal/thermal_zone%d/type"
+#define TZ_WSA "/sys/class/thermal/thermal_zone%d/temp"
+
+bool is_wsa_found(void)
+{
+    DIR *tdir = NULL;
+    struct dirent *tdirent = NULL;
+    int tzn = 0;
+    char name[MAX_PATH] = {0};
+    char cwd[MAX_PATH] = {0};
+    char file[10] = "wsa";
+    bool found = false;
+
+    if (!getcwd(cwd, sizeof(cwd)))
+        return false;
+
+    chdir(THERMAL_SYSFS); /* Change dir to read the entries. Doesnt work
+                             otherwise */
+    tdir = opendir(THERMAL_SYSFS);
+    if (!tdir) {
+        ALOGE("Unable to open %s\n", THERMAL_SYSFS);
+        return false;
+    }
+
+    while ((tdirent = readdir(tdir))) {
+        char buf[50];
+        struct dirent *tzdirent;
+        DIR *tzdir = NULL;
+
+        tzdir = opendir(tdirent->d_name);
+        if (!tzdir)
+            continue;
+        while ((tzdirent = readdir(tzdir))) {
+            if (strcmp(tzdirent->d_name, "type"))
+                continue;
+            snprintf(name, MAX_PATH, TZ_TYPE, tzn);
+            ALOGD("Opening %s\n", name);
+            read_line_from_file(name, buf, sizeof(buf));
+            if (strstr(buf, file)) {
+                found = true;
+                break;
+            }
+            tzn++;
+        }
+        closedir(tzdir);
+        if (found == true)
+            break;
+    }
+    closedir(tdir);
+    chdir(cwd); /* Restore current working dir */
+    return found;
+}
+
 void *platform_init(struct audio_device *adev)
 {
     char platform[PROPERTY_VALUE_MAX];
@@ -1418,6 +1579,12 @@
         acdb_device_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 131;
     }
 
+    /* Check if Vbat speaker enabled property is set, this should be done before acdb init */
+    bool ret = false;
+    ret = audio_extn_can_use_vbat();
+    if (ret)
+        my_data->is_vbat_speaker = true;
+
     my_data->voice_feature_set = VOICE_FEATURE_SET_DEFAULT;
     my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
     if (my_data->acdb_handle == NULL) {
@@ -1467,6 +1634,14 @@
             ALOGE("%s: Could not find the symbol acdb_get_default_app_type from %s",
                   __func__, LIB_ACDB_LOADER);
 
+        my_data->acdb_set_codec_data = (acdb_set_codec_data_t)dlsym(
+                                                    my_data->acdb_handle,
+                                                    "acdb_loader_set_codec_data");
+        if (!my_data->acdb_set_codec_data)
+            ALOGE("%s: Could not find the symbol acdb_get_default_app_type from %s",
+                  __func__, LIB_ACDB_LOADER);
+
+
         my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_init_v2");
         if (my_data->acdb_init == NULL) {
@@ -1477,24 +1652,8 @@
     }
     audio_extn_pm_vote();
 
-    // Check if WSA speaker is supported in codec
-    char CodecPeek[1024] = "/sys/kernel/debug/asoc/";
-    DIR *dir;
-    struct dirent *dirent;
-    char file_name[10] = "wsa";
-    strlcat(CodecPeek, snd_card_name, sizeof(CodecPeek));
-
-    dir = opendir(CodecPeek);
-    if (dir != NULL) {
-        while (NULL != (dirent = readdir(dir))) {
-            if (strstr (dirent->d_name,file_name))
-            {
-                my_data->is_wsa_speaker = true;
-                break;
-            }
-        }
-        closedir(dir);
-    }
+    if (is_wsa_found())
+        my_data->is_wsa_speaker = true;
 
     /* Configure active back end for HPX*/
     ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
@@ -1526,7 +1685,6 @@
     audio_extn_dap_hal_init(adev->snd_card);
 
     audio_extn_dolby_set_license(adev);
-    audio_hwdep_send_cal(my_data);
 
     /* init audio device arbitration */
     audio_extn_dev_arbi_init();
@@ -1620,13 +1778,20 @@
     return 0;
 }
 
-void platform_add_backend_name(char *mixer_path, snd_device_t snd_device)
+void platform_add_backend_name(char *mixer_path, snd_device_t snd_device,
+                               struct audio_usecase *usecase)
 {
     if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
         ALOGE("%s: Invalid snd_device = %d", __func__, snd_device);
         return;
     }
 
+    if((snd_device == SND_DEVICE_OUT_VOICE_SPEAKER_VBAT) &&
+        !(usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)) {
+        ALOGI("%s: Not adding vbat speaker device to non voice use cases", __func__);
+        return;
+    }
+
     const char * suffix = backend_table[snd_device];
 
     if (suffix != NULL) {
@@ -1810,7 +1975,7 @@
 {
     if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
         ALOGE("%s: Invalid snd_device = %d", __func__, snd_device);
-        return DEFAULT_OUTPUT_SAMPLING_RATE;
+        return CODEC_BACKEND_DEFAULT_BIT_WIDTH;
     }
     return backend_bit_width_table[snd_device];
 }
@@ -1991,9 +2156,12 @@
         return ret;
 
     if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER &&
-        audio_extn_spkr_prot_is_enabled())
-        acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED];
-    else
+        audio_extn_spkr_prot_is_enabled()) {
+        if (my_data->is_vbat_speaker)
+            acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT];
+        else
+            acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED];
+    } else
         acdb_rx_id = acdb_device_table[out_snd_device];
 
     acdb_tx_id = acdb_device_table[in_snd_device];
@@ -2051,9 +2219,12 @@
         return ret;
 
     if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER &&
-        audio_extn_spkr_prot_is_enabled())
-        acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED];
-    else
+        audio_extn_spkr_prot_is_enabled()) {
+        if (my_data->is_vbat_speaker)
+            acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT];
+         else
+            acdb_rx_id = acdb_device_table[SND_DEVICE_OUT_SPEAKER_PROTECTED];
+    } else
         acdb_rx_id = acdb_device_table[out_snd_device];
 
     acdb_tx_id = acdb_device_table[in_snd_device];
@@ -2315,7 +2486,9 @@
             else
                 snd_device = SND_DEVICE_OUT_BT_SCO;
         } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
-                if (my_data->is_wsa_speaker)
+                if (my_data->is_vbat_speaker)
+                    snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_VBAT;
+                else if (my_data->is_wsa_speaker)
                     snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_WSA;
                 else
                     snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
@@ -2375,7 +2548,9 @@
                 snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
             else
             {
-                if (my_data->is_wsa_speaker)
+                if (my_data->is_vbat_speaker)
+                    snd_device = SND_DEVICE_OUT_SPEAKER_VBAT;
+                else if (my_data->is_wsa_speaker)
                     snd_device = SND_DEVICE_OUT_SPEAKER_WSA;
                 else
                     snd_device = SND_DEVICE_OUT_SPEAKER;
@@ -3784,6 +3959,16 @@
             sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
         }
     }
+
+    /*
+     * Sample rate greater than 48K is only supported by external codecs on
+     * specific devices e.g. Headphones, reset the sample rate to
+     * default value if not external codec.
+     */
+    if (!is_external_codec)
+        sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+
+
     ALOGI("%s Codec selected backend: %d updated bit width: %d and sample rate: %d",
                __func__, backend_idx, bit_width, sample_rate);
     // Force routing if the expected bitwdith or samplerate
@@ -4011,14 +4196,15 @@
     edid_data[0] = count;
     memcpy(&edid_data[1], block, count);
 
-#ifdef AUDIO_FEATURE_ENABLED_HDMI_EDID
+#ifdef HDMI_EDID_ENABLED
     if (!edid_get_sink_caps(info, edid_data)) {
         ALOGE("%s: Failed to get HDMI sink capabilities", __func__);
         goto fail;
     }
+#endif
+
     my_data->edid_valid = true;
     return 0;
-#endif
 fail:
     if (my_data->edid_info) {
         free(my_data->edid_info);
@@ -4494,13 +4680,14 @@
     return ret;
 }
 
-int platform_get_wsa_mode(void *platform)
+int platform_get_wsa_mode(void *adev)
 {
-    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev_h = adev;
     char *snd_card_name;
 
-    snd_card_name = mixer_get_name(my_data->adev->mixer);
+    snd_card_name = mixer_get_name(adev_h->mixer);
     if ((!strcmp(snd_card_name, "msm8952-skum-snd-card")) ||
+        (!strcmp(snd_card_name, "msm8952-snd-card")) ||
         (!strcmp(snd_card_name, "msm8952-snd-card-mtp")))
         return 1;
     else
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index 9f0015a..bf5e834 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -47,6 +47,15 @@
     (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | \
      AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE)
 
+/*
+ * Below are the input devices for which back end is same, SLIMBUS_0_TX.
+ * All these devices are handled by the internal HW codec. We can
+ * enable any one of these devices at any time
+ */
+#define AUDIO_DEVICE_IN_ALL_CODEC_BACKEND \
+    (AUDIO_DEVICE_IN_BUILTIN_MIC | AUDIO_DEVICE_IN_BACK_MIC | \
+     AUDIO_DEVICE_IN_WIRED_HEADSET | AUDIO_DEVICE_IN_VOICE_CALL) & ~AUDIO_DEVICE_BIT_IN
+
 /* Sound devices specific to the platform
  * The DEVICE_OUT_* and DEVICE_IN_* should be mapped to these sound
  * devices to enable corresponding mixer paths
@@ -63,6 +72,7 @@
     SND_DEVICE_OUT_SPEAKER_EXTERNAL_2,
     SND_DEVICE_OUT_SPEAKER_REVERSE,
     SND_DEVICE_OUT_SPEAKER_WSA,
+    SND_DEVICE_OUT_SPEAKER_VBAT,
     SND_DEVICE_OUT_HEADPHONES,
     SND_DEVICE_OUT_HEADPHONES_44_1,
     SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
@@ -71,6 +81,7 @@
     SND_DEVICE_OUT_VOICE_HANDSET,
     SND_DEVICE_OUT_VOICE_SPEAKER,
     SND_DEVICE_OUT_VOICE_SPEAKER_WSA,
+    SND_DEVICE_OUT_VOICE_SPEAKER_VBAT,
     SND_DEVICE_OUT_VOICE_HEADPHONES,
     SND_DEVICE_OUT_HDMI,
     SND_DEVICE_OUT_SPEAKER_AND_HDMI,
@@ -92,6 +103,8 @@
     SND_DEVICE_OUT_ANC_HANDSET,
     SND_DEVICE_OUT_SPEAKER_PROTECTED,
     SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED,
+    SND_DEVICE_OUT_SPEAKER_PROTECTED_VBAT,
+    SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED_VBAT,
 #ifdef RECORD_PLAY_CONCURRENCY
     SND_DEVICE_OUT_VOIP_HANDSET,
     SND_DEVICE_OUT_VOIP_SPEAKER,
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 6212f23..a35b4f1 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -382,7 +382,7 @@
     return 0;
 }
 
-void platform_add_backend_name(char *mixer_path, snd_device_t snd_device)
+void platform_add_backend_name(char *mixer_path, snd_device_t snd_device, struct audio_usecase *usecase)
 {
     if (snd_device == SND_DEVICE_IN_BT_SCO_MIC)
         strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
@@ -1176,7 +1176,7 @@
     return -ENOSYS;
 }
 
-int platform_get_wsa_mode(void *platform)
+int platform_get_wsa_mode(void *adev)
 {
     return 0;
 }
diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h
index 4b4d14e..aab5436 100644
--- a/hal/msm8960/platform.h
+++ b/hal/msm8960/platform.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013, 2015 The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -35,6 +35,15 @@
     (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | \
      AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE)
 
+/*
+ * Below are the input devices for which back end is same, SLIMBUS_0_TX.
+ * All these devices are handled by the internal HW codec. We can
+ * enable any one of these devices at any time
+ */
+#define AUDIO_DEVICE_IN_ALL_CODEC_BACKEND \
+    (AUDIO_DEVICE_IN_BUILTIN_MIC | AUDIO_DEVICE_IN_BACK_MIC | \
+     AUDIO_DEVICE_IN_WIRED_HEADSET | AUDIO_DEVICE_IN_VOICE_CALL) & ~AUDIO_DEVICE_BIT_IN
+
 /* Sound devices specific to the platform
  * The DEVICE_OUT_* and DEVICE_IN_* should be mapped to these sound
  * devices to enable corresponding mixer paths
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 019a889..f2d975f 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1440,7 +1440,7 @@
     return 0;
 }
 
-void platform_add_backend_name(char *mixer_path, snd_device_t snd_device)
+void platform_add_backend_name(char *mixer_path, snd_device_t snd_device, struct audio_usecase *usecase)
 {
     if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
         ALOGE("%s: Invalid snd_device = %d", __func__, snd_device);
@@ -4093,7 +4093,7 @@
     return ret;
 }
 
-int platform_get_wsa_mode (void *platform)
+int platform_get_wsa_mode (void *adev)
 {
     return 0;
 }
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 4b90f8b..79e0816 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -45,6 +45,15 @@
     (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | \
      AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE)
 
+/*
+ * Below are the input devices for which back end is same, SLIMBUS_0_TX.
+ * All these devices are handled by the internal HW codec. We can
+ * enable any one of these devices at any time
+ */
+#define AUDIO_DEVICE_IN_ALL_CODEC_BACKEND \
+    (AUDIO_DEVICE_IN_BUILTIN_MIC | AUDIO_DEVICE_IN_BACK_MIC | \
+     AUDIO_DEVICE_IN_WIRED_HEADSET | AUDIO_DEVICE_IN_VOICE_CALL) & ~AUDIO_DEVICE_BIT_IN
+
 /* Sound devices specific to the platform
  * The DEVICE_OUT_* and DEVICE_IN_* should be mapped to these sound
  * devices to enable corresponding mixer paths
diff --git a/hal/platform_api.h b/hal/platform_api.h
index d8fa8fa..15f9225 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -31,7 +31,7 @@
 const char *platform_get_snd_device_name(snd_device_t snd_device);
 int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device,
                                       char *device_name);
-void platform_add_backend_name(char *mixer_path, snd_device_t snd_device);
+void platform_add_backend_name(char *mixer_path, snd_device_t snd_device, struct audio_usecase *usecase);
 int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type);
 int platform_get_snd_device_index(char *snd_device_index_name);
 int platform_set_fluence_type(void *platform, char *value);
@@ -121,5 +121,6 @@
                                        const char *spkr_1_tz_name, const char *spkr_2_tz_name);
 const char *platform_get_spkr_1_tz_name(snd_device_t snd_device);
 const char *platform_get_spkr_2_tz_name(snd_device_t snd_device);
-int platform_get_wsa_mode(void *platform);
+int platform_get_wsa_mode(void *adev);
+void platform_set_gsm_mode(void *platform, bool enable);
 #endif // AUDIO_PLATFORM_API_H
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
index b806bab..c408709 100644
--- a/hal/voice_extn/voice_extn.c
+++ b/hal/voice_extn/voice_extn.c
@@ -41,6 +41,7 @@
 #define AUDIO_PARAMETER_KEY_DEVICE_MUTE         "device_mute"
 #define AUDIO_PARAMETER_KEY_DIRECTION           "direction"
 #define AUDIO_PARAMETER_KEY_IN_CALL             "in_call"
+#define AUDIO_PARAMETER_KEY_CALL_TYPE           "call_type"
 
 #define VOICE_EXTN_PARAMETER_VALUE_MAX_LEN 256
 
@@ -514,6 +515,20 @@
         }
     }
 
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_CALL_TYPE, str_value,
+                            sizeof(str_value));
+    if (err >= 0) {
+          str_parms_del(parms, AUDIO_PARAMETER_KEY_CALL_TYPE);
+          ALOGD("%s: call type is %s",__func__,str_value);
+
+           /* Expected call types are CDMA/GSM/WCDMA/LTE/TDSDMA/WLAN/UNKNOWN */
+           if (!strncmp("GSM", str_value, sizeof("GSM"))) {
+               platform_set_gsm_mode(adev->platform, true);
+           } else {
+               platform_set_gsm_mode(adev->platform, false);
+           }
+    }
+
 done:
     ALOGV("%s: exit with code(%d)", __func__, ret);
     free(kv_pairs);
diff --git a/post_proc/EffectsHwAcc.cpp b/post_proc/EffectsHwAcc.cpp
index 0e4c55a..e11cfc7 100644
--- a/post_proc/EffectsHwAcc.cpp
+++ b/post_proc/EffectsHwAcc.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-15, 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
@@ -72,7 +72,7 @@
     size_t reqOutputFrameCount = pBuffer->frameCount;
     int ret = 0;
 
-    if (mTrackBufferProvider != NULL) {
+    if (mTrackInputBufferProvider != NULL) {
         while (1) {
             reqInputFrameCount = ((reqOutputFrameCount *
                                    mEffectsConfig.inputCfg.samplingRate)/
@@ -89,7 +89,7 @@
                      popcount(mEffectsConfig.inputCfg.channels);
             while (frameCount) {
                 pBuffer->frameCount = frameCount;
-                ret = mTrackBufferProvider->getNextBuffer(pBuffer, pts);
+                ret = mTrackInputBufferProvider->getNextBuffer(pBuffer, pts);
                 if (ret == OK) {
                     int bytesInBuffer = pBuffer->frameCount *
                                         FRAME_SIZE(mEffectsConfig.inputCfg.format) *
@@ -98,7 +98,7 @@
                     frameCount -= pBuffer->frameCount;
                     mInputBufferFrameCountOffset += pBuffer->frameCount;
                     offset += bytesInBuffer;
-                    mTrackBufferProvider->releaseBuffer(pBuffer);
+                    mTrackInputBufferProvider->releaseBuffer(pBuffer);
                 } else
                     break;
             }
@@ -133,7 +133,7 @@
                                           AudioBufferProvider::Buffer *pBuffer)
 {
     ALOGV("EffBufferProvider::releaseBuffer()");
-    if (this->mTrackBufferProvider != NULL) {
+    if (this->mTrackInputBufferProvider != NULL) {
         pBuffer->frameCount = 0;
         pBuffer->raw = NULL;
     } else {
@@ -189,7 +189,8 @@
     mEnabled = false;
 }
 
-status_t EffectsHwAcc::prepareEffects(AudioBufferProvider **bufferProvider,
+status_t EffectsHwAcc::prepareEffects(AudioBufferProvider **inputBufferProvider,
+                                      AudioBufferProvider **bufferProvider,
                                       int sessionId,
                                       audio_channel_mask_t channelMask,
                                       int frameCount)
@@ -316,10 +317,11 @@
         goto noEffectsForActiveTrack;
     }
     // initialization successful:
-    // - keep track of the real buffer provider in case it was set before
+    // - keep backup of track's buffer provider
     pHwAccbp->mTrackBufferProvider = *bufferProvider;
-    // - we'll use the hw acc effect integrated inside this
-    //    track's buffer provider, and we'll use it as the track's buffer provider
+    pHwAccbp->mTrackInputBufferProvider = *inputBufferProvider;
+    // - we'll use the hw acc effect integrated inside this track's buffer provider,
+    //   and we'll use it as the track's buffer provider
     mBufferProvider = pHwAccbp;
     *bufferProvider = pHwAccbp;
 
@@ -332,14 +334,14 @@
     return NO_INIT;
 }
 
-void EffectsHwAcc::setBufferProvider(AudioBufferProvider **bufferProvider,
+void EffectsHwAcc::setBufferProvider(AudioBufferProvider **trackInputBufferProvider,
                                      AudioBufferProvider **trackBufferProvider)
 {
     ALOGV("setBufferProvider");
     if (mBufferProvider &&
-        (mBufferProvider->mTrackBufferProvider != *bufferProvider)) {
+        (mBufferProvider->mTrackInputBufferProvider != *trackInputBufferProvider)) {
         *trackBufferProvider = mBufferProvider;
-        mBufferProvider->mTrackBufferProvider = *bufferProvider;
+        mBufferProvider->mTrackInputBufferProvider = *trackInputBufferProvider;
     }
 }
 
diff --git a/post_proc/EffectsHwAcc.h b/post_proc/EffectsHwAcc.h
index 6420a9b..0452f57 100644
--- a/post_proc/EffectsHwAcc.h
+++ b/post_proc/EffectsHwAcc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-15, 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
@@ -43,10 +43,11 @@
 
     virtual void setSampleRate(uint32_t inpSR, uint32_t outSR);
     virtual void unprepareEffects(AudioBufferProvider **trackBufferProvider);
-    virtual status_t prepareEffects(AudioBufferProvider **trackBufferProvider,
+    virtual status_t prepareEffects(AudioBufferProvider **trackInputBufferProvider,
+                            AudioBufferProvider **trackBufferProvider,
                             int sessionId, audio_channel_mask_t channelMask,
                             int frameCount);
-    virtual void setBufferProvider(AudioBufferProvider **bufferProvider,
+    virtual void setBufferProvider(AudioBufferProvider **trackInputbufferProvider,
                            AudioBufferProvider **trackBufferProvider);
 #ifdef HW_ACC_HPX
     virtual void updateHPXState(uint32_t state);
@@ -62,6 +63,7 @@
         virtual status_t getNextBuffer(Buffer* buffer, int64_t pts);
         virtual void releaseBuffer(Buffer* buffer);
 
+        AudioBufferProvider* mTrackInputBufferProvider;
         AudioBufferProvider* mTrackBufferProvider;
         effect_handle_t    mEffectsHandle;
         effect_config_t    mEffectsConfig;
diff --git a/post_proc/reverb.c b/post_proc/reverb.c
index b256e53..450ce81 100644
--- a/post_proc/reverb.c
+++ b/post_proc/reverb.c
@@ -281,17 +281,19 @@
     context->next_preset = preset;
     offload_reverb_set_preset(&(context->offload_reverb), preset);
 
-    enable = (preset == REVERB_PRESET_NONE) ? false: true;
-    offload_reverb_set_enable_flag(&(context->offload_reverb), enable);
+    if (context->enabled_by_client) {
+        enable = (preset == REVERB_PRESET_NONE) ? false: true;
+        offload_reverb_set_enable_flag(&(context->offload_reverb), enable);
 
-    if (context->ctl)
-        offload_reverb_send_params(context->ctl, &context->offload_reverb,
+        if (context->ctl)
+            offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_PRESET);
-    if (context->hw_acc_fd > 0)
-        hw_acc_reverb_send_params(context->hw_acc_fd, &context->offload_reverb,
+        if (context->hw_acc_fd > 0)
+            hw_acc_reverb_send_params(context->hw_acc_fd, &context->offload_reverb,
                                   OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                   OFFLOAD_SEND_REVERB_PRESET);
+    }
 }
 
 void reverb_set_all_properties(reverb_context_t *context,
@@ -600,6 +602,7 @@
     set_config(context, &context->config);
 
     reverb_ctxt->hw_acc_fd = -1;
+    reverb_ctxt->enabled_by_client = false;
     memset(&(reverb_ctxt->reverb_settings), 0, sizeof(reverb_settings_t));
     memset(&(reverb_ctxt->offload_reverb), 0, sizeof(struct reverb_params));
 
@@ -615,6 +618,16 @@
     reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
 
     ALOGV("%s: ctxt %p", __func__, reverb_ctxt);
+    reverb_ctxt->enabled_by_client = true;
+
+    /* REVERB_PRESET_NONE is equivalent to disabled state,
+     * But support for this state is not provided in DSP.
+     * Hence, do not set enable flag, if in peset mode with preset "NONE".
+     * Effect would be enabled when valid preset is set.
+     */
+    if ((reverb_ctxt->preset == true) &&
+        (reverb_ctxt->next_preset == REVERB_PRESET_NONE))
+        return 0;
 
     if (!offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb)))
         offload_reverb_set_enable_flag(&(reverb_ctxt->offload_reverb), true);
@@ -626,6 +639,7 @@
     reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
 
     ALOGV("%s: ctxt %p", __func__, reverb_ctxt);
+    reverb_ctxt->enabled_by_client = false;
     if (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))) {
         offload_reverb_set_enable_flag(&(reverb_ctxt->offload_reverb), false);
         if (reverb_ctxt->ctl)
diff --git a/post_proc/reverb.h b/post_proc/reverb.h
index 991151e..1a5ca0d 100644
--- a/post_proc/reverb.h
+++ b/post_proc/reverb.h
@@ -48,6 +48,7 @@
     // Offload vars
     struct mixer_ctl *ctl;
     int hw_acc_fd;
+    bool enabled_by_client;
     bool auxiliary;
     bool preset;
     uint16_t cur_preset;
diff --git a/post_proc/virtualizer.c b/post_proc/virtualizer.c
index 2748568..3874f0b 100644
--- a/post_proc/virtualizer.c
+++ b/post_proc/virtualizer.c
@@ -56,6 +56,15 @@
     ALOGV("%s: ctxt %p, strength: %d", __func__, context, strength);
     context->strength = strength;
 
+    /*
+     *  Zero strength is not equivalent to disable state as down mix
+     *  is still happening for multichannel inputs.
+     *  For better user experience, explicitly disable virtualizer module
+     *  when strength is 0.
+     */
+    offload_virtualizer_set_enable_flag(&(context->offload_virt),
+                                        ((strength > 0) && !(context->temp_disabled)) ?
+                                        true : false);
     offload_virtualizer_set_strength(&(context->offload_virt), strength);
     if (context->ctl)
         offload_virtualizer_send_params(context->ctl, &context->offload_virt,