hal: remote merge from master to LA.BR.1 branch

- Merge commit 'b87c2eeacfec214f198169319b11e4aca8ab8e87'

Conflicts:
	hal/Android.mk
	hal/audio_extn/audio_extn.c
	hal/audio_extn/audio_extn.h
	hal/audio_extn/dolby.c
	hal/audio_hw.c
	hal/msm8916/hw_info.c
	hal/msm8916/platform.c
	hal/msm8916/platform.h
	hal/msm8974/platform.c
	hal/platform_api.h
	policy_hal/AudioPolicyManager.cpp

Change-Id: Ic9e8a18a5d82719b02038999c92c9991f843981b
diff --git a/Android.mk b/Android.mk
index bc466ed..6e129a1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,4 +1,4 @@
-ifneq ($(filter mpq8092 msm8960 msm8226 msm8x26 msm8610 msm8974 msm8x74 apq8084 msm8916 msm8994 msm8909,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter mpq8092 msm8960 msm8226 msm8x26 msm8610 msm8974 msm8x74 apq8084 msm8916 msm8994 msm8992 msm8909 msm8996 msm8952,$(TARGET_BOARD_PLATFORM)),)
 
 MY_LOCAL_PATH := $(call my-dir)
 
diff --git a/hal/Android.mk b/hal/Android.mk
index ea7d799..4e5f846 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -8,7 +8,7 @@
 
 AUDIO_PLATFORM := $(TARGET_BOARD_PLATFORM)
 
-ifneq ($(filter msm8974 msm8226 msm8610 apq8084 msm8994,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8974 msm8226 msm8610 apq8084 msm8994 msm8992 msm8996,$(TARGET_BOARD_PLATFORM)),)
   # B-family platform uses msm8974 code base
   AUDIO_PLATFORM = msm8974
   MULTIPLE_HW_VARIANTS_ENABLED := true
@@ -24,9 +24,15 @@
 ifneq ($(filter msm8994,$(TARGET_BOARD_PLATFORM)),)
   LOCAL_CFLAGS := -DPLATFORM_MSM8994
 endif
+ifneq ($(filter msm8992,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_CFLAGS := -DPLATFORM_MSM8994
+endif
+ifneq ($(filter msm8996,$(TARGET_BOARD_PLATFORM)),)
+  LOCAL_CFLAGS := -DPLATFORM_MSM8996
+endif
 endif
 
-ifneq ($(filter msm8916 msm8909,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8916 msm8909 msm8952,$(TARGET_BOARD_PLATFORM)),)
   AUDIO_PLATFORM = msm8916
   MULTIPLE_HW_VARIANTS_ENABLED := true
   LOCAL_CFLAGS := -DPLATFORM_MSM8916
@@ -46,6 +52,14 @@
 LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
 LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HDMI_EDID)),true)
+    LOCAL_SRC_FILES += edid.c
+endif
+
+ifeq ($(strip $(AUDIO_USE_LL_AS_PRIMARY_OUTPUT)),true)
+    LOCAL_CFLAGS += -DUSE_LL_AS_PRIMARY_OUTPUT
+endif
+
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PCM_OFFLOAD)),true)
     LOCAL_CFLAGS += -DPCM_OFFLOAD_ENABLED
 endif
@@ -125,6 +139,11 @@
     LOCAL_SRC_FILES += audio_extn/compress_capture.c
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_DTS_EAGLE)),true)
+    LOCAL_CFLAGS += -DDTS_EAGLE
+    LOCAL_SRC_FILES += audio_extn/dts_eagle.c
+endif
+
 ifeq ($(strip $(DOLBY_DDP)),true)
     LOCAL_CFLAGS += -DDS1_DOLBY_DDP_ENABLED
     LOCAL_SRC_FILES += audio_extn/dolby.c
@@ -142,7 +161,33 @@
 endif
 
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_FLAC_DECODER)),true)
-    LOCAL_CFLAGS += -DQTI_FLAC_DECODER
+    LOCAL_CFLAGS += -DFLAC_OFFLOAD_ENABLED
+    LOCAL_CFLAGS += -DCOMPRESS_METADATA_NEEDED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_VORBIS_OFFLOAD)),true)
+    LOCAL_CFLAGS += -DVORBIS_OFFLOAD_ENABLED
+    LOCAL_CFLAGS += -DCOMPRESS_METADATA_NEEDED
+
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_WMA_OFFLOAD)),true)
+    LOCAL_CFLAGS += -DWMA_OFFLOAD_ENABLED
+    LOCAL_CFLAGS += -DCOMPRESS_METADATA_NEEDED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_ALAC_OFFLOAD)),true)
+    LOCAL_CFLAGS += -DALAC_OFFLOAD_ENABLED
+    LOCAL_CFLAGS += -DCOMPRESS_METADATA_NEEDED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_APE_OFFLOAD)),true)
+    LOCAL_CFLAGS += -DAPE_OFFLOAD_ENABLED
+    LOCAL_CFLAGS += -DCOMPRESS_METADATA_NEEDED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PCM_OFFLOAD_24)),true)
+       LOCAL_CFLAGS += -DPCM_OFFLOAD_ENABLED_24
 endif
 
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_DEV_ARBI)),true)
@@ -167,6 +212,19 @@
 endif
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HDMI_PASSTHROUGH)),true)
+    LOCAL_CFLAGS += -DHDMI_PASSTHROUGH_ENABLED
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_SOURCE_TRACKING)),true)
+    LOCAL_CFLAGS += -DSOURCE_TRACKING_ENABLED
+    LOCAL_SRC_FILES += audio_extn/source_track.c
+endif
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AUDIOSPHERE)),true)
+    LOCAL_CFLAGS += -DAUDIOSPHERE_ENABLED
+endif
+
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
 	libcutils \
diff --git a/hal/audio_extn/audio_defs.h b/hal/audio_extn/audio_defs.h
index 335a629..96b0a8b 100644
--- a/hal/audio_extn/audio_defs.h
+++ b/hal/audio_extn/audio_defs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015, 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
@@ -48,6 +48,30 @@
 #define AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE "music_offload_flac_min_frame_size"
 #define AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE "music_offload_flac_max_frame_size"
 
+#define AUDIO_OFFLOAD_CODEC_ALAC_FRAME_LENGTH "music_offload_alac_frame_length"
+#define AUDIO_OFFLOAD_CODEC_ALAC_COMPATIBLE_VERSION "music_offload_alac_compatible_version"
+#define AUDIO_OFFLOAD_CODEC_ALAC_BIT_DEPTH "music_offload_alac_bit_depth"
+#define AUDIO_OFFLOAD_CODEC_ALAC_PB "music_offload_alac_pb"
+#define AUDIO_OFFLOAD_CODEC_ALAC_MB "music_offload_alac_mb"
+#define AUDIO_OFFLOAD_CODEC_ALAC_KB "music_offload_alac_kb"
+#define AUDIO_OFFLOAD_CODEC_ALAC_NUM_CHANNELS "music_offload_alac_num_channels"
+#define AUDIO_OFFLOAD_CODEC_ALAC_MAX_RUN "music_offload_alac_max_run"
+#define AUDIO_OFFLOAD_CODEC_ALAC_MAX_FRAME_BYTES "music_offload_alac_max_frame_bytes"
+#define AUDIO_OFFLOAD_CODEC_ALAC_AVG_BIT_RATE "music_offload_alac_avg_bit_rate"
+#define AUDIO_OFFLOAD_CODEC_ALAC_SAMPLING_RATE "music_offload_alac_sampling_rate"
+#define AUDIO_OFFLOAD_CODEC_ALAC_CHANNEL_LAYOUT_TAG "music_offload_alac_channel_layout_tag"
+
+#define AUDIO_OFFLOAD_CODEC_APE_COMPATIBLE_VERSION "music_offload_ape_compatible_version"
+#define AUDIO_OFFLOAD_CODEC_APE_COMPRESSION_LEVEL "music_offload_ape_compression_level"
+#define AUDIO_OFFLOAD_CODEC_APE_FORMAT_FLAGS "music_offload_ape_format_flags"
+#define AUDIO_OFFLOAD_CODEC_APE_BLOCKS_PER_FRAME "music_offload_ape_blocks_per_frame"
+#define AUDIO_OFFLOAD_CODEC_APE_FINAL_FRAME_BLOCKS "music_offload_ape_final_frame_blocks"
+#define AUDIO_OFFLOAD_CODEC_APE_TOTAL_FRAMES "music_offload_ape_total_frames"
+#define AUDIO_OFFLOAD_CODEC_APE_BITS_PER_SAMPLE "music_offload_ape_bits_per_sample"
+#define AUDIO_OFFLOAD_CODEC_APE_NUM_CHANNELS "music_offload_ape_num_channels"
+#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"
+
 /* 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 cae961d..ca5fd59 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -15,6 +15,24 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
+ * This file was modified by DTS, Inc. The portions of the
+ * code modified by DTS, Inc are copyrighted and
+ * licensed separately, as follows:
+ *
+ * (C) 2014 DTS, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 #define LOG_TAG "audio_hw_extn"
@@ -31,6 +49,9 @@
 #include "audio_extn.h"
 #include "platform.h"
 #include "platform_api.h"
+#include "edid.h"
+
+#include "sound/compress_params.h"
 
 #define MAX_SLEEP_RETRY 100
 #define WIFI_INIT_WAIT_SLEEP 50
@@ -40,6 +61,7 @@
     bool aanc_enabled;
     bool custom_stereo_enabled;
     uint32_t proxy_channel_num;
+    bool hpx_enabled;
 };
 
 static struct audio_extn_module aextnmod = {
@@ -47,6 +69,7 @@
     .aanc_enabled = 0,
     .custom_stereo_enabled = 0,
     .proxy_channel_num = 2,
+    .hpx_enabled = 0,
 };
 
 #define AUDIO_PARAMETER_KEY_ANC        "anc_enabled"
@@ -55,6 +78,9 @@
 #define AUDIO_PARAMETER_CUSTOM_STEREO  "stereo_as_dual_mono"
 /* Query offload playback instances count */
 #define AUDIO_PARAMETER_OFFLOAD_NUM_ACTIVE "offload_num_active"
+#define AUDIO_PARAMETER_HPX            "HPX"
+#define AUDIO_PARAMETER_KEY_ASPHERE_ENABLE   "asphere_enable"
+#define AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH "asphere_strength"
 
 #ifndef FM_ENABLED
 #define audio_extn_fm_set_parameters(adev, parms) (0)
@@ -69,6 +95,17 @@
                                            struct str_parms *parms);
 #endif
 
+#ifndef SOURCE_TRACKING_ENABLED
+#define audio_extn_source_track_set_parameters(adev, parms) (0)
+#define audio_extn_source_track_get_parameters(adev, query, reply) (0)
+#else
+void audio_extn_source_track_set_parameters(struct audio_device *adev,
+                                            struct str_parms *parms);
+void audio_extn_source_track_get_parameters(struct audio_device *adev,
+                                            struct str_parms *query,
+                                            struct str_parms *reply);
+#endif
+
 #ifndef CUSTOM_STEREO_ENABLED
 #define audio_extn_customstereo_set_parameters(adev, parms)         (0)
 #else
@@ -108,6 +145,76 @@
 }
 #endif /* CUSTOM_STEREO_ENABLED */
 
+#ifndef DTS_EAGLE
+#define audio_extn_hpx_set_parameters(adev, parms)         (0)
+#define audio_extn_hpx_get_parameters(query, reply)  (0)
+#define audio_extn_check_and_set_dts_hpx_state(adev)       (0)
+#else
+void audio_extn_hpx_set_parameters(struct audio_device *adev,
+                                   struct str_parms *parms)
+{
+    int ret = 0;
+    char value[32]={0};
+    char prop[PROPERTY_VALUE_MAX] = "false";
+    bool hpx_state = false;
+    const char *mixer_ctl_name = "Set HPX OnOff";
+    struct mixer_ctl *ctl = NULL;
+    ALOGV("%s", __func__);
+
+    property_get("use.dts_eagle", prop, "0");
+    if (strncmp("true", prop, sizeof("true")))
+        return;
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_HPX, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        if (!strncmp("ON", value, sizeof("ON")))
+            hpx_state = true;
+
+        if (hpx_state == aextnmod.hpx_enabled)
+            return;
+
+        aextnmod.hpx_enabled = hpx_state;
+        /* set HPX state on stream pp */
+        if (adev->offload_effects_set_hpx_state != NULL)
+            adev->offload_effects_set_hpx_state(hpx_state);
+
+        /* set HPX state on device pp */
+        ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+        if (ctl)
+            mixer_ctl_set_value(ctl, 0, aextnmod.hpx_enabled);
+    }
+}
+
+static int audio_extn_hpx_get_parameters(struct str_parms *query,
+                                       struct str_parms *reply)
+{
+    int ret;
+    char value[32]={0};
+
+    ALOGV("%s: hpx %d", __func__, aextnmod.hpx_enabled);
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_HPX, value,
+                            sizeof(value));
+    if (ret >= 0) {
+        if (aextnmod.hpx_enabled)
+            str_parms_add_str(reply, AUDIO_PARAMETER_HPX, "ON");
+        else
+            str_parms_add_str(reply, AUDIO_PARAMETER_HPX, "OFF");
+    }
+    return ret;
+}
+
+void audio_extn_check_and_set_dts_hpx_state(const struct audio_device *adev)
+{
+    char prop[PROPERTY_VALUE_MAX];
+    property_get("use.dts_eagle", prop, "0");
+    if (strncmp("true", prop, sizeof("true")))
+        return;
+    if (adev->offload_effects_set_hpx_state)
+        adev->offload_effects_set_hpx_state(aextnmod.hpx_enabled);
+}
+#endif
+
 #ifndef ANC_HEADSET_ENABLED
 #define audio_extn_set_anc_parameters(adev, parms)       (0)
 #else
@@ -236,35 +343,11 @@
 #define audio_extn_set_afe_proxy_parameters(adev, parms)  (0)
 #define audio_extn_get_afe_proxy_parameters(query, reply) (0)
 #else
-/* Front left channel. */
-#define PCM_CHANNEL_FL    1
-
-/* Front right channel. */
-#define PCM_CHANNEL_FR    2
-
-/* Front center channel. */
-#define PCM_CHANNEL_FC    3
-
-/* Left surround channel.*/
-#define PCM_CHANNEL_LS   4
-
-/* Right surround channel.*/
-#define PCM_CHANNEL_RS   5
-
-/* Low frequency effect channel. */
-#define PCM_CHANNEL_LFE  6
-
-/* Left back channel; Rear left channel. */
-#define PCM_CHANNEL_LB   8
-
-/* Right back channel; Rear right channel. */
-#define PCM_CHANNEL_RB   9
-
 static int32_t afe_proxy_set_channel_mapping(struct audio_device *adev,
                                                      int channel_count)
 {
     struct mixer_ctl *ctl;
-    const char *mixer_ctl_name = "Playback Channel Map";
+    const char *mixer_ctl_name = "Playback Device Channel Map";
     int set_values[8] = {0};
     int ret;
     ALOGV("%s channel_count:%d",__func__, channel_count);
@@ -451,6 +534,103 @@
     return ret;
 }
 
+#ifndef AUDIOSPHERE_ENABLED
+#define audio_extn_asphere_set_parameters(adev, parms)  (0)
+#define audio_extn_asphere_get_parameters(adev, query, reply) (0)
+#else
+int32_t audio_extn_asphere_set_parameters(const struct audio_device *adev,
+                                     struct str_parms *parms)
+{
+    int ret = 0, val[2];
+    char value[32] = {0};
+    int set_enable, set_strength;
+    int enable = -1, strength = -1;
+    struct mixer_ctl *ctl = NULL;
+    const char *mixer_ctl_name = "MSM ASphere Set Param";
+    char propValue[PROPERTY_VALUE_MAX] = {0};
+    bool asphere_prop_enabled = false;
+
+    if (property_get("audio.pp.asphere.enabled", propValue, "false")) {
+        if (!strncmp("true", propValue, 4))
+            asphere_prop_enabled = true;
+    }
+
+    if (!asphere_prop_enabled) {
+        ALOGV("%s: property not set!!! not doing anything", __func__);
+        return ret;
+    }
+
+    set_enable = str_parms_get_str(parms,
+                            AUDIO_PARAMETER_KEY_ASPHERE_ENABLE,
+                            value, sizeof(value));
+    if (set_enable > 0)
+        enable = atoi(value);
+
+    set_strength = str_parms_get_str(parms,
+                            AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH,
+                            value, sizeof(value));
+    if (set_strength > 0)
+        strength = atoi(value);
+
+    if (set_enable >= 0 || set_strength >= 0) {
+        ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+        if (!ctl) {
+            ALOGE("%s: could not get ctl for mixer cmd - %s",
+                  __func__, mixer_ctl_name);
+            return -EINVAL;
+        }
+        ALOGD("%s: set ctl \"%s:%d,%d\"",
+              __func__, mixer_ctl_name, enable, strength);
+        val[0] = enable;
+        val[1] = strength;
+        ret = mixer_ctl_set_array(ctl, val, sizeof(val)/sizeof(val[0]));
+        if (ret)
+            ALOGE("%s: set ctl failed!!!\"%s:%d,%d\"",
+                  __func__, mixer_ctl_name, enable, strength);
+    }
+    ALOGV("%s: exit ret %d", __func__, ret);
+    return ret;
+}
+
+int32_t audio_extn_asphere_get_parameters(const struct audio_device *adev,
+                                          struct str_parms *query,
+                                          struct str_parms *reply)
+{
+    int ret = 0, val[2] = {-1, -1};
+    char value[32] = {0};
+    int get_enable, get_strength;
+    struct mixer_ctl *ctl = NULL;
+    const char *mixer_ctl_name = "MSM ASphere Set Param";
+
+    get_enable = str_parms_get_str(query,
+                                   AUDIO_PARAMETER_KEY_ASPHERE_ENABLE,
+                                   value, sizeof(value));
+    get_strength = str_parms_get_str(query,
+                                     AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH,
+                                     value, sizeof(value));
+    if (get_enable > 0 || get_strength > 0) {
+        ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+        if (!ctl) {
+            ALOGE("%s: could not get ctl for mixer cmd - %s",
+                  __func__, mixer_ctl_name);
+            return -EINVAL;
+        }
+        ret = mixer_ctl_get_array(ctl, val, sizeof(val)/sizeof(val[0]));
+        if (ret)
+            ALOGE("%s: got ctl failed!!! \"%s:%d,%d\"",
+                   __func__, mixer_ctl_name, val[0], val[1]);
+        if (get_enable > 0)
+            str_parms_add_int(reply,
+                              AUDIO_PARAMETER_KEY_ASPHERE_ENABLE, val[0]);
+        if (get_strength > 0)
+            str_parms_add_int(reply,
+                              AUDIO_PARAMETER_KEY_ASPHERE_STRENGTH, val[1]);
+    }
+    ALOGV("%s: exit ret %d", __func__, ret);
+    return ret;
+}
+#endif
+
 void audio_extn_set_parameters(struct audio_device *adev,
                                struct str_parms *parms)
 {
@@ -461,10 +641,14 @@
    audio_extn_sound_trigger_set_parameters(adev, parms);
    audio_extn_listen_set_parameters(adev, parms);
    audio_extn_hfp_set_parameters(adev, parms);
+   audio_extn_dts_eagle_set_parameters(adev, parms);
    audio_extn_ddp_set_parameters(adev, parms);
    audio_extn_ds2_set_parameters(adev, parms);
    audio_extn_customstereo_set_parameters(adev, parms);
+   audio_extn_hpx_set_parameters(adev, parms);
    audio_extn_pm_set_parameters(parms);
+   audio_extn_source_track_set_parameters(adev, parms);
+   audio_extn_asphere_set_parameters(adev, parms);
 }
 
 void audio_extn_get_parameters(const struct audio_device *adev,
@@ -475,12 +659,250 @@
     audio_extn_get_afe_proxy_parameters(query, reply);
     audio_extn_get_fluence_parameters(adev, query, reply);
     get_active_offload_usecases(adev, query, reply);
+    audio_extn_dts_eagle_get_parameters(adev, query, reply);
+    audio_extn_hpx_get_parameters(query, reply);
+    audio_extn_source_track_get_parameters(adev, query, reply);
+    audio_extn_asphere_get_parameters(adev, query, reply);
 
     kv_pairs = str_parms_to_str(reply);
     ALOGD_IF(kv_pairs != NULL, "%s: returns %s", __func__, kv_pairs);
     free(kv_pairs);
 }
 
+#ifndef COMPRESS_METADATA_NEEDED
+#define audio_extn_parse_compress_metadata(out, parms) (0)
+#else
+int audio_extn_parse_compress_metadata(struct stream_out *out,
+                                       struct str_parms *parms)
+{
+    int ret = 0;
+    char value[32];
+
+    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;
+        }
+        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;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.flac_dec.min_frame_size = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE, value, sizeof(value));
+        if (ret >= 0) {
+            out->compr_config.codec->options.flac_dec.max_frame_size = atoi(value);
+            out->send_new_metadata = 1;
+        }
+        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,
+              out->compr_config.codec->options.flac_dec.max_blk_size,
+              out->compr_config.codec->options.flac_dec.min_frame_size,
+              out->compr_config.codec->options.flac_dec.max_frame_size);
+    }
+
+    else if (out->format == AUDIO_FORMAT_ALAC) {
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        ALOGV("ALAC CSD values: frameLength %d bitDepth %d numChannels %d"
+                " maxFrameBytes %d, avgBitRate %d, sampleRate %d",
+                out->compr_config.codec->options.alac.frame_length,
+                out->compr_config.codec->options.alac.bit_depth,
+                out->compr_config.codec->options.alac.num_channels,
+                out->compr_config.codec->options.alac.max_frame_bytes,
+                out->compr_config.codec->options.alac.avg_bit_rate,
+                out->compr_config.codec->options.alac.sample_rate);
+    }
+
+    else if (out->format == AUDIO_FORMAT_APE) {
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        ALOGV("APE CSD values: compatibleVersion %d compressionLevel %d"
+                " formatFlags %d blocksPerFrame %d finalFrameBlocks %d"
+                " totalFrames %d bitsPerSample %d numChannels %d"
+                " sampleRate %d seekTablePresent %d",
+                out->compr_config.codec->options.ape.compatible_version,
+                out->compr_config.codec->options.ape.compression_level,
+                out->compr_config.codec->options.ape.format_flags,
+                out->compr_config.codec->options.ape.blocks_per_frame,
+                out->compr_config.codec->options.ape.final_frame_blocks,
+                out->compr_config.codec->options.ape.total_frames,
+                out->compr_config.codec->options.ape.bits_per_sample,
+                out->compr_config.codec->options.ape.num_channels,
+                out->compr_config.codec->options.ape.sample_rate,
+                out->compr_config.codec->options.ape.seek_table_present);
+    }
+
+    else if (out->format == AUDIO_FORMAT_VORBIS) {
+        // transcoded bitstream mode
+        out->compr_config.codec->options.vorbis_dec.bit_stream_fmt = 1;
+        out->send_new_metadata = 1;
+    }
+
+    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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        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;
+        }
+        ALOGV("WMA params: fmt %x, balgn %x, sr %d, chmsk %x, encop %x, op1 %x, op2 %x",
+                out->compr_config.codec->format,
+                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,
+                out->compr_config.codec->options.wma.encodeopt,
+                out->compr_config.codec->options.wma.encodeopt1,
+                out->compr_config.codec->options.wma.encodeopt2);
+    }
+
+    return ret;
+}
+#endif
+
 #ifdef AUXPCM_BT_ENABLED
 int32_t audio_extn_read_xml(struct audio_device *adev, uint32_t mixer_card,
                             const char* mixer_xml_path,
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 6baa37f..98b2672 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -15,6 +15,24 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
+ * This file was modified by DTS, Inc. The portions of the
+ * code modified by DTS, Inc are copyrighted and
+ * licensed separately, as follows:
+ *
+ * (C) 2014 DTS, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 #ifndef AUDIO_EXTN_H
@@ -51,15 +69,34 @@
 #define AUDIO_DEVICE_IN_FM_RX_A2DP (AUDIO_DEVICE_BIT_IN | 0x10000)
 #endif
 
-#ifndef QTI_FLAC_DECODER
-#define AUDIO_FORMAT_FLAC 0x19000000UL
-#define AUDIO_OFFLOAD_CODEC_FLAC_MIN_BLK_SIZE "music_offload_flac_min_blk_size"
-#define AUDIO_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE "music_offload_flac_max_blk_size"
-#define AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE "music_offload_flac_min_frame_size"
-#define AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE "music_offload_flac_max_frame_size"
-#define PCM_OUTPUT_BIT_WIDTH (CODEC_BACKEND_DEFAULT_BIT_WIDTH)
+#ifndef FLAC_OFFLOAD_ENABLED
+#define AUDIO_FORMAT_FLAC 0x1D000000UL
+#endif
+
+#ifndef WMA_OFFLOAD_ENABLED
+#define AUDIO_FORMAT_WMA 0x13000000UL
+#define AUDIO_FORMAT_WMAPRO 0x14000000UL
+#endif
+
+#ifndef ALAC_OFFLOAD_ENABLED
+#define AUDIO_FORMAT_ALAC 0x1F000000UL
+#endif
+
+#ifndef APE_OFFLOAD_ENABLED
+#define AUDIO_FORMAT_APE 0x20000000UL
+#endif
+
+#ifndef COMPRESS_METADATA_NEEDED
+#define audio_extn_parse_compress_metadata(out, parms) (0)
 #else
+int audio_extn_parse_compress_metadata(struct stream_out *out,
+                                       struct str_parms *parms);
+#endif
+
+#ifdef PCM_OFFLOAD_ENABLED_24
 #define PCM_OUTPUT_BIT_WIDTH (config->offload_info.bit_width)
+#else
+#define PCM_OUTPUT_BIT_WIDTH (CODEC_BACKEND_DEFAULT_BIT_WIDTH)
 #endif
 
 #define MAX_LENGTH_MIXER_CONTROL_IN_INT                  (128)
@@ -251,6 +288,28 @@
 void audio_extn_compr_cap_deinit();
 #endif
 
+#ifndef DTS_EAGLE
+#define audio_extn_dts_eagle_set_parameters(adev, parms)     (0)
+#define audio_extn_dts_eagle_get_parameters(adev, query, reply) (0)
+#define audio_extn_dts_eagle_fade(adev, fade_in, out) (0)
+#define audio_extn_dts_create_state_notifier_node(stream_out) (0)
+#define audio_extn_dts_notify_playback_state(stream_out, has_video, sample_rate, \
+                                    channels, is_playing) (0)
+#define audio_extn_dts_remove_state_notifier_node(stream_out) (0)
+#define audio_extn_check_and_set_dts_hpx_state(adev)       (0)
+#else
+void audio_extn_dts_eagle_set_parameters(struct audio_device *adev,
+                                         struct str_parms *parms);
+int audio_extn_dts_eagle_get_parameters(const struct audio_device *adev,
+                  struct str_parms *query, struct str_parms *reply);
+int audio_extn_dts_eagle_fade(const struct audio_device *adev, bool fade_in, const struct stream_out *out);
+void audio_extn_dts_create_state_notifier_node(int stream_out);
+void audio_extn_dts_notify_playback_state(int stream_out, int has_video, int sample_rate,
+                                  int channels, int is_playing);
+void audio_extn_dts_remove_state_notifier_node(int stream_out);
+void audio_extn_check_and_set_dts_hpx_state(const struct audio_device *adev);
+#endif
+
 #if defined(DS1_DOLBY_DDP_ENABLED) || defined(DS1_DOLBY_DAP_ENABLED)
 void audio_extn_dolby_set_dmid(struct audio_device *adev);
 #else
@@ -288,6 +347,34 @@
 void audio_extn_ddp_set_parameters(struct audio_device *adev,
                                    struct str_parms *parms);
 void audio_extn_dolby_send_ddp_endp_params(struct audio_device *adev);
+
+#endif
+
+#ifndef HDMI_PASSTHROUGH_ENABLED
+#define audio_extn_dolby_update_passt_formats(adev, out)                   (0)
+#define audio_extn_dolby_update_passt_stream_configuration(adev, out)      (0)
+#define audio_extn_dolby_is_passt_convert_supported(adev, out)             (0)
+#define audio_extn_dolby_is_passt_supported(adev, out)                     (0)
+#define audio_extn_dolby_is_passthrough_stream(flags)                      (0)
+#define audio_extn_dolby_set_hdmi_config(adev, out)                        (0)
+#define audio_extn_dolby_get_passt_buffer_size(info)                       (0)
+#define audio_extn_dolby_set_passt_volume(out, mute)                       (0)
+#define audio_extn_dolby_set_passt_latency(out, latency)                   (0)
+#else
+int audio_extn_dolby_update_passt_formats(struct audio_device *adev,
+                                          struct stream_out *out);
+bool audio_extn_dolby_is_passt_convert_supported(struct audio_device *adev,
+                                                 struct stream_out *out);
+bool audio_extn_dolby_is_passt_supported(struct audio_device *adev,
+                                         struct stream_out *out);
+void audio_extn_dolby_update_passt_stream_configuration(struct audio_device *adev,
+                                                 struct stream_out *out);
+bool audio_extn_dolby_is_passthrough_stream(int flags);
+int audio_extn_dolby_set_hdmi_config(struct audio_device *adev,
+                                     struct stream_out *out);
+int audio_extn_dolby_get_passt_buffer_size(audio_offload_info_t* info);
+int audio_extn_dolby_set_passt_volume(struct stream_out *out, int mute);
+int audio_extn_dolby_set_passt_latency(struct stream_out *out, int latency);
 #endif
 
 #ifndef HFP_ENABLED
@@ -373,11 +460,14 @@
 typedef enum {
     DAP_STATE_ON = 0,
     DAP_STATE_BYPASS,
-};
+} dap_state;
 #ifndef AUDIO_FORMAT_E_AC3_JOC
 #define AUDIO_FORMAT_E_AC3_JOC  0x19000000UL
 #endif
 
+int b64decode(char *inp, int ilen, uint8_t* outp);
+int b64encode(uint8_t *inp, int ilen, char* outp);
+
 #ifndef KPI_OPTIMIZE_ENABLED
 #define audio_extn_perf_lock_init() (0)
 #define audio_extn_perf_lock_acquire() (0)
diff --git a/hal/audio_extn/dev_arbi.c b/hal/audio_extn/dev_arbi.c
index d3c01c5..d7ab5ff 100644
--- a/hal/audio_extn/dev_arbi.c
+++ b/hal/audio_extn/dev_arbi.c
@@ -128,7 +128,13 @@
 {
     static snd_aud_dev_mapping_t snd_aud_dev_map[] = {
         {SND_DEVICE_OUT_HANDSET, AUDIO_DEVICE_OUT_EARPIECE},
-        {SND_DEVICE_OUT_VOICE_HANDSET, AUDIO_DEVICE_OUT_EARPIECE}
+        {SND_DEVICE_OUT_VOICE_HANDSET, AUDIO_DEVICE_OUT_EARPIECE},
+        {SND_DEVICE_OUT_SPEAKER, AUDIO_DEVICE_OUT_SPEAKER},
+        {SND_DEVICE_OUT_VOICE_SPEAKER, AUDIO_DEVICE_OUT_SPEAKER},
+        {SND_DEVICE_OUT_HEADPHONES, AUDIO_DEVICE_OUT_WIRED_HEADPHONE},
+        {SND_DEVICE_OUT_VOICE_HEADPHONES, AUDIO_DEVICE_OUT_WIRED_HEADPHONE},
+        {SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+            AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_WIRED_HEADPHONE}
     };
 
     audio_devices_t aud_device = AUDIO_DEVICE_NONE;
diff --git a/hal/audio_extn/dolby.c b/hal/audio_extn/dolby.c
index 6e0b0ee..92ef4ac 100644
--- a/hal/audio_extn/dolby.c
+++ b/hal/audio_extn/dolby.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2010 The Android Open Source Project
@@ -18,9 +18,8 @@
  */
 
 #define LOG_TAG "audio_hw_dolby"
-#define LOG_NDEBUG 0
-#define LOG_NDDEBUG 0
-
+//#define LOG_NDEBUG 0
+//#define LOG_NDDEBUG 0
 #include <errno.h>
 #include <cutils/properties.h>
 #include <stdlib.h>
@@ -408,6 +407,118 @@
 }
 #endif /* DS1_DOLBY_DDP_ENABLED || DS2_DOLBY_DAP_ENABLED */
 
+#ifdef HDMI_PASSTHROUGH_ENABLED
+int audio_extn_dolby_update_passt_formats(struct audio_device *adev,
+                                          struct stream_out *out) {
+    int32_t i = 0, ret = -ENOSYS;
+
+    if (platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_AC3) ||
+        platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_E_AC3)) {
+        out->supported_formats[i++] = AUDIO_FORMAT_AC3;
+        out->supported_formats[i++] = AUDIO_FORMAT_E_AC3;
+        /* Reciever must support JOC and advertise, otherwise JOC is treated as DDP */
+        out->supported_formats[i++] = AUDIO_FORMAT_E_AC3_JOC;
+        ret = 0;
+    }
+    ALOGV("%s: ret = %d", __func__, ret);
+    return ret;
+}
+
+bool audio_extn_dolby_is_passt_convert_supported(struct audio_device *adev,
+                                                 struct stream_out *out) {
+
+    bool convert = false;
+    switch (out->format) {
+    case AUDIO_FORMAT_E_AC3:
+    case AUDIO_FORMAT_E_AC3_JOC:
+        if (!platform_is_edid_supported_format(adev->platform,
+            AUDIO_FORMAT_E_AC3)) {
+            ALOGV("%s:PASSTHROUGH_CONVERT supported", __func__);
+            convert = true;
+        }
+        break;
+    default:
+        ALOGE("%s: PASSTHROUGH_CONVERT not supported for format 0x%x",
+              __func__, out->format);
+        break;
+    }
+    ALOGE("%s: convert %d", __func__, convert);
+    return convert;
+}
+
+bool audio_extn_dolby_is_passt_supported(struct audio_device *adev,
+                                         struct stream_out *out) {
+    bool passt = false;
+    switch (out->format) {
+    case AUDIO_FORMAT_E_AC3:
+        if (platform_is_edid_supported_format(adev->platform, out->format)) {
+            ALOGV("%s:PASSTHROUGH supported for format %x",
+                   __func__, out->format);
+            passt = true;
+        }
+        break;
+    case AUDIO_FORMAT_AC3:
+        if (platform_is_edid_supported_format(adev->platform, AUDIO_FORMAT_AC3)
+            || platform_is_edid_supported_format(adev->platform,
+            AUDIO_FORMAT_E_AC3)) {
+            ALOGV("%s:PASSTHROUGH supported for format %x",
+                   __func__, out->format);
+            passt = true;
+        }
+        break;
+    case AUDIO_FORMAT_E_AC3_JOC:
+         /* Check for DDP capability in edid for JOC contents.*/
+         if (platform_is_edid_supported_format(adev->platform,
+             AUDIO_FORMAT_E_AC3)) {
+             ALOGV("%s:PASSTHROUGH supported for format %x",
+                   __func__, out->format);
+             passt = true;
+         }
+    default:
+        ALOGV("%s:Passthrough not supported", __func__);
+    }
+    return passt;
+}
+
+void audio_extn_dolby_update_passt_stream_configuration(
+        struct audio_device *adev, struct stream_out *out) {
+    if (audio_extn_dolby_is_passt_supported(adev, out)) {
+        ALOGV("%s:PASSTHROUGH", __func__);
+        out->compr_config.codec->compr_passthr = PASSTHROUGH;
+    } else if (audio_extn_dolby_is_passt_convert_supported(adev, out)){
+        ALOGV("%s:PASSTHROUGH CONVERT", __func__);
+        out->compr_config.codec->compr_passthr = PASSTHROUGH_CONVERT;
+    } else {
+        ALOGV("%s:NO PASSTHROUGH", __func__);
+        out->compr_config.codec->compr_passthr = LEGACY_PCM;
+    }
+}
+
+bool audio_extn_dolby_is_passthrough_stream(int flags) {
+
+    if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH)
+        return true;
+    return false;
+}
+
+int audio_extn_dolby_set_hdmi_config(struct audio_device *adev,
+                                                    struct stream_out *out) {
+    return platform_set_hdmi_config(out);
+}
+
+int audio_extn_dolby_get_passt_buffer_size(audio_offload_info_t* info) {
+    return platform_get_compress_passthrough_buffer_size(info);
+}
+
+int audio_extn_dolby_set_passt_volume(struct stream_out *out,  int mute) {
+    return platform_set_device_params(out, DEVICE_PARAM_MUTE_ID, mute);
+}
+
+int audio_extn_dolby_set_passt_latency(struct stream_out *out, int latency) {
+    return platform_set_device_params(out, DEVICE_PARAM_LATENCY_ID, latency);
+}
+#endif /* HDMI_PASSTHROUGH_ENABLED */
+
 #ifdef DS1_DOLBY_DAP_ENABLED
 void audio_extn_dolby_set_endpoint(struct audio_device *adev)
 {
@@ -464,7 +575,7 @@
         return;
 
     property_get("dmid",c_dmid,"0");
-    i_dmid = atoi(c_dmid);
+    i_dmid = atoll(c_dmid);
 
     ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
     if (!ctl) {
@@ -653,7 +764,7 @@
     i_key = 0;
 #endif
     property_get("dmid",c_dmid,"0");
-    i_dmid = atoi(c_dmid);
+    i_dmid = atoll(c_dmid);
     ALOGV("%s Setting DS1 License, key:0x%x dmid %d",__func__, i_key,i_dmid);
     dolby_license.dmid = i_dmid;
     dolby_license.license_key = i_key;
diff --git a/hal/audio_extn/dts_eagle.c b/hal/audio_extn/dts_eagle.c
new file mode 100644
index 0000000..52d7abb
--- /dev/null
+++ b/hal/audio_extn/dts_eagle.c
@@ -0,0 +1,501 @@
+/*
+ *  (C) 2014 DTS, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_dts_eagle"
+/*#define LOG_NDEBUG 0*/
+
+#include <errno.h>
+#include <math.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <cutils/str_parms.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sound/asound.h>
+#include <sound/audio_effects.h>
+#include <sound/devdep_params.h>
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+
+#ifdef DTS_EAGLE
+
+#define AUDIO_PARAMETER_KEY_DTS_EAGLE   "DTS_EAGLE"
+#define STATE_NOTIFY_FILE               "/data/misc/dts/stream"
+#define FADE_NOTIFY_FILE                "/data/misc/dts/fade"
+#define DTS_EAGLE_KEY                   "DTS_EAGLE"
+#define DEVICE_NODE                     "/dev/snd/hwC0D3"
+#define MAX_LENGTH_OF_INTEGER_IN_STRING 13
+#define PARAM_GET_MAX_SIZE              512
+
+struct dts_eagle_param_desc_alsa {
+    int alsa_effect_ID;
+    struct dts_eagle_param_desc d;
+};
+
+static struct dts_eagle_param_desc_alsa *fade_in_data = NULL;
+static struct dts_eagle_param_desc_alsa *fade_out_data = NULL;
+static int32_t mDevices = 0;
+static int32_t mCurrDevice = 0;
+static const char* DTS_EAGLE_STR = DTS_EAGLE_KEY;
+
+static int do_DTS_Eagle_params_stream(struct stream_out *out, struct dts_eagle_param_desc_alsa *t, bool get) {
+    char mixer_string[128];
+    char mixer_str_query[128];
+    struct mixer_ctl *ctl;
+    struct mixer_ctl *query_ctl;
+    int pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
+
+    ALOGV("DTS_EAGLE_HAL (%s): enter", __func__);
+    snprintf(mixer_string, sizeof(mixer_string), "%s %d", "Audio Effects Config", pcm_device_id);
+    ctl = mixer_get_ctl_by_name(out->dev->mixer, mixer_string);
+    if (!ctl) {
+        ALOGE("DTS_EAGLE_HAL (%s): failed to open mixer %s", __func__, mixer_string);
+    } else if (t) {
+        int size = t->d.size + sizeof(struct dts_eagle_param_desc_alsa);
+        ALOGD("DTS_EAGLE_HAL (%s): opened mixer %s", __func__, mixer_string);
+        if (get) {
+            ALOGD("DTS_EAGLE_HAL (%s): get request", __func__);
+            snprintf(mixer_str_query, sizeof(mixer_str_query), "%s %d", "Query Audio Effect Param", pcm_device_id);
+            query_ctl = mixer_get_ctl_by_name(out->dev->mixer, mixer_str_query);
+            if (!query_ctl) {
+                ALOGE("DTS_EAGLE_HAL (%s): failed to open mixer %s", __func__, mixer_str_query);
+                return -EINVAL;
+            }
+            mixer_ctl_set_array(query_ctl, t, size);
+            return mixer_ctl_get_array(ctl, t, size);
+        }
+        ALOGD("DTS_EAGLE_HAL (%s): set request", __func__);
+        return mixer_ctl_set_array(ctl, t, size);
+    } else {
+        ALOGD("DTS_EAGLE_HAL (%s): parameter data NULL", __func__);
+    }
+    return -EINVAL;
+}
+
+static int do_DTS_Eagle_params(const struct audio_device *adev, struct dts_eagle_param_desc_alsa *t, bool get, const struct stream_out *out) {
+    struct listnode *node;
+    struct audio_usecase *usecase;
+    int ret = 0, sent = 0, tret = 0;
+
+    ALOGV("DTS_EAGLE_HAL (%s): enter", __func__);
+
+    if (out) {
+        /* if valid out stream is given, then send params to this stream only */
+        tret = do_DTS_Eagle_params_stream(out, t, get);
+        if (tret < 0)
+            ret = tret;
+        else
+            sent = 1;
+    } else {
+        list_for_each(node, &adev->usecase_list) {
+            usecase = node_to_item(node, struct audio_usecase, list);
+            /* set/get eagle params for offload usecases only */
+            if ((usecase->type == PCM_PLAYBACK) && is_offload_usecase(usecase->id)) {
+                tret = do_DTS_Eagle_params_stream(usecase->stream.out, t, get);
+                if (tret < 0)
+                    ret = tret;
+                else
+                    sent = 1;
+            }
+        }
+    }
+
+    if (!sent) {
+        int fd = open(DEVICE_NODE, O_RDWR);
+
+        if (get) {
+            ALOGD("DTS_EAGLE_HAL (%s): no stream opened, attempting to retrieve directly from cache", __func__);
+            t->d.device &= ~DTS_EAGLE_FLAG_ALSA_GET;
+        } else {
+            ALOGD("DTS_EAGLE_HAL (%s): no stream opened, attempting to send directly to cache", __func__);
+            t->d.device |= DTS_EAGLE_FLAG_IOCTL_JUSTSETCACHE;
+        }
+
+        if (fd > 0) {
+            int cmd = get ? DTS_EAGLE_IOCTL_GET_PARAM : DTS_EAGLE_IOCTL_SET_PARAM;
+            if (ioctl(fd, cmd, &t->d) < 0) {
+                ALOGE("DTS_EAGLE_HAL (%s): error sending/getting param\n", __func__);
+                ret = -EINVAL;
+            } else {
+                ALOGD("DTS_EAGLE_HAL (%s): sent/retrieved param\n", __func__);
+            }
+            close(fd);
+        } else {
+            ALOGE("DTS_EAGLE_HAL (%s): couldn't open device %s\n", __func__, DEVICE_NODE);
+            ret = -EINVAL;
+        }
+    }
+    return ret;
+}
+
+static void fade_node(bool need_data) {
+    char prop[PROPERTY_VALUE_MAX];
+    property_get("use.dts_eagle", prop, "0");
+    if (strncmp("true", prop, sizeof("true")))
+        return;
+    int fd, n = 0;
+    if ((fd = open(FADE_NOTIFY_FILE, O_TRUNC|O_WRONLY)) < 0) {
+        ALOGV("No fade node, create one");
+        fd = creat(FADE_NOTIFY_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+        if (fd < 0) {
+            ALOGE("DTS_EAGLE_HAL (%s): Creating fade notifier node failed", __func__);
+            return;
+        }
+        chmod(FADE_NOTIFY_FILE, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH);
+    }
+    char *str = need_data ? "need" : "have";
+    n = write(fd, str, strlen(str));
+    close(fd);
+    if (n > 0)
+        ALOGI("DTS_EAGLE_HAL (%s): fade notifier node set to \"%s\", %i bytes written", __func__, str, n);
+    else
+        ALOGE("DTS_EAGLE_HAL (%s): error writing to fade notifier node", __func__);
+}
+
+int audio_extn_dts_eagle_fade(const struct audio_device *adev, bool fade_in, const struct stream_out *out) {
+    char prop[PROPERTY_VALUE_MAX];
+
+    ALOGV("DTS_EAGLE_HAL (%s): enter with fade %s requested", __func__, fade_in ? "in" : "out");
+
+    property_get("use.dts_eagle", prop, "0");
+    if (strncmp("true", prop, sizeof("true")))
+        return 0;
+
+    if (!fade_in_data || !fade_out_data)
+        fade_node(true);
+
+    if (fade_in) {
+        if (fade_in_data)
+            return do_DTS_Eagle_params(adev, fade_in_data, false, out);
+    } else {
+        if (fade_out_data)
+            return do_DTS_Eagle_params(adev, fade_out_data, false, out);
+    }
+    return 0;
+}
+
+void audio_extn_dts_eagle_set_parameters(struct audio_device *adev, struct str_parms *parms) {
+    int ret, val;
+    char value[32] = { 0 }, prop[PROPERTY_VALUE_MAX];
+
+    ALOGV("DTS_EAGLE_HAL (%s): enter", __func__);
+
+    property_get("use.dts_eagle", prop, "0");
+    if (strncmp("true", prop, sizeof("true")))
+        return;
+
+    memset(value, 0, sizeof(value));
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DTS_EAGLE, value, sizeof(value));
+    if (ret >= 0) {
+        int *data = NULL, id, size, offset, count, dev, dts_found = 0, fade_in = 0;
+        struct dts_eagle_param_desc_alsa *t2 = NULL, **t = &t2;
+
+        ret = str_parms_get_str(parms, "fade", value, sizeof(value));
+        if (ret >= 0) {
+            fade_in = atoi(value);
+            if (fade_in > 0) {
+                t = (fade_in == 1) ? &fade_in_data : &fade_out_data;
+            }
+        }
+
+        ret = str_parms_get_str(parms, "count", value, sizeof(value));
+        if (ret >= 0) {
+            count = atoi(value);
+            if (count > 1) {
+                int tmp_size = count * 32;
+                char *tmp = malloc(tmp_size+1);
+                data = malloc(sizeof(int) * count);
+                ALOGV("DTS_EAGLE_HAL (%s): multi count param detected, count: %d", __func__, count);
+                if (data && tmp) {
+                    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DTS_EAGLE, tmp, tmp_size);
+                    if (ret >= 0) {
+                        int idx = 0, tidx, tcnt = 0;
+                        dts_found = 1;
+                        do {
+                            sscanf(&tmp[idx], "%i", &data[tcnt]);
+                            tidx = strcspn(&tmp[idx], ",");
+                            if (idx + tidx >= ret && tcnt < count-1) {
+                                ALOGE("DTS_EAGLE_HAL (%s): malformed multi value string.", __func__);
+                                dts_found = 0;
+                                break;
+                            }
+                            ALOGD("DTS_EAGLE_HAL (%s): %i:%i (next %s)", __func__, tcnt, data[tcnt], &tmp[idx+tidx]);
+                            idx += tidx + 1;
+                            tidx = 0;
+                            tcnt++;
+                        } while (tcnt < count);
+                    }
+                } else {
+                    ALOGE("DTS_EAGLE_HAL (%s): mem alloc for multi count param parse failed.", __func__);
+                }
+                free(tmp);
+            }
+        }
+
+        if (!dts_found) {
+            data = malloc(sizeof(int));
+            if (data) {
+                ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DTS_EAGLE, value, sizeof(value));
+                if (ret >= 0) {
+                    *data = atoi(value);
+                    dts_found = 1;
+                    count = 1;
+                } else {
+                    ALOGE("DTS_EAGLE_HAL (%s): malformed value string.", __func__);
+                }
+            } else {
+                ALOGE("DTS_EAGLE_HAL (%s): mem alloc for param parse failed.", __func__);
+            }
+        }
+
+        if (dts_found) {
+            dts_found = 0;
+            ret = str_parms_get_str(parms, "id", value, sizeof(value));
+            if (ret >= 0) {
+                if (sscanf(value, "%x", &id) == 1) {
+                    ret = str_parms_get_str(parms, "size", value, sizeof(value));
+                    if (ret >= 0) {
+                        size = atoi(value);
+                        ret = str_parms_get_str(parms, "offset", value, sizeof(value));
+                        if (ret >= 0) {
+                            offset = atoi(value);
+                            ret = str_parms_get_str(parms, "device", value, sizeof(value));
+                            if (ret >= 0) {
+                                dev = atoi(value);
+                                dts_found = 1;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        if (dts_found && count > 1 && size != (int)(count * sizeof(int))) {
+            ALOGE("DTS_EAGLE_HAL (%s): size/count mismatch (size = %i bytes, count = %i integers / %u bytes).", __func__, size, count, count*sizeof(int));
+        } else if (dts_found) {
+            ALOGI("DTS_EAGLE_HAL (%s): param detected: %s", __func__, str_parms_to_str(parms));
+            if (!(*t))
+                *t = (struct dts_eagle_param_desc_alsa*)malloc(sizeof(struct dts_eagle_param_desc_alsa) + size);
+            if (*t) {
+                (*t)->alsa_effect_ID = DTS_EAGLE_MODULE;
+                (*t)->d.id = id;
+                (*t)->d.size = size;
+                (*t)->d.offset = offset;
+                (*t)->d.device = dev;
+                memcpy((void*)((char*)*t + sizeof(struct dts_eagle_param_desc_alsa)), data, size);
+                ALOGD("DTS_EAGLE_HAL (%s): id: 0x%X, size: %d, offset: %d, device: %d", __func__,
+                       (*t)->d.id, (*t)->d.size, (*t)->d.offset, (*t)->d.device);
+                if (!fade_in) {
+                    ret = do_DTS_Eagle_params(adev, *t, false, NULL);
+                    if (ret < 0)
+                        ALOGE("DTS_EAGLE_HAL (%s): failed setting params in kernel with error %i", __func__, ret);
+                }
+                free(t2);
+            } else {
+                ALOGE("DTS_EAGLE_HAL (%s): mem alloc for dsp structure failed.", __func__);
+            }
+        } else {
+            ALOGE("DTS_EAGLE_HAL (%s): param detected but failed parse: %s", __func__, str_parms_to_str(parms));
+        }
+        free(data);
+
+        if (fade_in > 0 && fade_in_data && fade_out_data)
+            fade_node(false);
+    }
+    ALOGV("DTS_EAGLE_HAL (%s): exit", __func__);
+}
+
+int audio_extn_dts_eagle_get_parameters(const struct audio_device *adev,
+                  struct str_parms *query, struct str_parms *reply) {
+    int ret, val;
+    char value[32] = { 0 }, prop[PROPERTY_VALUE_MAX];
+    char params[PARAM_GET_MAX_SIZE];
+
+    ALOGV("DTS_EAGLE_HAL (%s): enter", __func__);
+
+    property_get("use.dts_eagle", prop, "0");
+    if (strncmp("true", prop, sizeof("true")))
+        return 0;
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_KEY_DTS_EAGLE, value, sizeof(value));
+    if (ret >= 0) {
+        int *data = NULL, id = 0, size = 0, offset = 0,
+            count = 1, dev = 0, idx = 0, dts_found = 0, i = 0;
+        const size_t chars_4_int = 16;
+        ret = str_parms_get_str(query, "count", value, sizeof(value));
+        if (ret >= 0) {
+            count = atoi(value);
+            if (count > 1) {
+                ALOGV("DTS_EAGLE_HAL (%s): multi count param detected, count: %d", __func__, count);
+            } else {
+                count = 1;
+            }
+        }
+
+        ret = str_parms_get_str(query, "id", value, sizeof(value));
+        if (ret >= 0) {
+            if (sscanf(value, "%x", &id) == 1) {
+                ret = str_parms_get_str(query, "size", value, sizeof(value));
+                if (ret >= 0) {
+                    size = atoi(value);
+                    ret = str_parms_get_str(query, "offset", value, sizeof(value));
+                    if (ret >= 0) {
+                        offset = atoi(value);
+                        ret = str_parms_get_str(query, "device", value, sizeof(value));
+                        if (ret >= 0) {
+                            dev = atoi(value);
+                            dts_found = 1;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (dts_found) {
+            ALOGI("DTS_EAGLE_HAL (%s): param (get) detected: %s", __func__, str_parms_to_str(query));
+            struct dts_eagle_param_desc_alsa *t = (struct dts_eagle_param_desc_alsa *)params;
+            if (t) {
+                char buf[chars_4_int*count];
+                t->alsa_effect_ID = DTS_EAGLE_MODULE;
+                t->d.id = id;
+                t->d.size = size;
+                t->d.offset = offset;
+                t->d.device = dev;
+                ALOGV("DTS_EAGLE_HAL (%s): id (get): 0x%X, size: %d, offset: %d, device: %d", __func__,
+                       t->d.id, t->d.size, t->d.offset, t->d.device & 0x7FFFFFFF);
+                if ((sizeof(struct dts_eagle_param_desc_alsa) + size) > PARAM_GET_MAX_SIZE) {
+                    ALOGE("%s: requested data too large", __func__);
+                    return -1;
+                }
+                ret = do_DTS_Eagle_params(adev, t, true, NULL);
+                if (ret >= 0) {
+                    data = (int*)(params + sizeof(struct dts_eagle_param_desc_alsa));
+                    for (i = 0; i < count; i++)
+                        idx += snprintf(&buf[idx], chars_4_int, "%i,", data[i]);
+                    buf[idx > 0 ? idx-1 : 0] = 0;
+                    ALOGD("DTS_EAGLE_HAL (%s): get result: %s", __func__, buf);
+                    str_parms_add_int(reply, "size", size);
+                    str_parms_add_str(reply, AUDIO_PARAMETER_KEY_DTS_EAGLE, buf);
+                    str_parms_add_int(reply, "count", count);
+                    snprintf(value, sizeof(value), "0x%x", id);
+                    str_parms_add_str(reply, "id", value);
+                    str_parms_add_int(reply, "device", dev);
+                    str_parms_add_int(reply, "offset", offset);
+                    ALOGV("DTS_EAGLE_HAL (%s): reply: %s", __func__, str_parms_to_str(reply));
+                } else {
+                    ALOGE("DTS_EAGLE_HAL (%s): failed getting params from kernel with error %i", __func__, ret);
+                    return -1;
+                }
+            } else {
+                ALOGE("DTS_EAGLE_HAL (%s): mem alloc for (get) dsp structure failed.", __func__);
+                return -1;
+            }
+        } else {
+            ALOGE("DTS_EAGLE_HAL (%s): param (get) detected but failed parse: %s", __func__, str_parms_to_str(query));
+            return -1;
+        }
+    }
+
+    ALOGV("DTS_EAGLE_HAL (%s): exit", __func__);
+    return 0;
+}
+
+void audio_extn_dts_create_state_notifier_node(int stream_out)
+{
+    char prop[PROPERTY_VALUE_MAX];
+    char path[PATH_MAX];
+    char value[MAX_LENGTH_OF_INTEGER_IN_STRING];
+    int fd;
+    property_get("use.dts_eagle", prop, "0");
+    if ((!strncmp("true", prop, sizeof("true")) || atoi(prop))) {
+        ALOGV("DTS_EAGLE_NODE_STREAM (%s): create_state_notifier_node - stream_out: %d", __func__, stream_out);
+        strlcpy(path, STATE_NOTIFY_FILE, sizeof(path));
+        snprintf(value, sizeof(value), "%d", stream_out);
+        strlcat(path, value, sizeof(path));
+
+        if ((fd=open(path, O_RDONLY)) < 0) {
+            ALOGV("DTS_EAGLE_NODE_STREAM (%s): no file exists", __func__);
+        } else {
+            ALOGV("DTS_EAGLE_NODE_STREAM (%s): a file with the same name exists, removing it before creating it", __func__);
+            close(fd);
+            remove(path);
+        }
+        if ((fd=creat(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
+            ALOGE("DTS_EAGLE_NODE_STREAM (%s): opening state notifier node failed returned", __func__);
+            return;
+        }
+        chmod(path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH);
+        ALOGV("DTS_EAGLE_NODE_STREAM (%s): opening state notifier node successful", __func__);
+        close(fd);
+        if (!fade_in_data || !fade_out_data)
+            fade_node(true);
+    }
+}
+
+void audio_extn_dts_notify_playback_state(int stream_out, int has_video, int sample_rate,
+                           int channels, int is_playing) {
+    char prop[PROPERTY_VALUE_MAX];
+    char path[PATH_MAX];
+    char value[MAX_LENGTH_OF_INTEGER_IN_STRING];
+    char buf[1024];
+    int fd;
+    property_get("use.dts_eagle", prop, "0");
+    if ((!strncmp("true", prop, sizeof("true")) || atoi(prop))) {
+        ALOGV("DTS_EAGLE_NODE_STREAM (%s): notify_playback_state - is_playing: %d", __func__, is_playing);
+        strlcpy(path, STATE_NOTIFY_FILE, sizeof(path));
+        snprintf(value, sizeof(value), "%d", stream_out);
+        strlcat(path, value, sizeof(path));
+        if ((fd=open(path, O_TRUNC|O_WRONLY)) < 0) {
+            ALOGE("DTS_EAGLE_NODE_STREAM (%s): open state notifier node failed", __func__);
+        } else {
+            snprintf(buf, sizeof(buf), "has_video=%d;sample_rate=%d;channel_mode=%d;playback_state=%d",
+                     has_video, sample_rate, channels, is_playing);
+            int n = write(fd, buf, strlen(buf));
+            if (n > 0)
+                ALOGV("DTS_EAGLE_NODE_STREAM (%s): write to state notifier node successful, bytes written: %d", __func__, n);
+            else
+                ALOGE("DTS_EAGLE_NODE_STREAM (%s): write state notifier node failed", __func__);
+            close(fd);
+        }
+    }
+}
+
+void audio_extn_dts_remove_state_notifier_node(int stream_out)
+{
+    char prop[PROPERTY_VALUE_MAX];
+    char path[PATH_MAX];
+    char value[MAX_LENGTH_OF_INTEGER_IN_STRING];
+    int fd;
+    property_get("use.dts_eagle", prop, "0");
+    if ((!strncmp("true", prop, sizeof("true")) || atoi(prop)) && (stream_out)) {
+        ALOGV("DTS_EAGLE_NODE_STREAM (%s): remove_state_notifier_node: stream_out - %d", __func__, stream_out);
+        strlcpy(path, STATE_NOTIFY_FILE, sizeof(path));
+        snprintf(value, sizeof(value), "%d", stream_out);
+        strlcat(path, value, sizeof(path));
+        if ((fd=open(path, O_RDONLY)) < 0) {
+            ALOGV("DTS_EAGLE_NODE_STREAM (%s): open state notifier node failed", __func__);
+        } else {
+            ALOGV("DTS_EAGLE_NODE_STREAM (%s): open state notifier node successful, removing the file", __func__);
+            close(fd);
+            remove(path);
+        }
+    }
+}
+
+#endif /* DTS_EAGLE end */
diff --git a/hal/audio_extn/soundtrigger.c b/hal/audio_extn/soundtrigger.c
index 5f4c6ba..9051334 100644
--- a/hal/audio_extn/soundtrigger.c
+++ b/hal/audio_extn/soundtrigger.c
@@ -165,6 +165,7 @@
             in->config = st_ses_info->st_ses.config;
             in->channel_mask = audio_channel_in_mask_from_count(in->config.channels);
             in->is_st_session = true;
+            in->is_st_session_active = true;
             ALOGD("%s: capture_handle %d is sound trigger", __func__, in->capture_handle);
             break;
         }
diff --git a/hal/audio_extn/source_track.c b/hal/audio_extn/source_track.c
new file mode 100644
index 0000000..316e52d
--- /dev/null
+++ b/hal/audio_extn/source_track.c
@@ -0,0 +1,640 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#define LOG_TAG "source_track"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <errno.h>
+#include <math.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include "voice_extn.h"
+#include <stdlib.h>
+#include <cutils/str_parms.h>
+
+#ifdef SOURCE_TRACKING_ENABLED
+/* Audio Paramater Key to identify the list of start angles.
+ * Starting angle (in degrees) defines the boundary starting angle for each sector.
+ */
+#define AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES        "SoundFocus.start_angles"
+/* Audio Paramater Key to identify the list of enable flags corresponding to each sector.
+ */
+#define AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS      "SoundFocus.enable_sectors"
+/* Audio Paramater Key to identify the gain step value to be applied to all enabled sectors.
+ */
+#define AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP           "SoundFocus.gain_step"
+/* Audio Paramater Key to identify the list of voice activity detector outputs corresponding
+ * to each sector.
+ */
+#define AUDIO_PARAMETER_KEY_SOURCE_TRACK_VAD                "SourceTrack.vad"
+/* Audio Paramater Key to identify the direction (in degrees) of arrival for desired talker
+ * (dominant source of speech).
+ */
+#define AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_SPEECH         "SourceTrack.doa_speech"
+/* Audio Paramater Key to identify the list of directions (in degrees) of arrival for
+ * interferers (interfering noise sources).
+ */
+#define AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_NOISE          "SourceTrack.doa_noise"
+/* Audio Paramater Key to identify the list of sound strength indicators at each degree
+ * of the horizontal plane referred to by a full circle (360 degrees).
+ */
+#define AUDIO_PARAMETER_KEY_SOURCE_TRACK_POLAR_ACTIVITY     "SourceTrack.polar_activity"
+
+#define BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES        0x1
+#define BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS      0x2
+#define BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP           0x4
+#define BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_VAD                0x8
+#define BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_SPEECH         0x10
+#define BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_NOISE          0x20
+#define BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_POLAR_ACTIVITY     0x40
+
+#define BITMASK_AUDIO_PARAMETER_KEYS_SOUND_FOCUS \
+     (BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES |\
+      BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS |\
+      BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP)
+
+#define BITMASK_AUDIO_PARAMETER_KEYS_SOURCE_TRACKING \
+     (BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_VAD |\
+      BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_SPEECH |\
+      BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_NOISE |\
+      BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_POLAR_ACTIVITY)
+
+#define MAX_SECTORS                                         8
+#define MAX_STR_SIZE                                       2048
+
+struct audio_device_to_audio_interface audio_device_to_interface_table[];
+int audio_device_to_interface_table_len;
+
+struct sound_focus_param {
+    uint16_t start_angle[MAX_SECTORS];
+    uint8_t enable[MAX_SECTORS];
+    uint16_t gain_step;
+};
+
+struct source_tracking_param {
+    uint8_t vad[MAX_SECTORS];
+    uint16_t doa_speech;
+    uint16_t doa_noise[3];
+    uint8_t polar_activity[360];
+};
+
+static int add_audio_intf_name_to_mixer_ctl(audio_devices_t device, char *mixer_ctl_name,
+                                struct audio_device_to_audio_interface *table, int len)
+{
+    int ret = 0;
+    int i;
+
+    if (table == NULL) {
+        ALOGE("%s: table is NULL", __func__);
+
+        ret = -EINVAL;
+        goto done;
+    }
+
+    if (mixer_ctl_name == NULL) {
+        ret = -EINVAL;
+        goto done;
+    }
+
+    for (i=0; i < len; i++) {
+        if (device == table[i].device) {
+             strlcat(mixer_ctl_name, " ", MIXER_PATH_MAX_LENGTH);
+             strlcat(mixer_ctl_name, table[i].interface_name, MIXER_PATH_MAX_LENGTH);
+             break;
+        }
+    }
+
+    if (i == len) {
+        ALOGE("%s: Audio Device not found in the table", __func__);
+
+        ret = -EINVAL;
+    }
+done:
+    return ret;
+}
+
+static bool is_stt_supported_snd_device(snd_device_t snd_device)
+{
+    bool ret = false;
+
+    switch (snd_device) {
+    case SND_DEVICE_IN_HANDSET_DMIC:
+    case SND_DEVICE_IN_HANDSET_DMIC_AEC:
+    case SND_DEVICE_IN_HANDSET_DMIC_NS:
+    case SND_DEVICE_IN_HANDSET_DMIC_AEC_NS:
+    case SND_DEVICE_IN_HANDSET_STEREO_DMIC:
+    case SND_DEVICE_IN_HANDSET_QMIC:
+    case SND_DEVICE_IN_VOICE_DMIC:
+    case SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE:
+    case SND_DEVICE_IN_HEADSET_MIC_FLUENCE:
+    case SND_DEVICE_IN_SPEAKER_DMIC:
+    case SND_DEVICE_IN_SPEAKER_DMIC_AEC:
+    case SND_DEVICE_IN_SPEAKER_DMIC_NS:
+    case SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS:
+    case SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE:
+    case SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE:
+    case SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE:
+    case SND_DEVICE_IN_SPEAKER_QMIC_AEC:
+    case SND_DEVICE_IN_SPEAKER_QMIC_NS:
+    case SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS:
+    case SND_DEVICE_IN_VOICE_SPEAKER_DMIC:
+    case SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE:
+    case SND_DEVICE_IN_VOICE_SPEAKER_QMIC:
+        ret = true;
+        break;
+    default:
+        break;
+    }
+
+    return ret;
+}
+
+audio_devices_t get_input_audio_device(audio_devices_t device)
+{
+    audio_devices_t in_device = device;
+
+    switch (device) {
+    case AUDIO_DEVICE_OUT_EARPIECE:
+    case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+        in_device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+        break;
+    case AUDIO_DEVICE_OUT_SPEAKER:
+        in_device = AUDIO_DEVICE_IN_BACK_MIC;
+        break;
+    case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+        in_device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+        break;
+    case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+        in_device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+        break;
+    default:
+        break;
+    }
+
+    return in_device;
+}
+
+static int derive_mixer_ctl_from_usecase_intf(struct audio_device *adev,
+                                              char *mixer_ctl_name) {
+    struct audio_usecase *usecase = NULL;
+    audio_devices_t in_device;
+    int ret = 0;
+
+    if (mixer_ctl_name == NULL) {
+        ALOGE("%s: mixer_ctl_name is NULL", __func__);
+
+        ret = -EINVAL;
+        goto done;
+    }
+
+    if (voice_is_in_call(adev)) {
+        strlcat(mixer_ctl_name, " ", MIXER_PATH_MAX_LENGTH);
+        strlcat(mixer_ctl_name, "Voice Tx", MIXER_PATH_MAX_LENGTH);
+        usecase = get_usecase_from_list(adev,
+                                        get_usecase_id_from_usecase_type(adev, VOICE_CALL));
+    } else if (voice_extn_compress_voip_is_active(adev)) {
+        strlcat(mixer_ctl_name, " ", MIXER_PATH_MAX_LENGTH);
+        strlcat(mixer_ctl_name, "Voice Tx", MIXER_PATH_MAX_LENGTH);
+        usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
+    } else {
+        strlcat(mixer_ctl_name, " ", MIXER_PATH_MAX_LENGTH);
+        strlcat(mixer_ctl_name, "Audio Tx", MIXER_PATH_MAX_LENGTH);
+        usecase = get_usecase_from_list(adev, get_usecase_id_from_usecase_type(adev, PCM_CAPTURE));
+    }
+
+    if (usecase && (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
+        if (is_stt_supported_snd_device(usecase->in_snd_device)) {
+             in_device = get_input_audio_device(usecase->devices);
+             ret = add_audio_intf_name_to_mixer_ctl(in_device, mixer_ctl_name,
+                audio_device_to_interface_table, audio_device_to_interface_table_len);
+        } else {
+            ALOGE("%s: Sound Focus/Source Tracking not supported on the input sound device (%s)",
+                    __func__, platform_get_snd_device_name(usecase->in_snd_device));
+
+            ret = -EINVAL;
+        }
+    } else {
+        ALOGE("%s: No use case is active which supports Sound Focus/Source Tracking",
+               __func__);
+
+        ret = -EINVAL;
+    }
+
+done:
+    return ret;
+}
+
+static int parse_soundfocus_sourcetracking_keys(struct str_parms *parms)
+{
+    char *str;
+    char *value = NULL;
+    int val, len;
+    int ret = 0, err;
+    char *kv_pairs = str_parms_to_str(parms);
+
+    ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
+
+    len = strlen(kv_pairs);
+    value = (char*)calloc(len, sizeof(char));
+    if(value == NULL) {
+        ret = -ENOMEM;
+        ALOGE("%s: failed to allocate memory", __func__);
+
+        goto done;
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES,
+                            value, len);
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES);
+        ret = ret | BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES;
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS,
+                            value, len);
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS);
+        ret = ret | BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS;
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP,
+                            value, len);
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP);
+        ret = ret | BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP;
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOURCE_TRACK_VAD,
+                            value, len);
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_SOURCE_TRACK_VAD);
+        ret = ret | BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_VAD;
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_SPEECH,
+                            value, len);
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_SPEECH);
+        ret = ret | BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_SPEECH;
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_NOISE,
+                            value, len);
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_NOISE);
+        ret = ret | BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_NOISE;
+    }
+
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOURCE_TRACK_POLAR_ACTIVITY,
+                            value, len);
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_SOURCE_TRACK_POLAR_ACTIVITY);
+        ret = ret | BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_POLAR_ACTIVITY;
+    }
+
+done:
+    free(kv_pairs);
+    if(value != NULL)
+        free(value);
+    ALOGV("%s: returning bitmask = %d", __func__, ret);
+
+    return ret;
+}
+
+static int get_soundfocus_sourcetracking_data(struct audio_device *adev,
+                                        const int bitmask,
+                                        struct sound_focus_param *sound_focus_data,
+                                        struct source_tracking_param *source_tracking_data)
+{
+    struct mixer_ctl *ctl;
+    char sound_focus_mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = "Sound Focus";
+    char source_tracking_mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = "Source Tracking";
+    int ret = -EINVAL;
+    int i, count;
+
+    if (bitmask & BITMASK_AUDIO_PARAMETER_KEYS_SOUND_FOCUS) {
+        /* Derive the mixer control name based on the use case and the audio interface
+         * for the corresponding audio device
+         */
+        ret = derive_mixer_ctl_from_usecase_intf(adev, sound_focus_mixer_ctl_name);
+        if (ret != 0) {
+            ALOGE("%s: Could not get Sound Focus Params", __func__);
+
+            goto done;
+        } else {
+            ALOGV("%s: Mixer Ctl name: %s", __func__, sound_focus_mixer_ctl_name);
+        }
+
+        ctl = mixer_get_ctl_by_name(adev->mixer, sound_focus_mixer_ctl_name);
+        if (!ctl) {
+            ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                  __func__, sound_focus_mixer_ctl_name);
+
+            ret = -EINVAL;
+            goto done;
+        } else {
+            ALOGV("%s: Getting Sound Focus Params", __func__);
+
+            mixer_ctl_update(ctl);
+            count = mixer_ctl_get_num_values(ctl);
+            if (count != sizeof(struct sound_focus_param)) {
+                ALOGE("%s: mixer_ctl_get_num_values() invalid sound focus data size", __func__);
+
+                ret = -EINVAL;
+                goto done;
+            }
+
+            ret = mixer_ctl_get_array(ctl, (void *)sound_focus_data, count);
+            if (ret != 0) {
+                ALOGE("%s: mixer_ctl_get_array() failed to get Sound Focus Params", __func__);
+
+                ret = -EINVAL;
+                goto done;
+            }
+        }
+    }
+
+    if (bitmask & BITMASK_AUDIO_PARAMETER_KEYS_SOURCE_TRACKING) {
+        /* Derive the mixer control name based on the use case and the audio interface
+         * for the corresponding audio device
+         */
+        ret = derive_mixer_ctl_from_usecase_intf(adev, source_tracking_mixer_ctl_name);
+        if (ret != 0) {
+            ALOGE("%s: Could not get Source Tracking Params", __func__);
+
+            goto done;
+        } else {
+            ALOGV("%s: Mixer Ctl name: %s", __func__, source_tracking_mixer_ctl_name);
+        }
+
+        ctl = mixer_get_ctl_by_name(adev->mixer, source_tracking_mixer_ctl_name);
+        if (!ctl) {
+            ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                  __func__, source_tracking_mixer_ctl_name);
+
+            ret = -EINVAL;
+            goto done;
+        } else {
+            ALOGV("%s: Getting Source Tracking Params", __func__);
+
+            mixer_ctl_update(ctl);
+            count = mixer_ctl_get_num_values(ctl);
+            if (count != sizeof(struct source_tracking_param)) {
+                ALOGE("%s: mixer_ctl_get_num_values() invalid source tracking data size", __func__);
+
+                ret = -EINVAL;
+                goto done;
+            }
+
+            ret = mixer_ctl_get_array(ctl, (void *)source_tracking_data, count);
+            if (ret != 0) {
+                ALOGE("%s: mixer_ctl_get_array() failed to get Source Tracking Params", __func__);
+
+                ret = -EINVAL;
+                goto done;
+            }
+        }
+    }
+
+done:
+    return ret;
+}
+
+static void send_soundfocus_sourcetracking_params(struct str_parms *reply,
+                                                const int bitmask,
+                                                const struct sound_focus_param sound_focus_data,
+                                                const struct source_tracking_param source_tracking_data)
+{
+    int i = 0, len = 0;
+    char value[MAX_STR_SIZE] = "";
+
+    if (bitmask & BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES) {
+        for (i = 0; i < MAX_SECTORS; i++) {
+            if ((i >=4) && (sound_focus_data.start_angle[i] == 0xFFFF))
+                continue;
+            if (i)
+                snprintf(value + strlen(value), MAX_STR_SIZE, ",");
+            snprintf(value + strlen(value), MAX_STR_SIZE, "%d", sound_focus_data.start_angle[i]);
+        }
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES, value);
+    }
+
+    strlcpy(value, "", sizeof(""));
+    if (bitmask & BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS) {
+        for (i = 0; i < MAX_SECTORS; i++) {
+            if ((i >=4) && (sound_focus_data.enable[i] == 0xFF))
+                continue;
+            if (i)
+                snprintf(value + strlen(value), MAX_STR_SIZE, ",");
+            snprintf(value + strlen(value), MAX_STR_SIZE, "%d", sound_focus_data.enable[i]);
+        }
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS, value);
+    }
+
+    if (bitmask & BITMASK_AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP)
+        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP, sound_focus_data.gain_step);
+
+    strlcpy(value, "", sizeof(""));
+    if (bitmask & BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_VAD) {
+        for (i = 0; i < MAX_SECTORS; i++) {
+            if ((i >=4) && (source_tracking_data.vad[i] == 0xFF))
+                continue;
+            if (i)
+                snprintf(value + strlen(value), MAX_STR_SIZE, ",");
+            snprintf(value + strlen(value), MAX_STR_SIZE, "%d", source_tracking_data.vad[i]);
+        }
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SOURCE_TRACK_VAD, value);
+    }
+
+    if (bitmask & BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_SPEECH)
+        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_SPEECH, source_tracking_data.doa_speech);
+
+    strlcpy(value, "", sizeof(""));
+    if (bitmask & BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_NOISE) {
+        snprintf(value, MAX_STR_SIZE,
+                     "%d,%d,%d", source_tracking_data.doa_noise[0], source_tracking_data.doa_noise[1], source_tracking_data.doa_noise[2]);
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SOURCE_TRACK_DOA_NOISE, value);
+    }
+
+    strlcpy(value, "", sizeof(""));
+    if (bitmask & BITMASK_AUDIO_PARAMETER_KEY_SOURCE_TRACK_POLAR_ACTIVITY) {
+        for (i = 0; i < 360; i++) {
+            if (i)
+                snprintf(value + strlen(value), MAX_STR_SIZE, ",");
+            snprintf(value + strlen(value), MAX_STR_SIZE, "%d", source_tracking_data.polar_activity[i]);
+        }
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_SOURCE_TRACK_POLAR_ACTIVITY, value);
+    }
+}
+
+void audio_extn_source_track_get_parameters(struct audio_device *adev,
+                                            struct str_parms *query,
+                                            struct str_parms *reply)
+{
+    int bitmask = 0, ret = 0;
+    struct sound_focus_param sound_focus_data;
+    struct source_tracking_param source_tracking_data;
+
+    memset(&sound_focus_data, 0xFF, sizeof(struct sound_focus_param));
+    memset(&source_tracking_data, 0xFF, sizeof(struct source_tracking_param));
+
+    // Parse the input parameters string for Source Tracking keys
+    bitmask = parse_soundfocus_sourcetracking_keys(query);
+    if (bitmask) {
+        // Get the parameter values from the backend
+        ret = get_soundfocus_sourcetracking_data(adev, bitmask, &sound_focus_data, &source_tracking_data);
+        if (ret == 0) {
+            // Construct the return string with key, value pairs
+            send_soundfocus_sourcetracking_params(reply, bitmask, sound_focus_data, source_tracking_data);
+        }
+    }
+}
+
+void audio_extn_source_track_set_parameters(struct audio_device *adev,
+                                            struct str_parms *parms)
+{
+    int len, ret, count;;
+    struct mixer_ctl *ctl;
+    char sound_focus_mixer_ctl_name[MIXER_PATH_MAX_LENGTH] = "Sound Focus";
+    char *value = NULL;
+    char *kv_pairs = str_parms_to_str(parms);
+
+    len = strlen(kv_pairs);
+    value = (char*)calloc(len, sizeof(char));
+    if(value == NULL) {
+        ret = -ENOMEM;
+        ALOGE("%s: failed to allocate memory", __func__);
+
+        goto done;
+    }
+
+    // Parse the input parameter string for Source Tracking key, value pairs
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES,
+                            value, len);
+    if (ret >= 0) {
+        char *saveptr, *tok;
+        int i = 0, val;
+        struct sound_focus_param sound_focus_param;
+
+        memset(&sound_focus_param, 0xFF, sizeof(struct sound_focus_param));
+
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_START_ANGLES);
+        tok = strtok_r(value, ",", &saveptr);
+        while ((i < MAX_SECTORS) && (tok != NULL)) {
+            if (sscanf(tok, "%d", &val) == 1) {
+                sound_focus_param.start_angle[i++] = (uint16_t)val;
+            }
+            tok = strtok_r(NULL, ",", &saveptr);
+        }
+
+        ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS,
+                                value, len);
+        if (ret >= 0) {
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_ENABLE_SECTORS);
+            tok = strtok_r(value, ",", &saveptr);
+            i = 0;
+            while ((i < MAX_SECTORS) && (tok != NULL)) {
+                if (sscanf(tok, "%d", &val) == 1) {
+                    sound_focus_param.enable[i++] = (uint8_t)val;
+                }
+                tok = strtok_r(NULL, ",", &saveptr);
+            }
+        } else {
+            ALOGE("%s: SoundFocus.enable_sectors key not found", __func__);
+
+            goto done;
+        }
+
+        ret = str_parms_get_int(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP, &val);
+        if (ret >= 0) {
+            str_parms_del(parms, AUDIO_PARAMETER_KEY_SOUND_FOCUS_GAIN_STEP);
+            sound_focus_param.gain_step = (uint16_t)val;
+        } else {
+            ALOGE("%s: SoundFocus.gain_step key not found", __func__);
+
+            goto done;
+        }
+
+        /* Derive the mixer control name based on the use case and the audio h/w
+         * interface name for the corresponding audio device
+         */
+        ret = derive_mixer_ctl_from_usecase_intf(adev, sound_focus_mixer_ctl_name);
+        if (ret != 0) {
+            ALOGE("%s: Could not set Sound Focus Params", __func__);
+
+            goto done;
+        } else {
+            ALOGV("%s: Mixer Ctl name: %s", __func__, sound_focus_mixer_ctl_name);
+        }
+
+        ctl = mixer_get_ctl_by_name(adev->mixer, sound_focus_mixer_ctl_name);
+        if (!ctl) {
+            ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                  __func__, sound_focus_mixer_ctl_name);
+
+            goto done;
+        } else {
+            ALOGV("%s: Setting Sound Focus Params", __func__);
+
+            for (i = 0; i < MAX_SECTORS;i++) {
+                ALOGV("%s: start_angles[%d] = %d", __func__, i, sound_focus_param.start_angle[i]);
+            }
+            for (i = 0; i < MAX_SECTORS;i++) {
+                ALOGV("%s: enable_sectors[%d] = %d", __func__, i, sound_focus_param.enable[i]);
+            }
+            ALOGV("%s: gain_step = %d", __func__, sound_focus_param.gain_step);
+
+            mixer_ctl_update(ctl);
+            count = mixer_ctl_get_num_values(ctl);
+            if (count != sizeof(struct sound_focus_param)) {
+                ALOGE("%s: mixer_ctl_get_num_values() invalid data size", __func__);
+
+                goto done;
+            }
+
+            // Set the parameters on the mixer control derived above
+            ret = mixer_ctl_set_array(ctl, (void *)&sound_focus_param, count);
+            if (ret != 0) {
+                ALOGE("%s: mixer_ctl_set_array() failed to set Sound Focus Params", __func__);
+
+                goto done;
+            }
+       }
+    }
+
+done:
+    free(kv_pairs);
+    if(value != NULL)
+        free(value);
+    return;
+}
+#endif /* SOURCE_TRACKING_ENABLED end */
diff --git a/hal/audio_extn/spkr_protection.c b/hal/audio_extn/spkr_protection.c
index a350198..312be97 100644
--- a/hal/audio_extn/spkr_protection.c
+++ b/hal/audio_extn/spkr_protection.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 - 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013 - 2015, 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
@@ -141,7 +141,7 @@
        handle.spkr_in_use = true;
     else {
        handle.spkr_in_use = false;
-       clock_gettime(CLOCK_MONOTONIC, &handle.spkr_last_time_used);
+       clock_gettime(CLOCK_BOOTTIME, &handle.spkr_last_time_used);
    }
 }
 
@@ -181,7 +181,7 @@
         *sec = 0;
          return true;
      } else {
-         clock_gettime(CLOCK_MONOTONIC, &temp);
+         clock_gettime(CLOCK_BOOTTIME, &temp);
          *sec = temp.tv_sec - handle.spkr_last_time_used.tv_sec;
          return false;
      }
@@ -475,9 +475,15 @@
             pcm_close(handle.pcm_tx);
         handle.pcm_tx = NULL;
         /* Clear TX calibration to handset mic */
-        platform_send_audio_calibration(adev->platform,
-        SND_DEVICE_IN_HANDSET_MIC,
-        platform_get_default_app_type(adev->platform), 8000);
+        if (disable_tx) {
+            uc_info_tx->id = USECASE_AUDIO_RECORD;
+            uc_info_tx->type = PCM_CAPTURE;
+            uc_info_tx->in_snd_device = SND_DEVICE_IN_HANDSET_MIC;
+            uc_info_tx->out_snd_device = SND_DEVICE_NONE;
+            platform_send_audio_calibration(adev->platform,
+              uc_info_tx,
+              platform_get_default_app_type(adev->platform), 8000);
+        }
         if (!status.status) {
             protCfg.mode = MSM_SPKR_PROT_CALIBRATED;
             protCfg.r0[SP_V2_SPKR_1] = status.r0[SP_V2_SPKR_1];
@@ -810,6 +816,7 @@
     struct audio_usecase *uc_info_tx;
     struct audio_device *adev = handle.adev_handle;
     int32_t pcm_dev_tx_id = -1, ret = 0;
+    bool disable_tx = false;
 
     ALOGV("%s: Entry", __func__);
     /* cancel speaker calibration */
@@ -836,6 +843,7 @@
         uc_info_tx->out_snd_device = SND_DEVICE_NONE;
         handle.pcm_tx = NULL;
         list_add_tail(&adev->usecase_list, &uc_info_tx->list);
+        disable_tx = true;
         enable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK);
         enable_audio_route(adev, uc_info_tx);
 
@@ -862,14 +870,24 @@
 
 exit:
    /* Clear VI feedback cal and replace with handset MIC  */
-   platform_send_audio_calibration(adev->platform,
-        SND_DEVICE_IN_HANDSET_MIC,
-        platform_get_default_app_type(adev->platform), 8000);
-    if (ret) {
+    if (disable_tx) {
+        uc_info_tx->id = USECASE_AUDIO_RECORD;
+        uc_info_tx->type = PCM_CAPTURE;
+        uc_info_tx->in_snd_device = SND_DEVICE_IN_HANDSET_MIC;
+        uc_info_tx->out_snd_device = SND_DEVICE_NONE;
+        platform_send_audio_calibration(adev->platform,
+          uc_info_tx,
+          platform_get_default_app_type(adev->platform), 8000);
+     }
+     if (ret) {
         if (handle.pcm_tx)
             pcm_close(handle.pcm_tx);
         handle.pcm_tx = NULL;
         list_remove(&uc_info_tx->list);
+        uc_info_tx->id = USECASE_AUDIO_SPKR_CALIB_TX;
+        uc_info_tx->type = PCM_CAPTURE;
+        uc_info_tx->in_snd_device = SND_DEVICE_IN_CAPTURE_VI_FEEDBACK;
+        uc_info_tx->out_snd_device = SND_DEVICE_NONE;
         disable_snd_device(adev, SND_DEVICE_IN_CAPTURE_VI_FEEDBACK);
         disable_audio_route(adev, uc_info_tx);
         free(uc_info_tx);
diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c
index a4ea134..13e3138 100644
--- a/hal/audio_extn/usb.c
+++ b/hal/audio_extn/usb.c
@@ -111,8 +111,8 @@
          // Look for the first control named ".*Playback Volume" that isn't for a microphone
          for (i = 0; i < num_ctls; i++) {
              ctl = mixer_get_ctl(usbMixer, i);
-             if (strstr((const char *)mixer_ctl_get_name(ctl), "Playback Volume") &&
-                 !strstr((const char *)mixer_ctl_get_name(ctl), "Mic")) {
+             if ((ctl) && (strstr((const char *)mixer_ctl_get_name(ctl), "Playback Volume") &&
+                 !strstr((const char *)mixer_ctl_get_name(ctl), "Mic"))) {
                    break;
              }
          }
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 273a194..82b596f 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -33,6 +33,7 @@
 #include "platform.h"
 #include "platform_api.h"
 #include "audio_extn.h"
+#include "voice.h"
 
 #define AUDIO_OUTPUT_POLICY_VENDOR_CONFIG_FILE "/vendor/etc/audio_output_policy.conf"
 
@@ -48,6 +49,9 @@
 #define STRING_TO_ENUM(string) { #string, string }
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
+#define BASE_TABLE_SIZE 64
+#define MAX_BASEINDEX_LEN 256
+
 struct string_to_enum {
     const char *name;
     uint32_t value;
@@ -60,12 +64,14 @@
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_HW_AV_SYNC),
 #ifdef INCALL_MUSIC_ENABLED
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_INCALL_MUSIC),
 #endif
 #ifdef COMPRESS_VOIP_ENABLED
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_VOIP_RX),
 #endif
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH),
 };
 
 const struct string_to_enum s_format_name_to_enum_table[] = {
@@ -94,9 +100,24 @@
     STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT_OFFLOAD),
     STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_OFFLOAD),
     STRING_TO_ENUM(AUDIO_FORMAT_FLAC),
+    STRING_TO_ENUM(AUDIO_FORMAT_ALAC),
+    STRING_TO_ENUM(AUDIO_FORMAT_APE),
+    STRING_TO_ENUM(AUDIO_FORMAT_E_AC3_JOC),
+    STRING_TO_ENUM(AUDIO_FORMAT_AAC_LC),
+    STRING_TO_ENUM(AUDIO_FORMAT_AAC_HE_V1),
+    STRING_TO_ENUM(AUDIO_FORMAT_AAC_HE_V2),
 #endif
 };
 
+static char bTable[BASE_TABLE_SIZE] = {
+            'A','B','C','D','E','F','G','H','I','J','K','L',
+            'M','N','O','P','Q','R','S','T','U','V','W','X',
+            'Y','Z','a','b','c','d','e','f','g','h','i','j',
+            'k','l','m','n','o','p','q','r','s','t','u','v',
+            'w','x','y','z','0','1','2','3','4','5','6','7',
+            '8','9','+','/'
+};
+
 static uint32_t string_to_enum(const struct string_to_enum *table, size_t size,
                                const char *name)
 {
@@ -394,6 +415,7 @@
         ss_info = node_to_item(node_i, struct stream_sample_rate, list);
         if ((sample_rate <= ss_info->sample_rate) &&
             (bit_width == so_info->app_type_cfg.bit_width)) {
+
             app_type_cfg->app_type = so_info->app_type_cfg.app_type;
             app_type_cfg->sample_rate = ss_info->sample_rate;
             app_type_cfg->bit_width = so_info->app_type_cfg.bit_width;
@@ -439,6 +461,9 @@
 
     if ((24 == bit_width) &&
         (devices & AUDIO_DEVICE_OUT_SPEAKER)) {
+        int32_t bw = platform_get_snd_device_bit_width(SND_DEVICE_OUT_SPEAKER);
+        if (-ENOSYS != bw)
+            bit_width = (uint32_t)bw;
         sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
         ALOGI("%s Allowing 24-bit playback on speaker ONLY at default sampling rate", __func__);
     }
@@ -495,8 +520,8 @@
     if ((usecase->id != USECASE_AUDIO_PLAYBACK_DEEP_BUFFER) &&
         (usecase->id != USECASE_AUDIO_PLAYBACK_LOW_LATENCY) &&
         (usecase->id != USECASE_AUDIO_PLAYBACK_MULTI_CH) &&
-        (usecase->id != USECASE_AUDIO_PLAYBACK_OFFLOAD)) {
-        ALOGV("%s: a playback path where app type cfg is not required", __func__);
+        (!is_offload_usecase(usecase->id))) {
+        ALOGV("%s: a playback path where app type cfg is not required %d", __func__, usecase->id);
         rc = 0;
         goto exit_send_app_type_cfg;
     }
@@ -535,8 +560,12 @@
 
     app_type_cfg[len++] = out->app_type_cfg.app_type;
     app_type_cfg[len++] = acdb_dev_id;
-    app_type_cfg[len++] = sample_rate;
-
+    if (((out->format == AUDIO_FORMAT_E_AC3) ||
+        (out->format == AUDIO_FORMAT_E_AC3_JOC)) &&
+        (out->flags  & AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH))
+        app_type_cfg[len++] = sample_rate * 4;
+    else
+        app_type_cfg[len++] = sample_rate;
     mixer_ctl_set_array(ctl, app_type_cfg, len);
     ALOGI("%s app_type %d, acdb_dev_id %d, sample_rate %d",
            __func__, out->app_type_cfg.app_type, acdb_dev_id, sample_rate);
@@ -567,3 +596,145 @@
     }
 }
 
+// Base64 Encode and Decode
+// Not all features supported. This must be used only with following conditions.
+// Decode Modes: Support with and without padding
+//         CRLF not handling. So no CRLF in string to decode.
+// Encode Modes: Supports only padding
+int b64decode(char *inp, int ilen, uint8_t* outp)
+{
+    int i, j, k, ii, num;
+    int rem, pcnt;
+    uint32_t res=0;
+    uint8_t getIndex[MAX_BASEINDEX_LEN];
+    uint8_t tmp, cflag;
+
+    if(inp == NULL || outp == NULL || ilen <= 0) {
+        ALOGE("[%s] received NULL pointer or zero length",__func__);
+        return -1;
+    }
+
+    memset(getIndex, MAX_BASEINDEX_LEN-1, sizeof(getIndex));
+    for(i=0;i<BASE_TABLE_SIZE;i++) {
+        getIndex[(uint8_t)bTable[i]] = (uint8_t)i;
+    }
+    getIndex[(uint8_t)'=']=0;
+
+    j=0;k=0;
+    num = ilen/4;
+    rem = ilen%4;
+    if(rem==0)
+        num = num-1;
+    cflag=0;
+    for(i=0; i<num; i++) {
+        res=0;
+        for(ii=0;ii<4;ii++) {
+            res = res << 6;
+            tmp = getIndex[(uint8_t)inp[j++]];
+            res = res | tmp;
+            cflag = cflag | tmp;
+        }
+        outp[k++] = (res >> 16)&0xFF;
+        outp[k++] = (res >> 8)&0xFF;
+        outp[k++] = res & 0xFF;
+    }
+
+    // Handle last bytes special
+    pcnt=0;
+    if(rem == 0) {
+        //With padding or full data
+        res = 0;
+        for(ii=0;ii<4;ii++) {
+            if(inp[j] == '=')
+                pcnt++;
+            res = res << 6;
+            tmp = getIndex[(uint8_t)inp[j++]];
+            res = res | tmp;
+            cflag = cflag | tmp;
+        }
+        outp[k++] = res >> 16;
+        if(pcnt == 2)
+            goto done;
+        outp[k++] = (res>>8)&0xFF;
+        if(pcnt == 1)
+            goto done;
+        outp[k++] = res&0xFF;
+    } else {
+        //without padding
+        res = 0;
+        for(i=0;i<rem;i++) {
+            res = res << 6;
+            tmp = getIndex[(uint8_t)inp[j++]];
+            res = res | tmp;
+            cflag = cflag | tmp;
+        }
+        for(i=rem;i<4;i++) {
+            res = res << 6;
+            pcnt++;
+        }
+        outp[k++] = res >> 16;
+        if(pcnt == 2)
+            goto done;
+        outp[k++] = (res>>8)&0xFF;
+        if(pcnt == 1)
+            goto done;
+        outp[k++] = res&0xFF;
+    }
+done:
+    if(cflag == 0xFF) {
+        ALOGE("[%s] base64 decode failed. Invalid character found %s",
+            __func__, inp);
+        return 0;
+    }
+    return k;
+}
+
+int b64encode(uint8_t *inp, int ilen, char* outp)
+{
+    int i,j,k, num;
+    int rem=0;
+    uint32_t res=0;
+
+    if(inp == NULL || outp == NULL || ilen<=0) {
+        ALOGE("[%s] received NULL pointer or zero input length",__func__);
+        return -1;
+    }
+
+    num = ilen/3;
+    rem = ilen%3;
+    j=0;k=0;
+    for(i=0; i<num; i++) {
+        //prepare index
+        res = inp[j++]<<16;
+        res = res | inp[j++]<<8;
+        res = res | inp[j++];
+        //get output map from index
+        outp[k++] = (char) bTable[(res>>18)&0x3F];
+        outp[k++] = (char) bTable[(res>>12)&0x3F];
+        outp[k++] = (char) bTable[(res>>6)&0x3F];
+        outp[k++] = (char) bTable[res&0x3F];
+    }
+
+    switch(rem) {
+        case 1:
+            res = inp[j++]<<16;
+            outp[k++] = (char) bTable[res>>18];
+            outp[k++] = (char) bTable[(res>>12)&0x3F];
+            //outp[k++] = '=';
+            //outp[k++] = '=';
+            break;
+        case 2:
+            res = inp[j++]<<16;
+            res = res | inp[j++]<<8;
+            outp[k++] = (char) bTable[res>>18];
+            outp[k++] = (char) bTable[(res>>12)&0x3F];
+            outp[k++] = (char) bTable[(res>>6)&0x3F];
+            //outp[k++] = '=';
+            break;
+        default:
+            break;
+    }
+done:
+    outp[k] = '\0';
+    return k;
+}
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index af097c1..3d157da 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -15,6 +15,24 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
+ * This file was modified by DTS, Inc. The portions of the
+ * code modified by DTS, Inc are copyrighted and
+ * licensed separately, as follows:
+ *
+ * (C) 2014 DTS, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 #define LOG_TAG "audio_hw_primary"
@@ -57,13 +75,19 @@
 
 #define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4
 /* ToDo: Check and update a proper value in msec */
-#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96
+#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 50
 #define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
 
 #define PROXY_OPEN_RETRY_COUNT           100
 #define PROXY_OPEN_WAIT_TIME             20
 
+#ifdef USE_LL_AS_PRIMARY_OUTPUT
+#define USECASE_AUDIO_PLAYBACK_PRIMARY USECASE_AUDIO_PLAYBACK_LOW_LATENCY
+#define PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY pcm_config_low_latency
+#else
 #define USECASE_AUDIO_PLAYBACK_PRIMARY USECASE_AUDIO_PLAYBACK_DEEP_BUFFER
+#define PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY pcm_config_deep_buffer
+#endif
 
 static unsigned int configured_low_latency_capture_period_size =
         LOW_LATENCY_CAPTURE_PERIOD_SIZE;
@@ -166,6 +190,8 @@
     [USECASE_VOLTE_CALL] = "volte-call",
     [USECASE_QCHAT_CALL] = "qchat-call",
     [USECASE_VOWLAN_CALL] = "vowlan-call",
+    [USECASE_VOICEMMODE1_CALL] = "voicemmode1-call",
+    [USECASE_VOICEMMODE2_CALL] = "voicemmode2-call",
     [USECASE_COMPRESS_VOIP_CALL] = "compress-voip-call",
     [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink",
     [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink",
@@ -206,7 +232,11 @@
 
 static const struct string_to_enum out_channels_name_to_enum_table[] = {
     STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
-    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
+    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_QUAD),/* QUAD_BACK is same as QUAD */
+    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_QUAD_SIDE),
+    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_PENTA),
+    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1), /* 5POINT1_BACK is same as 5POINT1 */
+    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1_SIDE),
     STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
 };
 
@@ -257,7 +287,12 @@
         format == AUDIO_FORMAT_AAC_HE_V2 ||
         format == AUDIO_FORMAT_PCM_16_BIT_OFFLOAD ||
         format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD ||
-        format == AUDIO_FORMAT_FLAC)
+        format == AUDIO_FORMAT_FLAC ||
+        format == AUDIO_FORMAT_ALAC ||
+        format == AUDIO_FORMAT_APE ||
+        format == AUDIO_FORMAT_VORBIS ||
+        format == AUDIO_FORMAT_WMA ||
+        format == AUDIO_FORMAT_WMA_PRO)
            return true;
 
     return false;
@@ -280,6 +315,21 @@
     case AUDIO_FORMAT_FLAC:
         id = SND_AUDIOCODEC_FLAC;
         break;
+    case AUDIO_FORMAT_ALAC:
+        id = SND_AUDIOCODEC_ALAC;
+        break;
+    case AUDIO_FORMAT_APE:
+        id = SND_AUDIOCODEC_APE;
+        break;
+    case AUDIO_FORMAT_VORBIS:
+        id = SND_AUDIOCODEC_VORBIS;
+        break;
+    case AUDIO_FORMAT_WMA:
+        id = SND_AUDIOCODEC_WMA;
+        break;
+    case AUDIO_FORMAT_WMA_PRO:
+        id = SND_AUDIOCODEC_WMA_PRO;
+        break;
     default:
         ALOGE("%s: Unsupported audio format :%x", __func__, format);
     }
@@ -326,8 +376,7 @@
        specified usecase to new snd devices */
     list_for_each(node, &adev->usecase_list) {
         usecase = node_to_item(node, struct audio_usecase, list);
-        if ((usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) &&
-             (usecase != uc_info))
+        if ((usecase->type == VOICE_CALL) && (usecase != uc_info))
             enable_audio_route(adev, usecase);
     }
     return 0;
@@ -444,8 +493,10 @@
            adev->snd_dev_ref_cnt[snd_device]--;
            return -EINVAL;
        }
+       audio_extn_dev_arbi_acquire(snd_device);
         if (audio_extn_spkr_prot_start_processing(snd_device)) {
             ALOGE("%s: spkr_start_processing failed", __func__);
+            audio_extn_dev_arbi_release(snd_device);
             return -EINVAL;
         }
     } else {
@@ -511,9 +562,9 @@
             audio_extn_spkr_prot_stop_processing(snd_device);
         } else {
             audio_route_reset_and_update_path(adev->audio_route, device_name);
-            audio_extn_dev_arbi_release(snd_device);
         }
 
+        audio_extn_dev_arbi_release(snd_device);
         audio_extn_sound_trigger_update_device_status(snd_device,
                                         ST_EVENT_SND_DEVICE_FREE);
         audio_extn_listen_update_device_status(snd_device,
@@ -597,7 +648,7 @@
             /* 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 && usecase->type != VOIP_CALL)
+                if (usecase->type != VOICE_CALL)
                     enable_audio_route(adev, usecase);
             }
         }
@@ -630,7 +681,9 @@
         usecase = node_to_item(node, struct audio_usecase, list);
         if (usecase->type != PCM_PLAYBACK &&
                 usecase != uc_info &&
-                usecase->in_snd_device != snd_device) {
+                usecase->in_snd_device != snd_device &&
+                (usecase->devices & AUDIO_DEVICE_OUT_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],
                   platform_get_snd_device_name(usecase->in_snd_device));
@@ -666,7 +719,7 @@
             /* Update the in_snd_device only before enabling the audio route */
             if (switch_device[usecase->id] ) {
                 usecase->in_snd_device = snd_device;
-                if (usecase->type != VOICE_CALL && usecase->type != VOIP_CALL)
+                if (usecase->type != VOICE_CALL)
                     enable_audio_route(adev, usecase);
             }
         }
@@ -676,7 +729,7 @@
 /* must be called with hw device mutex locked */
 static int read_hdmi_channel_masks(struct stream_out *out)
 {
-    int ret = 0;
+    int ret = 0, i = 0;
     int channels = platform_edid_get_max_channels(out->dev->platform);
 
     switch (channels) {
@@ -685,13 +738,21 @@
          * Stereo case is handled in normal playback path
          */
     case 6:
-        ALOGV("%s: HDMI supports 5.1", __func__);
-        out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1;
+        ALOGV("%s: HDMI supports Quad and 5.1", __func__);
+        out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_QUAD;
+        out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_QUAD_SIDE;
+        out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_PENTA;
+        out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_5POINT1;
+        out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_5POINT1_SIDE;
         break;
     case 8:
-        ALOGV("%s: HDMI supports 5.1 and 7.1 channels", __func__);
-        out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1;
-        out->supported_channel_masks[1] = AUDIO_CHANNEL_OUT_7POINT1;
+        ALOGV("%s: HDMI supports Quad, 5.1 and 7.1 channels", __func__);
+        out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_QUAD;
+        out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_QUAD_SIDE;
+        out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_PENTA;
+        out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_5POINT1;
+        out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_5POINT1_SIDE;
+        out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_7POINT1;
         break;
     default:
         ALOGE("HDMI does not support multi channel playback");
@@ -701,14 +762,15 @@
     return ret;
 }
 
-static audio_usecase_t get_voice_usecase_id_from_list(struct audio_device *adev)
+audio_usecase_t get_usecase_id_from_usecase_type(struct audio_device *adev,
+                                                 usecase_type_t type)
 {
     struct audio_usecase *usecase;
     struct listnode *node;
 
     list_for_each(node, &adev->usecase_list) {
         usecase = node_to_item(node, struct audio_usecase, list);
-        if (usecase->type == VOICE_CALL) {
+        if (usecase->type == type) {
             ALOGV("%s: usecase id %d", __func__, usecase->id);
             return usecase->id;
         }
@@ -765,7 +827,7 @@
          */
         if (voice_is_in_call(adev) && adev->mode == AUDIO_MODE_IN_CALL) {
             vc_usecase = get_usecase_from_list(adev,
-                                               get_voice_usecase_id_from_list(adev));
+                                               get_usecase_id_from_usecase_type(adev, VOICE_CALL));
             if ((vc_usecase) && ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
                 (usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL))) {
                 in_snd_device = vc_usecase->in_snd_device;
@@ -794,7 +856,9 @@
                 out_snd_device = platform_get_output_snd_device(adev->platform,
                                             usecase->stream.out->devices);
                 if (usecase->stream.out == adev->primary_output &&
-                        adev->active_input) {
+                        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);
                 }
             }
@@ -808,6 +872,7 @@
                      adev->active_input->source == AUDIO_SOURCE_MIC)) &&
                      adev->primary_output && !adev->primary_output->standby) {
                     out_device = adev->primary_output->devices;
+                    platform_set_echo_reference(adev->platform, false);
                 } else if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY) {
                     out_device = AUDIO_DEVICE_OUT_TELEPHONY_TX;
                 }
@@ -965,7 +1030,8 @@
     if (ret)
         goto error_config;
     else
-        ALOGV("%s: usecase(%d)", __func__, in->usecase);
+        ALOGD("%s: Updated usecase(%d: %s)",
+              __func__, in->usecase, use_case_table[in->usecase]);
 
     in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
     if (in->pcm_device_id < 0) {
@@ -1184,7 +1250,6 @@
                 compress_drain(out->compr);
             else
                 ALOGE("%s: Next track returned error %d",__func__, ret);
-
             if (ret != -ENETRESET) {
                 send_callback = true;
                 event = STREAM_CBK_EVENT_DRAIN_READY;
@@ -1207,6 +1272,7 @@
         out->offload_thread_blocked = false;
         pthread_cond_signal(&out->cond);
         if (send_callback) {
+            ALOGVV("%s: sending offload_callback event %d", __func__, event);
             out->offload_callback(event, NULL, out->offload_cookie);
         }
         free(cmd);
@@ -1272,8 +1338,9 @@
                 break;
             } else if (is_offload_usecase(usecase->id) &&
                        audio_channel_count_from_out_mask(usecase->stream.out->channel_mask) > 2) {
-                ALOGD("%s: multi-channel(%x) compress offload playback is active, "
-                      "no change in HDMI channels", __func__, usecase->stream.out->channel_mask);
+                ALOGD("%s:multi-channel(%x) compress offload playback is active"
+                      ", no change in HDMI channels", __func__,
+                      usecase->stream.out->channel_mask);
                 ret = false;
                 break;
             }
@@ -1288,16 +1355,25 @@
     struct listnode *node;
     struct audio_usecase *usecase;
 
+    unsigned int supported_channels = platform_edid_get_max_channels(
+                                          adev->platform);
+    ALOGV("supported_channels %d, channels %d", supported_channels, channels);
     /* Check if change in HDMI channel config is allowed */
     if (!allow_hdmi_channel_config(adev))
         return 0;
 
+    if (channels > supported_channels)
+        channels = supported_channels;
+
     if (channels == adev->cur_hdmi_channels) {
-        ALOGD("%s: Requested channels are same as current channels(%d)", __func__, channels);
+        ALOGD("%s: Requested channels are same as current channels(%d)",
+               __func__, channels);
         return 0;
     }
 
+    /*TODO: CHECK for passthrough don't set channel map for passthrough*/
     platform_set_hdmi_channels(adev->platform, channels);
+    platform_set_edid_channels_configuration(adev->platform, channels);
     adev->cur_hdmi_channels = channels;
 
     /*
@@ -1343,9 +1419,13 @@
         return -EINVAL;
     }
 
-    if (is_offload_usecase(out->usecase)) {
+    if (is_offload_usecase(out->usecase) &&
+        !(audio_extn_dolby_is_passthrough_stream(out->flags))) {
         if (adev->visualizer_stop_output != NULL)
             adev->visualizer_stop_output(out->handle, out->pcm_device_id);
+
+        audio_extn_dts_remove_state_notifier_node(out->usecase);
+
         if (adev->offload_effects_stop_output != NULL)
             adev->offload_effects_stop_output(out->handle, out->pcm_device_id);
     }
@@ -1359,6 +1439,15 @@
     list_remove(&uc_info->list);
     free(uc_info);
 
+    if (is_offload_usecase(out->usecase) &&
+        (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+        (audio_extn_dolby_is_passthrough_stream(out->flags))) {
+        ALOGV("Disable passthrough , reset mixer to pcm");
+        /* NO_PASSTHROUGH */
+        out->compr_config.codec->compr_passthr = 0;
+        audio_extn_dolby_set_hdmi_config(adev, out);
+        audio_extn_dolby_set_dap_bypass(adev, DAP_STATE_ON);
+    }
     /* Must be called after removing the usecase from list */
     if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
         check_and_set_hdmi_channels(adev, DEFAULT_HDMI_OUT_CHANNELS);
@@ -1396,7 +1485,7 @@
         ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
               __func__, out->pcm_device_id, out->usecase);
         ret = -EINVAL;
-        goto error_config;
+        goto error_open;
     }
 
     uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
@@ -1412,22 +1501,31 @@
     uc_info->devices = out->devices;
     uc_info->in_snd_device = SND_DEVICE_NONE;
     uc_info->out_snd_device = SND_DEVICE_NONE;
-
     /* This must be called before adding this usecase to the list */
     if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+        if (is_offload_usecase(out->usecase)) {
+            if (audio_extn_dolby_is_passthrough_stream(out->flags)) {
+                audio_extn_dolby_update_passt_stream_configuration(adev, out);
+            }
+        }
         property_get("audio.use.hdmi.sink.cap", prop_value, NULL);
         if (!strncmp("true", prop_value, 4)) {
             sink_channels = platform_edid_get_max_channels(out->dev->platform);
-            ALOGD("%s: set HDMI channel count[%d] based on sink capability", __func__, sink_channels);
+            ALOGD("%s: set HDMI channel count[%d] based on sink capability",
+                   __func__, sink_channels);
             check_and_set_hdmi_channels(adev, sink_channels);
         } else {
-            if (is_offload_usecase(out->usecase))
-                check_and_set_hdmi_channels(adev, out->compr_config.codec->ch_in);
-            else
+            if (is_offload_usecase(out->usecase)) {
+                unsigned int ch_count =  out->compr_config.codec->ch_in;
+                if (audio_extn_dolby_is_passthrough_stream(out->flags))
+                    /* backend channel config for passthrough stream is stereo */
+                    ch_count = 2;
+                check_and_set_hdmi_channels(adev, ch_count);
+            } else
                 check_and_set_hdmi_channels(adev, out->config.channels);
         }
+        audio_extn_dolby_set_hdmi_config(adev, out);
     }
-
     list_add_tail(&adev->usecase_list, &uc_info->list);
 
     select_devices(adev, out->usecase);
@@ -1461,7 +1559,11 @@
             }
             break;
         }
+        platform_set_stream_channel_map(adev->platform, out->channel_mask,
+                                    out->pcm_device_id);
     } else {
+        platform_set_stream_channel_map(adev->platform, out->channel_mask,
+                                    out->pcm_device_id);
         out->pcm = NULL;
         out->compr = compress_open(adev->snd_card,
                                    out->pcm_device_id,
@@ -1476,15 +1578,30 @@
         if (out->offload_callback)
             compress_nonblock(out->compr, out->non_blocking);
 
+        /* Since small bufs uses blocking writes, a write will be blocked
+           for the default max poll time (20s) in the event of an SSR.
+           Reduce the poll time to observe and deal with SSR faster.
+        */
+        if (out->use_small_bufs) {
+            compress_set_max_poll_wait(out->compr, 1000);
+        }
+
+        audio_extn_dts_create_state_notifier_node(out->usecase);
+        audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
+                                             popcount(out->channel_mask),
+                                             out->playback_started);
+
 #ifdef DS1_DOLBY_DDP_ENABLED
         if (audio_extn_is_dolby_format(out->format))
             audio_extn_dolby_send_ddp_endp_params(adev);
 #endif
-
-        if (adev->visualizer_start_output != NULL)
-            adev->visualizer_start_output(out->handle, out->pcm_device_id);
-        if (adev->offload_effects_start_output != NULL)
-            adev->offload_effects_start_output(out->handle, out->pcm_device_id);
+        if (!(audio_extn_dolby_is_passthrough_stream(out->flags))) {
+            if (adev->visualizer_start_output != NULL)
+                adev->visualizer_start_output(out->handle, out->pcm_device_id);
+            if (adev->offload_effects_start_output != NULL)
+                adev->offload_effects_start_output(out->handle, out->pcm_device_id);
+            audio_extn_check_and_set_dts_hpx_state(adev);
+        }
     }
     ALOGV("%s: exit", __func__);
     return 0;
@@ -1658,9 +1775,6 @@
     int ret = 0;
     char value[32];
     bool is_meta_data_params = false;
-    struct compr_gapless_mdata tmp_mdata;
-    tmp_mdata.encoder_delay = 0;
-    tmp_mdata.encoder_padding = 0;
 
     if (!out || !parms) {
         ALOGE("%s: return invalid ",__func__);
@@ -1676,54 +1790,32 @@
         out->send_new_metadata = 1;
     }
 
-    if (out->format == AUDIO_FORMAT_FLAC) {
-        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_BLK_SIZE, value, sizeof(value));
-        if (ret >= 0) {
-            out->compr_config.codec->options.flac_dec.min_blk_size = atoi(value);
-            out->send_new_metadata = 1;
-        }
-        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_BLK_SIZE, value, sizeof(value));
-        if (ret >= 0) {
-            out->compr_config.codec->options.flac_dec.max_blk_size = atoi(value);
-            out->send_new_metadata = 1;
-        }
-        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MIN_FRAME_SIZE, value, sizeof(value));
-        if (ret >= 0) {
-            out->compr_config.codec->options.flac_dec.min_frame_size = atoi(value);
-            out->send_new_metadata = 1;
-        }
-        ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_FLAC_MAX_FRAME_SIZE, value, sizeof(value));
-        if (ret >= 0) {
-            out->compr_config.codec->options.flac_dec.max_frame_size = atoi(value);
-            out->send_new_metadata = 1;
-        }
-    }
+    ret = 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 )
+    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 )
+    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;
-        tmp_mdata.encoder_delay = atoi(value); //whats a good limit check?
+        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;
-        tmp_mdata.encoder_padding = atoi(value);
+        out->gapless_mdata.encoder_padding = atoi(value);
     }
 
     if(!is_meta_data_params) {
         ALOGV("%s: Not gapless meta data params", __func__);
         return 0;
     }
-    out->gapless_mdata = tmp_mdata;
     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);
@@ -1768,7 +1860,8 @@
         if ((out->devices == AUDIO_DEVICE_OUT_AUX_DIGITAL ||
                 out->devices == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET) &&
                 val == AUDIO_DEVICE_NONE) {
-            val = AUDIO_DEVICE_OUT_SPEAKER;
+            if (!audio_extn_dolby_is_passthrough_stream(out->flags))
+                val = AUDIO_DEVICE_OUT_SPEAKER;
         }
 
         /*
@@ -1795,13 +1888,16 @@
             if (!out->standby)
                 select_devices(adev, out->usecase);
 
-            if ((adev->mode == AUDIO_MODE_IN_CALL) &&
-                    output_drives_call(adev, out)) {
-                adev->current_call_output = out;
-                if (!voice_is_in_call(adev))
-                    ret = voice_start_call(adev);
-                else
+            if (output_drives_call(adev, out)) {
+                if(!voice_is_in_call(adev)) {
+                    if (adev->mode == AUDIO_MODE_IN_CALL) {
+                        adev->current_call_output = out;
+                        ret = voice_start_call(adev);
+                    }
+                } else {
+                    adev->current_call_output = out;
                     voice_update_devices_for_all_voice_usecases(adev);
+                }
             }
         }
 
@@ -1817,6 +1913,12 @@
     if (is_offload_usecase(out->usecase)) {
         pthread_mutex_lock(&out->lock);
         parse_compress_metadata(out, parms);
+
+        audio_extn_dts_create_state_notifier_node(out->usecase);
+        audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
+                                                 popcount(out->channel_mask),
+                                                 out->playback_started);
+
         pthread_mutex_unlock(&out->lock);
     }
 
@@ -1865,11 +1967,33 @@
     } else {
         voice_extn_out_get_parameters(out, query, reply);
         str = str_parms_to_str(reply);
-        if (!strncmp(str, "", sizeof(""))) {
+        if (str && !strncmp(str, "", sizeof(""))) {
             free(str);
             str = strdup(keys);
         }
     }
+
+    ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value, sizeof(value));
+    if (ret >= 0) {
+        value[0] = '\0';
+        i = 0;
+        first = true;
+        while (out->supported_formats[i] != 0) {
+            for (j = 0; j < ARRAY_SIZE(out_formats_name_to_enum_table); j++) {
+                if (out_formats_name_to_enum_table[j].value == out->supported_formats[i]) {
+                    if (!first) {
+                        strcat(value, "|");
+                    }
+                    strlcat(value, out_formats_name_to_enum_table[j].name, sizeof(value));
+                    first = false;
+                    break;
+                }
+            }
+            i++;
+        }
+        str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
+        str = str_parms_to_str(reply);
+    }
     str_parms_destroy(query);
     str_parms_destroy(reply);
     ALOGV("%s: exit: returns - %s", __func__, str);
@@ -1879,12 +2003,17 @@
 static uint32_t out_get_latency(const struct audio_stream_out *stream)
 {
     struct stream_out *out = (struct stream_out *)stream;
+    uint32_t latency = 0;
 
-    if (is_offload_usecase(out->usecase))
-        return COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
-
-    return (out->config.period_count * out->config.period_size * 1000) /
+    if (is_offload_usecase(out->usecase)) {
+        latency = COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
+    } else {
+        latency = (out->config.period_count * out->config.period_size * 1000) /
            (out->config.rate);
+    }
+
+    ALOGV("%s: Latency %d", __func__, latency);
+    return latency;
 }
 
 static int out_set_volume(struct audio_stream_out *stream, float left,
@@ -1898,24 +2027,33 @@
         out->muted = (left == 0.0f);
         return 0;
     } else if (is_offload_usecase(out->usecase)) {
-        char mixer_ctl_name[128];
-        struct audio_device *adev = out->dev;
-        struct mixer_ctl *ctl;
-        int pcm_device_id = platform_get_pcm_device_id(out->usecase,
+        if (audio_extn_dolby_is_passthrough_stream(out->flags)) {
+            /*
+             * Set mute or umute on HDMI passthrough stream.
+             * Only take left channel into account.
+             * Mute is 0 and unmute 1
+             */
+            audio_extn_dolby_set_passt_volume(out, (left == 0.0f));
+        } else {
+            char mixer_ctl_name[128];
+            struct audio_device *adev = out->dev;
+            struct mixer_ctl *ctl;
+            int pcm_device_id = platform_get_pcm_device_id(out->usecase,
                                                        PCM_PLAYBACK);
 
-        snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
-                 "Compress Playback %d Volume", pcm_device_id);
-        ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
-        if (!ctl) {
-            ALOGE("%s: Could not get ctl for mixer cmd - %s",
-                  __func__, mixer_ctl_name);
-            return -EINVAL;
+            snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+                     "Compress Playback %d Volume", pcm_device_id);
+            ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+            if (!ctl) {
+                ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                      __func__, mixer_ctl_name);
+                return -EINVAL;
+            }
+            volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX);
+            volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
+            mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
+            return 0;
         }
-        volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX);
-        volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
-        mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
-        return 0;
     }
 
     return -ENOSYS;
@@ -1932,11 +2070,16 @@
     pthread_mutex_lock(&out->lock);
 
     if (SND_CARD_STATE_OFFLINE == snd_scard_state) {
+        // increase written size during SSR to avoid mismatch
+        // with the written frames count in AF
+        if (!is_offload_usecase(out->usecase))
+            out->written += bytes / (out->config.channels * sizeof(short));
+
         if (out->pcm) {
             ALOGD(" %s: sound card is not active/SSR state", __func__);
             ret= -EIO;
             goto exit;
-        } else if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+        } else if (is_offload_usecase(out->usecase)) {
             //during SSR for compress usecase we should return error to flinger
             ALOGD(" copl %s: sound card is not active/SSR state", __func__);
             pthread_mutex_unlock(&out->lock);
@@ -1960,7 +2103,7 @@
     }
 
     if (is_offload_usecase(out->usecase)) {
-        ALOGD("copl(%p): writing buffer (%zu bytes) to compress device", out, bytes);
+        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);
@@ -1983,8 +2126,13 @@
         }
         if (!out->playback_started && ret >= 0) {
             compress_start(out->compr);
+            audio_extn_dts_eagle_fade(adev, true, out);
             out->playback_started = 1;
             out->offload_state = OFFLOAD_STATE_PLAYING;
+
+            audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
+                                                     popcount(out->channel_mask),
+                                                     out->playback_started);
         }
         pthread_mutex_unlock(&out->lock);
         return ret;
@@ -2035,9 +2183,13 @@
 {
     struct stream_out *out = (struct stream_out *)stream;
     struct audio_device *adev = out->dev;
-    if (is_offload_usecase(out->usecase) && (dsp_frames != NULL)) {
+
+    if (dsp_frames == NULL)
+        return -EINVAL;
+
+    *dsp_frames = 0;
+    if (is_offload_usecase(out->usecase)) {
         ssize_t ret = 0;
-        *dsp_frames = 0;
         pthread_mutex_lock(&out->lock);
         if (out->compr != NULL) {
             ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
@@ -2065,6 +2217,9 @@
         } else {
             return 0;
         }
+    } else if (audio_is_linear_pcm(out->format)) {
+        *dsp_frames = out->written;
+        return 0;
     } else
         return -EINVAL;
 }
@@ -2169,6 +2324,11 @@
                 status = compress_pause(out->compr);
 
             out->offload_state = OFFLOAD_STATE_PAUSED;
+
+            audio_extn_dts_eagle_fade(adev, false, out);
+            audio_extn_dts_notify_playback_state(out->usecase, 0,
+                                                 out->sample_rate, popcount(out->channel_mask),
+                                                 0);
         }
         pthread_mutex_unlock(&out->lock);
     }
@@ -2192,6 +2352,10 @@
                 status = compress_resume(out->compr);
 
             out->offload_state = OFFLOAD_STATE_PLAYING;
+
+            audio_extn_dts_eagle_fade(adev, true, out);
+            audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
+                                                     popcount(out->channel_mask), 1);
         }
         pthread_mutex_unlock(&out->lock);
     }
@@ -2425,6 +2589,12 @@
             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;
+            }
         }
     }
 
@@ -2461,14 +2631,23 @@
      * Instead of writing zeroes here, we could trust the hardware
      * to always provide zeroes when muted.
      */
-    if (ret == 0 && voice_get_mic_mute(adev) && !voice_is_in_call_rec_stream(in))
+    if (ret == 0 && voice_get_mic_mute(adev) && !voice_is_in_call_rec_stream(in) &&
+            in->usecase != USECASE_AUDIO_RECORD_AFE_PROXY)
         memset(buffer, 0, bytes);
 
 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) {
-        set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
+        /* 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;
     }
     pthread_mutex_unlock(&in->lock);
 
@@ -2572,6 +2751,9 @@
         return -ENOMEM;
     }
 
+    pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
+    pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL);
+
     if (devices == AUDIO_DEVICE_NONE)
         devices = AUDIO_DEVICE_OUT_SPEAKER;
 
@@ -2584,6 +2766,8 @@
     out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
     out->handle = handle;
     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) &&
@@ -2628,6 +2812,18 @@
             ret = -EINVAL;
             goto error_open;
         }
+
+        if ((out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
+            ((audio_extn_dolby_is_passthrough_stream(out->flags)))) {
+            ALOGV("read and update_pass through formats");
+            ret = audio_extn_dolby_update_passt_formats(adev, out);
+            if(ret != 0) {
+                goto error_open;
+            }
+            if(config->offload_info.format == 0)
+                config->offload_info.format = out->supported_formats[0];
+        }
+
         if (!is_supported_format(config->offload_info.format) &&
                 !audio_extn_is_dolby_format(config->offload_info.format)) {
             ALOGE("%s: Unsupported audio format", __func__);
@@ -2669,20 +2865,25 @@
                 get_snd_codec_id(config->offload_info.format);
         if (audio_is_offload_pcm(config->offload_info.format)) {
             out->compr_config.fragment_size =
-                       platform_get_pcm_offload_buffer_size(&config->offload_info);
+               platform_get_pcm_offload_buffer_size(&config->offload_info);
+        } else if (audio_extn_dolby_is_passthrough_stream(out->flags)) {
+            out->compr_config.fragment_size =
+               audio_extn_dolby_get_passt_buffer_size(&config->offload_info);
         } else {
             out->compr_config.fragment_size =
-                       platform_get_compress_offload_buffer_size(&config->offload_info);
+               platform_get_compress_offload_buffer_size(&config->offload_info);
         }
         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 =
                 audio_channel_count_from_out_mask(config->channel_mask);
         out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
         out->bit_width = PCM_OUTPUT_BIT_WIDTH;
+        /*TODO: Do we need to change it for passthrough */
+        out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
 
         if (config->offload_info.format == AUDIO_FORMAT_AAC)
             out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
@@ -2701,17 +2902,27 @@
         if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
             out->non_blocking = 1;
 
+        if (config->offload_info.use_small_bufs) {
+            //this flag is set from framework only if its for PCM formats
+            //no need to check for PCM format again
+            out->non_blocking = 0;
+            out->use_small_bufs = true;
+            ALOGI("Keep write blocking for small buff: non_blockling %d",
+                  out->non_blocking);
+        }
+
         out->send_new_metadata = 1;
         out->offload_state = OFFLOAD_STATE_IDLE;
         out->playback_started = 0;
 
+        audio_extn_dts_create_state_notifier_node(out->usecase);
+
         create_offload_callback_thread(out);
         ALOGV("%s: offloaded output offload_info version %04x bit rate %d",
                 __func__, config->offload_info.version,
                 config->offload_info.bit_rate);
         //Decide if we need to use gapless mode by default
         check_and_set_gapless_mode(adev);
-
     } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
         ret = voice_check_and_set_incall_music_usecase(adev, out);
         if (ret != 0) {
@@ -2746,16 +2957,24 @@
         out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
         out->config = pcm_config_low_latency;
         out->sample_rate = out->config.rate;
+    } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
+        format = AUDIO_FORMAT_PCM_16_BIT;
+        out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
+        out->config = pcm_config_deep_buffer;
+        out->sample_rate = out->config.rate;
     } else {
         /* primary path is the default path selected if no other outputs are available/suitable */
         format = AUDIO_FORMAT_PCM_16_BIT;
         out->usecase = USECASE_AUDIO_PLAYBACK_PRIMARY;
-        out->config = pcm_config_deep_buffer;
+        out->config = PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY;
         out->sample_rate = out->config.rate;
     }
 
     ALOGV("%s devices %d,flags %x, format %x, out->sample_rate %d, out->bit_width %d",
            __func__, devices, flags, format, out->sample_rate, out->bit_width);
+    /* TODO remove this hardcoding and check why width is zero*/
+    if (out->bit_width == 0)
+        out->bit_width = 16;
     audio_extn_utils_update_stream_app_type_cfg(adev->platform,
                                                 &adev->streams_output_cfg_list,
                                                 devices, flags, format, out->sample_rate,
@@ -2806,9 +3025,6 @@
     /* out->muted = false; by calloc() */
     /* out->written = 0; by calloc() */
 
-    pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
-    pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL);
-
     config->format = out->stream.common.get_format(&out->stream.common);
     config->channel_mask = out->stream.common.get_channels(&out->stream.common);
     config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common);
@@ -2816,6 +3032,11 @@
     *stream_out = &out->stream;
     ALOGD("%s: Stream (%p) picks up usecase (%s)", __func__, &out->stream,
         use_case_table[out->usecase]);
+
+    if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
+        audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
+                                             popcount(out->channel_mask), out->playback_started);
+
     ALOGV("%s: exit", __func__);
     return 0;
 
@@ -2846,6 +3067,7 @@
         out_standby(&stream->common);
 
     if (is_offload_usecase(out->usecase)) {
+        audio_extn_dts_remove_state_notifier_node(out->usecase);
         destroy_offload_callback_thread(out);
         free_offload_usecase(adev, out->usecase);
         if (out->compr_config.codec != NULL)
@@ -2861,6 +3083,27 @@
     ALOGV("%s: exit", __func__);
 }
 
+static void close_compress_sessions(struct audio_device *adev)
+{
+    struct stream_out *out;
+    struct listnode *node;
+    struct audio_usecase *usecase;
+    pthread_mutex_lock(&adev->lock);
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        if (usecase && is_offload_usecase(usecase->id)) {
+            if (usecase && usecase->stream.out) {
+                ALOGI(" %s closing compress session %d on OFFLINE state", __func__, usecase->id);
+                out = usecase->stream.out;
+                pthread_mutex_unlock(&adev->lock);
+                out_standby(&out->stream.common);
+                pthread_mutex_lock(&adev->lock);
+            }
+        }
+    }
+    pthread_mutex_unlock(&adev->lock);
+}
+
 static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
 {
     struct audio_device *adev = (struct audio_device *)dev;
@@ -2882,22 +3125,10 @@
         if (strstr(snd_card_status, "OFFLINE")) {
             struct listnode *node;
             struct audio_usecase *usecase;
-
             ALOGD("Received sound card OFFLINE status");
             set_snd_card_state(adev,SND_CARD_STATE_OFFLINE);
-
-            pthread_mutex_lock(&adev->lock);
-            //close compress session on OFFLINE status
-            usecase = get_usecase_from_list(adev,USECASE_AUDIO_PLAYBACK_OFFLOAD);
-            if (usecase && usecase->stream.out) {
-                ALOGD(" %s closing compress session on OFFLINE state", __func__);
-
-                struct stream_out *out = usecase->stream.out;
-
-                pthread_mutex_unlock(&adev->lock);
-                out_standby(&out->stream.common);
-            } else
-                pthread_mutex_unlock(&adev->lock);
+            //close compress sessions on OFFLINE status
+            close_compress_sessions(adev);
         } else if (strstr(snd_card_status, "ONLINE")) {
             ALOGD("Received sound card ONLINE status");
             set_snd_card_state(adev,SND_CARD_STATE_ONLINE);
@@ -2973,6 +3204,24 @@
             adev->bt_wb_speech_enabled = false;
     }
 
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
+    if (ret >= 0) {
+        val = atoi(value);
+        if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            ALOGV("cache new edid");
+            platform_cache_edid(adev->platform);
+        }
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
+    if (ret >= 0) {
+        val = atoi(value);
+        if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            ALOGV("invalidate cached edid");
+            platform_invalidate_edid(adev->platform);
+        }
+    }
+
     audio_extn_set_parameters(adev, parms);
 
 done:
@@ -3117,7 +3366,7 @@
                                   struct audio_stream_in **stream_in,
                                   audio_input_flags_t flags __unused,
                                   const char *address __unused,
-                                  audio_source_t source __unused)
+                                  audio_source_t source)
 {
     struct audio_device *adev = (struct audio_device *)dev;
     struct stream_in *in;
@@ -3137,8 +3386,8 @@
     }
 
     ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x)\
-        stream_handle(%p) io_handle(%d)",__func__, config->sample_rate, config->channel_mask,
-        devices, &in->stream, handle);
+        stream_handle(%p) io_handle(%d) source(%d)",__func__, config->sample_rate, config->channel_mask,
+        devices, &in->stream, handle, source);
 
     pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
 
@@ -3159,7 +3408,7 @@
     in->stream.get_input_frames_lost = in_get_input_frames_lost;
 
     in->device = devices;
-    in->source = AUDIO_SOURCE_DEFAULT;
+    in->source = source;
     in->dev = adev;
     in->standby = 1;
     in->channel_mask = config->channel_mask;
@@ -3179,6 +3428,10 @@
     in->format = config->format;
 
     if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
+        if (adev->mode != AUDIO_MODE_IN_CALL) {
+            ret = -EINVAL;
+            goto err_open;
+        }
         if (config->sample_rate == 0)
             config->sample_rate = AFE_PROXY_SAMPLING_RATE;
         if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
@@ -3221,6 +3474,13 @@
                                             channel_count,
                                             is_low_latency);
         in->config.period_size = buffer_size / frame_size;
+        if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
+               (in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
+               (voice_extn_compress_voip_is_format_supported(in->format)) &&
+               (in->config.rate == 8000 || in->config.rate == 16000) &&
+               (audio_channel_count_from_in_mask(in->channel_mask) == 1)) {
+            voice_extn_compress_voip_open_input_stream(in);
+        }
     }
 
     /* This stream could be for sound trigger lab,
@@ -3260,7 +3520,7 @@
     } else
         in_standby(&stream->common);
 
-    if (audio_extn_ssr_get_enabled() && 
+    if (audio_extn_ssr_get_enabled() &&
             (audio_channel_count_from_in_mask(in->channel_mask) == 6)) {
         audio_extn_ssr_deinit();
     }
@@ -3431,6 +3691,9 @@
             adev->offload_effects_stop_output =
                         (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
                                          "offload_effects_bundle_hal_stop_output");
+            adev->offload_effects_set_hpx_state =
+                        (int (*)(bool))dlsym(adev->offload_effects_lib,
+                                         "offload_effects_bundle_set_hpx_state");
         }
     }
 
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index d05f743..67f5279 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.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
@@ -15,6 +15,24 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
+ * This file was modified by DTS, Inc. The portions of the
+ * code modified by DTS, Inc are copyrighted and
+ * licensed separately, as follows:
+ *
+ * (C) 2014 DTS, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 #ifndef QCOM_AUDIO_HW_H
@@ -47,12 +65,12 @@
 #define ACDB_DEV_TYPE_OUT 1
 #define ACDB_DEV_TYPE_IN 2
 
-#define MAX_SUPPORTED_CHANNEL_MASKS 2
+#define MAX_SUPPORTED_CHANNEL_MASKS 8
+#define MAX_SUPPORTED_FORMATS 3
 #define DEFAULT_HDMI_OUT_CHANNELS   2
 
 #define SND_CARD_STATE_OFFLINE 0
 #define SND_CARD_STATE_ONLINE 1
-typedef int snd_device_t;
 
 /* These are the supported use cases by the hardware.
  * Each usecase is mapped to a specific PCM device.
@@ -97,6 +115,8 @@
     USECASE_VOLTE_CALL,
     USECASE_QCHAT_CALL,
     USECASE_VOWLAN_CALL,
+    USECASE_VOICEMMODE1_CALL,
+    USECASE_VOICEMMODE2_CALL,
     USECASE_COMPRESS_VOIP_CALL,
 
     USECASE_INCALL_REC_UPLINK,
@@ -174,12 +194,14 @@
     audio_usecase_t usecase;
     /* Array of supported channel mask configurations. +1 so that the last entry is always 0 */
     audio_channel_mask_t supported_channel_masks[MAX_SUPPORTED_CHANNEL_MASKS + 1];
+    audio_format_t supported_formats[MAX_SUPPORTED_FORMATS+1];
     bool muted;
     uint64_t written; /* total frames written, not cleared when entering standby */
     audio_io_handle_t handle;
     struct stream_app_type_cfg app_type_cfg;
 
     int non_blocking;
+    bool use_small_bufs;
     int playback_started;
     int offload_state;
     pthread_cond_t offload_cond;
@@ -212,6 +234,7 @@
     audio_format_t format;
     audio_io_handle_t capture_handle;
     bool is_st_session;
+    bool is_st_session_active;
 
     struct audio_device *dev;
 };
@@ -298,6 +321,7 @@
     int (*offload_effects_stop_output)(audio_io_handle_t, int);
 
     struct sound_card_status snd_card_status;
+    int (*offload_effects_set_hpx_state)(bool);
 };
 
 int select_devices(struct audio_device *adev,
@@ -320,6 +344,8 @@
 int pcm_ioctl(struct pcm *pcm, int request, ...);
 
 int get_snd_card_state(struct audio_device *adev);
+audio_usecase_t get_usecase_id_from_usecase_type(struct audio_device *adev,
+                                                 usecase_type_t type);
 
 #define LITERAL_TO_STRING(x) #x
 #define CHECK(condition) LOG_ALWAYS_FATAL_IF(!(condition), "%s",\
diff --git a/hal/edid.c b/hal/edid.c
new file mode 100644
index 0000000..9b05950
--- /dev/null
+++ b/hal/edid.c
@@ -0,0 +1,687 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_edid"
+/*#define LOG_NDEBUG 0*/
+/*#define LOG_NDDEBUG 0*/
+
+#include <errno.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/str_parms.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include "edid.h"
+
+static const char * edid_format_to_str(unsigned char format)
+{
+    char * format_str = "??";
+
+    switch (format) {
+    case LPCM:
+        format_str = "Format:LPCM";
+        break;
+    case AC3:
+        format_str = "Format:AC-3";
+        break;
+    case MPEG1:
+        format_str = "Format:MPEG1 (Layers 1 & 2)";
+        break;
+    case MP3:
+        format_str = "Format:MP3 (MPEG1 Layer 3)";
+        break;
+    case MPEG2_MULTI_CHANNEL:
+        format_str = "Format:MPEG2 (multichannel)";
+        break;
+    case AAC:
+        format_str = "Format:AAC";
+        break;
+    case DTS:
+        format_str = "Format:DTS";
+        break;
+    case ATRAC:
+        format_str = "Format:ATRAC";
+        break;
+    case SACD:
+        format_str = "Format:One-bit audio aka SACD";
+        break;
+    case DOLBY_DIGITAL_PLUS:
+        format_str = "Format:Dolby Digital +";
+        break;
+    case DTS_HD:
+        format_str = "Format:DTS-HD";
+        break;
+    case MAT:
+        format_str = "Format:MAT (MLP)";
+        break;
+    case DST:
+        format_str = "Format:DST";
+        break;
+    case WMA_PRO:
+        format_str = "Format:WMA Pro";
+        break;
+    default:
+        break;
+    }
+    return format_str;
+}
+
+static int get_edid_sf(unsigned char byte)
+{
+    int nfreq = 0;
+
+    if (byte & BIT(6)) {
+        ALOGV("192kHz");
+        nfreq = 192000;
+    } else if (byte & BIT(5)) {
+        ALOGV("176kHz");
+        nfreq = 176000;
+    } else if (byte & BIT(4)) {
+        ALOGV("96kHz");
+        nfreq = 96000;
+    } else if (byte & BIT(3)) {
+        ALOGV("88.2kHz");
+        nfreq = 88200;
+    } else if (byte & BIT(2)) {
+        ALOGV("48kHz");
+        nfreq = 48000;
+    } else if (byte & BIT(1)) {
+        ALOGV("44.1kHz");
+        nfreq = 44100;
+    } else if (byte & BIT(0)) {
+        ALOGV("32kHz");
+        nfreq = 32000;
+    }
+    return nfreq;
+}
+
+static int get_edid_bps(unsigned char byte,
+                        unsigned char format)
+{
+    int bits_per_sample = 0;
+    if (format == 1) {
+        if (byte & BIT(2)) {
+            ALOGV("24bit");
+            bits_per_sample = 24;
+        } else if (byte & BIT(1)) {
+            ALOGV("20bit");
+            bits_per_sample = 20;
+        } else if (byte & BIT(0)) {
+            ALOGV("16bit");
+            bits_per_sample = 16;
+        }
+    } else {
+        ALOGV("not lpcm format, return 0");
+        return 0;
+    }
+    return bits_per_sample;
+}
+
+static void update_channel_map(edid_audio_info* info)
+{
+    /* HDMI Cable follows CEA standard so SAD is received in CEA
+     * Input source file channel map is fed to ASM in WAV standard(audio.h)
+     * so upto 7.1 SAD bits are:
+     * in CEA convention: RLC/RRC,FLC/FRC,RC,RL/RR,FC,LFE,FL/FR
+     * in WAV convention: BL/BR,FLC/FRC,BC,SL/SR,FC,LFE,FL/FR
+     * Corresponding ADSP IDs (apr-audio_v2.h):
+     * PCM_CHANNEL_FL/PCM_CHANNEL_FR,
+     * PCM_CHANNEL_LFE,
+     * PCM_CHANNEL_FC,
+     * PCM_CHANNEL_LS/PCM_CHANNEL_RS,
+     * PCM_CHANNEL_CS,
+     * PCM_CHANNEL_FLC/PCM_CHANNEL_FRC
+     * PCM_CHANNEL_LB/PCM_CHANNEL_RB
+     */
+    if (!info)
+        return;
+    memset(info->channel_map, 0, MAX_CHANNELS_SUPPORTED);
+    if(info->speaker_allocation[0] & BIT(0)) {
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+    }
+    if(info->speaker_allocation[0] & BIT(1)) {
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+    }
+    if(info->speaker_allocation[0] & BIT(2)) {
+        info->channel_map[3] = PCM_CHANNEL_FC;
+    }
+    if(info->speaker_allocation[0] & BIT(3)) {
+    /*
+     * As per CEA(HDMI Cable) standard Bit 3 is equivalent
+     * to SideLeft/SideRight of WAV standard
+     */
+        info->channel_map[4] = PCM_CHANNEL_LS;
+        info->channel_map[5] = PCM_CHANNEL_RS;
+    }
+    if(info->speaker_allocation[0] & BIT(4)) {
+        if(info->speaker_allocation[0] & BIT(3)) {
+            info->channel_map[6] = PCM_CHANNEL_CS;
+            info->channel_map[7] = 0;
+        } else if (info->speaker_allocation[1] & BIT(1)) {
+            info->channel_map[6] = PCM_CHANNEL_CS;
+            info->channel_map[7] = PCM_CHANNEL_TS;
+        } else if (info->speaker_allocation[1] & BIT(2)) {
+            info->channel_map[6] = PCM_CHANNEL_CS;
+            info->channel_map[7] = PCM_CHANNEL_CVH;
+        } else {
+            info->channel_map[4] = PCM_CHANNEL_CS;
+            info->channel_map[5] = 0;
+        }
+    }
+    if(info->speaker_allocation[0] & BIT(5)) {
+        info->channel_map[6] = PCM_CHANNEL_FLC;
+        info->channel_map[7] = PCM_CHANNEL_FRC;
+    }
+    if(info->speaker_allocation[0] & BIT(6)) {
+        // If RLC/RRC is present, RC is invalid as per specification
+        info->speaker_allocation[0] &= 0xef;
+        /*
+         * As per CEA(HDMI Cable) standard Bit 6 is equivalent
+         * to BackLeft/BackRight of WAV standard
+         */
+        info->channel_map[6] = PCM_CHANNEL_LB;
+        info->channel_map[7] = PCM_CHANNEL_RB;
+    }
+    // higher channel are not defined by LPASS
+    //info->nSpeakerAllocation[0] &= 0x3f;
+    if(info->speaker_allocation[0] & BIT(7)) {
+        info->channel_map[6] = 0; // PCM_CHANNEL_FLW; but not defined by LPASS
+        info->channel_map[7] = 0; // PCM_CHANNEL_FRW; but not defined by LPASS
+    }
+    if(info->speaker_allocation[1] & BIT(0)) {
+        info->channel_map[6] = 0; // PCM_CHANNEL_FLH; but not defined by LPASS
+        info->channel_map[7] = 0; // PCM_CHANNEL_FRH; but not defined by LPASS
+    }
+
+    ALOGI("%s channel map updated to [%d %d %d %d %d %d %d %d ]  [%x %x %x]", __func__
+        , info->channel_map[0], info->channel_map[1], info->channel_map[2]
+        , info->channel_map[3], info->channel_map[4], info->channel_map[5]
+        , info->channel_map[6], info->channel_map[7]
+        , info->speaker_allocation[0], info->speaker_allocation[1]
+        , info->speaker_allocation[2]);
+}
+
+static void dump_speaker_allocation(edid_audio_info* info)
+{
+    if (!info)
+        return;
+
+    if (info->speaker_allocation[0] & BIT(7))
+        ALOGV("FLW/FRW");
+    if (info->speaker_allocation[0] & BIT(6))
+        ALOGV("RLC/RRC");
+    if (info->speaker_allocation[0] & BIT(5))
+        ALOGV("FLC/FRC");
+    if (info->speaker_allocation[0] & BIT(4))
+        ALOGV("RC");
+    if (info->speaker_allocation[0] & BIT(3))
+        ALOGV("RL/RR");
+    if (info->speaker_allocation[0] & BIT(2))
+        ALOGV("FC");
+    if (info->speaker_allocation[0] & BIT(1))
+        ALOGV("LFE");
+    if (info->speaker_allocation[0] & BIT(0))
+        ALOGV("FL/FR");
+    if (info->speaker_allocation[1] & BIT(2))
+        ALOGV("FCH");
+    if (info->speaker_allocation[1] & BIT(1))
+        ALOGV("TC");
+    if (info->speaker_allocation[1] & BIT(0))
+        ALOGV("FLH/FRH");
+}
+
+static void update_channel_allocation(edid_audio_info* info)
+{
+    int16_t ca;
+    int16_t spkr_alloc;
+
+    if (!info)
+        return;
+
+    /* Most common 5.1 SAD is 0xF, ca 0x0b
+     * and 7.1 SAD is 0x4F, ca 0x13 */
+    spkr_alloc = ((info->speaker_allocation[1]) << 8) |
+               (info->speaker_allocation[0]);
+    ALOGV("info->nSpeakerAllocation %x %x\n", info->speaker_allocation[0],
+                                              info->speaker_allocation[1]);
+    ALOGV("spkr_alloc: %x", spkr_alloc);
+
+    /* The below switch case calculates channel allocation values
+       as defined in CEA-861 section 6.6.2 */
+    switch (spkr_alloc) {
+    case BIT(0):                                           ca = 0x00; break;
+    case BIT(0)|BIT(1):                                    ca = 0x01; break;
+    case BIT(0)|BIT(2):                                    ca = 0x02; break;
+    case BIT(0)|BIT(1)|BIT(2):                             ca = 0x03; break;
+    case BIT(0)|BIT(4):                                    ca = 0x04; break;
+    case BIT(0)|BIT(1)|BIT(4):                             ca = 0x05; break;
+    case BIT(0)|BIT(2)|BIT(4):                             ca = 0x06; break;
+    case BIT(0)|BIT(1)|BIT(2)|BIT(4):                      ca = 0x07; break;
+    case BIT(0)|BIT(3):                                    ca = 0x08; break;
+    case BIT(0)|BIT(1)|BIT(3):                             ca = 0x09; break;
+    case BIT(0)|BIT(2)|BIT(3):                             ca = 0x0A; break;
+    case BIT(0)|BIT(1)|BIT(2)|BIT(3):                      ca = 0x0B; break;
+    case BIT(0)|BIT(3)|BIT(4):                             ca = 0x0C; break;
+    case BIT(0)|BIT(1)|BIT(3)|BIT(4):                      ca = 0x0D; break;
+    case BIT(0)|BIT(2)|BIT(3)|BIT(4):                      ca = 0x0E; break;
+    case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(4):               ca = 0x0F; break;
+    case BIT(0)|BIT(3)|BIT(6):                             ca = 0x10; break;
+    case BIT(0)|BIT(1)|BIT(3)|BIT(6):                      ca = 0x11; break;
+    case BIT(0)|BIT(2)|BIT(3)|BIT(6):                      ca = 0x12; break;
+    case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(6):               ca = 0x13; break;
+    case BIT(0)|BIT(5):                                    ca = 0x14; break;
+    case BIT(0)|BIT(1)|BIT(5):                             ca = 0x15; break;
+    case BIT(0)|BIT(2)|BIT(5):                             ca = 0x16; break;
+    case BIT(0)|BIT(1)|BIT(2)|BIT(5):                      ca = 0x17; break;
+    case BIT(0)|BIT(4)|BIT(5):                             ca = 0x18; break;
+    case BIT(0)|BIT(1)|BIT(4)|BIT(5):                      ca = 0x19; break;
+    case BIT(0)|BIT(2)|BIT(4)|BIT(5):                      ca = 0x1A; break;
+    case BIT(0)|BIT(1)|BIT(2)|BIT(4)|BIT(5):               ca = 0x1B; break;
+    case BIT(0)|BIT(3)|BIT(5):                             ca = 0x1C; break;
+    case BIT(0)|BIT(1)|BIT(3)|BIT(5):                      ca = 0x1D; break;
+    case BIT(0)|BIT(2)|BIT(3)|BIT(5):                      ca = 0x1E; break;
+    case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(5):               ca = 0x1F; break;
+    case BIT(0)|BIT(2)|BIT(3)|BIT(10):                     ca = 0x20; break;
+    case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(10):              ca = 0x21; break;
+    case BIT(0)|BIT(2)|BIT(3)|BIT(9):                      ca = 0x22; break;
+    case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(9):               ca = 0x23; break;
+    case BIT(0)|BIT(3)|BIT(8):                             ca = 0x24; break;
+    case BIT(0)|BIT(1)|BIT(3)|BIT(8):                      ca = 0x25; break;
+    case BIT(0)|BIT(3)|BIT(7):                             ca = 0x26; break;
+    case BIT(0)|BIT(1)|BIT(3)|BIT(7):                      ca = 0x27; break;
+    case BIT(0)|BIT(2)|BIT(3)|BIT(4)|BIT(9):               ca = 0x28; break;
+    case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(4)|BIT(9):        ca = 0x29; break;
+    case BIT(0)|BIT(2)|BIT(3)|BIT(4)|BIT(10):              ca = 0x2A; break;
+    case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(4)|BIT(10):       ca = 0x2B; break;
+    case BIT(0)|BIT(2)|BIT(3)|BIT(9)|BIT(10):              ca = 0x2C; break;
+    case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(9)|BIT(10):       ca = 0x2D; break;
+    case BIT(0)|BIT(2)|BIT(3)|BIT(8):                      ca = 0x2E; break;
+    case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(8):               ca = 0x2F; break;
+    case BIT(0)|BIT(2)|BIT(3)|BIT(7):                      ca = 0x30; break;
+    case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(7):               ca = 0x31; break;
+    default:                                               ca = 0x0;  break;
+    }
+    ALOGD("%s channel allocation: %x", __func__, ca);
+    info->channel_allocation = ca;
+}
+
+static void update_channel_map_lpass(edid_audio_info* info)
+{
+    if (!info)
+        return;
+    if (info->channel_allocation < 0 || info->channel_allocation > 0x1f) {
+        ALOGE("Channel allocation out of supported range");
+        return;
+    }
+    ALOGV("channel_allocation 0x%x", info->channel_allocation);
+    memset(info->channel_map, 0, MAX_CHANNELS_SUPPORTED);
+    switch(info->channel_allocation) {
+    case 0x0:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        break;
+    case 0x1:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+        break;
+    case 0x2:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_FC;
+        break;
+    case 0x3:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+        info->channel_map[3] = PCM_CHANNEL_FC;
+        break;
+    case 0x4:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_CS;
+        break;
+    case 0x5:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+        info->channel_map[3] = PCM_CHANNEL_CS;
+        break;
+    case 0x6:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_FC;
+        info->channel_map[3] = PCM_CHANNEL_CS;
+        break;
+    case 0x7:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+        info->channel_map[3] = PCM_CHANNEL_FC;
+        info->channel_map[4] = PCM_CHANNEL_CS;
+        break;
+    case 0x8:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LS;
+        info->channel_map[3] = PCM_CHANNEL_RS;
+        break;
+    case 0x9:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+        info->channel_map[3] = PCM_CHANNEL_LS;
+        info->channel_map[4] = PCM_CHANNEL_RS;
+        break;
+    case 0xa:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_FC;
+        info->channel_map[3] = PCM_CHANNEL_LS;
+        info->channel_map[4] = PCM_CHANNEL_RS;
+        break;
+    case 0xb:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+        info->channel_map[3] = PCM_CHANNEL_FC;
+        info->channel_map[4] = PCM_CHANNEL_LS;
+        info->channel_map[5] = PCM_CHANNEL_RS;
+        break;
+    case 0xc:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LS;
+        info->channel_map[3] = PCM_CHANNEL_RS;
+        info->channel_map[4] = PCM_CHANNEL_CS;
+        break;
+    case 0xd:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+        info->channel_map[3] = PCM_CHANNEL_LS;
+        info->channel_map[4] = PCM_CHANNEL_RS;
+        info->channel_map[5] = PCM_CHANNEL_CS;
+        break;
+    case 0xe:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_FC;
+        info->channel_map[3] = PCM_CHANNEL_LS;
+        info->channel_map[4] = PCM_CHANNEL_RS;
+        info->channel_map[5] = PCM_CHANNEL_CS;
+        break;
+    case 0xf:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+        info->channel_map[3] = PCM_CHANNEL_FC;
+        info->channel_map[4] = PCM_CHANNEL_LS;
+        info->channel_map[5] = PCM_CHANNEL_RS;
+        info->channel_map[6] = PCM_CHANNEL_CS;
+        break;
+    case 0x10:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LS;
+        info->channel_map[3] = PCM_CHANNEL_RS;
+        info->channel_map[4] = PCM_CHANNEL_LB;
+        info->channel_map[5] = PCM_CHANNEL_RB;
+        break;
+    case 0x11:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+        info->channel_map[3] = PCM_CHANNEL_LS;
+        info->channel_map[4] = PCM_CHANNEL_RS;
+        info->channel_map[5] = PCM_CHANNEL_LB;
+        info->channel_map[6] = PCM_CHANNEL_RB;
+        break;
+    case 0x12:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_FC;
+        info->channel_map[3] = PCM_CHANNEL_LS;
+        info->channel_map[4] = PCM_CHANNEL_RS;
+        info->channel_map[5] = PCM_CHANNEL_LB;
+        info->channel_map[6] = PCM_CHANNEL_RB;
+        break;
+    case 0x13:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+        info->channel_map[3] = PCM_CHANNEL_FC;
+        info->channel_map[4] = PCM_CHANNEL_LS;
+        info->channel_map[5] = PCM_CHANNEL_RS;
+        info->channel_map[6] = PCM_CHANNEL_LB;
+        info->channel_map[7] = PCM_CHANNEL_RB;
+        break;
+    case 0x14:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_FLC;
+        info->channel_map[3] = PCM_CHANNEL_FRC;
+        break;
+    case 0x15:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+        info->channel_map[3] = PCM_CHANNEL_FLC;
+        info->channel_map[4] = PCM_CHANNEL_FRC;
+        break;
+    case 0x16:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_FC;
+        info->channel_map[3] = PCM_CHANNEL_FLC;
+        info->channel_map[4] = PCM_CHANNEL_FRC;
+        break;
+    case 0x17:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+        info->channel_map[3] = PCM_CHANNEL_FC;
+        info->channel_map[4] = PCM_CHANNEL_FLC;
+        info->channel_map[5] = PCM_CHANNEL_FRC;
+        break;
+    case 0x18:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_CS;
+        info->channel_map[3] = PCM_CHANNEL_FLC;
+        info->channel_map[4] = PCM_CHANNEL_FRC;
+        break;
+    case 0x19:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+        info->channel_map[3] = PCM_CHANNEL_CS;
+        info->channel_map[4] = PCM_CHANNEL_FLC;
+        info->channel_map[5] = PCM_CHANNEL_FRC;
+        break;
+    case 0x1a:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_FC;
+        info->channel_map[3] = PCM_CHANNEL_CS;
+        info->channel_map[4] = PCM_CHANNEL_FLC;
+        info->channel_map[5] = PCM_CHANNEL_FRC;
+        break;
+    case 0x1b:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+        info->channel_map[3] = PCM_CHANNEL_FC;
+        info->channel_map[4] = PCM_CHANNEL_CS;
+        info->channel_map[5] = PCM_CHANNEL_FLC;
+        info->channel_map[6] = PCM_CHANNEL_FRC;
+        break;
+    case 0x1c:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LS;
+        info->channel_map[3] = PCM_CHANNEL_RS;
+        info->channel_map[4] = PCM_CHANNEL_FLC;
+        info->channel_map[5] = PCM_CHANNEL_FRC;
+        break;
+    case 0x1d:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+        info->channel_map[3] = PCM_CHANNEL_LS;
+        info->channel_map[4] = PCM_CHANNEL_RS;
+        info->channel_map[5] = PCM_CHANNEL_FLC;
+        info->channel_map[6] = PCM_CHANNEL_FRC;
+        break;
+    case 0x1e:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_FC;
+        info->channel_map[3] = PCM_CHANNEL_LS;
+        info->channel_map[4] = PCM_CHANNEL_RS;
+        info->channel_map[5] = PCM_CHANNEL_FLC;
+        info->channel_map[6] = PCM_CHANNEL_FRC;
+        break;
+    case 0x1f:
+        info->channel_map[0] = PCM_CHANNEL_FL;
+        info->channel_map[1] = PCM_CHANNEL_FR;
+        info->channel_map[2] = PCM_CHANNEL_LFE;
+        info->channel_map[3] = PCM_CHANNEL_FC;
+        info->channel_map[4] = PCM_CHANNEL_LS;
+        info->channel_map[5] = PCM_CHANNEL_RS;
+        info->channel_map[6] = PCM_CHANNEL_FLC;
+        info->channel_map[7] = PCM_CHANNEL_FRC;
+        break;
+    default:
+        break;
+    }
+    ALOGD("%s channel map updated to [%d %d %d %d %d %d %d %d ]", __func__
+        , info->channel_map[0], info->channel_map[1], info->channel_map[2]
+        , info->channel_map[3], info->channel_map[4], info->channel_map[5]
+        , info->channel_map[6], info->channel_map[7]);
+}
+
+static void dump_edid_data(edid_audio_info *info)
+{
+
+    int i;
+    for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
+        ALOGV("%s:FormatId:%d rate:%d bps:%d channels:%d", __func__,
+              info->audio_blocks_array[i].format_id,
+              info->audio_blocks_array[i].sampling_freq,
+              info->audio_blocks_array[i].bits_per_sample,
+              info->audio_blocks_array[i].channels);
+    }
+    ALOGV("%s:no of audio blocks:%d", __func__, info->audio_blocks);
+    ALOGV("%s:speaker allocation:[%x %x %x]", __func__,
+           info->speaker_allocation[0], info->speaker_allocation[1],
+           info->speaker_allocation[2]);
+    ALOGV("%s:channel map:[%x %x %x %x %x %x %x %x]", __func__,
+           info->channel_map[0], info->channel_map[1],
+           info->channel_map[2], info->channel_map[3],
+           info->channel_map[4], info->channel_map[5],
+           info->channel_map[6], info->channel_map[7]);
+    ALOGV("%s:channel allocation:%d", __func__, info->channel_allocation);
+    ALOGV("%s:[%d %d %d %d %d %d %d %d ]", __func__,
+           info->channel_map[0], info->channel_map[1],
+           info->channel_map[2], info->channel_map[3],
+           info->channel_map[4], info->channel_map[5],
+           info->channel_map[6], info->channel_map[7]);
+}
+
+bool edid_get_sink_caps(edid_audio_info* info, char *edid_data)
+{
+    unsigned char channels[MAX_EDID_BLOCKS];
+    unsigned char formats[MAX_EDID_BLOCKS];
+    unsigned char frequency[MAX_EDID_BLOCKS];
+    unsigned char bitrate[MAX_EDID_BLOCKS];
+    int i = 0;
+    int length, count_desc;
+
+    if (!info || !edid_data) {
+        ALOGE("No valid EDID");
+        return false;
+    }
+
+    length = (int) *edid_data++;
+    ALOGV("Total length is %d",length);
+
+    count_desc = length/MIN_AUDIO_DESC_LENGTH;
+
+    if (!count_desc) {
+        ALOGE("insufficient descriptors");
+        return false;
+    }
+
+    memset(info, 0, sizeof(edid_audio_info));
+
+    info->audio_blocks = count_desc-1;
+    if (info->audio_blocks > MAX_EDID_BLOCKS) {
+        info->audio_blocks = MAX_EDID_BLOCKS;
+    }
+
+    ALOGV("Total # of audio descriptors %d",count_desc);
+
+    for (i=0; i<info->audio_blocks; i++) {
+        // last block for speaker allocation;
+        channels [i]   = (*edid_data & 0x7) + 1;
+        formats  [i]   = (*edid_data++) >> 3;
+        frequency[i]   = *edid_data++;
+        bitrate  [i]   = *edid_data++;
+    }
+    info->speaker_allocation[0] = *edid_data++;
+    info->speaker_allocation[1] = *edid_data++;
+    info->speaker_allocation[2] = *edid_data++;
+
+    update_channel_map(info);
+    update_channel_allocation(info);
+    update_channel_map_lpass(info);
+
+    for (i=0; i<info->audio_blocks; i++) {
+        ALOGV("AUDIO DESC BLOCK # %d\n",i);
+
+        info->audio_blocks_array[i].channels = channels[i];
+        ALOGV("info->audio_blocks_array[i].channels %d\n",
+              info->audio_blocks_array[i].channels);
+
+        ALOGV("Format Byte %d\n", formats[i]);
+        info->audio_blocks_array[i].format_id = (edid_audio_format_id)formats[i];
+        ALOGV("info->audio_blocks_array[i].format_id %s",
+              edid_format_to_str(formats[i]));
+
+        ALOGV("Frequency Byte %d\n", frequency[i]);
+        info->audio_blocks_array[i].sampling_freq = get_edid_sf(frequency[i]);
+        ALOGV("info->audio_blocks_array[i].sampling_freq %d",
+              info->audio_blocks_array[i].sampling_freq);
+
+        ALOGV("BitsPerSample Byte %d\n", bitrate[i]);
+        info->audio_blocks_array[i].bits_per_sample =
+                   get_edid_bps(bitrate[i],formats[i]);
+        ALOGV("info->audio_blocks_array[i].bits_per_sample %d",
+              info->audio_blocks_array[i].bits_per_sample);
+    }
+    dump_speaker_allocation(info);
+    dump_edid_data(info);
+    return true;
+}
diff --git a/hal/edid.h b/hal/edid.h
new file mode 100644
index 0000000..ec83ec8
--- /dev/null
+++ b/hal/edid.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef EDID_H
+#define EDID_H
+
+/* HDMI EDID Information */
+#define BIT(nr)     (1UL << (nr))
+#define MAX_EDID_BLOCKS 10
+#define MAX_SHORT_AUDIO_DESC_CNT        30
+#define MIN_AUDIO_DESC_LENGTH           3
+#define MIN_SPKR_ALLOCATION_DATA_LENGTH 3
+#define MAX_CHANNELS_SUPPORTED          8
+#define MAX_DISPLAY_DEVICES             3
+#define MAX_FRAME_BUFFER_NAME_SIZE      80
+#define MAX_CHAR_PER_INT                13
+
+#define PCM_CHANNEL_FL    1  /* Front left channel.                           */
+#define PCM_CHANNEL_FR    2  /* Front right channel.                          */
+#define PCM_CHANNEL_FC    3  /* Front center channel.                         */
+#define PCM_CHANNEL_LS    4  /* Left surround channel.                        */
+#define PCM_CHANNEL_RS    5  /* Right surround channel.                       */
+#define PCM_CHANNEL_LFE   6  /* Low frequency effect channel.                 */
+#define PCM_CHANNEL_CS    7  /* Center surround channel; Rear center channel. */
+#define PCM_CHANNEL_LB    8  /* Left back channel; Rear left channel.         */
+#define PCM_CHANNEL_RB    9  /* Right back channel; Rear right channel.       */
+#define PCM_CHANNEL_TS   10  /* Top surround channel.                         */
+#define PCM_CHANNEL_CVH  11  /* Center vertical height channel.               */
+#define PCM_CHANNEL_MS   12  /* Mono surround channel.                        */
+#define PCM_CHANNEL_FLC  13  /* Front left of center.                         */
+#define PCM_CHANNEL_FRC  14  /* Front right of center.                        */
+#define PCM_CHANNEL_RLC  15  /* Rear left of center.                          */
+#define PCM_CHANNEL_RRC  16  /* Rear right of center.                         */
+
+#define MAX_HDMI_CHANNEL_CNT 8
+
+typedef enum edid_audio_format_id {
+    LPCM = 1,
+    AC3,
+    MPEG1,
+    MP3,
+    MPEG2_MULTI_CHANNEL,
+    AAC,
+    DTS,
+    ATRAC,
+    SACD,
+    DOLBY_DIGITAL_PLUS,
+    DTS_HD,
+    MAT,
+    DST,
+    WMA_PRO
+} edid_audio_format_id;
+
+typedef struct edid_audio_block_info {
+    edid_audio_format_id format_id;
+    int sampling_freq;
+    int bits_per_sample;
+    int channels;
+} edid_audio_block_info;
+
+typedef struct edid_audio_info {
+    int audio_blocks;
+    unsigned char speaker_allocation[MIN_SPKR_ALLOCATION_DATA_LENGTH];
+    edid_audio_block_info audio_blocks_array[MAX_EDID_BLOCKS];
+    char channel_map[MAX_CHANNELS_SUPPORTED];
+    int  channel_allocation;
+} edid_audio_info;
+
+bool edid_get_sink_caps(edid_audio_info* info, char *edid_data);
+#endif /* EDID_H */
diff --git a/hal/msm8916/hw_info.c b/hal/msm8916/hw_info.c
index 17e1a76..69c9341 100644
--- a/hal/msm8916/hw_info.c
+++ b/hal/msm8916/hw_info.c
@@ -210,8 +210,38 @@
         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, "msm8939-snd-card-skul")) {
+        strlcpy(hw_info->type, "skul", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8939", 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 if (!strcmp(snd_card_name, "msm8952-snd-card")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8952", 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 if (!strcmp(snd_card_name, "msm8952-snd-card-mtp")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8952", 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 if (!strcmp(snd_card_name, "msm8952-tomtom-snd-card")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8952", 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 if (!strcmp(snd_card_name, "msm8952-skum-snd-card")) {
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8952", 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 device", __func__);
+        ALOGW("%s: Not an  8x16/8939/8909/8952 device", __func__);
     }
 }
 
@@ -226,7 +256,7 @@
     }
 
     if (strstr(snd_card_name, "msm8x16") || strstr(snd_card_name, "msm8939") ||
-        strstr(snd_card_name, "msm8909")) {
+        strstr(snd_card_name, "msm8909") || strstr(snd_card_name, "msm8952")) {
         ALOGV("8x16 - variant soundcard");
         update_hardware_info_8x16(hw_info, snd_card_name);
     } else {
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index ea81d42..a15d73d 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -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
@@ -33,7 +33,10 @@
 #include "platform.h"
 #include "audio_extn.h"
 #include "voice_extn.h"
+#include "edid.h"
+#include "sound/compress_params.h"
 #include "sound/msmcal-hwdep.h"
+#include <dirent.h>
 #define SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID (100)
 
 #define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
@@ -46,11 +49,16 @@
 #define MIXER_XML_PATH_SKUA "/system/etc/mixer_paths_skua.xml"
 #define MIXER_XML_PATH_SKUC "/system/etc/mixer_paths_skuc.xml"
 #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_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"
 #define MIXER_XML_PATH_WCD9306 "/system/etc/mixer_paths_wcd9306.xml"
 #define MIXER_XML_PATH_WCD9330 "/system/etc/mixer_paths_wcd9330.xml"
 #define PLATFORM_INFO_XML_PATH      "/system/etc/audio_platform_info.xml"
+#define PLATFORM_INFO_XML_PATH_I2S  "/system/etc/audio_platform_info_i2s.xml"
+
 #define LIB_ACDB_LOADER "libacdbloader.so"
 #define AUDIO_DATA_BLOCK_MIXER_CTL "HDMI EDID"
 #define CVD_VERSION_MIXER_CTL "CVD Version"
@@ -60,17 +68,26 @@
 #define COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING (2 * 1024)
 #define COMPRESS_OFFLOAD_FRAGMENT_SIZE (32 * 1024)
 /* Used in calculating fragment size for pcm offload */
-#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV 2000 /* 2 secs */
-#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING 100 /* 100 millisecs */
+#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV 1000 /* 1 sec */
+#define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING 80 /* 80 millisecs */
+#define PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS 20 /* 20 millisecs */
+#define PCM_OFFLOAD_BUFFER_DURATION_MAX 1200  /* 1200 millisecs */
 
 /* MAX PCM fragment size cannot be increased  further due
  * to flinger's cblk size of 1mb,and it has to be a multiple of
  * 24 - lcm of channels supported by DSP
  */
 #define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
-#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (32 * 1024)
+#define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (4 * 1024)
 
-#define ALIGN( num, to ) (((num) + (to-1)) & (~(to-1)))
+/*
+ * Offload buffer size for compress passthrough
+ */
+#define MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE (2 * 1024)
+#define MAX_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE (8 * 1024)
+
+#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y))
+#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
 /*
  * This file will have a maximum of 38 bytes:
  *
@@ -87,6 +104,8 @@
 
 /* fallback app type if the default app type from acdb loader fails */
 #define DEFAULT_APP_TYPE  0x11130
+#define DEFAULT_APP_TYPE_RX_PATH  0x11130
+#define DEFAULT_APP_TYPE_TX_PATH 0x11132
 
 /* Retry for delay in FW loading*/
 #define RETRY_NUMBER 20
@@ -96,13 +115,23 @@
 #define SAMPLE_RATE_8KHZ  8000
 #define SAMPLE_RATE_16KHZ 16000
 
+#define MAX_SET_CAL_BYTE_SIZE 65536
+
 #define AUDIO_PARAMETER_KEY_FLUENCE_TYPE  "fluence"
 #define AUDIO_PARAMETER_KEY_SLOWTALK      "st_enable"
 #define AUDIO_PARAMETER_KEY_HD_VOICE      "hd_voice"
 #define AUDIO_PARAMETER_KEY_VOLUME_BOOST  "volume_boost"
+#define AUDIO_PARAMETER_KEY_AUD_CALDATA   "cal_data"
+#define AUDIO_PARAMETER_KEY_AUD_CALRESULT "cal_result"
+
+
+/* Query external audio device connection status */
+#define AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE "ext_audio_device"
+
+#define EVENT_EXTERNAL_SPK_1 "qc_ext_spk_1"
+#define EVENT_EXTERNAL_SPK_2 "qc_ext_spk_2"
+#define EVENT_EXTERNAL_MIC   "qc_ext_mic"
 #define MAX_CAL_NAME 20
-#define APP_TYPE_SYSTEM_SOUNDS 0x00011131
-#define APP_TYPE_GENERAL_RECORDING 0x00011132
 
 char cal_name_info[WCD9XXX_MAX_CAL][MAX_CAL_NAME] = {
         [WCD9XXX_ANC_CAL] = "anc_cal",
@@ -123,15 +152,30 @@
     int length;
 };
 
+typedef struct acdb_audio_cal_cfg {
+    uint32_t             persist;
+    uint32_t             snd_dev_id;
+    audio_devices_t      dev_id;
+    int32_t              acdb_dev_id;
+    uint32_t             app_type;
+    uint32_t             topo_id;
+    uint32_t             sampling_rate;
+    uint32_t             cal_type;
+    uint32_t             module_id;
+    uint32_t             param_id;
+} acdb_audio_cal_cfg_t;
+
 /* Audio calibration related functions */
 typedef void (*acdb_deallocate_t)();
-typedef int  (*acdb_init_t)(char *, char *, int);
-typedef void (*acdb_send_audio_cal_t)(int, int, int, int);
+typedef int  (*acdb_init_t)(const char *, char *, int);
+typedef void (*acdb_send_audio_cal_t)(int, int, int , int);
 typedef void (*acdb_send_voice_cal_t)(int, int);
 typedef int (*acdb_reload_vocvoltable_t)(int);
 typedef int  (*acdb_get_default_app_type_t)(void);
 typedef int (*acdb_loader_get_calibration_t)(char *attr, int size, void *data);
 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*);
 
 struct platform_data {
     struct audio_device *adev;
@@ -139,18 +183,24 @@
     bool fluence_in_voice_call;
     bool fluence_in_voice_rec;
     bool fluence_in_audio_rec;
+    bool external_spk_1;
+    bool external_spk_2;
+    bool external_mic;
     int  fluence_type;
     char fluence_cap[PROPERTY_VALUE_MAX];
     int  fluence_mode;
     bool slowtalk;
     bool hd_voice;
     bool ec_ref_enabled;
+    bool is_wsa_speaker;
     /* Audio calibration related functions */
     void                       *acdb_handle;
     int                        voice_feature_set;
     acdb_init_t                acdb_init;
     acdb_deallocate_t          acdb_deallocate;
     acdb_send_audio_cal_t      acdb_send_audio_cal;
+    acdb_set_audio_cal_t       acdb_set_audio_cal;
+    acdb_get_audio_cal_t       acdb_get_audio_cal;
     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;
@@ -159,9 +209,19 @@
 #endif
     void *hw_info;
     struct csd_data *csd;
+    void *edid_info;
+    bool edid_valid;
 };
 
-static const int pcm_device_table[AUDIO_USECASE_MAX][2] = {
+static bool is_external_codec = false;
+static const int pcm_device_table_of_ext_codec[AUDIO_USECASE_MAX][2] = {
+   [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE_OF_EXT_CODEC, QCHAT_CALL_PCM_DEVICE_OF_EXT_CODEC}
+};
+
+/* List of use cases that has different PCM device ID's for internal and external codecs */
+static const int misc_usecase[AUDIO_USECASE_MAX] = { USECASE_QCHAT_CALL };
+
+int pcm_device_table[AUDIO_USECASE_MAX][2] = {
     [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {DEEP_BUFFER_PCM_DEVICE,
                                             DEEP_BUFFER_PCM_DEVICE},
     [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
@@ -170,6 +230,24 @@
                                         MULTIMEDIA2_PCM_DEVICE},
     [USECASE_AUDIO_PLAYBACK_OFFLOAD] =
                      {PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE},
+#ifdef MULTIPLE_OFFLOAD_ENABLED
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD2] =
+                     {PLAYBACK_OFFLOAD_DEVICE2, PLAYBACK_OFFLOAD_DEVICE2},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD3] =
+                     {PLAYBACK_OFFLOAD_DEVICE3, PLAYBACK_OFFLOAD_DEVICE3},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD4] =
+                     {PLAYBACK_OFFLOAD_DEVICE4, PLAYBACK_OFFLOAD_DEVICE4},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD5] =
+                     {PLAYBACK_OFFLOAD_DEVICE5, PLAYBACK_OFFLOAD_DEVICE5},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD6] =
+                     {PLAYBACK_OFFLOAD_DEVICE6, PLAYBACK_OFFLOAD_DEVICE6},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD7] =
+                     {PLAYBACK_OFFLOAD_DEVICE7, PLAYBACK_OFFLOAD_DEVICE7},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD8] =
+                     {PLAYBACK_OFFLOAD_DEVICE8, PLAYBACK_OFFLOAD_DEVICE8},
+    [USECASE_AUDIO_PLAYBACK_OFFLOAD9] =
+                     {PLAYBACK_OFFLOAD_DEVICE9, PLAYBACK_OFFLOAD_DEVICE9},
+#endif
     [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE, AUDIO_RECORD_PCM_DEVICE},
     [USECASE_AUDIO_RECORD_COMPRESS] = {COMPRESS_CAPTURE_DEVICE, COMPRESS_CAPTURE_DEVICE},
     [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
@@ -203,6 +281,10 @@
                                       INCALL_MUSIC_UPLINK2_PCM_DEVICE},
     [USECASE_AUDIO_SPKR_CALIB_RX] = {SPKR_PROT_CALIB_RX_PCM_DEVICE, -1},
     [USECASE_AUDIO_SPKR_CALIB_TX] = {-1, SPKR_PROT_CALIB_TX_PCM_DEVICE},
+    [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = {AFE_PROXY_PLAYBACK_PCM_DEVICE,
+                                          AFE_PROXY_RECORD_PCM_DEVICE},
+    [USECASE_AUDIO_RECORD_AFE_PROXY] = {AFE_PROXY_PLAYBACK_PCM_DEVICE,
+                                        AFE_PROXY_RECORD_PCM_DEVICE},
 };
 
 /* Array to store sound devices */
@@ -211,11 +293,17 @@
     /* Playback sound devices */
     [SND_DEVICE_OUT_HANDSET] = "handset",
     [SND_DEVICE_OUT_SPEAKER] = "speaker",
+    [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_REVERSE] = "speaker-reverse",
     [SND_DEVICE_OUT_HEADPHONES] = "headphones",
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = "speaker-and-headphones",
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1] = "speaker-and-headphones-ext-1",
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2] = "speaker-and-headphones-ext-2",
     [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_HEADPHONES] = "voice-headphones",
     [SND_DEVICE_OUT_HDMI] = "hdmi",
     [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = "speaker-and-hdmi",
@@ -224,6 +312,7 @@
     [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones",
     [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones",
     [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset",
+    [SND_DEVICE_OUT_VOICE_TX] = "voice-tx",
     [SND_DEVICE_OUT_AFE_PROXY] = "afe-proxy",
     [SND_DEVICE_OUT_USB_HEADSET] = "usb-headphones",
     [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = "speaker-and-usb-headphones",
@@ -235,6 +324,7 @@
     [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = "speaker-and-anc-headphones",
     [SND_DEVICE_OUT_ANC_HANDSET] = "anc-handset",
     [SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected",
+    [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = "voice-speaker-protected",
 #ifdef RECORD_PLAY_CONCURRENCY
     [SND_DEVICE_OUT_VOIP_HANDSET] = "voip-handset",
     [SND_DEVICE_OUT_VOIP_SPEAKER] = "voip-speaker",
@@ -243,6 +333,7 @@
 
     /* Capture sound devices */
     [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic",
+    [SND_DEVICE_IN_HANDSET_MIC_EXTERNAL] = "handset-mic-ext",
     [SND_DEVICE_IN_HANDSET_MIC_AEC] = "handset-mic",
     [SND_DEVICE_IN_HANDSET_MIC_NS] = "handset-mic",
     [SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = "handset-mic",
@@ -278,6 +369,7 @@
     [SND_DEVICE_IN_VOICE_REC_MIC_NS] = "voice-rec-mic",
     [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = "voice-rec-dmic-ef",
     [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence",
+    [SND_DEVICE_IN_VOICE_RX] = "voice-rx",
     [SND_DEVICE_IN_USB_HEADSET_MIC] = "usb-headset-mic",
     [SND_DEVICE_IN_CAPTURE_FM] = "capture-fm",
     [SND_DEVICE_IN_AANC_HANDSET_MIC] = "aanc-handset-mic",
@@ -291,18 +383,31 @@
     [SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE] = "speaker-dmic-broadside",
     [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE] = "speaker-dmic-broadside",
     [SND_DEVICE_IN_VOICE_FLUENCE_DMIC_AANC] = "aanc-fluence-dmic-handset",
+    [SND_DEVICE_IN_HANDSET_QMIC] = "quad-mic",
+    [SND_DEVICE_IN_SPEAKER_QMIC_AEC] = "quad-mic",
+    [SND_DEVICE_IN_SPEAKER_QMIC_NS] = "quad-mic",
+    [SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS] = "quad-mic",
 };
 
+// Platform specific backend bit width table
+static int backend_bit_width_table[SND_DEVICE_MAX] = {0};
+
 /* ACDB IDs (audio DSP path configuration IDs) for each sound device */
 static int acdb_device_table[SND_DEVICE_MAX] = {
     [SND_DEVICE_NONE] = -1,
     [SND_DEVICE_OUT_HANDSET] = 7,
     [SND_DEVICE_OUT_SPEAKER] = 14,
+    [SND_DEVICE_OUT_SPEAKER_EXTERNAL_1] = 14,
+    [SND_DEVICE_OUT_SPEAKER_EXTERNAL_2] = 14,
+    [SND_DEVICE_OUT_SPEAKER_WSA] = 135,
     [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14,
     [SND_DEVICE_OUT_HEADPHONES] = 10,
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10,
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1] = 10,
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2] = 10,
     [SND_DEVICE_OUT_VOICE_HANDSET] = 7,
     [SND_DEVICE_OUT_VOICE_SPEAKER] = 14,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_WSA] = 135,
     [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10,
     [SND_DEVICE_OUT_HDMI] = 18,
     [SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 14,
@@ -311,6 +416,7 @@
     [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
     [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
     [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37,
+    [SND_DEVICE_OUT_VOICE_TX] = 45,
     [SND_DEVICE_OUT_AFE_PROXY] = 0,
     [SND_DEVICE_OUT_USB_HEADSET] = 45,
     [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 14,
@@ -321,7 +427,8 @@
     [SND_DEVICE_OUT_VOICE_ANC_FB_HEADSET] = 27,
     [SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET] = 26,
     [SND_DEVICE_OUT_ANC_HANDSET] = 103,
-    [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 101,
+    [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 124,
+    [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = 101,
 #ifdef RECORD_PLAY_CONCURRENCY
     [SND_DEVICE_OUT_VOIP_HANDSET] = 133,
     [SND_DEVICE_OUT_VOIP_SPEAKER] = 132,
@@ -329,6 +436,7 @@
 #endif
 
     [SND_DEVICE_IN_HANDSET_MIC] = 4,
+    [SND_DEVICE_IN_HANDSET_MIC_EXTERNAL] = 4,
     [SND_DEVICE_IN_HANDSET_MIC_AEC] = 106,
     [SND_DEVICE_IN_HANDSET_MIC_NS] = 107,
     [SND_DEVICE_IN_HANDSET_MIC_AEC_NS] = 108,
@@ -364,6 +472,7 @@
     [SND_DEVICE_IN_VOICE_REC_MIC_NS] = 107,
     [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = 34,
     [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = 41,
+    [SND_DEVICE_IN_VOICE_RX] = 44,
     [SND_DEVICE_IN_USB_HEADSET_MIC] = 44,
     [SND_DEVICE_IN_CAPTURE_FM] = 0,
     [SND_DEVICE_IN_AANC_HANDSET_MIC] = 104,
@@ -377,9 +486,13 @@
     [SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE] = 121,
     [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE] = 120,
     [SND_DEVICE_IN_VOICE_FLUENCE_DMIC_AANC] = 135,
+    [SND_DEVICE_IN_HANDSET_QMIC] = 125,
+    [SND_DEVICE_IN_SPEAKER_QMIC_AEC] = 126,
+    [SND_DEVICE_IN_SPEAKER_QMIC_NS] = 127,
+    [SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS] = 129,
 };
 
-struct snd_device_index {
+struct name_to_index {
     char name[100];
     unsigned int index;
 };
@@ -387,14 +500,20 @@
 #define TO_NAME_INDEX(X)   #X, X
 
 /* Used to get index from parsed sting */
-struct snd_device_index snd_device_name_index[SND_DEVICE_MAX] = {
+static struct name_to_index snd_device_name_index[SND_DEVICE_MAX] = {
     {TO_NAME_INDEX(SND_DEVICE_OUT_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_EXTERNAL_1)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_EXTERNAL_2)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_WSA)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_REVERSE)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_HEADPHONES)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2)},
     {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_HEADPHONES)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_HDMI)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_HDMI)},
@@ -403,6 +522,7 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TX)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_AFE_PROXY)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_USB_HEADSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET)},
@@ -414,12 +534,14 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET)},
     {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)},
 #ifdef RECORD_PLAY_CONCURRENCY
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_HANDSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_SPEAKER)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOIP_HEADPHONES)},
 #endif
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_EXTERNAL)},
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_NS)},
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC_NS)},
@@ -455,6 +577,7 @@
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_MIC_NS)},
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_DMIC_STEREO)},
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_RX)},
     {TO_NAME_INDEX(SND_DEVICE_IN_USB_HEADSET_MIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_FM)},
     {TO_NAME_INDEX(SND_DEVICE_IN_AANC_HANDSET_MIC)},
@@ -463,6 +586,45 @@
     {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_STEREO_DMIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_CAPTURE_VI_FEEDBACK)},
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_FLUENCE_DMIC_AANC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_BROADSIDE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_QMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_AEC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS)},
+};
+
+static char * backend_table[SND_DEVICE_MAX] = {0};
+
+static struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = {
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_DEEP_BUFFER)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_LOW_LATENCY)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MULTI_CH)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD)},
+#ifdef MULTIPLE_OFFLOAD_ENABLED
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD2)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD3)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD4)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD5)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD6)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD7)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD8)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD9)},
+#endif
+    {TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
+    {TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)},
+    {TO_NAME_INDEX(USECASE_VOICE_CALL)},
+    {TO_NAME_INDEX(USECASE_VOICE2_CALL)},
+    {TO_NAME_INDEX(USECASE_VOLTE_CALL)},
+    {TO_NAME_INDEX(USECASE_QCHAT_CALL)},
+    {TO_NAME_INDEX(USECASE_VOWLAN_CALL)},
+    {TO_NAME_INDEX(USECASE_INCALL_REC_UPLINK)},
+    {TO_NAME_INDEX(USECASE_INCALL_REC_DOWNLINK)},
+    {TO_NAME_INDEX(USECASE_INCALL_REC_UPLINK_AND_DOWNLINK)},
+    {TO_NAME_INDEX(USECASE_AUDIO_HFP_SCO)},
 };
 
 #define NO_COLS 2
@@ -526,6 +688,32 @@
 #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
 #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
 
+static bool is_misc_usecase(audio_usecase_t usecase) {
+     bool ret = false;
+     int i;
+
+     for (i = 0; i < AUDIO_USECASE_MAX; i++) {
+          if(usecase == misc_usecase[i]) {
+             ret = true;
+             break;
+          }
+     }
+     return ret;
+}
+
+
+static void update_codec_type(const char *snd_card_name) {
+
+     if (!strncmp(snd_card_name, "msm8939-tapan-snd-card",
+                  sizeof("msm8939-tapan-snd-card")) ||
+         !strncmp(snd_card_name, "msm8939-tapan9302-snd-card",
+                  sizeof("msm8939-tapan9302-snd-card"))||
+         !strncmp(snd_card_name, "msm8939-tomtom9330-snd-card",
+                  sizeof("msm8939-tomtom9330-snd-card"))) {
+         ALOGI("%s: snd_card_name: %s",__func__,snd_card_name);
+         is_external_codec = true;
+     }
+}
 static void query_platform(const char *snd_card_name,
                                       char *mixer_xml_path)
 {
@@ -640,6 +828,35 @@
         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, "msm8939-snd-card-skul",
+                 sizeof("msm8939-snd-card-skul"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_SKUL,
+                sizeof(MIXER_XML_PATH_SKUL));
+        msm_device_to_be_id = msm_device_to_be_id_internal_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_internal_codec[0]);
+    } else if (!strncmp(snd_card_name, "msm8952-snd-card-mtp",
+                 sizeof("msm8952-snd-card-mtpmsm8952-snd-card-mtp"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_MTP,
+                sizeof(MIXER_XML_PATH_MTP));
+        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, "msm8952-tomtom-snd-card",
+                 sizeof("msm8952-tomtom-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_WCD9330,
+                sizeof(MIXER_XML_PATH_WCD9330));
+        msm_device_to_be_id = msm_device_to_be_id_external_codec;
+        msm_be_id_array_len  =
+            sizeof(msm_device_to_be_id_external_codec) / sizeof(msm_device_to_be_id_external_codec[0]);
+    } else if (!strncmp(snd_card_name, "msm8952-skum-snd-card",
+                 sizeof("msm8952-skum-snd-card"))) {
+        strlcpy(mixer_xml_path, MIXER_XML_PATH_SKUM,
+                sizeof(MIXER_XML_PATH_SKUM));
+        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));
@@ -656,19 +873,17 @@
     struct platform_data *my_data = (struct platform_data *)platform;
     struct audio_device *adev = my_data->adev;
 
-    if (enable) {
-        my_data->ec_ref_enabled = enable;
-        audio_route_apply_and_update_path(adev->audio_route, "echo-reference");
-    } else {
-        if (my_data->ec_ref_enabled) {
-            audio_route_reset_and_update_path(adev->audio_route, "echo-reference");
-            my_data->ec_ref_enabled = enable;
-        } else {
-            ALOGV("EC reference is already disabled : %d", my_data->ec_ref_enabled);
-        }
+    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");
     }
 
-    ALOGV("Setting EC Reference: %d", enable);
+    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");
+    }
 }
 
 static struct csd_data *open_csd_client()
@@ -785,6 +1000,8 @@
                   __func__, dlerror());
             goto error;
         }
+
+
         csd->init = (init_t)dlsym(csd->csd_client, "csd_client_init");
 
         if (csd->init == NULL) {
@@ -813,6 +1030,38 @@
     }
 }
 
+
+static void set_platform_defaults()
+{
+    int32_t dev;
+    for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
+        backend_table[dev] = NULL;
+    }
+    for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
+        backend_bit_width_table[dev] = 16;
+    }
+
+    // TBD - do these go to the platform-info.xml file.
+    // will help in avoiding strdups here
+    backend_table[SND_DEVICE_IN_BT_SCO_MIC] = strdup("bt-sco");
+    backend_table[SND_DEVICE_IN_BT_SCO_MIC_WB] = strdup("bt-sco-wb");
+    backend_table[SND_DEVICE_IN_BT_SCO_MIC_NREC] = strdup("bt-sco");
+    backend_table[SND_DEVICE_IN_BT_SCO_MIC_WB_NREC] = strdup("bt-sco-wb");
+    backend_table[SND_DEVICE_OUT_BT_SCO] = strdup("bt-sco");
+    backend_table[SND_DEVICE_OUT_BT_SCO_WB] = strdup("bt-sco-wb");
+    backend_table[SND_DEVICE_OUT_HDMI] = strdup("hdmi");
+    backend_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = strdup("speaker-and-hdmi");
+    backend_table[SND_DEVICE_OUT_VOICE_TX] = strdup("afe-proxy");
+    backend_table[SND_DEVICE_IN_VOICE_RX] = strdup("afe-proxy");
+    backend_table[SND_DEVICE_OUT_AFE_PROXY] = strdup("afe-proxy");
+    backend_table[SND_DEVICE_OUT_USB_HEADSET] = strdup("usb-headphones");
+    backend_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] =
+        strdup("speaker-and-usb-headphones");
+    backend_table[SND_DEVICE_IN_USB_HEADSET_MIC] = strdup("usb-headset-mic");
+    backend_table[SND_DEVICE_IN_CAPTURE_FM] = strdup("capture-fm");
+    backend_table[SND_DEVICE_OUT_TRANSMISSION_FM] = strdup("transmission-fm");
+}
+
 void get_cvd_version(char *cvd_version, struct audio_device *adev)
 {
     struct mixer_ctl *ctl;
@@ -989,6 +1238,7 @@
                 return NULL;
             }
             adev->snd_card = snd_card_num;
+            update_codec_type(snd_card_name);
             ALOGD("%s: Opened sound card:%d", __func__, snd_card_num);
             break;
         }
@@ -1007,10 +1257,15 @@
     my_data->fluence_in_voice_call = false;
     my_data->fluence_in_voice_rec = false;
     my_data->fluence_in_audio_rec = false;
+    my_data->external_spk_1 = false;
+    my_data->external_spk_2 = false;
+    my_data->external_mic = false;
     my_data->fluence_type = FLUENCE_NONE;
     my_data->fluence_mode = FLUENCE_ENDFIRE;
     my_data->slowtalk = false;
     my_data->hd_voice = false;
+    my_data->edid_info = NULL;
+    my_data->is_wsa_speaker = false;
 
     property_get("ro.qc.sdk.audio.fluencetype", my_data->fluence_cap, "");
     if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro"))) {
@@ -1050,6 +1305,7 @@
     property_get("persist.audio.FFSP.enable", ffspEnable, "");
     if (!strncmp("true", ffspEnable, sizeof("true"))) {
         acdb_device_table[SND_DEVICE_OUT_SPEAKER] = 131;
+        acdb_device_table[SND_DEVICE_OUT_SPEAKER_WSA] = 131;
         acdb_device_table[SND_DEVICE_OUT_SPEAKER_REVERSE] = 131;
         acdb_device_table[SND_DEVICE_OUT_SPEAKER_AND_HDMI] = 131;
         acdb_device_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 131;
@@ -1075,6 +1331,18 @@
             ALOGE("%s: Could not find the symbol acdb_send_audio_cal from %s",
                   __func__, LIB_ACDB_LOADER);
 
+        my_data->acdb_set_audio_cal = (acdb_set_audio_cal_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_set_audio_cal_v2");
+        if (!my_data->acdb_set_audio_cal)
+            ALOGE("%s: Could not find the symbol acdb_set_audio_cal_v2 from %s",
+                  __func__, LIB_ACDB_LOADER);
+
+        my_data->acdb_get_audio_cal = (acdb_get_audio_cal_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_get_audio_cal_v2");
+        if (!my_data->acdb_get_audio_cal)
+            ALOGE("%s: Could not find the symbol acdb_get_audio_cal_v2 from %s",
+                  __func__, LIB_ACDB_LOADER);
+
         my_data->acdb_send_voice_cal = (acdb_send_voice_cal_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_send_voice_cal");
         if (!my_data->acdb_send_voice_cal)
@@ -1106,14 +1374,35 @@
             ALOGE("Failed to allocate cvd version");
         else
             get_cvd_version(cvd_version, adev);
-
         my_data->acdb_init(snd_card_name, cvd_version, key);
         if (cvd_version)
             free(cvd_version);
     }
     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";
+    strcat(CodecPeek, snd_card_name);
+
+    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);
+    }
+
 acdb_init_fail:
+
+    set_platform_defaults();
+
     /* Initialize ACDB ID's */
     platform_info_init(PLATFORM_INFO_XML_PATH);
 
@@ -1132,6 +1421,10 @@
     audio_extn_dolby_set_license(adev);
     audio_hwdep_send_cal(my_data);
 
+    /* init audio device arbitration */
+    audio_extn_dev_arbi_init();
+
+    my_data->edid_info = NULL;
     return my_data;
 }
 
@@ -1139,9 +1432,30 @@
 {
     struct platform_data *my_data = (struct platform_data *)platform;
 
+    if (my_data->edid_info) {
+        free(my_data->edid_info);
+        my_data->edid_info = NULL;
+    }
+
     hw_info_deinit(my_data->hw_info);
     close_csd_client(my_data->csd);
 
+    int32_t dev;
+    for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
+        if (backend_table[dev]) {
+            free(backend_table[dev]);
+            backend_table[dev]= NULL;
+        }
+    }
+
+    /* deinit audio device arbitration */
+    audio_extn_dev_arbi_deinit();
+
+    if (my_data->edid_info) {
+        free(my_data->edid_info);
+        my_data->edid_info = NULL;
+    }
+
     free(platform);
     /* deinit usb */
     audio_extn_usb_deinit();
@@ -1174,64 +1488,67 @@
 
 void platform_add_backend_name(char *mixer_path, snd_device_t snd_device)
 {
-    if ((snd_device == SND_DEVICE_IN_BT_SCO_MIC) ||
-         (snd_device == SND_DEVICE_IN_BT_SCO_MIC_NREC))
-        strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
-    else if ((snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB) ||
-              (snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB_NREC))
-        strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
-    else if(snd_device == SND_DEVICE_OUT_BT_SCO)
-        strlcat(mixer_path, " bt-sco", MIXER_PATH_MAX_LENGTH);
-    else if(snd_device == SND_DEVICE_OUT_BT_SCO_WB)
-        strlcat(mixer_path, " bt-sco-wb", MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_OUT_HDMI)
-        strlcat(mixer_path, " hdmi", MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_HDMI)
-        strlcat(mixer_path, " speaker-and-hdmi", MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_OUT_AFE_PROXY)
-        strlcat(mixer_path, " afe-proxy", MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_OUT_USB_HEADSET)
-        strlcat(mixer_path, " usb-headphones", MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET)
-        strlcat(mixer_path, " speaker-and-usb-headphones",
-                MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_IN_USB_HEADSET_MIC)
-        strlcat(mixer_path, " usb-headset-mic", MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_IN_CAPTURE_FM)
-        strlcat(mixer_path, " capture-fm", MIXER_PATH_MAX_LENGTH);
-    else if (snd_device == SND_DEVICE_OUT_TRANSMISSION_FM)
-        strlcat(mixer_path, " transmission-fm", MIXER_PATH_MAX_LENGTH);
+    if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+        ALOGE("%s: Invalid snd_device = %d", __func__, snd_device);
+        return;
+    }
+
+    const char * suffix = backend_table[snd_device];
+
+    if (suffix != NULL) {
+        strlcat(mixer_path, " ", MIXER_PATH_MAX_LENGTH);
+        strlcat(mixer_path, suffix, MIXER_PATH_MAX_LENGTH);
+    }
 }
 
 int platform_get_pcm_device_id(audio_usecase_t usecase, int device_type)
 {
-    int device_id;
-    if (device_type == PCM_PLAYBACK)
-        device_id = pcm_device_table[usecase][0];
-    else
-        device_id = pcm_device_table[usecase][1];
+    int device_id = -1;
+
+    if (is_external_codec && is_misc_usecase(usecase)) {
+        if (device_type == PCM_PLAYBACK)
+            device_id = pcm_device_table_of_ext_codec[usecase][0];
+        else
+            device_id = pcm_device_table_of_ext_codec[usecase][1];
+    } else {
+        if (device_type == PCM_PLAYBACK)
+            device_id = pcm_device_table[usecase][0];
+        else
+            device_id = pcm_device_table[usecase][1];
+    }
     return device_id;
 }
 
-int platform_get_snd_device_index(char *snd_device_index_name)
+static int find_index(struct name_to_index * table, int32_t len, const char * name)
 {
     int ret = 0;
-    int i;
+    int32_t i;
 
-    if (snd_device_index_name == NULL) {
-        ALOGE("%s: snd_device_index_name is NULL", __func__);
+    if (table == NULL) {
+        ALOGE("%s: table is NULL", __func__);
         ret = -ENODEV;
         goto done;
     }
 
-    for (i=0; i < SND_DEVICE_MAX; i++) {
-        if(strcmp(snd_device_name_index[i].name, snd_device_index_name) == 0) {
-            ret = snd_device_name_index[i].index;
+    if (name == NULL) {
+        ALOGE("null key");
+        ret = -ENODEV;
+        goto done;
+    }
+
+    for (i=0; i < len; i++) {
+        const char* tn = table[i].name;
+        size_t len = strlen(tn);
+        if (strncmp(tn, name, len) == 0) {
+            if (strlen(name) != len) {
+                continue; // substring
+            }
+            ret = table[i].index;
             goto done;
         }
     }
-    ALOGE("%s: Could not find index for snd_device_index_name = %s",
-            __func__, snd_device_index_name);
+    ALOGE("%s: Could not find index for name = %s",
+            __func__, name);
     ret = -ENODEV;
 done:
     return ret;
@@ -1294,6 +1611,16 @@
     return ret;
 }
 
+int platform_get_snd_device_index(char *device_name)
+{
+    return find_index(snd_device_name_index, SND_DEVICE_MAX, device_name);
+}
+
+int platform_get_usecase_index(const char *usecase_name)
+{
+    return find_index(usecase_name_index, AUDIO_USECASE_MAX, usecase_name);
+}
+
 int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id)
 {
     int ret = 0;
@@ -1329,6 +1656,31 @@
     return acdb_device_table[snd_device];
 }
 
+int platform_set_snd_device_bit_width(snd_device_t snd_device, unsigned int bit_width)
+{
+    int ret = 0;
+
+    if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+        ALOGE("%s: Invalid snd_device = %d",
+            __func__, snd_device);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    backend_bit_width_table[snd_device] = bit_width;
+done:
+    return ret;
+}
+
+int platform_get_snd_device_bit_width(snd_device_t snd_device)
+{
+    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 backend_bit_width_table[snd_device];
+}
+
 int platform_send_audio_calibration(void *platform, struct audio_usecase *usecase,
                                     int app_type, int sample_rate)
 {
@@ -1337,18 +1689,17 @@
     struct audio_device *adev = my_data->adev;
     int snd_device = SND_DEVICE_OUT_SPEAKER;
 
-    if (usecase->type == PCM_PLAYBACK) {
-        snd_device = platform_get_output_snd_device(adev->platform,
-                                            usecase->stream.out->devices);
-        if(usecase->id != USECASE_AUDIO_PLAYBACK_OFFLOAD)
-            app_type = APP_TYPE_SYSTEM_SOUNDS;
-    } else if ((usecase->type == PCM_HFP_CALL) || (usecase->type == PCM_CAPTURE)) {
-        snd_device = platform_get_input_snd_device(adev->platform,
-                                            adev->primary_output->devices);
-        app_type = APP_TYPE_GENERAL_RECORDING;
-    }
+    if (usecase->type == PCM_PLAYBACK)
+        snd_device = usecase->out_snd_device;
+    else if ((usecase->type == PCM_HFP_CALL) || (usecase->type == PCM_CAPTURE))
+        snd_device = usecase->in_snd_device;
+    acdb_dev_id = acdb_device_table[audio_extn_get_spkr_prot_snd_device(snd_device)];
 
-    acdb_dev_id = acdb_device_table[snd_device];
+    // Do not use Rx path default app type for TX path
+    if ((usecase->type == PCM_CAPTURE) && (app_type == DEFAULT_APP_TYPE_RX_PATH)) {
+        ALOGD("Resetting app type for Tx path to default");
+        app_type  = DEFAULT_APP_TYPE_TX_PATH;
+    }
     if (acdb_dev_id < 0) {
         ALOGE("%s: Could not find acdb id for device(%d)",
               __func__, snd_device);
@@ -1374,7 +1725,7 @@
     int ret = 0;
 
     if (my_data->csd != NULL &&
-        my_data->adev->mode == AUDIO_MODE_IN_CALL) {
+        voice_is_in_call(my_data->adev)) {
         /* This must be called before disabling mixer controls on APQ side */
         ret = my_data->csd->disable_device();
         if (ret < 0) {
@@ -1384,6 +1735,7 @@
     }
     return ret;
 }
+
 int platform_switch_voice_call_enable_device_config(void *platform,
                                                     snd_device_t out_snd_device,
                                                     snd_device_t in_snd_device)
@@ -1392,25 +1744,31 @@
     int acdb_rx_id, acdb_tx_id;
     int ret = 0;
 
-    acdb_rx_id = acdb_device_table[out_snd_device];
+    if (my_data->csd == NULL)
+        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
+        acdb_rx_id = acdb_device_table[out_snd_device];
+
     acdb_tx_id = acdb_device_table[in_snd_device];
 
-    if (my_data->csd != NULL) {
-        if (acdb_rx_id > 0 && acdb_tx_id > 0) {
-            ret = my_data->csd->enable_device_config(acdb_rx_id, acdb_tx_id);
-            if (ret < 0) {
-                ALOGE("%s: csd_enable_device_config, failed, error %d",
-                      __func__, ret);
-            }
-        } else {
-            ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
-                  acdb_rx_id, acdb_tx_id);
+    if (acdb_rx_id > 0 && acdb_tx_id > 0) {
+        ret = my_data->csd->enable_device_config(acdb_rx_id, acdb_tx_id);
+        if (ret < 0) {
+            ALOGE("%s: csd_enable_device_config, failed, error %d",
+                  __func__, ret);
         }
+    } else {
+        ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+              acdb_rx_id, acdb_tx_id);
     }
+
     return ret;
 }
 
-
 int platform_switch_voice_call_device_post(void *platform,
                                            snd_device_t out_snd_device,
                                            snd_device_t in_snd_device)
@@ -1421,6 +1779,10 @@
     if (my_data->acdb_send_voice_cal == NULL) {
         ALOGE("%s: dlsym error for acdb_send_voice_call", __func__);
     } else {
+        if (out_snd_device == SND_DEVICE_OUT_VOICE_SPEAKER &&
+            audio_extn_spkr_prot_is_enabled())
+            out_snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED;
+
         acdb_rx_id = acdb_device_table[out_snd_device];
         acdb_tx_id = acdb_device_table[in_snd_device];
 
@@ -1442,22 +1804,28 @@
     int acdb_rx_id, acdb_tx_id;
     int ret = 0;
 
-    acdb_rx_id = acdb_device_table[out_snd_device];
+    if (my_data->csd == NULL)
+        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
+        acdb_rx_id = acdb_device_table[out_snd_device];
+
     acdb_tx_id = acdb_device_table[in_snd_device];
 
-    if (my_data->csd != NULL) {
-        if (acdb_rx_id > 0 && acdb_tx_id > 0) {
-            ret = my_data->csd->enable_device(acdb_rx_id, acdb_tx_id,
-                                              my_data->adev->acdb_settings);
-            if (ret < 0) {
-                ALOGE("%s: csd_enable_device, failed, error %d",
-                      __func__, ret);
-            }
-        } else {
-            ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
-                  acdb_rx_id, acdb_tx_id);
+    if (acdb_rx_id > 0 && acdb_tx_id > 0) {
+        ret = my_data->csd->enable_device(acdb_rx_id, acdb_tx_id,
+                                          my_data->adev->acdb_settings);
+        if (ret < 0) {
+            ALOGE("%s: csd_enable_device, failed, error %d", __func__, ret);
         }
+    } else {
+        ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+              acdb_rx_id, acdb_tx_id);
     }
+
     return ret;
 }
 
@@ -1489,7 +1857,7 @@
     return ret;
 }
 
-int platform_get_sample_rate(void *platform __unused, uint32_t *rate __unused)
+int platform_get_sample_rate(void *platform, uint32_t *rate)
 {
     return 0;
 }
@@ -1521,7 +1889,8 @@
     mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
 
     if (my_data->csd != NULL) {
-        ret = my_data->csd->volume(ALL_SESSION_VSID, volume);
+        ret = my_data->csd->volume(ALL_SESSION_VSID, volume,
+                                   DEFAULT_VOLUME_RAMP_DURATION_MS);
         if (ret < 0) {
             ALOGE("%s: csd_volume error %d", __func__, ret);
         }
@@ -1538,7 +1907,7 @@
     int ret = 0;
     uint32_t set_values[ ] = {0,
                               ALL_SESSION_VSID,
-                              DEFAULT_VOLUME_RAMP_DURATION_MS};
+                              DEFAULT_MUTE_RAMP_DURATION_MS};
 
     set_values[0] = state;
     ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
@@ -1551,7 +1920,8 @@
     mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
 
     if (my_data->csd != NULL) {
-        ret = my_data->csd->mic_mute(ALL_SESSION_VSID, state);
+        ret = my_data->csd->mic_mute(ALL_SESSION_VSID, state,
+                                     DEFAULT_MUTE_RAMP_DURATION_MS);
         if (ret < 0) {
             ALOGE("%s: csd_mic_mute error %d", __func__, ret);
         }
@@ -1630,11 +2000,20 @@
     if (popcount(devices) == 2) {
         if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
                         AUDIO_DEVICE_OUT_SPEAKER)) {
-            snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
+            if (my_data->external_spk_1)
+                snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1;
+            else if (my_data->external_spk_2)
+                snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2;
+            else
+                snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
         } else if (devices == (AUDIO_DEVICE_OUT_WIRED_HEADSET |
                                AUDIO_DEVICE_OUT_SPEAKER)) {
             if (audio_extn_get_anc_enabled())
                 snd_device = SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET;
+            else if (my_data->external_spk_1)
+                snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1;
+            else if (my_data->external_spk_2)
+                snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2;
             else
                 snd_device = SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES;
         } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL |
@@ -1657,8 +2036,7 @@
         goto exit;
     }
 
-    if ((mode == AUDIO_MODE_IN_CALL) ||
-        voice_extn_compress_voip_is_active(adev)) {
+    if (voice_is_in_call(adev) || voice_extn_compress_voip_is_active(adev)) {
         if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
             devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
             if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
@@ -1691,7 +2069,10 @@
             else
                 snd_device = SND_DEVICE_OUT_BT_SCO;
         } else if (devices & AUDIO_DEVICE_OUT_SPEAKER) {
-            snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
+                if (my_data->is_wsa_speaker)
+                    snd_device = SND_DEVICE_OUT_VOICE_SPEAKER_WSA;
+                else
+                    snd_device = SND_DEVICE_OUT_VOICE_SPEAKER;
         } else if (devices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ||
                    devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
             snd_device = SND_DEVICE_OUT_USB_HEADSET;
@@ -1702,7 +2083,9 @@
                 snd_device = SND_DEVICE_OUT_ANC_HANDSET;
             else
                 snd_device = SND_DEVICE_OUT_VOICE_HANDSET;
-        }
+        } else if (devices & AUDIO_DEVICE_OUT_TELEPHONY_TX)
+            snd_device = SND_DEVICE_OUT_VOICE_TX;
+
         if (snd_device != SND_DEVICE_NONE) {
             goto exit;
         }
@@ -1742,7 +2125,12 @@
             if (adev->speaker_lr_swap)
                 snd_device = SND_DEVICE_OUT_SPEAKER_REVERSE;
             else
-                snd_device = SND_DEVICE_OUT_SPEAKER;
+            {
+                if (my_data->is_wsa_speaker)
+                    snd_device = SND_DEVICE_OUT_SPEAKER_WSA;
+                else
+                    snd_device = SND_DEVICE_OUT_SPEAKER;
+            }
         }
     } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
         if (adev->bt_wb_speech_enabled)
@@ -1796,7 +2184,23 @@
 
     ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
           __func__, out_device, in_device);
-    if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) ||
+    if (my_data->external_mic) {
+        if ((out_device != AUDIO_DEVICE_NONE && voice_is_in_call(adev)) ||
+            voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev)) {
+            if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+               out_device & AUDIO_DEVICE_OUT_EARPIECE ||
+               out_device & AUDIO_DEVICE_OUT_SPEAKER )
+                snd_device = SND_DEVICE_IN_HANDSET_MIC_EXTERNAL;
+        } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
+                   in_device & AUDIO_DEVICE_IN_BACK_MIC) {
+            snd_device = SND_DEVICE_IN_HANDSET_MIC_EXTERNAL;
+        }
+    }
+
+    if (snd_device != AUDIO_DEVICE_NONE)
+        goto exit;
+
+    if ((out_device != AUDIO_DEVICE_NONE) && ((voice_is_in_call(adev)) ||
         voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev))) {
         if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
             !voice_extn_compress_voip_is_active(adev)) {
@@ -1830,6 +2234,7 @@
             } else if (out_device & AUDIO_DEVICE_OUT_EARPIECE &&
                 audio_extn_should_use_handset_anc(channel_count)) {
                 snd_device = SND_DEVICE_IN_AANC_HANDSET_MIC;
+                adev->acdb_settings |= ANC_FLAG;
             } else if (my_data->fluence_type == FLUENCE_NONE ||
                 my_data->fluence_in_voice_call == false) {
                 snd_device = SND_DEVICE_IN_HANDSET_MIC;
@@ -1841,8 +2246,8 @@
             }
         } else if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
             snd_device = SND_DEVICE_IN_VOICE_HEADSET_MIC;
-               if (audio_extn_hfp_is_active(adev))
-                   platform_set_echo_reference(adev->platform, true);
+            if (audio_extn_hfp_is_active(adev))
+                platform_set_echo_reference(adev->platform, true);
         } else if (out_device & AUDIO_DEVICE_OUT_ALL_SCO) {
             if (adev->bt_wb_speech_enabled) {
                 if (adev->bluetooth_nrec)
@@ -1874,7 +2279,8 @@
                 if (audio_extn_hfp_is_active(adev))
                     platform_set_echo_reference(adev->platform, true);
             }
-        }
+        } else if (out_device & AUDIO_DEVICE_OUT_TELEPHONY_TX)
+            snd_device = SND_DEVICE_IN_VOICE_RX;
     } else if (source == AUDIO_SOURCE_CAMCORDER) {
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
             in_device & AUDIO_DEVICE_IN_BACK_MIC) {
@@ -1907,12 +2313,15 @@
             if (adev->active_input->enable_aec &&
                     adev->active_input->enable_ns) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
-                    if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
-                       my_data->fluence_in_spkr_mode) {
-                        if (my_data->fluence_mode == FLUENCE_BROADSIDE)
-                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE;
-                        else
-                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
+                    if (my_data->fluence_in_spkr_mode) {
+                        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                            snd_device = SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS;
+                        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                            if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE;
+                            else
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
+                        }
                         adev->acdb_settings |= DMIC_FLAG;
                     } else
                         snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
@@ -1928,12 +2337,15 @@
                 platform_set_echo_reference(adev->platform, true);
             } else if (adev->active_input->enable_aec) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
-                    if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
-                        my_data->fluence_in_spkr_mode) {
-                        if (my_data->fluence_mode == FLUENCE_BROADSIDE)
-                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE;
-                        else
-                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC;
+                    if (my_data->fluence_in_spkr_mode) {
+                        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                            snd_device = SND_DEVICE_IN_SPEAKER_QMIC_AEC;
+                        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                            if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE;
+                            else
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC;
+                        }
                         adev->acdb_settings |= DMIC_FLAG;
                     } else
                         snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC;
@@ -1949,12 +2361,15 @@
                 platform_set_echo_reference(adev->platform, true);
             } else if (adev->active_input->enable_ns) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
-                    if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
-                        my_data->fluence_in_spkr_mode) {
-                        if (my_data->fluence_mode == FLUENCE_BROADSIDE)
-                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE;
-                        else
-                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS;
+                    if (my_data->fluence_in_spkr_mode) {
+                        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                            snd_device = SND_DEVICE_IN_SPEAKER_QMIC_NS;
+                        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                            if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE;
+                            else
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS;
+                        }
                         adev->acdb_settings |= DMIC_FLAG;
                     } else
                         snd_device = SND_DEVICE_IN_SPEAKER_MIC_NS;
@@ -1974,9 +2389,15 @@
     } else if (source == AUDIO_SOURCE_MIC) {
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC &&
                 channel_count == 1 ) {
-            if(my_data->fluence_type & FLUENCE_DUAL_MIC &&
-                    my_data->fluence_in_audio_rec)
-                snd_device = SND_DEVICE_IN_HANDSET_DMIC;
+            if(my_data->fluence_in_audio_rec) {
+                if(my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                    snd_device = SND_DEVICE_IN_HANDSET_QMIC;
+                    platform_set_echo_reference(adev->platform, true);
+                } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                    snd_device = SND_DEVICE_IN_HANDSET_DMIC;
+                    platform_set_echo_reference(adev->platform, true);
+                }
+            }
         }
     } else if (source == AUDIO_SOURCE_FM_RX ||
                source == AUDIO_SOURCE_FM_RX_A2DP) {
@@ -1996,7 +2417,8 @@
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
             if (audio_extn_ssr_get_enabled() && channel_count == 6)
                 snd_device = SND_DEVICE_IN_QUAD_MIC;
-            else if (channel_count == 2)
+            else if (my_data->fluence_type & (FLUENCE_DUAL_MIC | FLUENCE_QUAD_MIC) &&
+                    channel_count == 2)
                 snd_device = SND_DEVICE_IN_HANDSET_STEREO_DMIC;
             else
                 snd_device = SND_DEVICE_IN_HANDSET_MIC;
@@ -2104,54 +2526,27 @@
 
 int platform_edid_get_max_channels(void *platform)
 {
+    int channel_count;
+    int max_channels = 2;
+    int i = 0, ret = 0;
     struct platform_data *my_data = (struct platform_data *)platform;
     struct audio_device *adev = my_data->adev;
-    char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE];
-    char *sad = block;
-    int num_audio_blocks;
-    int channel_count;
-    int max_channels = 0;
-    int i, ret, count;
+    edid_audio_info *info = NULL;
+    ret = platform_get_edid_info(platform);
+    info = (edid_audio_info *)my_data->edid_info;
 
-    struct mixer_ctl *ctl;
-
-    ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_DATA_BLOCK_MIXER_CTL);
-    if (!ctl) {
-        ALOGE("%s: Could not get ctl for mixer cmd - %s",
-              __func__, AUDIO_DATA_BLOCK_MIXER_CTL);
-        return 0;
-    }
-
-    mixer_ctl_update(ctl);
-
-    count = mixer_ctl_get_num_values(ctl);
-
-    /* Read SAD blocks, clamping the maximum size for safety */
-    if (count > (int)sizeof(block))
-        count = (int)sizeof(block);
-
-    ret = mixer_ctl_get_array(ctl, block, count);
-    if (ret != 0) {
-        ALOGE("%s: mixer_ctl_get_array() failed to get EDID info", __func__);
-        return 0;
-    }
-
-    /* Calculate the number of SAD blocks */
-    num_audio_blocks = count / SAD_BLOCK_SIZE;
-
-    for (i = 0; i < num_audio_blocks; i++) {
-        /* Only consider LPCM blocks */
-        if ((sad[0] >> 3) != EDID_FORMAT_LPCM) {
-            sad += 3;
-            continue;
+    if(ret == 0 && info != NULL) {
+        for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
+            ALOGV("%s:format %d channel %d", __func__,
+                   info->audio_blocks_array[i].format_id,
+                   info->audio_blocks_array[i].channels);
+            if (info->audio_blocks_array[i].format_id == LPCM) {
+                channel_count = info->audio_blocks_array[i].channels;
+                if (channel_count > max_channels) {
+                   max_channels = channel_count;
+                }
+            }
         }
-
-        channel_count = (sad[0] & 0x7) + 1;
-        if (channel_count > max_channels)
-            max_channels = channel_count;
-
-        /* Advance to next block */
-        sad += 3;
     }
 
     return max_channels;
@@ -2212,6 +2607,159 @@
     return ret;
 }
 
+static int update_external_device_status(struct platform_data *my_data,
+                                 char* event_name, bool status)
+{
+    int ret = 0;
+    struct audio_usecase *usecase;
+    struct listnode *node;
+
+    ALOGD("Recieved  external event switch %s", event_name);
+
+    if (!strcmp(event_name, EVENT_EXTERNAL_SPK_1))
+        my_data->external_spk_1 = status;
+    else if (!strcmp(event_name, EVENT_EXTERNAL_SPK_2))
+        my_data->external_spk_2 = status;
+    else if (!strcmp(event_name, EVENT_EXTERNAL_MIC))
+        my_data->external_mic = status;
+    else {
+        ALOGE("The audio event type is not found");
+        return -EINVAL;
+    }
+
+    list_for_each(node, &my_data->adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        select_devices(my_data->adev, usecase->id);
+    }
+
+    return ret;
+}
+
+static int parse_audiocal_cfg(struct str_parms *parms, acdb_audio_cal_cfg_t *cal)
+{
+    int err;
+    unsigned int val;
+    char value[64];
+    int ret = 0;
+
+    if(parms == NULL || cal == NULL)
+        return ret;
+
+    err = str_parms_get_str(parms, "cal_persist", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_persist");
+        cal->persist = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x1;
+    }
+    err = str_parms_get_str(parms, "cal_apptype", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_apptype");
+        cal->app_type = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x2;
+    }
+    err = str_parms_get_str(parms, "cal_caltype", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_caltype");
+        cal->cal_type = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x4;
+    }
+    err = str_parms_get_str(parms, "cal_samplerate", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_samplerate");
+        cal->sampling_rate = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x8;
+    }
+    err = str_parms_get_str(parms, "cal_devid", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_devid");
+        cal->dev_id = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x10;
+    }
+    err = str_parms_get_str(parms, "cal_snddevid", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_snddevid");
+        cal->snd_dev_id = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x20;
+    }
+    err = str_parms_get_str(parms, "cal_topoid", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_topoid");
+        cal->topo_id = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x40;
+    }
+    err = str_parms_get_str(parms, "cal_moduleid", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_moduleid");
+        cal->module_id = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x80;
+    }
+    err = str_parms_get_str(parms, "cal_paramid", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_paramid");
+        cal->param_id = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x100;
+    }
+    return ret;
+}
+
+static void set_audiocal(void *platform, struct str_parms *parms, char *value, int len) {
+    struct platform_data *my_data = (struct platform_data *)platform;
+    acdb_audio_cal_cfg_t cal={0};
+    uint8_t *dptr = NULL;
+    int32_t dlen;
+    int err, ret;
+    if(value == NULL || platform == NULL || parms == NULL) {
+        ALOGE("[%s] received null pointer, failed",__func__);
+        goto done_key_audcal;
+    }
+
+    /* parse audio calibration keys */
+    ret = parse_audiocal_cfg(parms, &cal);
+
+    /* handle audio calibration data now */
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_AUD_CALDATA, value, len);
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_AUD_CALDATA);
+        dlen = strlen(value);
+        if(dlen <= 0) {
+            ALOGE("[%s] null data received",__func__);
+            goto done_key_audcal;
+        }
+        dptr = (uint8_t*) calloc(dlen, sizeof(uint8_t));
+        if(dptr == NULL) {
+            ALOGE("[%s] memory allocation failed for %d",__func__, dlen);
+            goto done_key_audcal;
+        }
+        dlen = b64decode(value, strlen(value), dptr);
+        if(dlen<=0) {
+            ALOGE("[%s] data decoding failed %d", __func__, dlen);
+            goto done_key_audcal;
+        }
+
+        if(cal.dev_id) {
+          if(audio_is_input_device(cal.dev_id)) {
+              cal.snd_dev_id = platform_get_input_snd_device(platform, cal.dev_id);
+          } else {
+              cal.snd_dev_id = platform_get_output_snd_device(platform, cal.dev_id);
+          }
+        }
+        cal.acdb_dev_id = platform_get_snd_device_acdb_id(cal.snd_dev_id);
+        ALOGD("Setting audio calibration for snd_device(%d) acdb_id(%d)",
+                cal.snd_dev_id, cal.acdb_dev_id);
+        if(cal.acdb_dev_id == -EINVAL) {
+            ALOGE("[%s] Invalid acdb_device id %d for snd device id %d",
+                       __func__, cal.acdb_dev_id, cal.snd_dev_id);
+            goto done_key_audcal;
+        }
+        if(my_data->acdb_set_audio_cal) {
+            ret = my_data->acdb_set_audio_cal((void *)&cal, (void*)dptr, dlen);
+        }
+    }
+done_key_audcal:
+    if(dptr != NULL)
+        free(dptr);
+}
+
 int platform_set_parameters(void *platform, struct str_parms *parms)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
@@ -2389,13 +2937,106 @@
     return ret;
 }
 
+static void get_audiocal(void *platform, void *keys, void *pReply) {
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct str_parms *query = (struct str_parms *)keys;
+    struct str_parms *reply=(struct str_parms *)pReply;
+    acdb_audio_cal_cfg_t cal={0};
+    uint8_t *dptr = NULL;
+    char value[512] = {0};
+    char *rparms=NULL;
+    int ret=0, err;
+    uint32_t param_len;
+
+    if(query==NULL || platform==NULL || reply==NULL) {
+        ALOGE("[%s] received null pointer",__func__);
+        ret=-EINVAL;
+        goto done;
+    }
+    /* parse audiocal configuration keys */
+    ret = parse_audiocal_cfg(query, &cal);
+    if(ret == 0) {
+        /* No calibration keys found */
+        goto done;
+    }
+    err = str_parms_get_str(query, AUDIO_PARAMETER_KEY_AUD_CALDATA, value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(query, AUDIO_PARAMETER_KEY_AUD_CALDATA);
+    } else {
+        goto done;
+    }
+
+    if(cal.dev_id & AUDIO_DEVICE_BIT_IN) {
+        cal.snd_dev_id = platform_get_input_snd_device(platform, cal.dev_id);
+    } else if(cal.dev_id) {
+        cal.snd_dev_id = platform_get_output_snd_device(platform, cal.dev_id);
+    }
+    cal.acdb_dev_id =  platform_get_snd_device_acdb_id(cal.snd_dev_id);
+    if (cal.acdb_dev_id < 0) {
+        ALOGE("%s: Failed. Could not find acdb id for snd device(%d)",
+              __func__, cal.snd_dev_id);
+        ret = -EINVAL;
+        goto done_key_audcal;
+    }
+    ALOGD("[%s] Getting audio calibration for snd_device(%d) acdb_id(%d)",
+           __func__, cal.snd_dev_id, cal.acdb_dev_id);
+
+    param_len = MAX_SET_CAL_BYTE_SIZE;
+    dptr = (uint8_t*)calloc(param_len, sizeof(uint8_t));
+    if(dptr == NULL) {
+        ALOGE("[%s] Memory allocation failed for length %d",__func__,param_len);
+        ret = -ENOMEM;
+        goto done_key_audcal;
+    }
+    if (my_data->acdb_get_audio_cal != NULL) {
+        ret = my_data->acdb_get_audio_cal((void*)&cal, (void*)dptr, &param_len);
+        if (ret == 0) {
+            int dlen;
+            if(param_len == 0 || param_len == MAX_SET_CAL_BYTE_SIZE) {
+                ret = -EINVAL;
+                goto done_key_audcal;
+            }
+            /* Allocate memory for encoding */
+            rparms = (char*)calloc((param_len*2), sizeof(char));
+            if(rparms == NULL) {
+                ALOGE("[%s] Memory allocation failed for size %d",
+                            __func__, param_len*2);
+                ret = -ENOMEM;
+                goto done_key_audcal;
+            }
+            if(cal.persist==0 && cal.module_id && cal.param_id) {
+                err = b64encode(dptr+12, param_len-12, rparms);
+            } else {
+                err = b64encode(dptr, param_len, rparms);
+            }
+            if(err < 0) {
+                ALOGE("[%s] failed to convert data to string", __func__);
+                ret = -EINVAL;
+                goto done_key_audcal;
+            }
+            str_parms_add_int(reply, AUDIO_PARAMETER_KEY_AUD_CALRESULT, ret);
+            str_parms_add_str(reply, AUDIO_PARAMETER_KEY_AUD_CALDATA, rparms);
+        }
+    }
+done_key_audcal:
+    if(ret != 0) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_AUD_CALRESULT, ret);
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_AUD_CALDATA, "");
+    }
+done:
+    if(dptr != NULL)
+        free(dptr);
+    if(rparms != NULL)
+        free(rparms);
+}
+
 void platform_get_parameters(void *platform,
                             struct str_parms *query,
                             struct str_parms *reply)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
     char *str = NULL;
-    char value[256] = {0};
+    char value[512] = {0};
     int ret;
     char *kv_pairs = NULL;
 
@@ -2425,6 +3066,7 @@
         str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VOLUME_BOOST, value);
     }
 
+    /* Handle audio calibration keys */
     kv_pairs = str_parms_to_str(reply);
     ALOGV("%s: exit: returns - %s", __func__, kv_pairs);
     free(kv_pairs);
@@ -2586,6 +3228,14 @@
         fragment_size =  atoi(value) * 1024;
     }
 
+    // For FLAC use max size since it is loss less, and has sampling rates
+    // upto 192kHZ
+    if (info != NULL && !info->has_video &&
+        info->format == AUDIO_FORMAT_FLAC) {
+       fragment_size = MAX_COMPRESS_OFFLOAD_FRAGMENT_SIZE;
+       ALOGV("FLAC fragment size %d", fragment_size);
+    }
+
     if (info != NULL && info->has_video && info->is_streaming) {
         fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE_FOR_AV_STREAMING;
         ALOGV("%s: offload fragment size reduced for AV streaming to %d",
@@ -2604,71 +3254,757 @@
 
 uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info)
 {
-    uint32_t fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
+    uint32_t fragment_size = 0;
     uint32_t bits_per_sample = 16;
+    uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS;
 
     if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) {
         bits_per_sample = 32;
     }
 
-    if (!info->has_video) {
-        fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
-
-    } else if (info->has_video && info->is_streaming) {
-        fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING
-                                     * info->sample_rate
-                                     * bits_per_sample
-                                     * popcount(info->channel_mask))/1000;
-
-    } else if (info->has_video) {
-        fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV
-                                     * info->sample_rate
-                                     * bits_per_sample
-                                     * popcount(info->channel_mask))/1000;
+    if (info->use_small_bufs) {
+        pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS;
+    } else {
+        if (!info->has_video) {
+            pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_MAX;
+        } else if (info->has_video && info->is_streaming) {
+            pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING;
+        } else if (info->has_video) {
+            pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_AV;
+        }
     }
 
-    fragment_size = ALIGN( fragment_size, 1024);
-
+    //duration is set to 20 ms worth of stereo data at 48Khz
+    //with 16 bit per sample, modify this when the channel
+    //configuration is different
+    fragment_size = (pcm_offload_time
+                     * info->sample_rate
+                     * (bits_per_sample >> 3)
+                     * popcount(info->channel_mask))/1000;
     if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
         fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
     else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
         fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
+    // To have same PCM samples for all channels, the buffer size requires to
+    // be multiple of (number of channels * bytes per sample)
+    // For writes to succeed, the buffer must be written at address which is multiple of 32
+    // Alignment of 96 satsfies both of the above requirements
+    fragment_size = ALIGN(fragment_size, 96);
 
-    ALOGV("%s: fragment_size %d", __func__, fragment_size);
+    ALOGI("PCM offload Fragment size to %d bytes", fragment_size);
     return fragment_size;
 }
 
+int platform_set_codec_backend_cfg(struct audio_device* adev,
+                         unsigned int bit_width, unsigned int sample_rate)
+{
+    ALOGV("%s bit width: %d, sample rate: %d", __func__, bit_width, sample_rate);
+
+    int ret = 0;
+    const char *snd_card_name = mixer_get_name(adev->mixer);
+    if (bit_width != adev->cur_codec_backend_bit_width) {
+        const char * mixer_ctl_name;
+        if (!strncmp(snd_card_name, "msm8952-tomtom-snd-card",
+                 sizeof("msm8952-tomtom-snd-card"))) {
+            mixer_ctl_name = "SLIM_0_RX Format";
+        }
+        else
+            mixer_ctl_name = "MI2S_RX Format";
+        struct  mixer_ctl *ctl;
+        ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+        if (!ctl) {
+            ALOGE("%s: Could not get ctl for mixer command - %s",
+                    __func__, mixer_ctl_name);
+            return -EINVAL;
+        }
+
+        if (bit_width == 24) {
+                mixer_ctl_set_enum_by_string(ctl, "S24_LE");
+        } else {
+            mixer_ctl_set_enum_by_string(ctl, "S16_LE");
+            sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+        }
+        adev->cur_codec_backend_bit_width = bit_width;
+        ALOGE("Backend bit width is set to %d ", bit_width);
+    }
+
+    /*
+     * Backend sample rate configuration follows:
+     * 16 bit playback - 48khz for streams at any valid sample rate
+     * 24 bit playback - 48khz for stream sample rate less than 48khz
+     * 24 bit playback - 96khz for sample rate range of 48khz to 96khz
+     * 24 bit playback - 192khz for sample rate range of 96khz to 192 khz
+     * Upper limit is inclusive in the sample rate range.
+     */
+    // TODO: This has to be more dynamic based on policy file
+    if (sample_rate != adev->cur_codec_backend_samplerate) {
+            char *rate_str = NULL;
+            const char * mixer_ctl_name = "SLIM_0_RX SampleRate";
+            struct  mixer_ctl *ctl;
+
+            switch (sample_rate) {
+            case 8000:
+            case 11025:
+            case 16000:
+            case 22050:
+            case 32000:
+            case 44100:
+            case 48000:
+                rate_str = "KHZ_48";
+                break;
+            case 64000:
+            case 88200:
+            case 96000:
+                rate_str = "KHZ_96";
+                break;
+            case 176400:
+            case 192000:
+                rate_str = "KHZ_192";
+                break;
+            default:
+                rate_str = "KHZ_48";
+                break;
+            }
+
+            ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+            if(!ctl) {
+                ALOGE("%s: Could not get ctl for mixer command - %s",
+                    __func__, mixer_ctl_name);
+                return -EINVAL;
+            }
+
+            ALOGV("Set sample rate as rate_str = %s", rate_str);
+            mixer_ctl_set_enum_by_string(ctl, rate_str);
+            adev->cur_codec_backend_samplerate = sample_rate;
+    }
+
+    return ret;
+}
+
+bool platform_check_codec_backend_cfg(struct audio_device* adev,
+                                   struct audio_usecase* usecase __unused,
+                                   unsigned int* new_bit_width,
+                                   unsigned int* new_sample_rate)
+{
+    bool backend_change = false;
+    struct listnode *node;
+    struct stream_out *out = NULL;
+    unsigned int bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+    unsigned int sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+
+    // For voice calls use default configuration
+    // force routing is not required here, caller will do it anyway
+    if (voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
+        ALOGW("%s:Use default bw and sr for voice/voip calls ",__func__);
+        bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+        sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    } else {
+        /*
+         * The backend should be configured at highest bit width and/or
+         * sample rate amongst all playback usecases.
+         * If the selected sample rate and/or bit width differ with
+         * current backend sample rate and/or bit width, then, we set the
+         * backend re-configuration flag.
+         *
+         * Exception: 16 bit playbacks is allowed through 16 bit/48 khz backend only
+         */
+        list_for_each(node, &adev->usecase_list) {
+            struct audio_usecase *curr_usecase;
+            curr_usecase = node_to_item(node, struct audio_usecase, list);
+            if (curr_usecase->type == PCM_PLAYBACK) {
+                struct stream_out *out =
+                           (struct stream_out*) curr_usecase->stream.out;
+                if (out != NULL ) {
+                    ALOGV("Offload playback running bw %d sr %d",
+                              out->bit_width, out->sample_rate);
+                        if (bit_width < out->bit_width)
+                            bit_width = out->bit_width;
+                        if (sample_rate < out->sample_rate)
+                            sample_rate = out->sample_rate;
+                }
+            }
+        }
+    }
+
+    // 16 bit playback on speakers is allowed through 48 khz backend only
+    if (16 == bit_width) {
+        sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    }
+    // 24 bit playback on speakers is allowed through 48 khz backend only
+    // bit width re-configured based on platform info
+    if ((24 == bit_width) &&
+        (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER)) {
+        bit_width = (uint32_t)platform_get_snd_device_bit_width(SND_DEVICE_OUT_SPEAKER);
+        sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    }
+    // Force routing if the expected bitwdith or samplerate
+    // is not same as current backend comfiguration
+    if ((bit_width != adev->cur_codec_backend_bit_width) ||
+        (sample_rate != adev->cur_codec_backend_samplerate)) {
+        *new_bit_width = bit_width;
+        *new_sample_rate = sample_rate;
+        backend_change = true;
+        ALOGI("%s Codec backend needs to be updated. new bit width: %d new sample rate: %d",
+               __func__, *new_bit_width, *new_sample_rate);
+    }
+
+    return backend_change;
+}
+
+bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase)
+{
+    ALOGV("platform_check_and_set_codec_backend_cfg usecase = %d",usecase->id );
+
+    unsigned int new_bit_width, old_bit_width;
+    unsigned int new_sample_rate, old_sample_rate;
+
+    new_bit_width = old_bit_width = adev->cur_codec_backend_bit_width;
+    new_sample_rate = old_sample_rate = adev->cur_codec_backend_samplerate;
+
+    ALOGW("Codec backend bitwidth %d, samplerate %d", old_bit_width, old_sample_rate);
+    if (platform_check_codec_backend_cfg(adev, usecase,
+                                      &new_bit_width, &new_sample_rate)) {
+        platform_set_codec_backend_cfg(adev, new_bit_width, new_sample_rate);
+        return true;
+    }
+
+    return false;
+}
+
+int platform_set_snd_device_backend(snd_device_t device, const char *backend)
+{
+    int ret = 0;
+
+    if ((device < SND_DEVICE_MIN) || (device >= SND_DEVICE_MAX)) {
+        ALOGE("%s: Invalid snd_device = %d",
+            __func__, device);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    if (backend_table[device]) {
+        free(backend_table[device]);
+    }
+    backend_table[device] = strdup(backend);
+done:
+    return ret;
+}
+
+int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id)
+{
+    int ret = 0;
+    if ((usecase <= USECASE_INVALID) || (usecase >= AUDIO_USECASE_MAX)) {
+        ALOGE("%s: invalid usecase case idx %d", __func__, usecase);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    if ((type != 0) && (type != 1)) {
+        ALOGE("%s: invalid usecase type", __func__);
+        ret = -EINVAL;
+    }
+    pcm_device_table[usecase][type] = pcm_id;
+done:
+    return ret;
+}
+
 void platform_get_device_to_be_id_map(int **device_to_be_id, int *length)
 {
      *device_to_be_id = msm_device_to_be_id;
      *length = msm_be_id_array_len;
 }
+int platform_set_stream_channel_map(void *platform, audio_channel_mask_t channel_mask, int snd_id)
+{
+    int ret = 0;
+    int channels = audio_channel_count_from_out_mask(channel_mask);
 
-bool platform_check_24_bit_support() {
+    char channel_map[8];
+    memset(channel_map, 0, sizeof(channel_map));
+    /* Following are all most common standard WAV channel layouts
+       overridden by channel mask if its allowed and different */
+    switch (channels) {
+        case 1:
+            /* AUDIO_CHANNEL_OUT_MONO */
+            channel_map[0] = PCM_CHANNEL_FC;
+            break;
+        case 2:
+            /* AUDIO_CHANNEL_OUT_STEREO */
+            channel_map[0] = PCM_CHANNEL_FL;
+            channel_map[1] = PCM_CHANNEL_FR;
+            break;
+        case 3:
+            /* AUDIO_CHANNEL_OUT_2POINT1 */
+            channel_map[0] = PCM_CHANNEL_FL;
+            channel_map[1] = PCM_CHANNEL_FR;
+            channel_map[2] = PCM_CHANNEL_FC;
+            break;
+        case 4:
+            /* AUDIO_CHANNEL_OUT_QUAD_SIDE */
+            channel_map[0] = PCM_CHANNEL_FL;
+            channel_map[1] = PCM_CHANNEL_FR;
+            channel_map[2] = PCM_CHANNEL_LS;
+            channel_map[3] = PCM_CHANNEL_RS;
+            if (channel_mask == AUDIO_CHANNEL_OUT_QUAD_BACK)
+            {
+                channel_map[2] = PCM_CHANNEL_LB;
+                channel_map[3] = PCM_CHANNEL_RB;
+            }
+            if (channel_mask == AUDIO_CHANNEL_OUT_SURROUND)
+            {
+                channel_map[2] = PCM_CHANNEL_FC;
+                channel_map[3] = PCM_CHANNEL_CS;
+            }
+            break;
+        case 5:
+            /* AUDIO_CHANNEL_OUT_PENTA */
+            channel_map[0] = PCM_CHANNEL_FL;
+            channel_map[1] = PCM_CHANNEL_FR;
+            channel_map[2] = PCM_CHANNEL_FC;
+            channel_map[3] = PCM_CHANNEL_LB;
+            channel_map[4] = PCM_CHANNEL_RB;
+            break;
+        case 6:
+            /* AUDIO_CHANNEL_OUT_5POINT1 */
+            channel_map[0] = PCM_CHANNEL_FL;
+            channel_map[1] = PCM_CHANNEL_FR;
+            channel_map[2] = PCM_CHANNEL_FC;
+            channel_map[3] = PCM_CHANNEL_LFE;
+            channel_map[4] = PCM_CHANNEL_LB;
+            channel_map[5] = PCM_CHANNEL_RB;
+            if (channel_mask == AUDIO_CHANNEL_OUT_5POINT1_SIDE)
+            {
+                channel_map[4] = PCM_CHANNEL_LS;
+                channel_map[5] = PCM_CHANNEL_RS;
+            }
+            break;
+        case 7:
+            /* AUDIO_CHANNEL_OUT_6POINT1 */
+            channel_map[0] = PCM_CHANNEL_FL;
+            channel_map[1] = PCM_CHANNEL_FR;
+            channel_map[2] = PCM_CHANNEL_FC;
+            channel_map[3] = PCM_CHANNEL_LFE;
+            channel_map[4] = PCM_CHANNEL_LB;
+            channel_map[5] = PCM_CHANNEL_RB;
+            channel_map[6] = PCM_CHANNEL_CS;
+            break;
+        case 8:
+            /* AUDIO_CHANNEL_OUT_7POINT1 */
+            channel_map[0] = PCM_CHANNEL_FL;
+            channel_map[1] = PCM_CHANNEL_FR;
+            channel_map[2] = PCM_CHANNEL_FC;
+            channel_map[3] = PCM_CHANNEL_LFE;
+            channel_map[4] = PCM_CHANNEL_LB;
+            channel_map[5] = PCM_CHANNEL_RB;
+            channel_map[6] = PCM_CHANNEL_LS;
+            channel_map[7] = PCM_CHANNEL_RS;
+            break;
+        default:
+            ALOGE("unsupported channels %d for setting channel map", channels);
+            return -1;
+    }
+    ret = platform_set_channel_map(platform, channels, channel_map, snd_id);
+    return ret;
+}
+
+int platform_get_edid_info(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE];
+    char *sad = block;
+    int num_audio_blocks;
+    int channel_count = 2;
+    int i, ret, count;
+
+    struct mixer_ctl *ctl;
+    char edid_data[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE + 1] = {0};
+    edid_audio_info *info;
+
+    if (my_data->edid_valid) {
+        /* use cached edid */
+        return 0;
+    }
+
+    if (my_data->edid_info == NULL) {
+        my_data->edid_info =
+            (struct edid_audio_info *)calloc(1, sizeof(struct edid_audio_info));
+    }
+
+    info = my_data->edid_info;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_DATA_BLOCK_MIXER_CTL);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, AUDIO_DATA_BLOCK_MIXER_CTL);
+        goto fail;
+    }
+
+    mixer_ctl_update(ctl);
+
+    count = mixer_ctl_get_num_values(ctl);
+
+    /* Read SAD blocks, clamping the maximum size for safety */
+    if (count > (int)sizeof(block))
+        count = (int)sizeof(block);
+
+    ret = mixer_ctl_get_array(ctl, block, count);
+    if (ret != 0) {
+        ALOGE("%s: mixer_ctl_get_array() failed to get EDID info", __func__);
+        goto fail;
+    }
+    edid_data[0] = count;
+    memcpy(&edid_data[1], block, count);
+
+#ifdef AUDIO_FEATURE_ENABLED_HDMI_EDID
+    if (!edid_get_sink_caps(info, edid_data)) {
+        ALOGE("%s: Failed to get HDMI sink capabilities", __func__);
+        goto fail;
+    }
+    my_data->edid_valid = true;
+    return 0;
+#endif
+fail:
+    if (my_data->edid_info) {
+        free(my_data->edid_info);
+        my_data->edid_info = NULL;
+        my_data->edid_valid = false;
+    }
+    ALOGE("%s: return -EINVAL", __func__);
+    return -EINVAL;
+}
+
+
+int platform_set_channel_allocation(void *platform, int channel_alloc)
+{
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "HDMI RX CA";
+    int ret;
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        ret = EINVAL;
+    }
+    ALOGD(":%s channel allocation = 0x%x", __func__, channel_alloc);
+    ret = mixer_ctl_set_value(ctl, 0, channel_alloc);
+
+    if (ret < 0) {
+        ALOGE("%s: Could not set ctl, error:%d ", __func__, ret);
+    }
+
+    return ret;
+}
+
+int platform_set_channel_map(void *platform, int ch_count, char *ch_map, int snd_id)
+{
+    struct mixer_ctl *ctl;
+    char mixer_ctl_name[44]; // max length of name is 44 as defined
+    int ret;
+    unsigned int i;
+    int set_values[8] = {0};
+    char device_num[13]; // device number up to 2 digit
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    ALOGV("%s channel_count:%d",__func__, ch_count);
+    if (NULL == ch_map) {
+        ALOGE("%s: Invalid channel mapping used", __func__);
+        return -EINVAL;
+    }
+    strlcpy(mixer_ctl_name, "Playback Channel Map", sizeof(mixer_ctl_name));
+    if (snd_id >= 0) {
+        snprintf(device_num, sizeof(device_num), "%d", snd_id);
+        strncat(mixer_ctl_name, device_num, 13);
+    }
+
+    ALOGD("%s mixer_ctl_name:%s", __func__, mixer_ctl_name);
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    for (i = 0; i< ARRAY_SIZE(set_values); i++) {
+        set_values[i] = ch_map[i];
+    }
+
+    ALOGD("%s: set mapping(%d %d %d %d %d %d %d %d) for channel:%d", __func__,
+        set_values[0], set_values[1], set_values[2], set_values[3], set_values[4],
+        set_values[5], set_values[6], set_values[7], ch_count);
+
+    ret = mixer_ctl_set_array(ctl, set_values, ch_count);
+    if (ret < 0) {
+        ALOGE("%s: Could not set ctl, error:%d ch_count:%d",
+              __func__, ret, ch_count);
+    }
+    return ret;
+}
+
+unsigned char platform_map_to_edid_format(int audio_format)
+{
+    unsigned char format;
+    switch (audio_format & AUDIO_FORMAT_MAIN_MASK) {
+    case AUDIO_FORMAT_AC3:
+        ALOGV("%s: AC3", __func__);
+        format = AC3;
+        break;
+    case AUDIO_FORMAT_AAC:
+        ALOGV("%s:AAC", __func__);
+        format = AAC;
+        break;
+    case AUDIO_FORMAT_E_AC3:
+        ALOGV("%s:E_AC3", __func__);
+        format = DOLBY_DIGITAL_PLUS;
+        break;
+    case AUDIO_FORMAT_PCM_16_BIT:
+    case AUDIO_FORMAT_PCM_16_BIT_OFFLOAD:
+    case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD:
+    default:
+        ALOGV("%s:PCM", __func__);
+        format =  LPCM;
+        break;
+    }
+    return format;
+}
+
+uint32_t platform_get_compress_passthrough_buffer_size(
+                                          audio_offload_info_t* info)
+{
+    uint32_t fragment_size = MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE;
+    if (!info->has_video)
+        fragment_size = MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE;
+
+    return fragment_size;
+}
+
+void platform_reset_edid_info(void *platform) {
+
+    ALOGV("%s:", __func__);
+    struct platform_data *my_data = (struct platform_data *)platform;
+    if (my_data->edid_info) {
+        ALOGV("%s :free edid", __func__);
+        free(my_data->edid_info);
+        my_data->edid_info = NULL;
+    }
+}
+
+bool platform_is_edid_supported_format(void *platform, int format)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    edid_audio_info *info = NULL;
+    int num_audio_blocks;
+    int i, ret, count;
+    unsigned char format_id = platform_map_to_edid_format(format);
+
+    ret = platform_get_edid_info(platform);
+    info = (edid_audio_info *)my_data->edid_info;
+    if (ret == 0 && info != NULL) {
+        for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
+             /*
+              * To check
+              *  is there any special for CONFIG_HDMI_PASSTHROUGH_CONVERT
+              *  & DOLBY_DIGITAL_PLUS
+              */
+            if (info->audio_blocks_array[i].format_id == format_id) {
+                ALOGV("%s:platform_is_edid_supported_format true %x",
+                      __func__, format);
+                return true;
+            }
+        }
+    }
+    ALOGV("%s:platform_is_edid_supported_format false %x",
+           __func__, format);
     return false;
 }
 
-bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev __unused,
-                                              struct audio_usecase *usecase __unused)
-{
-    return false;
+int platform_set_edid_channels_configuration(void *platform, int channels) {
+
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    edid_audio_info *info = NULL;
+    int num_audio_blocks;
+    int channel_count = 2;
+    int i, ret, count;
+    char default_channelMap[MAX_CHANNELS_SUPPORTED] = {0};
+
+    ret = platform_get_edid_info(platform);
+    info = (edid_audio_info *)my_data->edid_info;
+    if(ret == 0 && info != NULL) {
+        if (channels > 2) {
+
+            ALOGV("%s:able to get HDMI sink capabilities multi channel playback",
+                   __func__);
+            for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
+                if (info->audio_blocks_array[i].format_id == LPCM &&
+                      info->audio_blocks_array[i].channels > channel_count &&
+                      info->audio_blocks_array[i].channels <= MAX_HDMI_CHANNEL_CNT) {
+                    channel_count = info->audio_blocks_array[i].channels;
+                }
+            }
+            ALOGV("%s:channel_count:%d", __func__, channel_count);
+            /*
+             * Channel map is set for supported hdmi max channel count even
+             * though the input channel count set on adm is less than or equal to
+             * max supported channel count
+             */
+            platform_set_channel_map(platform, channel_count, info->channel_map, -1);
+            platform_set_channel_allocation(platform, info->channel_allocation);
+        } else {
+            default_channelMap[0] = PCM_CHANNEL_FL;
+            default_channelMap[1] = PCM_CHANNEL_FR;
+            platform_set_channel_map(platform,2,default_channelMap,-1);
+            platform_set_channel_allocation(platform,0);
+        }
+    }
+
+    return 0;
 }
 
-int platform_get_usecase_index(const char * usecase __unused)
+void platform_cache_edid(void * platform)
 {
-    return -ENOSYS;
+    platform_get_edid_info(platform);
 }
 
-int platform_set_usecase_pcm_id(audio_usecase_t usecase __unused, int32_t type __unused,
-                                int32_t pcm_id __unused)
+void platform_invalidate_edid(void * platform)
 {
-    return -ENOSYS;
+    struct platform_data *my_data = (struct platform_data *)platform;
+    my_data->edid_valid = false;
+    if (my_data->edid_info) {
+        memset(my_data->edid_info, 0, sizeof(struct edid_audio_info));
+    }
 }
 
-int platform_set_snd_device_backend(snd_device_t snd_device __unused,
-                                    const char * backend __unused)
+int platform_set_mixer_control(struct stream_out *out, const char * mixer_ctl_name,
+                      const char *mixer_val)
 {
-    return -ENOSYS;
+    struct audio_device *adev = out->dev;
+    struct mixer_ctl *ctl = NULL;
+    ALOGD("setting mixer ctl %s with value %s", mixer_ctl_name, mixer_val);
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+
+    return mixer_ctl_set_enum_by_string(ctl, mixer_val);
+}
+
+int platform_set_hdmi_config(struct stream_out *out)
+{
+    struct listnode *node;
+    struct audio_usecase *usecase;
+    struct audio_device *adev = out->dev;
+    const char *hdmi_format_ctrl = "HDMI RX Format";
+    const char *hdmi_rate_ctrl = "HDMI_RX SampleRate";
+    int sample_rate = out->sample_rate;
+    /*TODO: Add rules and check if this needs to be done.*/
+    if((is_offload_usecase(out->usecase)) &&
+        (out->compr_config.codec->compr_passthr == PASSTHROUGH ||
+        out->compr_config.codec->compr_passthr == PASSTHROUGH_CONVERT)) {
+        /* TODO: can we add mixer control for channels here avoid setting */
+        if ((out->format == AUDIO_FORMAT_E_AC3 ||
+            out->format == AUDIO_FORMAT_E_AC3_JOC) &&
+            (out->compr_config.codec->compr_passthr == PASSTHROUGH))
+            sample_rate = out->sample_rate * 4;
+        ALOGD("%s:HDMI compress format and samplerate %d, sample_rate %d",
+               __func__, out->sample_rate, sample_rate);
+        platform_set_mixer_control(out, hdmi_format_ctrl, "Compr");
+        switch (sample_rate) {
+            case 32000:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_32");
+                break;
+            case 44100:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_44_1");
+                break;
+            case 96000:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_96");
+                break;
+            case 176400:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_176_4");
+                break;
+            case 192000:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_192");
+                break;
+            case 128000:
+                if (out->format != AUDIO_FORMAT_E_AC3) {
+                    platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_128");
+                    break;
+                } else
+                   ALOGW("Unsupported sample rate for E_AC3 32K");
+            default:
+            case 48000:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_48");
+                break;
+        }
+    } else {
+        ALOGD("%s: HDMI pcm and samplerate %d", __func__,
+               out->sample_rate);
+        platform_set_mixer_control(out, hdmi_format_ctrl, "LPCM");
+        platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_48");
+    }
+
+    /*
+     * Deroute all the playback streams routed to HDMI so that
+     * the back end is deactivated. Note that backend will not
+     * be deactivated if any one stream is connected to it.
+     */
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        ALOGV("%s:disable: usecase type %d, devices 0x%x", __func__,
+               usecase->type, usecase->devices);
+        if (usecase->type == PCM_PLAYBACK &&
+                usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            disable_audio_route(adev, usecase);
+        }
+    }
+
+    /*
+     * Enable all the streams disabled above. Now the HDMI backend
+     * will be activated with new channel configuration
+     */
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        ALOGV("%s:enable: usecase type %d, devices 0x%x", __func__,
+               usecase->type, usecase->devices);
+        if (usecase->type == PCM_PLAYBACK &&
+                usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            enable_audio_route(adev, usecase);
+        }
+    }
+
+    return 0;
+}
+
+int platform_set_device_params(struct stream_out *out, int param, int value)
+{
+    struct audio_device *adev = out->dev;
+    struct mixer_ctl *ctl;
+    char *mixer_ctl_name = "Device PP Params";
+    int ret = 0;
+    uint32_t set_values[] = {0,0};
+
+    set_values[0] = param;
+    set_values[1] = value;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        ret = -EINVAL;
+        goto end;
+    }
+
+    ALOGV("%s: Setting device pp params param: %d, value %d mixer ctrl:%s",
+          __func__,param, value, mixer_ctl_name);
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+end:
+    return ret;
 }
 
 int platform_get_subsys_image_name(char *buf)
@@ -2676,3 +4012,56 @@
     strlcpy(buf, PLATFORM_IMAGE_NAME, sizeof(PLATFORM_IMAGE_NAME));
     return 0;
 }
+
+/*
+ * This is a lookup table to map android audio input device to audio h/w interface (backend).
+ * The table can be extended for other input devices by adding appropriate entries.
+ * Also the audio interface for a particular input device can be overriden by adding
+ * corresponding entry in audio_platform_info.xml file.
+ */
+struct audio_device_to_audio_interface audio_device_to_interface_table[] = {
+    {AUDIO_DEVICE_IN_BUILTIN_MIC, ENUM_TO_STRING(AUDIO_DEVICE_IN_BUILTIN_MIC), "TERT_MI2S"},
+    {AUDIO_DEVICE_IN_BACK_MIC, ENUM_TO_STRING(AUDIO_DEVICE_IN_BACK_MIC), "TERT_MI2S"},
+};
+
+int audio_device_to_interface_table_len  =
+    sizeof(audio_device_to_interface_table) / sizeof(audio_device_to_interface_table[0]);
+
+
+int platform_set_audio_device_interface(const char * device_name,
+                                        const char *intf_name)
+{
+    int ret = 0;
+    int i;
+
+    if (device_name == NULL || intf_name == NULL) {
+        ALOGE("%s: Invalid input", __func__);
+
+        ret = -EINVAL;
+        goto done;
+    }
+
+    ALOGD("%s: Enter, device name:%s, intf name:%s", __func__, device_name, intf_name);
+
+    size_t device_name_len = strlen(device_name);
+    for (i = 0; i < audio_device_to_interface_table_len; i++) {
+        char* name = audio_device_to_interface_table[i].device_name;
+        size_t name_len = strlen(name);
+        if ((name_len == device_name_len) &&
+            (strncmp(device_name, name, name_len) == 0)) {
+            ALOGD("%s: Matched device name:%s, overwrite intf name with %s",
+                  __func__, device_name, intf_name);
+
+            strlcpy(audio_device_to_interface_table[i].interface_name, intf_name,
+                    sizeof(audio_device_to_interface_table[i].interface_name));
+            goto done;
+        }
+    }
+    ALOGE("%s: Could not find matching device name %s",
+            __func__, device_name);
+
+    ret = -EINVAL;
+
+done:
+    return ret;
+}
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index 35b577e..6d5b4a0 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -55,11 +55,17 @@
     SND_DEVICE_OUT_BEGIN = SND_DEVICE_MIN,
     SND_DEVICE_OUT_HANDSET = SND_DEVICE_OUT_BEGIN,
     SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_EXTERNAL_1,
+    SND_DEVICE_OUT_SPEAKER_EXTERNAL_2,
     SND_DEVICE_OUT_SPEAKER_REVERSE,
+    SND_DEVICE_OUT_SPEAKER_WSA,
     SND_DEVICE_OUT_HEADPHONES,
     SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2,
     SND_DEVICE_OUT_VOICE_HANDSET,
     SND_DEVICE_OUT_VOICE_SPEAKER,
+    SND_DEVICE_OUT_VOICE_SPEAKER_WSA,
     SND_DEVICE_OUT_VOICE_HEADPHONES,
     SND_DEVICE_OUT_HDMI,
     SND_DEVICE_OUT_SPEAKER_AND_HDMI,
@@ -68,6 +74,7 @@
     SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
     SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
     SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET,
+    SND_DEVICE_OUT_VOICE_TX,
     SND_DEVICE_OUT_AFE_PROXY,
     SND_DEVICE_OUT_USB_HEADSET,
     SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET,
@@ -79,6 +86,7 @@
     SND_DEVICE_OUT_SPEAKER_AND_ANC_HEADSET,
     SND_DEVICE_OUT_ANC_HANDSET,
     SND_DEVICE_OUT_SPEAKER_PROTECTED,
+    SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED,
 #ifdef RECORD_PLAY_CONCURRENCY
     SND_DEVICE_OUT_VOIP_HANDSET,
     SND_DEVICE_OUT_VOIP_SPEAKER,
@@ -93,6 +101,7 @@
     /* Capture devices */
     SND_DEVICE_IN_BEGIN = SND_DEVICE_OUT_END,
     SND_DEVICE_IN_HANDSET_MIC  = SND_DEVICE_IN_BEGIN,
+    SND_DEVICE_IN_HANDSET_MIC_EXTERNAL,
     SND_DEVICE_IN_HANDSET_MIC_AEC,
     SND_DEVICE_IN_HANDSET_MIC_NS,
     SND_DEVICE_IN_HANDSET_MIC_AEC_NS,
@@ -128,6 +137,7 @@
     SND_DEVICE_IN_VOICE_REC_MIC_NS,
     SND_DEVICE_IN_VOICE_REC_DMIC_STEREO,
     SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+    SND_DEVICE_IN_VOICE_RX,
     SND_DEVICE_IN_USB_HEADSET_MIC,
     SND_DEVICE_IN_CAPTURE_FM,
     SND_DEVICE_IN_AANC_HANDSET_MIC,
@@ -141,6 +151,10 @@
     SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE,
     SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE,
     SND_DEVICE_IN_VOICE_FLUENCE_DMIC_AANC,
+    SND_DEVICE_IN_HANDSET_QMIC,
+    SND_DEVICE_IN_SPEAKER_QMIC_AEC,
+    SND_DEVICE_IN_SPEAKER_QMIC_NS,
+    SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS,
     SND_DEVICE_IN_END,
 
     SND_DEVICE_MAX = SND_DEVICE_IN_END,
@@ -150,7 +164,7 @@
 #define DEFAULT_OUTPUT_SAMPLING_RATE 48000
 
 #define ALL_SESSION_VSID                0xFFFFFFFF
-#define DEFAULT_MUTE_RAMP_DURATION      500
+#define DEFAULT_MUTE_RAMP_DURATION_MS   20
 #define DEFAULT_VOLUME_RAMP_DURATION_MS 20
 #define MIXER_PATH_MAX_LENGTH 100
 
@@ -168,7 +182,7 @@
  * the buffer size of an input/output stream
  */
 #define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 960
-#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 4
+#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 5
 #define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240
 #define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2
 
@@ -184,6 +198,10 @@
 #define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
 #define AUDIO_CAPTURE_PERIOD_COUNT 2
 
+#define LOW_LATENCY_CAPTURE_SAMPLE_RATE 48000
+#define LOW_LATENCY_CAPTURE_PERIOD_SIZE 240
+#define LOW_LATENCY_CAPTURE_USE_CASE 1
+
 #define DEVICE_NAME_MAX_SIZE 128
 #define HW_INFO_ARRAY_MAX_SIZE 32
 
@@ -199,8 +217,20 @@
 #define INCALL_MUSIC_UPLINK_PCM_DEVICE 1
 #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16
 #define SPKR_PROT_CALIB_RX_PCM_DEVICE 5
-#define SPKR_PROT_CALIB_TX_PCM_DEVICE 22
+#define SPKR_PROT_CALIB_TX_PCM_DEVICE 26
 #define PLAYBACK_OFFLOAD_DEVICE 9
+
+#ifdef MULTIPLE_OFFLOAD_ENABLED
+#define PLAYBACK_OFFLOAD_DEVICE2 17
+#define PLAYBACK_OFFLOAD_DEVICE3 18
+#define PLAYBACK_OFFLOAD_DEVICE4 37
+#define PLAYBACK_OFFLOAD_DEVICE5 38
+#define PLAYBACK_OFFLOAD_DEVICE6 39
+#define PLAYBACK_OFFLOAD_DEVICE7 40
+#define PLAYBACK_OFFLOAD_DEVICE8 41
+#define PLAYBACK_OFFLOAD_DEVICE9 42
+#endif
+
 #define COMPRESS_VOIP_CALL_PCM_DEVICE 3
 
 /* Define macro for Internal FM volume mixer */
@@ -213,9 +243,13 @@
 #define VOICE_CALL_PCM_DEVICE 2
 #define VOICE2_CALL_PCM_DEVICE 13
 #define VOLTE_CALL_PCM_DEVICE 15
-#define QCHAT_CALL_PCM_DEVICE 14
+#define QCHAT_CALL_PCM_DEVICE 26
+#define QCHAT_CALL_PCM_DEVICE_OF_EXT_CODEC 28
 #define VOWLAN_CALL_PCM_DEVICE 16
 
+#define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
+#define AFE_PROXY_RECORD_PCM_DEVICE 8
+
 #define LIB_CSD_CLIENT "libcsd-client.so"
 /* CSD-CLIENT related functions */
 typedef int (*init_t)();
@@ -223,8 +257,8 @@
 typedef int (*disable_device_t)();
 typedef int (*enable_device_config_t)(int, int);
 typedef int (*enable_device_t)(int, int, uint32_t);
-typedef int (*volume_t)(uint32_t, int);
-typedef int (*mic_mute_t)(uint32_t, int);
+typedef int (*volume_t)(uint32_t, int, uint16_t);
+typedef int (*mic_mute_t)(uint32_t, int, uint16_t);
 typedef int (*slow_talk_t)(uint32_t, uint8_t);
 typedef int (*start_voice_t)(uint32_t);
 typedef int (*stop_voice_t)(uint32_t);
@@ -255,4 +289,24 @@
 
 int platform_get_subsys_image_name (char *buf);
 
+/* HDMI Passthrough defines */
+enum {
+    LEGACY_PCM = 0,
+    PASSTHROUGH,
+    PASSTHROUGH_CONVERT
+};
+/*
+ * ID for setting mute and lateny on the device side
+ * through Device PP Params mixer control.
+ */
+#define DEVICE_PARAM_MUTE_ID    0
+#define DEVICE_PARAM_LATENCY_ID 1
+
+#define ENUM_TO_STRING(X) #X
+
+struct audio_device_to_audio_interface {
+    audio_devices_t device;
+    char device_name[100];
+    char interface_name[100];
+};
 #endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 593b66a..bbfa042 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -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
@@ -28,6 +28,7 @@
 #include <audio_hw.h>
 #include <platform_api.h>
 #include "platform.h"
+#include "audio_extn.h"
 
 #define LIB_ACDB_LOADER "libacdbloader.so"
 #define LIB_CSD_CLIENT "libcsd-client.so"
@@ -421,6 +422,19 @@
     return -ENOSYS;
 }
 
+int platform_set_snd_device_bit_width(snd_device_t snd_device __unused,
+                                      unsigned int bit_width __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
+int platform_get_snd_device_bit_width(snd_device_t snd_device __unused)
+{
+    ALOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
 int platform_switch_voice_call_enable_device_config(void *platform __unused,
                                                     snd_device_t out_snd_device __unused,
                                                     snd_device_t in_snd_device __unused)
@@ -501,7 +515,8 @@
     struct platform_data *my_data = (struct platform_data *)platform;
     int ret = 0;
 
-    if (my_data->csd_client != NULL) {
+    if (my_data->csd_client != NULL &&
+        voice_is_in_call(my_data->adev)) {
         /* This must be called before disabling the mixer controls on APQ side */
         if (my_data->csd_disable_device == NULL) {
             ALOGE("%s: dlsym error for csd_disable_device", __func__);
@@ -652,7 +667,7 @@
         goto exit;
     }
 
-    if (mode == AUDIO_MODE_IN_CALL) {
+    if (voice_is_in_call(adev)) {
         if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
             devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
             if (adev->voice.tty_mode == TTY_MODE_FULL)
@@ -744,11 +759,7 @@
 
     ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
           __func__, out_device, in_device);
-    if (mode == AUDIO_MODE_IN_CALL) {
-        if (out_device == AUDIO_DEVICE_NONE) {
-            ALOGE("%s: No output device set for voice call", __func__);
-            goto exit;
-        }
+    if ((out_device != AUDIO_DEVICE_NONE) && voice_is_in_call(adev)) {
         if (adev->voice.tty_mode != TTY_MODE_OFF) {
             if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
                 out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
@@ -1086,3 +1097,65 @@
 {
     return 0;
 }
+
+int platform_get_edid_info(void *platform __unused)
+{
+   return -ENOSYS;
+}
+
+int platform_set_channel_map(void *platform __unused, int ch_count __unused,
+                             char *ch_map __unused, int snd_id __unused)
+{
+    return -ENOSYS;
+}
+
+int platform_set_stream_channel_map(void *platform __unused,
+                                    audio_channel_mask_t channel_mask __unused,
+                                    int snd_id __unused)
+{
+    return -ENOSYS;
+}
+
+int platform_set_edid_channels_configuration(void *platform __unused,
+                                             int channels __unused)
+{
+    return 0;
+}
+
+unsigned char platform_map_to_edid_format(int format __unused)
+{
+    return 0;
+}
+
+bool platform_is_edid_supported_format(void *platform __unused,
+                                       int format __unused)
+{
+    return  false;
+}
+
+void platform_cache_edid(void * platform __unused)
+{
+
+}
+
+void platform_invalidate_edid(void * platform __unused)
+{
+
+}
+
+int platform_set_hdmi_config(struct stream_out *out __unused)
+{
+    return 0;
+}
+
+int platform_set_device_params(struct stream_out *out __unused,
+                                  int param __unused, int value __unused)
+{
+    return 0;
+}
+
+int platform_set_audio_device_interface(const char * device_name __unused,
+                                        const char *intf_name __unused)
+{
+    return -ENOSYS;
+}
diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h
index 950ea84..4b4d14e 100644
--- a/hal/msm8960/platform.h
+++ b/hal/msm8960/platform.h
@@ -145,4 +145,6 @@
 #define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
 #define AFE_PROXY_RECORD_PCM_DEVICE 8
 
+#define DEVICE_NAME_MAX_SIZE 128
+
 #endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c
index f7d19f4..c96d11e 100644
--- a/hal/msm8974/hw_info.c
+++ b/hal/msm8974/hw_info.c
@@ -87,6 +87,9 @@
     SND_DEVICE_IN_HANDSET_MIC,
 };
 
+static const snd_device_t tomtom_8996_CDP_variant_devices[] = {
+};
+
 static const snd_device_t tomtom_liquid_variant_devices[] = {
     SND_DEVICE_OUT_SPEAKER,
     SND_DEVICE_OUT_SPEAKER_EXTERNAL_1,
@@ -119,6 +122,18 @@
     SND_DEVICE_IN_QUAD_MIC,
 };
 
+static const snd_device_t tomtom_DB_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_EXTERNAL_1,
+    SND_DEVICE_OUT_SPEAKER_EXTERNAL_2,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2,
+    SND_DEVICE_OUT_VOICE_SPEAKER,
+    SND_DEVICE_IN_VOICE_SPEAKER_MIC,
+    SND_DEVICE_IN_HANDSET_MIC,
+    SND_DEVICE_IN_HANDSET_MIC_EXTERNAL
+};
+
 static const snd_device_t taiko_apq8084_sbc_variant_devices[] = {
     SND_DEVICE_IN_HANDSET_MIC,
     SND_DEVICE_IN_SPEAKER_MIC,
@@ -226,11 +241,48 @@
         hw_info->snd_devices = (snd_device_t *)tomtom_liquid_variant_devices;
         hw_info->num_snd_devices = ARRAY_SIZE(tomtom_liquid_variant_devices);
         strlcpy(hw_info->dev_extn, "-liquid", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8994-tomtom-db-snd-card")) {
+        strlcpy(hw_info->type, " dragon-board", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8994", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)tomtom_DB_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tomtom_DB_variant_devices);
+        strlcpy(hw_info->dev_extn, "-db", sizeof(hw_info->dev_extn));
     } else {
         ALOGW("%s: Not an 8994 device", __func__);
     }
 }
 
+static void  update_hardware_info_8996(struct hardware_info *hw_info, const char *snd_card_name)
+{
+    if (!strcmp(snd_card_name, "msm8996-tomtom-mtp-snd-card")) {
+        strlcpy(hw_info->type, " mtp", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8996", 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 if (!strcmp(snd_card_name, "msm8996-tomtom-cdp-snd-card")) {
+        strlcpy(hw_info->type, " cdp", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8996", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)tomtom_8996_CDP_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tomtom_8996_CDP_variant_devices);
+        strlcpy(hw_info->dev_extn, "-cdp", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8996-tomtom-stp-snd-card")) {
+        strlcpy(hw_info->type, " stp", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8996", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)tomtom_stp_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tomtom_stp_variant_devices);
+        strlcpy(hw_info->dev_extn, "-stp", sizeof(hw_info->dev_extn));
+    } else if (!strcmp(snd_card_name, "msm8996-tomtom-liquid-snd-card")) {
+        strlcpy(hw_info->type, " liquid", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "msm8996", sizeof(hw_info->name));
+        hw_info->snd_devices = (snd_device_t *)tomtom_liquid_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tomtom_liquid_variant_devices);
+        strlcpy(hw_info->dev_extn, "-liquid", sizeof(hw_info->dev_extn));
+    } else {
+        ALOGW("%s: Not a 8996 device", __func__);
+    }
+}
+
 static void  update_hardware_info_8974(struct hardware_info *hw_info, const char *snd_card_name)
 {
     if (!strcmp(snd_card_name, "msm8974-taiko-mtp-snd-card")) {
@@ -356,6 +408,9 @@
     } else if(strstr(snd_card_name, "msm8994")) {
         ALOGV("8994 - variant soundcard");
         update_hardware_info_8994(hw_info, snd_card_name);
+    } else if(strstr(snd_card_name, "msm8996")) {
+        ALOGV("8996 - variant soundcard");
+        update_hardware_info_8996(hw_info, snd_card_name);
     } else {
         ALOGE("%s: Unsupported target %s:",__func__, snd_card_name);
         free(hw_info);
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index a08a4a4..24e23e6 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -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
@@ -20,6 +20,12 @@
 #define LOG_TAG "msm8974_platform"
 /*#define LOG_NDEBUG 0*/
 #define LOG_NDDEBUG 0
+/*#define VERY_VERY_VERBOSE_LOGGING*/
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
 
 #include <stdlib.h>
 #include <dlfcn.h>
@@ -33,13 +39,18 @@
 #include "platform.h"
 #include "audio_extn.h"
 #include "voice_extn.h"
+#include "edid.h"
 #include "sound/compress_params.h"
 #include "sound/msmcal-hwdep.h"
 
 #define SOUND_TRIGGER_DEVICE_HANDSET_MONO_LOW_POWER_ACDB_ID (100)
-#define MIXER_XML_PATH "/system/etc/mixer_paths.xml"
+#define MIXER_XML_DEFAULT_PATH "/system/etc/mixer_paths.xml"
 #define MIXER_XML_PATH_AUXPCM "/system/etc/mixer_paths_auxpcm.xml"
 #define MIXER_XML_PATH_I2S "/system/etc/mixer_paths_i2s.xml"
+#define MIXER_XML_BASE_STRING "/system/etc/mixer_paths"
+#define MIXER_FILE_DELIMITER "_"
+#define MIXER_FILE_EXT ".xml"
+
 
 #define PLATFORM_INFO_XML_PATH      "/system/etc/audio_platform_info.xml"
 #define PLATFORM_INFO_XML_PATH_I2S  "/system/etc/audio_platform_info_i2s.xml"
@@ -56,6 +67,8 @@
 /* Used in calculating fragment size for pcm offload */
 #define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV 1000 /* 1 sec */
 #define PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING 80 /* 80 millisecs */
+#define PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS 20 /* 20 millisecs */
+#define PCM_OFFLOAD_BUFFER_DURATION_MAX 1200  /* 1200 millisecs */
 
 /* MAX PCM fragment size cannot be increased  further due
  * to flinger's cblk size of 1mb,and it has to be a multiple of
@@ -64,7 +77,14 @@
 #define MAX_PCM_OFFLOAD_FRAGMENT_SIZE (240 * 1024)
 #define MIN_PCM_OFFLOAD_FRAGMENT_SIZE (4 * 1024)
 
-#define ALIGN( num, to ) (((num) + (to-1)) & (~(to-1)))
+/*
+ * Offload buffer size for compress passthrough
+ */
+#define MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE (2 * 1024)
+#define MAX_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE (8 * 1024)
+
+#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y))
+#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
 /*
  * This file will have a maximum of 38 bytes:
  *
@@ -91,10 +111,16 @@
 #define SAMPLE_RATE_8KHZ  8000
 #define SAMPLE_RATE_16KHZ 16000
 
+#define MAX_SET_CAL_BYTE_SIZE 65536
+
 #define AUDIO_PARAMETER_KEY_FLUENCE_TYPE  "fluence"
 #define AUDIO_PARAMETER_KEY_SLOWTALK      "st_enable"
 #define AUDIO_PARAMETER_KEY_HD_VOICE      "hd_voice"
 #define AUDIO_PARAMETER_KEY_VOLUME_BOOST  "volume_boost"
+#define AUDIO_PARAMETER_KEY_AUD_CALDATA   "cal_data"
+#define AUDIO_PARAMETER_KEY_AUD_CALRESULT "cal_result"
+
+
 /* Query external audio device connection status */
 #define AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE "ext_audio_device"
 
@@ -120,6 +146,19 @@
     int length;
 };
 
+typedef struct acdb_audio_cal_cfg {
+    uint32_t             persist;
+    uint32_t             snd_dev_id;
+    audio_devices_t      dev_id;
+    int32_t              acdb_dev_id;
+    uint32_t             app_type;
+    uint32_t             topo_id;
+    uint32_t             sampling_rate;
+    uint32_t             cal_type;
+    uint32_t             module_id;
+    uint32_t             param_id;
+} acdb_audio_cal_cfg_t;
+
 /* Audio calibration related functions */
 typedef void (*acdb_deallocate_t)();
 typedef int  (*acdb_init_t)(const char *, char *, int);
@@ -129,6 +168,8 @@
 typedef int  (*acdb_get_default_app_type_t)(void);
 typedef int (*acdb_loader_get_calibration_t)(char *attr, int size, void *data);
 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*);
 
 struct platform_data {
     struct audio_device *adev;
@@ -152,12 +193,16 @@
     acdb_init_t                acdb_init;
     acdb_deallocate_t          acdb_deallocate;
     acdb_send_audio_cal_t      acdb_send_audio_cal;
+    acdb_set_audio_cal_t       acdb_set_audio_cal;
+    acdb_get_audio_cal_t       acdb_get_audio_cal;
     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;
 
     void *hw_info;
     struct csd_data *csd;
+    void *edid_info;
+    bool edid_valid;
 };
 
 static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
@@ -201,6 +246,10 @@
     [USECASE_VOLTE_CALL] = {VOLTE_CALL_PCM_DEVICE, VOLTE_CALL_PCM_DEVICE},
     [USECASE_QCHAT_CALL] = {QCHAT_CALL_PCM_DEVICE, QCHAT_CALL_PCM_DEVICE},
     [USECASE_VOWLAN_CALL] = {VOWLAN_CALL_PCM_DEVICE, VOWLAN_CALL_PCM_DEVICE},
+    [USECASE_VOICEMMODE1_CALL] = {VOICEMMODE1_CALL_PCM_DEVICE,
+                                  VOICEMMODE1_CALL_PCM_DEVICE},
+    [USECASE_VOICEMMODE2_CALL] = {VOICEMMODE2_CALL_PCM_DEVICE,
+                                  VOICEMMODE2_CALL_PCM_DEVICE},
     [USECASE_COMPRESS_VOIP_CALL] = {COMPRESS_VOIP_CALL_PCM_DEVICE, COMPRESS_VOIP_CALL_PCM_DEVICE},
     [USECASE_INCALL_REC_UPLINK] = {AUDIO_RECORD_PCM_DEVICE,
                                    AUDIO_RECORD_PCM_DEVICE},
@@ -317,20 +366,27 @@
     [SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE] = "speaker-dmic-broadside",
     [SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE] = "speaker-dmic-broadside",
     [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE] = "speaker-dmic-broadside",
+    [SND_DEVICE_IN_HANDSET_QMIC] = "quad-mic",
+    [SND_DEVICE_IN_SPEAKER_QMIC_AEC] = "quad-mic",
+    [SND_DEVICE_IN_SPEAKER_QMIC_NS] = "quad-mic",
+    [SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS] = "quad-mic",
 };
 
+// Platform specific backend bit width table
+static int backend_bit_width_table[SND_DEVICE_MAX] = {0};
+
 /* ACDB IDs (audio DSP path configuration IDs) for each sound device */
 static int acdb_device_table[SND_DEVICE_MAX] = {
     [SND_DEVICE_NONE] = -1,
     [SND_DEVICE_OUT_HANDSET] = 7,
     [SND_DEVICE_OUT_SPEAKER] = 14,
-    [SND_DEVICE_OUT_SPEAKER_EXTERNAL_1] = 14,
-    [SND_DEVICE_OUT_SPEAKER_EXTERNAL_2] = 14,
+    [SND_DEVICE_OUT_SPEAKER_EXTERNAL_1] = 130,
+    [SND_DEVICE_OUT_SPEAKER_EXTERNAL_2] = 130,
     [SND_DEVICE_OUT_SPEAKER_REVERSE] = 14,
     [SND_DEVICE_OUT_HEADPHONES] = 10,
     [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES] = 10,
-    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1] = 10,
-    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2] = 10,
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_1] = 130,
+    [SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES_EXTERNAL_2] = 130,
     [SND_DEVICE_OUT_VOICE_HANDSET] = 7,
     [SND_DEVICE_OUT_VOICE_SPEAKER] = 14,
     [SND_DEVICE_OUT_VOICE_HEADPHONES] = 10,
@@ -406,6 +462,10 @@
     [SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE] = 119,
     [SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE] = 121,
     [SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE] = 120,
+    [SND_DEVICE_IN_HANDSET_QMIC] = 125,
+    [SND_DEVICE_IN_SPEAKER_QMIC_AEC] = 126,
+    [SND_DEVICE_IN_SPEAKER_QMIC_NS] = 127,
+    [SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS] = 129,
 };
 
 struct name_to_index {
@@ -497,6 +557,10 @@
     {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE)},
     {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE)},
     {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_QMIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_AEC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_NS)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS)},
 };
 
 static char * backend_table[SND_DEVICE_MAX] = {0};
@@ -506,6 +570,16 @@
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_LOW_LATENCY)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MULTI_CH)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD)},
+#ifdef MULTIPLE_OFFLOAD_ENABLED
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD2)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD3)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD4)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD5)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD6)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD7)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD8)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD9)},
+#endif
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)},
     {TO_NAME_INDEX(USECASE_VOICE_CALL)},
@@ -571,6 +645,32 @@
        {AUDIO_DEVICE_NONE                               ,      -1},
        {AUDIO_DEVICE_OUT_DEFAULT                        ,      -1},
 };
+#elif PLATFORM_MSM8996
+static int msm_device_to_be_id [][NO_COLS] = {
+       {AUDIO_DEVICE_OUT_EARPIECE                       ,       2},
+       {AUDIO_DEVICE_OUT_SPEAKER                        ,       2},
+       {AUDIO_DEVICE_OUT_WIRED_HEADSET                  ,       2},
+       {AUDIO_DEVICE_OUT_WIRED_HEADPHONE                ,       2},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO                  ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET          ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT           ,       11},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP                 ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES      ,       -1},
+       {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER         ,       -1},
+       {AUDIO_DEVICE_OUT_AUX_DIGITAL                    ,       4},
+       {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET              ,       9},
+       {AUDIO_DEVICE_OUT_USB_ACCESSORY                  ,       -1},
+       {AUDIO_DEVICE_OUT_USB_DEVICE                     ,       -1},
+       {AUDIO_DEVICE_OUT_REMOTE_SUBMIX                  ,       9},
+       {AUDIO_DEVICE_OUT_PROXY                          ,       9},
+/* Add the correct be ids */
+       {AUDIO_DEVICE_OUT_FM                             ,       7},
+       {AUDIO_DEVICE_OUT_FM_TX                          ,       8},
+       {AUDIO_DEVICE_OUT_ALL                            ,      -1},
+       {AUDIO_DEVICE_NONE                               ,      -1},
+       {AUDIO_DEVICE_OUT_DEFAULT                        ,      -1},
+};
 #else
 static int msm_device_to_be_id [][NO_COLS] = {
     {AUDIO_DEVICE_NONE, -1},
@@ -588,19 +688,18 @@
     struct platform_data *my_data = (struct platform_data *)platform;
     struct audio_device *adev = my_data->adev;
 
-    if (enable) {
-         my_data->ec_ref_enabled = enable;
-         audio_route_apply_and_update_path(adev->audio_route, "echo-reference");
-    } else {
-         if (my_data->ec_ref_enabled) {
-             audio_route_reset_and_update_path(adev->audio_route, "echo-reference");
-             my_data->ec_ref_enabled = enable;
-         } else {
-             ALOGV("EC Reference is already disabled: %d", my_data->ec_ref_enabled);
-         }
+    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");
     }
 
-    ALOGV("Setting EC Reference: %d", enable);
+    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");
+    }
+
 }
 
 static struct csd_data *open_csd_client(bool i2s_ext_modem)
@@ -778,6 +877,9 @@
     for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
         backend_table[dev] = NULL;
     }
+    for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
+        backend_bit_width_table[dev] = 16;
+    }
 
     // TBD - do these go to the platform-info.xml file.
     // will help in avoiding strdups here
@@ -920,9 +1022,12 @@
     char baseband[PROPERTY_VALUE_MAX];
     char value[PROPERTY_VALUE_MAX];
     struct platform_data *my_data = NULL;
-    int retry_num = 0, snd_card_num = 0, key = 0;
+    int retry_num = 0, snd_card_num = 0, key = 0, ret = 0;
     const char *snd_card_name;
     char *cvd_version = NULL;
+    char *snd_internal_name = NULL;
+    char *tmp = NULL;
+    char mixer_xml_file[MIXER_PATH_MAX_LENGTH]= {0};
 
     my_data = calloc(1, sizeof(struct platform_data));
 
@@ -960,10 +1065,51 @@
 
                 adev->audio_route = audio_route_init(snd_card_num,
                                                      MIXER_XML_PATH_I2S);
-            } else if (audio_extn_read_xml(adev, snd_card_num, MIXER_XML_PATH,
-                                    MIXER_XML_PATH_AUXPCM) == -ENOSYS) {
-                adev->audio_route = audio_route_init(snd_card_num,
-                                                 MIXER_XML_PATH);
+            } else {
+                /* Get the codec internal name from the sound card name
+                 * and form the mixer paths file name dynamically. This
+                 * is generic way of picking any codec name based mixer
+                 * files in future with no code change. This code
+                 * assumes mixer files are formed with format as
+                 * mixer_paths_internalcodecname.xml
+
+                 * If this dynamically read mixer files fails to open then it
+                 * falls back to default mixer file i.e mixer_paths.xml. This is
+                 * done to preserve backward compatibility but not mandatory as
+                 * long as the mixer files are named as per above assumption.
+                */
+
+                snd_internal_name = strtok_r(snd_card_name, "-", &tmp);
+                if (snd_internal_name != NULL)
+                    snd_internal_name = strtok_r(NULL, "-", &tmp);
+
+                if (snd_internal_name != NULL) {
+                    strlcpy(mixer_xml_file, MIXER_XML_BASE_STRING,
+                        MIXER_PATH_MAX_LENGTH);
+                    strlcat(mixer_xml_file, MIXER_FILE_DELIMITER,
+                        MIXER_PATH_MAX_LENGTH);
+                    strlcat(mixer_xml_file, snd_internal_name,
+                        MIXER_PATH_MAX_LENGTH);
+                    strlcat(mixer_xml_file, MIXER_FILE_EXT,
+                        MIXER_PATH_MAX_LENGTH);
+                } else {
+                    strlcpy(mixer_xml_file, MIXER_XML_DEFAULT_PATH,
+                        MIXER_PATH_MAX_LENGTH);
+                }
+
+                if (F_OK == access(mixer_xml_file, 0)) {
+                    ALOGD("%s: Loading mixer file: %s", __func__, mixer_xml_file);
+                    if (audio_extn_read_xml(adev, snd_card_num, mixer_xml_file,
+                                    MIXER_XML_PATH_AUXPCM) == -ENOSYS)
+                        adev->audio_route = audio_route_init(snd_card_num,
+                                                       mixer_xml_file);
+                } else {
+                    ALOGD("%s: Loading default mixer file", __func__);
+                    if(audio_extn_read_xml(adev, snd_card_num, MIXER_XML_DEFAULT_PATH,
+                                    MIXER_XML_PATH_AUXPCM) == -ENOSYS)
+                        adev->audio_route = audio_route_init(snd_card_num,
+                                                       MIXER_XML_DEFAULT_PATH);
+                }
             }
             if (!adev->audio_route) {
                 ALOGE("%s: Failed to init audio route controls, aborting.",
@@ -997,6 +1143,7 @@
     my_data->fluence_mode = FLUENCE_ENDFIRE;
     my_data->slowtalk = false;
     my_data->hd_voice = false;
+    my_data->edid_info = NULL;
 
     property_get("ro.qc.sdk.audio.fluencetype", my_data->fluence_cap, "");
     if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro"))) {
@@ -1054,6 +1201,18 @@
             ALOGE("%s: Could not find the symbol acdb_send_audio_cal from %s",
                   __func__, LIB_ACDB_LOADER);
 
+        my_data->acdb_set_audio_cal = (acdb_set_audio_cal_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_set_audio_cal_v2");
+        if (!my_data->acdb_set_audio_cal)
+            ALOGE("%s: Could not find the symbol acdb_set_audio_cal_v2 from %s",
+                  __func__, LIB_ACDB_LOADER);
+
+        my_data->acdb_get_audio_cal = (acdb_get_audio_cal_t)dlsym(my_data->acdb_handle,
+                                                    "acdb_loader_get_audio_cal_v2");
+        if (!my_data->acdb_get_audio_cal)
+            ALOGE("%s: Could not find the symbol acdb_get_audio_cal_v2 from %s",
+                  __func__, LIB_ACDB_LOADER);
+
         my_data->acdb_send_voice_cal = (acdb_send_voice_cal_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_send_voice_cal");
         if (!my_data->acdb_send_voice_cal)
@@ -1132,6 +1291,7 @@
     /* init audio device arbitration */
     audio_extn_dev_arbi_init();
 
+    my_data->edid_info = NULL;
     return my_data;
 }
 
@@ -1139,6 +1299,11 @@
 {
     struct platform_data *my_data = (struct platform_data *)platform;
 
+    if (my_data->edid_info) {
+        free(my_data->edid_info);
+        my_data->edid_info = NULL;
+    }
+
     hw_info_deinit(my_data->hw_info);
     close_csd_client(my_data->csd);
 
@@ -1153,6 +1318,11 @@
     /* deinit audio device arbitration */
     audio_extn_dev_arbi_deinit();
 
+    if (my_data->edid_info) {
+        free(my_data->edid_info);
+        my_data->edid_info = NULL;
+    }
+
     free(platform);
     /* deinit usb */
     audio_extn_usb_deinit();
@@ -1345,6 +1515,31 @@
     return acdb_device_table[snd_device];
 }
 
+int platform_set_snd_device_bit_width(snd_device_t snd_device, unsigned int bit_width)
+{
+    int ret = 0;
+
+    if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+        ALOGE("%s: Invalid snd_device = %d",
+            __func__, snd_device);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    backend_bit_width_table[snd_device] = bit_width;
+done:
+    return ret;
+}
+
+int platform_get_snd_device_bit_width(snd_device_t snd_device)
+{
+    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 backend_bit_width_table[snd_device];
+}
+
 int platform_send_audio_calibration(void *platform, struct audio_usecase *usecase,
                                     int app_type, int sample_rate)
 {
@@ -1385,7 +1580,7 @@
     int ret = 0;
 
     if (my_data->csd != NULL &&
-        my_data->adev->mode == AUDIO_MODE_IN_CALL) {
+        voice_is_in_call(my_data->adev)) {
         /* This must be called before disabling mixer controls on APQ side */
         ret = my_data->csd->disable_device();
         if (ret < 0) {
@@ -1693,7 +1888,7 @@
         goto exit;
     }
 
-    if ((mode == AUDIO_MODE_IN_CALL) ||
+    if (voice_is_in_call(adev) ||
         voice_extn_compress_voip_is_active(adev)) {
         if (devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
             devices & AUDIO_DEVICE_OUT_WIRED_HEADSET) {
@@ -1813,7 +2008,7 @@
     ALOGV("%s: enter: out_device(%#x) in_device(%#x)",
           __func__, out_device, in_device);
     if (my_data->external_mic) {
-        if (((out_device != AUDIO_DEVICE_NONE) && (mode == AUDIO_MODE_IN_CALL)) ||
+        if ((out_device != AUDIO_DEVICE_NONE && voice_is_in_call(adev)) ||
             voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev)) {
             if (out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
                out_device & AUDIO_DEVICE_OUT_EARPIECE ||
@@ -1828,7 +2023,7 @@
     if (snd_device != AUDIO_DEVICE_NONE)
         goto exit;
 
-    if ((out_device != AUDIO_DEVICE_NONE) && ((mode == AUDIO_MODE_IN_CALL) ||
+    if ((out_device != AUDIO_DEVICE_NONE) && ((voice_is_in_call(adev)) ||
         voice_extn_compress_voip_is_active(adev) || audio_extn_hfp_is_active(adev))) {
         if ((adev->voice.tty_mode != TTY_MODE_OFF) &&
             !voice_extn_compress_voip_is_active(adev)) {
@@ -1924,12 +2119,15 @@
             if (adev->active_input->enable_aec &&
                     adev->active_input->enable_ns) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
-                    if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
-                       my_data->fluence_in_spkr_mode) {
-                        if (my_data->fluence_mode == FLUENCE_BROADSIDE)
-                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE;
-                        else
-                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
+                    if (my_data->fluence_in_spkr_mode) {
+                        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                            snd_device = SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS;
+                        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                            if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE;
+                            else
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS;
+                        }
                     } else
                         snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC_NS;
                 } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
@@ -1943,12 +2141,15 @@
                 platform_set_echo_reference(adev->platform, true);
             } else if (adev->active_input->enable_aec) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
-                    if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
-                        my_data->fluence_in_spkr_mode) {
-                        if (my_data->fluence_mode == FLUENCE_BROADSIDE)
-                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE;
-                        else
-                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC;
+                    if (my_data->fluence_in_spkr_mode) {
+                        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                            snd_device = SND_DEVICE_IN_SPEAKER_QMIC_AEC;
+                        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                            if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE;
+                            else
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_AEC;
+                        }
                     } else
                         snd_device = SND_DEVICE_IN_SPEAKER_MIC_AEC;
                 } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
@@ -1962,12 +2163,15 @@
                 platform_set_echo_reference(adev->platform, true);
             } else if (adev->active_input->enable_ns) {
                 if (in_device & AUDIO_DEVICE_IN_BACK_MIC) {
-                    if (my_data->fluence_type & FLUENCE_DUAL_MIC &&
-                        my_data->fluence_in_spkr_mode) {
-                        if (my_data->fluence_mode == FLUENCE_BROADSIDE)
-                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE;
-                        else
-                            snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS;
+                    if (my_data->fluence_in_spkr_mode) {
+                        if (my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                            snd_device = SND_DEVICE_IN_SPEAKER_QMIC_NS;
+                        } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                            if (my_data->fluence_mode == FLUENCE_BROADSIDE)
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE;
+                            else
+                                snd_device = SND_DEVICE_IN_SPEAKER_DMIC_NS;
+                        }
                     } else
                         snd_device = SND_DEVICE_IN_SPEAKER_MIC_NS;
                 } else if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
@@ -1985,10 +2189,14 @@
     } else if (source == AUDIO_SOURCE_MIC) {
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC &&
                 channel_count == 1 ) {
-            if(my_data->fluence_type & FLUENCE_DUAL_MIC &&
-                    my_data->fluence_in_audio_rec) {
-                snd_device = SND_DEVICE_IN_HANDSET_DMIC;
-                platform_set_echo_reference(adev->platform, true);
+            if(my_data->fluence_in_audio_rec) {
+                if(my_data->fluence_type & FLUENCE_QUAD_MIC) {
+                    snd_device = SND_DEVICE_IN_HANDSET_QMIC;
+                    platform_set_echo_reference(adev->platform, true);
+                } else if (my_data->fluence_type & FLUENCE_DUAL_MIC) {
+                    snd_device = SND_DEVICE_IN_HANDSET_DMIC;
+                    platform_set_echo_reference(adev->platform, true);
+                }
             }
         }
     } else if (source == AUDIO_SOURCE_FM_RX ||
@@ -2118,56 +2326,28 @@
 
 int platform_edid_get_max_channels(void *platform)
 {
+    int channel_count;
+    int max_channels = 2;
+    int i = 0, ret = 0;
     struct platform_data *my_data = (struct platform_data *)platform;
     struct audio_device *adev = my_data->adev;
-    char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE];
-    char *sad = block;
-    int num_audio_blocks;
-    int channel_count;
-    int max_channels = 0;
-    int i, ret, count;
+    edid_audio_info *info = NULL;
+    ret = platform_get_edid_info(platform);
+    info = (edid_audio_info *)my_data->edid_info;
 
-    struct mixer_ctl *ctl;
-
-    ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_DATA_BLOCK_MIXER_CTL);
-    if (!ctl) {
-        ALOGE("%s: Could not get ctl for mixer cmd - %s",
-              __func__, AUDIO_DATA_BLOCK_MIXER_CTL);
-        return 0;
-    }
-
-    mixer_ctl_update(ctl);
-
-    count = mixer_ctl_get_num_values(ctl);
-
-    /* Read SAD blocks, clamping the maximum size for safety */
-    if (count > (int)sizeof(block))
-        count = (int)sizeof(block);
-
-    ret = mixer_ctl_get_array(ctl, block, count);
-    if (ret != 0) {
-        ALOGE("%s: mixer_ctl_get_array() failed to get EDID info", __func__);
-        return 0;
-    }
-
-    /* Calculate the number of SAD blocks */
-    num_audio_blocks = count / SAD_BLOCK_SIZE;
-
-    for (i = 0; i < num_audio_blocks; i++) {
-        /* Only consider LPCM blocks */
-        if ((sad[0] >> 3) != EDID_FORMAT_LPCM) {
-            sad += 3;
-            continue;
+    if(ret == 0 && info != NULL) {
+        for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
+            ALOGV("%s:format %d channel %d", __func__,
+                   info->audio_blocks_array[i].format_id,
+                   info->audio_blocks_array[i].channels);
+            if (info->audio_blocks_array[i].format_id == LPCM) {
+                channel_count = info->audio_blocks_array[i].channels;
+                if (channel_count > max_channels) {
+                   max_channels = channel_count;
+                }
+            }
         }
-
-        channel_count = (sad[0] & 0x7) + 1;
-        if (channel_count > max_channels)
-            max_channels = channel_count;
-
-        /* Advance to next block */
-        sad += 3;
     }
-
     return max_channels;
 }
 
@@ -2254,18 +2434,156 @@
     return ret;
 }
 
+static int parse_audiocal_cfg(struct str_parms *parms, acdb_audio_cal_cfg_t *cal)
+{
+    int err;
+    unsigned int val;
+    char value[64];
+    int ret = 0;
+
+    if(parms == NULL || cal == NULL)
+        return ret;
+
+    err = str_parms_get_str(parms, "cal_persist", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_persist");
+        cal->persist = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x1;
+    }
+    err = str_parms_get_str(parms, "cal_apptype", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_apptype");
+        cal->app_type = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x2;
+    }
+    err = str_parms_get_str(parms, "cal_caltype", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_caltype");
+        cal->cal_type = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x4;
+    }
+    err = str_parms_get_str(parms, "cal_samplerate", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_samplerate");
+        cal->sampling_rate = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x8;
+    }
+    err = str_parms_get_str(parms, "cal_devid", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_devid");
+        cal->dev_id = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x10;
+    }
+    err = str_parms_get_str(parms, "cal_snddevid", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_snddevid");
+        cal->snd_dev_id = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x20;
+    }
+    err = str_parms_get_str(parms, "cal_topoid", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_topoid");
+        cal->topo_id = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x40;
+    }
+    err = str_parms_get_str(parms, "cal_moduleid", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_moduleid");
+        cal->module_id = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x80;
+    }
+    err = str_parms_get_str(parms, "cal_paramid", value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(parms, "cal_paramid");
+        cal->param_id = (uint32_t) strtoul(value, NULL, 0);
+        ret = ret | 0x100;
+    }
+    return ret;
+}
+
+static void set_audiocal(void *platform, struct str_parms *parms, char *value, int len) {
+    struct platform_data *my_data = (struct platform_data *)platform;
+    acdb_audio_cal_cfg_t cal={0};
+    uint8_t *dptr = NULL;
+    int32_t dlen;
+    int err, ret;
+    if(value == NULL || platform == NULL || parms == NULL) {
+        ALOGE("[%s] received null pointer, failed",__func__);
+        goto done_key_audcal;
+    }
+
+    /* parse audio calibration keys */
+    ret = parse_audiocal_cfg(parms, &cal);
+
+    /* handle audio calibration data now */
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_AUD_CALDATA, value, len);
+    if (err >= 0) {
+        str_parms_del(parms, AUDIO_PARAMETER_KEY_AUD_CALDATA);
+        dlen = strlen(value);
+        if(dlen <= 0) {
+            ALOGE("[%s] null data received",__func__);
+            goto done_key_audcal;
+        }
+        dptr = (uint8_t*) calloc(dlen, sizeof(uint8_t));
+        if(dptr == NULL) {
+            ALOGE("[%s] memory allocation failed for %d",__func__, dlen);
+            goto done_key_audcal;
+        }
+        dlen = b64decode(value, strlen(value), dptr);
+        if(dlen<=0) {
+            ALOGE("[%s] data decoding failed %d", __func__, dlen);
+            goto done_key_audcal;
+        }
+
+        if(cal.dev_id) {
+          if(audio_is_input_device(cal.dev_id)) {
+              cal.snd_dev_id = platform_get_input_snd_device(platform, cal.dev_id);
+          } else {
+              cal.snd_dev_id = platform_get_output_snd_device(platform, cal.dev_id);
+          }
+        }
+        cal.acdb_dev_id = platform_get_snd_device_acdb_id(cal.snd_dev_id);
+        ALOGD("Setting audio calibration for snd_device(%d) acdb_id(%d)",
+                cal.snd_dev_id, cal.acdb_dev_id);
+        if(cal.acdb_dev_id == -EINVAL) {
+            ALOGE("[%s] Invalid acdb_device id %d for snd device id %d",
+                       __func__, cal.acdb_dev_id, cal.snd_dev_id);
+            goto done_key_audcal;
+        }
+        if(my_data->acdb_set_audio_cal) {
+            ret = my_data->acdb_set_audio_cal((void *)&cal, (void*)dptr, dlen);
+        }
+    }
+done_key_audcal:
+    if(dptr != NULL)
+        free(dptr);
+}
+
 int platform_set_parameters(void *platform, struct str_parms *parms)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
     char *str;
-    char value[256] = {0};
-    int val;
+    char *value=NULL;
+    int val, len;
     int ret = 0, err;
     char *kv_pairs = str_parms_to_str(parms);
 
+    if(kv_pairs == NULL) {
+        ret = -ENOMEM;
+        ALOGE("[%s] key-value pair is NULL",__func__);
+        goto done;
+    }
+
     ALOGV_IF(kv_pairs != NULL, "%s: enter: %s", __func__, kv_pairs);
 
-    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SLOWTALK, value, sizeof(value));
+    len = strlen(kv_pairs);
+    value = (char*)calloc(len, sizeof(char));
+    if(value == NULL) {
+        ret = -ENOMEM;
+        ALOGE("[%s] failed to allocate memory",__func__);
+        goto done;
+    }
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_SLOWTALK, value, len);
     if (err >= 0) {
         bool state = false;
         if (!strncmp("true", value, sizeof("true"))) {
@@ -2278,7 +2596,7 @@
             ALOGE("%s: Failed to set slow talk err: %d", __func__, ret);
     }
 
-    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HD_VOICE, value, sizeof(value));
+    err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_HD_VOICE, value, len);
     if (err >= 0) {
         bool state = false;
         if (!strncmp("true", value, sizeof("true"))) {
@@ -2296,7 +2614,7 @@
     }
 
     err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VOLUME_BOOST,
-                            value, sizeof(value));
+                            value, len);
     if (err >= 0) {
         str_parms_del(parms, AUDIO_PARAMETER_KEY_VOLUME_BOOST);
 
@@ -2314,7 +2632,7 @@
     }
 
     err = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_EXT_AUDIO_DEVICE,
-                            value, sizeof(value));
+                            value, len);
     if (err >= 0) {
         char *event_name, *status_str;
         bool status = false;
@@ -2330,8 +2648,15 @@
         update_external_device_status(my_data, event_name, status);
     }
 
+    /* handle audio calibration parameters */
+    set_audiocal(platform, parms, value, len);
+
+done:
     ALOGV("%s: exit with code(%d)", __func__, ret);
-    free(kv_pairs);
+    if(kv_pairs != NULL)
+        free(kv_pairs);
+    if(value != NULL)
+        free(value);
     return ret;
 }
 
@@ -2435,13 +2760,106 @@
     return ret;
 }
 
+static void get_audiocal(void *platform, void *keys, void *pReply) {
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct str_parms *query = (struct str_parms *)keys;
+    struct str_parms *reply=(struct str_parms *)pReply;
+    acdb_audio_cal_cfg_t cal={0};
+    uint8_t *dptr = NULL;
+    char value[512] = {0};
+    char *rparms=NULL;
+    int ret=0, err;
+    uint32_t param_len;
+
+    if(query==NULL || platform==NULL || reply==NULL) {
+        ALOGE("[%s] received null pointer",__func__);
+        ret=-EINVAL;
+        goto done;
+    }
+    /* parse audiocal configuration keys */
+    ret = parse_audiocal_cfg(query, &cal);
+    if(ret == 0) {
+        /* No calibration keys found */
+        goto done;
+    }
+    err = str_parms_get_str(query, AUDIO_PARAMETER_KEY_AUD_CALDATA, value, sizeof(value));
+    if (err >= 0) {
+        str_parms_del(query, AUDIO_PARAMETER_KEY_AUD_CALDATA);
+    } else {
+        goto done;
+    }
+
+    if(cal.dev_id & AUDIO_DEVICE_BIT_IN) {
+        cal.snd_dev_id = platform_get_input_snd_device(platform, cal.dev_id);
+    } else if(cal.dev_id) {
+        cal.snd_dev_id = platform_get_output_snd_device(platform, cal.dev_id);
+    }
+    cal.acdb_dev_id =  platform_get_snd_device_acdb_id(cal.snd_dev_id);
+    if (cal.acdb_dev_id < 0) {
+        ALOGE("%s: Failed. Could not find acdb id for snd device(%d)",
+              __func__, cal.snd_dev_id);
+        ret = -EINVAL;
+        goto done_key_audcal;
+    }
+    ALOGD("[%s] Getting audio calibration for snd_device(%d) acdb_id(%d)",
+           __func__, cal.snd_dev_id, cal.acdb_dev_id);
+
+    param_len = MAX_SET_CAL_BYTE_SIZE;
+    dptr = (uint8_t*)calloc(param_len, sizeof(uint8_t));
+    if(dptr == NULL) {
+        ALOGE("[%s] Memory allocation failed for length %d",__func__,param_len);
+        ret = -ENOMEM;
+        goto done_key_audcal;
+    }
+    if (my_data->acdb_get_audio_cal != NULL) {
+        ret = my_data->acdb_get_audio_cal((void*)&cal, (void*)dptr, &param_len);
+        if (ret == 0) {
+            int dlen;
+            if(param_len == 0 || param_len == MAX_SET_CAL_BYTE_SIZE) {
+                ret = -EINVAL;
+                goto done_key_audcal;
+            }
+            /* Allocate memory for encoding */
+            rparms = (char*)calloc((param_len*2), sizeof(char));
+            if(rparms == NULL) {
+                ALOGE("[%s] Memory allocation failed for size %d",
+                            __func__, param_len*2);
+                ret = -ENOMEM;
+                goto done_key_audcal;
+            }
+            if(cal.persist==0 && cal.module_id && cal.param_id) {
+                err = b64encode(dptr+12, param_len-12, rparms);
+            } else {
+                err = b64encode(dptr, param_len, rparms);
+            }
+            if(err < 0) {
+                ALOGE("[%s] failed to convert data to string", __func__);
+                ret = -EINVAL;
+                goto done_key_audcal;
+            }
+            str_parms_add_int(reply, AUDIO_PARAMETER_KEY_AUD_CALRESULT, ret);
+            str_parms_add_str(reply, AUDIO_PARAMETER_KEY_AUD_CALDATA, rparms);
+        }
+    }
+done_key_audcal:
+    if(ret != 0) {
+        str_parms_add_int(reply, AUDIO_PARAMETER_KEY_AUD_CALRESULT, ret);
+        str_parms_add_str(reply, AUDIO_PARAMETER_KEY_AUD_CALDATA, "");
+    }
+done:
+    if(dptr != NULL)
+        free(dptr);
+    if(rparms != NULL)
+        free(rparms);
+}
+
 void platform_get_parameters(void *platform,
                             struct str_parms *query,
                             struct str_parms *reply)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
     char *str = NULL;
-    char value[256] = {0};
+    char value[512] = {0};
     int ret;
     char *kv_pairs = NULL;
 
@@ -2471,6 +2889,10 @@
         str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VOLUME_BOOST, value);
     }
 
+    /* Handle audio calibration keys */
+    get_audiocal(platform, query, reply);
+
+done:
     kv_pairs = str_parms_to_str(reply);
     ALOGV_IF(kv_pairs != NULL, "%s: exit: returns - %s", __func__, kv_pairs);
     free(kv_pairs);
@@ -2572,44 +2994,44 @@
 
 uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info)
 {
-    uint32_t fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
+    uint32_t fragment_size = 0;
     uint32_t bits_per_sample = 16;
+    uint32_t pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS;
 
     if (info->format == AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) {
         bits_per_sample = 32;
     }
 
-    if (!info->has_video) {
-        fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
-
-    } else if (info->has_video && info->is_streaming) {
-        fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING
-                                     * info->sample_rate
-                                     * (bits_per_sample >> 3)
-                                     * popcount(info->channel_mask))/1000;
-
-    } else if (info->has_video) {
-        fragment_size = (PCM_OFFLOAD_BUFFER_DURATION_FOR_AV
-                                     * info->sample_rate
-                                     * (bits_per_sample >> 3)
-                                     * popcount(info->channel_mask))/1000;
+    if (info->use_small_bufs) {
+        pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_SMALL_BUFFERS;
+    } else {
+        if (!info->has_video) {
+            pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_MAX;
+        } else if (info->has_video && info->is_streaming) {
+            pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_AV_STREAMING;
+        } else if (info->has_video) {
+            pcm_offload_time = PCM_OFFLOAD_BUFFER_DURATION_FOR_AV;
+        }
     }
 
-    char value[PROPERTY_VALUE_MAX] = {0};
-    if((property_get("audio.offload.pcm.buffer.size", value, "")) &&
-            atoi(value)) {
-        fragment_size =  atoi(value) * 1024;
-        ALOGV("Using buffer size from sys prop %d", fragment_size);
-    }
-
-    fragment_size = ALIGN( fragment_size, 1024);
-
+    //duration is set to 20 ms worth of stereo data at 48Khz
+    //with 16 bit per sample, modify this when the channel
+    //configuration is different
+    fragment_size = (pcm_offload_time
+                     * info->sample_rate
+                     * (bits_per_sample >> 3)
+                     * popcount(info->channel_mask))/1000;
+    // To have same PCM samples for all channels, the buffer size requires to
+    // be multiple of (number of channels * bytes per sample)
+    // For writes to succeed, the buffer must be written at address which is multiple of 32
+    // Alignment of 96 satsfies both of the above requirements
+    fragment_size = ALIGN(fragment_size, 96);
     if(fragment_size < MIN_PCM_OFFLOAD_FRAGMENT_SIZE)
         fragment_size = MIN_PCM_OFFLOAD_FRAGMENT_SIZE;
     else if(fragment_size > MAX_PCM_OFFLOAD_FRAGMENT_SIZE)
         fragment_size = MAX_PCM_OFFLOAD_FRAGMENT_SIZE;
 
-    ALOGV("%s: fragment_size %d", __func__, fragment_size);
+    ALOGI("PCM offload Fragment size to %d bytes", fragment_size);
     return fragment_size;
 }
 
@@ -2705,24 +3127,20 @@
 
     // For voice calls use default configuration
     // force routing is not required here, caller will do it anyway
-    if (adev->mode == AUDIO_MODE_IN_CALL ||
-        adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
+    if (voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
         ALOGW("%s:Use default bw and sr for voice/voip calls ",__func__);
-        *new_bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
-        *new_sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
-        backend_change = true;
-    }
-
-    /*
-     * The backend should be configured at highest bit width and/or
-     * sample rate amongst all playback usecases.
-     * If the selected sample rate and/or bit width differ with
-     * current backend sample rate and/or bit width, then, we set the
-     * backend re-configuration flag.
-     *
-     * Exception: 16 bit playbacks is allowed through 16 bit/48 khz backend only
-     */
-    if (!backend_change) {
+        bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+        sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    } else {
+        /*
+         * The backend should be configured at highest bit width and/or
+         * sample rate amongst all playback usecases.
+         * If the selected sample rate and/or bit width differ with
+         * current backend sample rate and/or bit width, then, we set the
+         * backend re-configuration flag.
+         *
+         * Exception: 16 bit playbacks is allowed through 16 bit/48 khz backend only
+         */
         list_for_each(node, &adev->usecase_list) {
             struct audio_usecase *curr_usecase;
             curr_usecase = node_to_item(node, struct audio_usecase, list);
@@ -2741,11 +3159,15 @@
         }
     }
 
-    // 24 bit playback on speakers and all 16 bit playbacks is allowed through
-    // 16 bit/48 khz backend only
-    if ((16 == bit_width) ||
-        ((24 == bit_width) &&
-         (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER))) {
+    // 16 bit playback on speakers is allowed through 48 khz backend only
+    if (16 == bit_width) {
+        sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    }
+    // 24 bit playback on speakers is allowed through 48 khz backend only
+    // bit width re-configured based on platform info
+    if ((24 == bit_width) &&
+        (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER)) {
+        bit_width = (uint32_t)platform_get_snd_device_bit_width(SND_DEVICE_OUT_SPEAKER);
         sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
     }
     // Force routing if the expected bitwdith or samplerate
@@ -2824,3 +3246,550 @@
      *device_to_be_id = msm_device_to_be_id;
      *length = msm_be_id_array_len;
 }
+int platform_set_stream_channel_map(void *platform, audio_channel_mask_t channel_mask, int snd_id)
+{
+    int ret = 0;
+    int channels = audio_channel_count_from_out_mask(channel_mask);
+
+    char channel_map[8];
+    memset(channel_map, 0, sizeof(channel_map));
+    /* Following are all most common standard WAV channel layouts
+       overridden by channel mask if its allowed and different */
+    switch (channels) {
+        case 1:
+            /* AUDIO_CHANNEL_OUT_MONO */
+            channel_map[0] = PCM_CHANNEL_FC;
+            break;
+        case 2:
+            /* AUDIO_CHANNEL_OUT_STEREO */
+            channel_map[0] = PCM_CHANNEL_FL;
+            channel_map[1] = PCM_CHANNEL_FR;
+            break;
+        case 3:
+            /* AUDIO_CHANNEL_OUT_2POINT1 */
+            channel_map[0] = PCM_CHANNEL_FL;
+            channel_map[1] = PCM_CHANNEL_FR;
+            channel_map[2] = PCM_CHANNEL_FC;
+            break;
+        case 4:
+            /* AUDIO_CHANNEL_OUT_QUAD_SIDE */
+            channel_map[0] = PCM_CHANNEL_FL;
+            channel_map[1] = PCM_CHANNEL_FR;
+            channel_map[2] = PCM_CHANNEL_LS;
+            channel_map[3] = PCM_CHANNEL_RS;
+            if (channel_mask == AUDIO_CHANNEL_OUT_QUAD_BACK)
+            {
+                channel_map[2] = PCM_CHANNEL_LB;
+                channel_map[3] = PCM_CHANNEL_RB;
+            }
+            if (channel_mask == AUDIO_CHANNEL_OUT_SURROUND)
+            {
+                channel_map[2] = PCM_CHANNEL_FC;
+                channel_map[3] = PCM_CHANNEL_CS;
+            }
+            break;
+        case 5:
+            /* AUDIO_CHANNEL_OUT_PENTA */
+            channel_map[0] = PCM_CHANNEL_FL;
+            channel_map[1] = PCM_CHANNEL_FR;
+            channel_map[2] = PCM_CHANNEL_FC;
+            channel_map[3] = PCM_CHANNEL_LB;
+            channel_map[4] = PCM_CHANNEL_RB;
+            break;
+        case 6:
+            /* AUDIO_CHANNEL_OUT_5POINT1 */
+            channel_map[0] = PCM_CHANNEL_FL;
+            channel_map[1] = PCM_CHANNEL_FR;
+            channel_map[2] = PCM_CHANNEL_FC;
+            channel_map[3] = PCM_CHANNEL_LFE;
+            channel_map[4] = PCM_CHANNEL_LB;
+            channel_map[5] = PCM_CHANNEL_RB;
+            if (channel_mask == AUDIO_CHANNEL_OUT_5POINT1_SIDE)
+            {
+                channel_map[4] = PCM_CHANNEL_LS;
+                channel_map[5] = PCM_CHANNEL_RS;
+            }
+            break;
+        case 7:
+            /* AUDIO_CHANNEL_OUT_6POINT1 */
+            channel_map[0] = PCM_CHANNEL_FL;
+            channel_map[1] = PCM_CHANNEL_FR;
+            channel_map[2] = PCM_CHANNEL_FC;
+            channel_map[3] = PCM_CHANNEL_LFE;
+            channel_map[4] = PCM_CHANNEL_LB;
+            channel_map[5] = PCM_CHANNEL_RB;
+            channel_map[6] = PCM_CHANNEL_CS;
+            break;
+        case 8:
+            /* AUDIO_CHANNEL_OUT_7POINT1 */
+            channel_map[0] = PCM_CHANNEL_FL;
+            channel_map[1] = PCM_CHANNEL_FR;
+            channel_map[2] = PCM_CHANNEL_FC;
+            channel_map[3] = PCM_CHANNEL_LFE;
+            channel_map[4] = PCM_CHANNEL_LB;
+            channel_map[5] = PCM_CHANNEL_RB;
+            channel_map[6] = PCM_CHANNEL_LS;
+            channel_map[7] = PCM_CHANNEL_RS;
+            break;
+        default:
+            ALOGE("unsupported channels %d for setting channel map", channels);
+            return -1;
+    }
+    ret = platform_set_channel_map(platform, channels, channel_map, snd_id);
+    return ret;
+}
+
+int platform_get_edid_info(void *platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE];
+    char *sad = block;
+    int num_audio_blocks;
+    int channel_count = 2;
+    int i, ret, count;
+
+    struct mixer_ctl *ctl;
+    char edid_data[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE + 1] = {0};
+    edid_audio_info *info;
+
+    if (my_data->edid_valid) {
+        /* use cached edid */
+        return 0;
+    }
+
+    if (my_data->edid_info == NULL) {
+        my_data->edid_info =
+            (struct edid_audio_info *)calloc(1, sizeof(struct edid_audio_info));
+    }
+
+    info = my_data->edid_info;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_DATA_BLOCK_MIXER_CTL);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, AUDIO_DATA_BLOCK_MIXER_CTL);
+        goto fail;
+    }
+
+    mixer_ctl_update(ctl);
+
+    count = mixer_ctl_get_num_values(ctl);
+
+    /* Read SAD blocks, clamping the maximum size for safety */
+    if (count > (int)sizeof(block))
+        count = (int)sizeof(block);
+
+    ret = mixer_ctl_get_array(ctl, block, count);
+    if (ret != 0) {
+        ALOGE("%s: mixer_ctl_get_array() failed to get EDID info", __func__);
+        goto fail;
+    }
+    edid_data[0] = count;
+    memcpy(&edid_data[1], block, count);
+
+    if (!edid_get_sink_caps(info, edid_data)) {
+        ALOGE("%s: Failed to get HDMI sink capabilities", __func__);
+        goto fail;
+    }
+    my_data->edid_valid = true;
+    return 0;
+fail:
+    if (my_data->edid_info) {
+        free(my_data->edid_info);
+        my_data->edid_info = NULL;
+        my_data->edid_valid = false;
+    }
+    ALOGE("%s: return -EINVAL", __func__);
+    return -EINVAL;
+}
+
+
+int platform_set_channel_allocation(void *platform, int channel_alloc)
+{
+    struct mixer_ctl *ctl;
+    const char *mixer_ctl_name = "HDMI RX CA";
+    int ret;
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        ret = EINVAL;
+    }
+    ALOGD(":%s channel allocation = 0x%x", __func__, channel_alloc);
+    ret = mixer_ctl_set_value(ctl, 0, channel_alloc);
+
+    if (ret < 0) {
+        ALOGE("%s: Could not set ctl, error:%d ", __func__, ret);
+    }
+
+    return ret;
+}
+
+int platform_set_channel_map(void *platform, int ch_count, char *ch_map, int snd_id)
+{
+    struct mixer_ctl *ctl;
+    char mixer_ctl_name[44]; // max length of name is 44 as defined
+    int ret;
+    unsigned int i;
+    int set_values[8] = {0};
+    char device_num[13]; // device number up to 2 digit
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    ALOGV("%s channel_count:%d",__func__, ch_count);
+    if (NULL == ch_map) {
+        ALOGE("%s: Invalid channel mapping used", __func__);
+        return -EINVAL;
+    }
+
+    /*
+     * If snd_id is greater than 0, stream channel mapping
+     * If snd_id is below 0, typically -1, device channel mapping
+     */
+    if (snd_id >= 0) {
+        snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Playback Channel Map%d", snd_id);
+    } else {
+        strlcpy(mixer_ctl_name, "Playback Device Channel Map", sizeof(mixer_ctl_name));
+    }
+
+    ALOGD("%s mixer_ctl_name:%s", __func__, mixer_ctl_name);
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+    for (i = 0; i< ARRAY_SIZE(set_values); i++) {
+        set_values[i] = ch_map[i];
+    }
+
+    ALOGD("%s: set mapping(%d %d %d %d %d %d %d %d) for channel:%d", __func__,
+        set_values[0], set_values[1], set_values[2], set_values[3], set_values[4],
+        set_values[5], set_values[6], set_values[7], ch_count);
+
+    ret = mixer_ctl_set_array(ctl, set_values, ch_count);
+    if (ret < 0) {
+        ALOGE("%s: Could not set ctl, error:%d ch_count:%d",
+              __func__, ret, ch_count);
+    }
+    return ret;
+}
+
+unsigned char platform_map_to_edid_format(int audio_format)
+{
+    unsigned char format;
+    switch (audio_format & AUDIO_FORMAT_MAIN_MASK) {
+    case AUDIO_FORMAT_AC3:
+        ALOGV("%s: AC3", __func__);
+        format = AC3;
+        break;
+    case AUDIO_FORMAT_AAC:
+        ALOGV("%s:AAC", __func__);
+        format = AAC;
+        break;
+    case AUDIO_FORMAT_E_AC3:
+        ALOGV("%s:E_AC3", __func__);
+        format = DOLBY_DIGITAL_PLUS;
+        break;
+    case AUDIO_FORMAT_PCM_16_BIT:
+    case AUDIO_FORMAT_PCM_16_BIT_OFFLOAD:
+    case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD:
+    default:
+        ALOGV("%s:PCM", __func__);
+        format =  LPCM;
+        break;
+    }
+    return format;
+}
+
+uint32_t platform_get_compress_passthrough_buffer_size(
+                                          audio_offload_info_t* info)
+{
+    uint32_t fragment_size = MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE;
+    if (!info->has_video)
+        fragment_size = MIN_COMPRESS_PASSTHROUGH_FRAGMENT_SIZE;
+
+    return fragment_size;
+}
+
+void platform_reset_edid_info(void *platform) {
+
+    ALOGV("%s:", __func__);
+    struct platform_data *my_data = (struct platform_data *)platform;
+    if (my_data->edid_info) {
+        ALOGV("%s :free edid", __func__);
+        free(my_data->edid_info);
+        my_data->edid_info = NULL;
+    }
+}
+
+bool platform_is_edid_supported_format(void *platform, int format)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    edid_audio_info *info = NULL;
+    int num_audio_blocks;
+    int i, ret, count;
+    unsigned char format_id = platform_map_to_edid_format(format);
+
+    ret = platform_get_edid_info(platform);
+    info = (edid_audio_info *)my_data->edid_info;
+    if (ret == 0 && info != NULL) {
+        for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
+             /*
+              * To check
+              *  is there any special for CONFIG_HDMI_PASSTHROUGH_CONVERT
+              *  & DOLBY_DIGITAL_PLUS
+              */
+            if (info->audio_blocks_array[i].format_id == format_id) {
+                ALOGV("%s:platform_is_edid_supported_format true %x",
+                      __func__, format);
+                return true;
+            }
+        }
+    }
+    ALOGV("%s:platform_is_edid_supported_format false %x",
+           __func__, format);
+    return false;
+}
+
+int platform_set_edid_channels_configuration(void *platform, int channels) {
+
+    struct platform_data *my_data = (struct platform_data *)platform;
+    struct audio_device *adev = my_data->adev;
+    edid_audio_info *info = NULL;
+    int num_audio_blocks;
+    int channel_count = 2;
+    int i, ret, count;
+    char default_channelMap[MAX_CHANNELS_SUPPORTED] = {0};
+
+    ret = platform_get_edid_info(platform);
+    info = (edid_audio_info *)my_data->edid_info;
+    if(ret == 0 && info != NULL) {
+        if (channels > 2) {
+
+            ALOGV("%s:able to get HDMI sink capabilities multi channel playback",
+                   __func__);
+            for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
+                if (info->audio_blocks_array[i].format_id == LPCM &&
+                      info->audio_blocks_array[i].channels > channel_count &&
+                      info->audio_blocks_array[i].channels <= MAX_HDMI_CHANNEL_CNT) {
+                    channel_count = info->audio_blocks_array[i].channels;
+                }
+            }
+            ALOGVV("%s:channel_count:%d", __func__, channel_count);
+            /*
+             * Channel map is set for supported hdmi max channel count even
+             * though the input channel count set on adm is less than or equal to
+             * max supported channel count
+             */
+            platform_set_channel_map(platform, channel_count, info->channel_map, -1);
+            platform_set_channel_allocation(platform, info->channel_allocation);
+        } else {
+            default_channelMap[0] = PCM_CHANNEL_FL;
+            default_channelMap[1] = PCM_CHANNEL_FR;
+            platform_set_channel_map(platform,2,default_channelMap,-1);
+            platform_set_channel_allocation(platform,0);
+        }
+    }
+
+    return 0;
+}
+
+void platform_cache_edid(void * platform)
+{
+    platform_get_edid_info(platform);
+}
+
+void platform_invalidate_edid(void * platform)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    my_data->edid_valid = false;
+    if (my_data->edid_info) {
+        memset(my_data->edid_info, 0, sizeof(struct edid_audio_info));
+    }
+}
+
+int platform_set_mixer_control(struct stream_out *out, const char * mixer_ctl_name,
+                      const char *mixer_val)
+{
+    struct audio_device *adev = out->dev;
+    struct mixer_ctl *ctl = NULL;
+    ALOGD("setting mixer ctl %s with value %s", mixer_ctl_name, mixer_val);
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        return -EINVAL;
+    }
+
+    return mixer_ctl_set_enum_by_string(ctl, mixer_val);
+}
+
+int platform_set_hdmi_config(struct stream_out *out)
+{
+    struct listnode *node;
+    struct audio_usecase *usecase;
+    struct audio_device *adev = out->dev;
+    const char *hdmi_format_ctrl = "HDMI RX Format";
+    const char *hdmi_rate_ctrl = "HDMI_RX SampleRate";
+    int sample_rate = out->sample_rate;
+    /*TODO: Add rules and check if this needs to be done.*/
+    if((is_offload_usecase(out->usecase)) &&
+        (out->compr_config.codec->compr_passthr == PASSTHROUGH ||
+        out->compr_config.codec->compr_passthr == PASSTHROUGH_CONVERT)) {
+        /* TODO: can we add mixer control for channels here avoid setting */
+        if ((out->format == AUDIO_FORMAT_E_AC3 ||
+            out->format == AUDIO_FORMAT_E_AC3_JOC) &&
+            (out->compr_config.codec->compr_passthr == PASSTHROUGH))
+            sample_rate = out->sample_rate * 4;
+        ALOGD("%s:HDMI compress format and samplerate %d, sample_rate %d",
+               __func__, out->sample_rate, sample_rate);
+        platform_set_mixer_control(out, hdmi_format_ctrl, "Compr");
+        switch (sample_rate) {
+            case 32000:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_32");
+                break;
+            case 44100:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_44_1");
+                break;
+            case 96000:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_96");
+                break;
+            case 176400:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_176_4");
+                break;
+            case 192000:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_192");
+                break;
+            case 128000:
+                if (out->format != AUDIO_FORMAT_E_AC3) {
+                    platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_128");
+                    break;
+                } else
+                   ALOGW("Unsupported sample rate for E_AC3 32K");
+            default:
+            case 48000:
+                platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_48");
+                break;
+        }
+    } else {
+        ALOGD("%s: HDMI pcm and samplerate %d", __func__,
+               out->sample_rate);
+        platform_set_mixer_control(out, hdmi_format_ctrl, "LPCM");
+        platform_set_mixer_control(out, hdmi_rate_ctrl, "KHZ_48");
+    }
+
+    /*
+     * Deroute all the playback streams routed to HDMI so that
+     * the back end is deactivated. Note that backend will not
+     * be deactivated if any one stream is connected to it.
+     */
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        ALOGV("%s:disable: usecase type %d, devices 0x%x", __func__,
+               usecase->type, usecase->devices);
+        if (usecase->type == PCM_PLAYBACK &&
+                usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            disable_audio_route(adev, usecase);
+        }
+    }
+
+    /*
+     * Enable all the streams disabled above. Now the HDMI backend
+     * will be activated with new channel configuration
+     */
+    list_for_each(node, &adev->usecase_list) {
+        usecase = node_to_item(node, struct audio_usecase, list);
+        ALOGV("%s:enable: usecase type %d, devices 0x%x", __func__,
+               usecase->type, usecase->devices);
+        if (usecase->type == PCM_PLAYBACK &&
+                usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+            enable_audio_route(adev, usecase);
+        }
+    }
+
+    return 0;
+}
+
+int platform_set_device_params(struct stream_out *out, int param, int value)
+{
+    struct audio_device *adev = out->dev;
+    struct mixer_ctl *ctl;
+    char *mixer_ctl_name = "Device PP Params";
+    int ret = 0;
+    uint32_t set_values[] = {0,0};
+
+    set_values[0] = param;
+    set_values[1] = value;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+              __func__, mixer_ctl_name);
+        ret = -EINVAL;
+        goto end;
+    }
+
+    ALOGV("%s: Setting device pp params param: %d, value %d mixer ctrl:%s",
+          __func__,param, value, mixer_ctl_name);
+    mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
+
+end:
+    return ret;
+}
+
+/*
+ * This is a lookup table to map android audio input device to audio h/w interface (backend).
+ * The table can be extended for other input devices by adding appropriate entries.
+ * Also the audio interface for a particular input device can be overriden by adding
+ * corresponding entry in audio_platform_info.xml file.
+ */
+struct audio_device_to_audio_interface audio_device_to_interface_table[] = {
+    {AUDIO_DEVICE_IN_BUILTIN_MIC, ENUM_TO_STRING(AUDIO_DEVICE_IN_BUILTIN_MIC), "SLIMBUS_0"},
+    {AUDIO_DEVICE_IN_BACK_MIC, ENUM_TO_STRING(AUDIO_DEVICE_IN_BACK_MIC), "SLIMBUS_0"},
+};
+
+int audio_device_to_interface_table_len  =
+    sizeof(audio_device_to_interface_table) / sizeof(audio_device_to_interface_table[0]);
+
+int platform_set_audio_device_interface(const char *device_name, const char *intf_name)
+{
+    int ret = 0;
+    int i;
+
+    if (device_name == NULL || intf_name == NULL) {
+        ALOGE("%s: Invalid input", __func__);
+
+        ret = -EINVAL;
+        goto done;
+    }
+
+    ALOGD("%s: Enter, device name:%s, intf name:%s", __func__, device_name, intf_name);
+
+    size_t device_name_len = strlen(device_name);
+    for (i = 0; i < audio_device_to_interface_table_len; i++) {
+        char* name = audio_device_to_interface_table[i].device_name;
+        size_t name_len = strlen(name);
+        if ((name_len == device_name_len) &&
+            (strncmp(device_name, name, name_len) == 0)) {
+            ALOGD("%s: Matched device name:%s, overwrite intf name with %s",
+                  __func__, device_name, intf_name);
+
+            strlcpy(audio_device_to_interface_table[i].interface_name, intf_name,
+                    sizeof(audio_device_to_interface_table[i].interface_name));
+            goto done;
+        }
+    }
+    ALOGE("%s: Could not find matching device name %s",
+            __func__, device_name);
+
+    ret = -EINVAL;
+
+done:
+    return ret;
+}
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 831ee58..83922d5 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/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
@@ -141,6 +141,10 @@
     SND_DEVICE_IN_SPEAKER_DMIC_AEC_BROADSIDE,
     SND_DEVICE_IN_SPEAKER_DMIC_NS_BROADSIDE,
     SND_DEVICE_IN_SPEAKER_DMIC_AEC_NS_BROADSIDE,
+    SND_DEVICE_IN_HANDSET_QMIC,
+    SND_DEVICE_IN_SPEAKER_QMIC_AEC,
+    SND_DEVICE_IN_SPEAKER_QMIC_NS,
+    SND_DEVICE_IN_SPEAKER_QMIC_AEC_NS,
     SND_DEVICE_IN_END,
 
     SND_DEVICE_MAX = SND_DEVICE_IN_END,
@@ -168,7 +172,7 @@
  * the buffer size of an input/output stream
  */
 #define DEEP_BUFFER_OUTPUT_PERIOD_SIZE 960
-#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 4
+#define DEEP_BUFFER_OUTPUT_PERIOD_COUNT 5
 #define LOW_LATENCY_OUTPUT_PERIOD_SIZE 240
 #define LOW_LATENCY_OUTPUT_PERIOD_COUNT 2
 
@@ -225,7 +229,7 @@
 #define PLAYBACK_OFFLOAD_DEVICE8 38
 #define PLAYBACK_OFFLOAD_DEVICE9 39
 #endif
-#ifdef PLATFORM_MSM8994
+#if defined (PLATFORM_MSM8994) || defined (PLATFORM_MSM8996)
 #define PLAYBACK_OFFLOAD_DEVICE2 17
 #define PLAYBACK_OFFLOAD_DEVICE3 18
 #define PLAYBACK_OFFLOAD_DEVICE4 37
@@ -276,6 +280,12 @@
 #define VOLTE_CALL_PCM_DEVICE 14
 #define QCHAT_CALL_PCM_DEVICE 20
 #define VOWLAN_CALL_PCM_DEVICE 36
+#elif PLATFORM_MSM8996
+#define VOICE_CALL_PCM_DEVICE 40
+#define VOICE2_CALL_PCM_DEVICE 41
+#define VOLTE_CALL_PCM_DEVICE 14
+#define QCHAT_CALL_PCM_DEVICE 20
+#define VOWLAN_CALL_PCM_DEVICE 33
 #else
 #define VOICE_CALL_PCM_DEVICE 2
 #define VOICE2_CALL_PCM_DEVICE 22
@@ -284,6 +294,14 @@
 #define VOWLAN_CALL_PCM_DEVICE 36
 #endif
 
+#ifdef PLATFORM_MSM8996
+#define VOICEMMODE1_CALL_PCM_DEVICE 2
+#define VOICEMMODE2_CALL_PCM_DEVICE 22
+#else
+#define VOICEMMODE1_CALL_PCM_DEVICE 44
+#define VOICEMMODE2_CALL_PCM_DEVICE 45
+#endif
+
 #define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
 #define AFE_PROXY_RECORD_PCM_DEVICE 8
 
@@ -299,6 +317,8 @@
 #define FM_RX_VOLUME "Quat MI2S FM RX Volume"
 #elif PLATFORM_MSM8994
 #define FM_RX_VOLUME "PRI MI2S LOOPBACK Volume"
+#elif PLATFORM_MSM8996
+#define FM_RX_VOLUME "Tert MI2S LOOPBACK Volume"
 #else
 #define FM_RX_VOLUME "Internal FM RX Volume"
 #endif
@@ -342,4 +362,24 @@
     get_sample_rate_t get_sample_rate;
 };
 
+/* HDMI Passthrough defines */
+enum {
+    LEGACY_PCM = 0,
+    PASSTHROUGH,
+    PASSTHROUGH_CONVERT
+};
+/*
+ * ID for setting mute and lateny on the device side
+ * through Device PP Params mixer control.
+ */
+#define DEVICE_PARAM_MUTE_ID    0
+#define DEVICE_PARAM_LATENCY_ID 1
+
+#define ENUM_TO_STRING(X) #X
+
+struct audio_device_to_audio_interface {
+    audio_devices_t device;
+    char device_name[100];
+    char interface_name[100];
+};
 #endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/platform_api.h b/hal/platform_api.h
index c7a45bd..3808b14 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.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
@@ -36,6 +36,8 @@
 int platform_get_fluence_type(void *platform, char *value, uint32_t len);
 int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id);
 int platform_get_snd_device_acdb_id(snd_device_t snd_device);
+int platform_set_snd_device_bit_width(snd_device_t snd_device, unsigned int bit_width);
+int platform_get_snd_device_bit_width(snd_device_t snd_device);
 int platform_send_audio_calibration(void *platform, struct audio_usecase *usecase,
                                     int app_type, int sample_rate);
 int platform_get_default_app_type(void *platform);
@@ -87,6 +89,7 @@
 struct audio_offload_info_t;
 uint32_t platform_get_compress_offload_buffer_size(audio_offload_info_t* info);
 uint32_t platform_get_pcm_offload_buffer_size(audio_offload_info_t* info);
+uint32_t platform_get_compress_passthrough_buffer_size(audio_offload_info_t* info);
 
 bool platform_check_and_set_codec_backend_cfg(struct audio_device* adev, struct audio_usecase *usecase);
 int platform_get_usecase_index(const char * usecase);
@@ -94,4 +97,17 @@
 void platform_set_echo_reference(void *platform, bool enable);
 void platform_get_device_to_be_id_map(int **be_id_map, int *length);
 
+int platform_set_channel_allocation(void *platform, int channel_alloc);
+int platform_get_edid_info(void *platform);
+int platform_set_channel_map(void *platform, int ch_count, char *ch_map,
+                             int snd_id);
+int platform_set_stream_channel_map(void *platform, audio_channel_mask_t channel_mask, int snd_id);
+int platform_set_edid_channels_configuration(void *platform, int channels);
+unsigned char platform_map_to_edid_format(int format);
+bool platform_is_edid_supported_format(void *platform, int format);
+void platform_cache_edid(void * platform);
+void platform_invalidate_edid(void * platform);
+int platform_set_hdmi_config(struct stream_out *out);
+int platform_set_device_params(struct stream_out *out, int param, int value);
+int platform_set_audio_device_interface(const char * device_name, const char *intf_name);
 #endif // AUDIO_PLATFORM_API_H
diff --git a/hal/platform_info.c b/hal/platform_info.c
index 615b9f3..13a314e 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015, 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,22 +43,28 @@
 typedef enum {
     ROOT,
     ACDB,
+    BITWIDTH,
     PCM_ID,
     BACKEND_NAME,
+    INTERFACE_NAME,
 } section_t;
 
 typedef void (* section_process_fn)(const XML_Char **attr);
 
 static void process_acdb_id(const XML_Char **attr);
+static void process_bit_width(const XML_Char **attr);
 static void process_pcm_id(const XML_Char **attr);
 static void process_backend_name(const XML_Char **attr);
+static void process_interface_name(const XML_Char **attr);
 static void process_root(const XML_Char **attr);
 
 static section_process_fn section_table[] = {
     [ROOT] = process_root,
     [ACDB] = process_acdb_id,
+    [BITWIDTH] = process_bit_width,
     [PCM_ID] = process_pcm_id,
     [BACKEND_NAME] = process_backend_name,
+    [INTERFACE_NAME] = process_interface_name,
 };
 
 static section_t section;
@@ -80,6 +86,11 @@
  * ...
  * ...
  * </pcm_ids>
+ * <interface_names>
+ * <device name="Use audio device name here, not sound device name" interface="PRIMARY_I2S"/>
+ * ...
+ * ...
+ * </interface_names>
  * </audio_platform_info>
  */
 
@@ -202,6 +213,66 @@
     return;
 }
 
+static void process_bit_width(const XML_Char **attr)
+{
+    int index;
+
+    if (strcmp(attr[0], "name") != 0) {
+        ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
+        goto done;
+    }
+
+    index = platform_get_snd_device_index((char *)attr[1]);
+    if (index < 0) {
+        ALOGE("%s: Device %s in platform info xml not found, no ACDB ID set!",
+              __func__, attr[1]);
+        goto done;
+    }
+
+    if (strcmp(attr[2], "bit_width") != 0) {
+        ALOGE("%s: Device %s in platform info xml has no bit_width, no ACDB ID set!",
+              __func__, attr[1]);
+        goto done;
+    }
+
+    if (platform_set_snd_device_bit_width(index, atoi((char *)attr[3])) < 0) {
+        ALOGE("%s: Device %s, ACDB ID %d was not set!",
+              __func__, attr[1], atoi((char *)attr[3]));
+        goto done;
+    }
+
+done:
+    return;
+}
+
+static void process_interface_name(const XML_Char **attr)
+{
+    int ret;
+
+    if (strcmp(attr[0], "name") != 0) {
+        ALOGE("%s: 'name' not found, no Audio Interface set!", __func__);
+
+        goto done;
+    }
+
+    if (strcmp(attr[2], "interface") != 0) {
+        ALOGE("%s: Device %s has no Audio Interface set!",
+              __func__, attr[1]);
+
+        goto done;
+    }
+
+    ret = platform_set_audio_device_interface((char *)attr[1], (char *)attr[3]);
+    if (ret < 0) {
+        ALOGE("%s: Audio Interface not set!", __func__);
+
+        goto done;
+    }
+
+done:
+    return;
+}
+
 static void start_tag(void *userdata __unused, const XML_Char *tag_name,
                       const XML_Char **attr)
 {
@@ -209,15 +280,20 @@
     const XML_Char              *attr_value = NULL;
     unsigned int                i;
 
-    if (strcmp(tag_name, "acdb_ids") == 0) {
+    if (strcmp(tag_name, "bit_width_configs") == 0) {
+        section = BITWIDTH;
+    } else if (strcmp(tag_name, "acdb_ids") == 0) {
         section = ACDB;
     } else if (strcmp(tag_name, "pcm_ids") == 0) {
         section = PCM_ID;
     } else if (strcmp(tag_name, "backend_names") == 0) {
         section = BACKEND_NAME;
+    } else if (strcmp(tag_name, "interface_names") == 0) {
+        section = INTERFACE_NAME;
     } else if (strcmp(tag_name, "device") == 0) {
-        if ((section != ACDB) && (section != BACKEND_NAME)) {
-            ALOGE("device tag only supported for acdb/backend names");
+        if ((section != ACDB) && (section != BACKEND_NAME) && (section != BITWIDTH) &&
+            (section != INTERFACE_NAME)) {
+            ALOGE("device tag only supported for acdb/backend names/bitwitdh/interface names");
             return;
         }
 
@@ -239,12 +315,16 @@
 
 static void end_tag(void *userdata __unused, const XML_Char *tag_name)
 {
-    if (strcmp(tag_name, "acdb_ids") == 0) {
+    if (strcmp(tag_name, "bit_width_configs") == 0) {
+        section = ROOT;
+    } else if (strcmp(tag_name, "acdb_ids") == 0) {
         section = ROOT;
     } else if (strcmp(tag_name, "pcm_ids") == 0) {
         section = ROOT;
     } else if (strcmp(tag_name, "backend_names") == 0) {
         section = ROOT;
+    } else if (strcmp(tag_name, "interface_names") == 0) {
+        section = ROOT;
     }
 }
 
diff --git a/hal/voice.c b/hal/voice.c
index c4fa163..9fc1081 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -157,6 +157,8 @@
     }
     ALOGD("voice_config.rate %d\n", voice_config.rate);
 
+    voice_set_mic_mute(adev, adev->voice.mic_mute);
+
     ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
           __func__, adev->snd_card, pcm_dev_rx_id);
     session->pcm_rx = pcm_open(adev->snd_card,
@@ -221,11 +223,16 @@
 bool voice_is_in_call_rec_stream(struct stream_in *in)
 {
     bool in_call_rec = false;
-    int ret = 0;
 
-    ret = voice_extn_is_in_call_rec_stream(in, &in_call_rec);
-    if (ret == -ENOSYS) {
-        in_call_rec = false;
+    if (!in) {
+       ALOGE("%s: input stream is NULL", __func__);
+       return in_call_rec;
+    }
+
+    if(in->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
+       in->source == AUDIO_SOURCE_VOICE_UPLINK ||
+       in->source == AUDIO_SOURCE_VOICE_CALL) {
+       in_call_rec = true;
     }
 
     return in_call_rec;
@@ -288,6 +295,18 @@
                                                        session_id, rec_mode);
         ALOGV("%s: Update usecase to %d",__func__, in->usecase);
     } else {
+        /*
+         * Reject the recording instances, where the recording is started
+         * with In-call voice recording source types but voice call is not
+         * active by the time input is started
+         */
+        if ((in->source == AUDIO_SOURCE_VOICE_UPLINK) ||
+            (in->source == AUDIO_SOURCE_VOICE_DOWNLINK) ||
+            (in->source == AUDIO_SOURCE_VOICE_CALL)) {
+            ret = -EINVAL;
+            ALOGE("%s: As voice call is not active, Incall rec usecase can't be \
+                   selected for requested source:%d",__func__, in->source);
+        }
         ALOGV("%s: voice call not active", __func__);
     }
 
@@ -309,6 +328,41 @@
     return ret;
 }
 
+snd_device_t voice_get_incall_rec_snd_device(snd_device_t in_snd_device)
+{
+    snd_device_t incall_record_device = in_snd_device;
+
+    /*
+     * For incall recording stream, AUDIO_COPP topology will be picked up
+     * from the calibration data of the input sound device which is nothing
+     * but the voice call's input device. But there are requirements to use
+     * AUDIO_COPP_MONO topology even if the voice call's input device is
+     * different. Hence override the input device with the one which uses
+     * the AUDIO_COPP_MONO topology.
+     */
+    switch(in_snd_device) {
+    case SND_DEVICE_IN_HANDSET_MIC:
+    case SND_DEVICE_IN_VOICE_DMIC:
+    case SND_DEVICE_IN_AANC_HANDSET_MIC:
+        incall_record_device = SND_DEVICE_IN_HANDSET_MIC;
+        break;
+    case SND_DEVICE_IN_VOICE_SPEAKER_MIC:
+    case SND_DEVICE_IN_VOICE_SPEAKER_DMIC:
+    case SND_DEVICE_IN_VOICE_SPEAKER_DMIC_BROADSIDE:
+    case SND_DEVICE_IN_VOICE_SPEAKER_QMIC:
+        incall_record_device = SND_DEVICE_IN_VOICE_SPEAKER_MIC;
+        break;
+    default:
+        incall_record_device = in_snd_device;
+    }
+
+    ALOGD("%s: in_snd_device(%d: %s) incall_record_device(%d: %s)", __func__,
+          in_snd_device, platform_get_snd_device_name(in_snd_device),
+          incall_record_device,  platform_get_snd_device_name(incall_record_device));
+
+    return incall_record_device;
+}
+
 int voice_check_and_set_incall_music_usecase(struct audio_device *adev,
                                              struct stream_out *out)
 {
@@ -373,11 +427,11 @@
 {
     int ret = 0;
 
+    adev->voice.in_call = true;
     ret = voice_extn_start_call(adev);
     if (ret == -ENOSYS) {
         ret = voice_start_usecase(adev, USECASE_VOICE_CALL);
     }
-    adev->voice.in_call = true;
 
     return ret;
 }
diff --git a/hal/voice.h b/hal/voice.h
index 9be8443..5a9cce1 100644
--- a/hal/voice.h
+++ b/hal/voice.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
@@ -24,7 +24,7 @@
 #define VOICE_SESS_IDX     (BASE_SESS_IDX)
 
 #ifdef MULTI_VOICE_SESSION_ENABLED
-#define MAX_VOICE_SESSIONS 5
+#define MAX_VOICE_SESSIONS 7
 #else
 #define MAX_VOICE_SESSIONS 1
 #endif
@@ -43,6 +43,7 @@
 struct stream_in;
 struct stream_out;
 typedef int audio_usecase_t;
+typedef int snd_device_t;
 
 struct call_state {
     int current;
@@ -93,4 +94,5 @@
 int voice_check_and_stop_incall_rec_usecase(struct audio_device *adev,
                                             struct stream_in *in);
 void voice_update_devices_for_all_voice_usecases(struct audio_device *adev);
+snd_device_t voice_get_incall_rec_snd_device(snd_device_t in_snd_device);
 #endif //VOICE_H
diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c
index 26636db..14af6fc 100644
--- a/hal/voice_extn/compress_voip.c
+++ b/hal/voice_extn/compress_voip.c
@@ -328,6 +328,7 @@
     int i, ret = 0;
     struct audio_usecase *uc_info;
     int pcm_dev_rx_id, pcm_dev_tx_id;
+    unsigned int flags = PCM_OUT | PCM_MONOTONIC;
 
     ALOGD("%s: enter", __func__);
 
@@ -368,7 +369,7 @@
               __func__, adev->snd_card, pcm_dev_rx_id);
         voip_data.pcm_rx = pcm_open(adev->snd_card,
                                     pcm_dev_rx_id,
-                                    PCM_OUT, voip_config);
+                                    flags, voip_config);
         if (voip_data.pcm_rx && !pcm_is_ready(voip_data.pcm_rx)) {
             ALOGE("%s: %s", __func__, pcm_get_error(voip_data.pcm_rx));
             pcm_close(voip_data.pcm_rx);
@@ -696,6 +697,10 @@
         voip_data.sample_rate = in->config.rate;
     }
 
+    ret = voip_set_mode(in->dev, in->format);
+    if (ret < 0)
+        goto done;
+
     in->usecase = USECASE_COMPRESS_VOIP_CALL;
     if (in->config.rate == 16000)
         in->config = pcm_config_voip_wb;
@@ -703,7 +708,6 @@
         in->config = pcm_config_voip_nb;
 
     voip_data.in_stream_count++;
-    ret = voip_set_mode(in->dev, in->format);
 
 done:
     ALOGV("%s: exit, ret=%d", __func__, ret);
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
index e5b979f..b806bab 100644
--- a/hal/voice_extn/voice_extn.c
+++ b/hal/voice_extn/voice_extn.c
@@ -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
@@ -44,17 +44,21 @@
 
 #define VOICE_EXTN_PARAMETER_VALUE_MAX_LEN 256
 
-#define VOICE2_VSID 0x10DC1000
-#define VOLTE_VSID  0x10C02000
-#define QCHAT_VSID  0x10803000
-#define VOWLAN_VSID 0x10002000
-#define ALL_VSID    0xFFFFFFFF
+#define VOICE2_VSID              0x10DC1000
+#define VOLTE_VSID               0x10C02000
+#define QCHAT_VSID               0x10803000
+#define VOWLAN_VSID              0x10002000
+#define VOICEMMODE1_VSID         0x11C05000
+#define VOICEMMODE2_VSID         0x11DC5000
+#define ALL_VSID                 0xFFFFFFFF
 
 /* Voice Session Indices */
 #define VOICE2_SESS_IDX    (VOICE_SESS_IDX + 1)
 #define VOLTE_SESS_IDX     (VOICE_SESS_IDX + 2)
 #define QCHAT_SESS_IDX     (VOICE_SESS_IDX + 3)
 #define VOWLAN_SESS_IDX    (VOICE_SESS_IDX + 4)
+#define MMODE1_SESS_IDX    (VOICE_SESS_IDX + 5)
+#define MMODE2_SESS_IDX    (VOICE_SESS_IDX + 6)
 
 /* Call States */
 #define CALL_HOLD           (BASE_CALL_STATE + 2)
@@ -87,6 +91,8 @@
         vsid == VOICE2_VSID ||
         vsid == VOLTE_VSID ||
         vsid == QCHAT_VSID ||
+        vsid == VOICEMMODE1_VSID ||
+        vsid == VOICEMMODE2_VSID ||
         vsid == VOWLAN_VSID)
         return true;
     else
@@ -118,6 +124,14 @@
         usecase_id = USECASE_VOWLAN_CALL;
         break;
 
+    case MMODE1_SESS_IDX:
+        usecase_id = USECASE_VOICEMMODE1_CALL;
+        break;
+
+    case MMODE2_SESS_IDX:
+        usecase_id = USECASE_VOICEMMODE2_CALL;
+        break;
+
     default:
         ALOGE("%s: Invalid voice session index\n", __func__);
     }
@@ -339,19 +353,6 @@
     return 0;
 }
 
-int voice_extn_is_in_call_rec_stream(struct stream_in *in, bool *in_call_rec)
-{
-    *in_call_rec = false;
-
-    if(in->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
-       in->source == AUDIO_SOURCE_VOICE_UPLINK ||
-       in->source == AUDIO_SOURCE_VOICE_CALL) {
-       *in_call_rec = true;
-    }
-
-    return 0;
-}
-
 void voice_extn_init(struct audio_device *adev)
 {
     adev->voice.session[VOICE_SESS_IDX].vsid =  VOICE_VSID;
@@ -359,6 +360,8 @@
     adev->voice.session[VOLTE_SESS_IDX].vsid =  VOLTE_VSID;
     adev->voice.session[QCHAT_SESS_IDX].vsid =  QCHAT_VSID;
     adev->voice.session[VOWLAN_SESS_IDX].vsid = VOWLAN_VSID;
+    adev->voice.session[MMODE1_SESS_IDX].vsid = VOICEMMODE1_VSID;
+    adev->voice.session[MMODE2_SESS_IDX].vsid = VOICEMMODE2_VSID;
 }
 
 int voice_extn_get_session_from_use_case(struct audio_device *adev,
@@ -388,6 +391,14 @@
         *session = &adev->voice.session[VOWLAN_SESS_IDX];
         break;
 
+    case USECASE_VOICEMMODE1_CALL:
+        *session = &adev->voice.session[MMODE1_SESS_IDX];
+        break;
+
+    case USECASE_VOICEMMODE2_CALL:
+        *session = &adev->voice.session[MMODE2_SESS_IDX];
+        break;
+
     default:
         ALOGE("%s: Invalid usecase_id:%d\n", __func__, usecase_id);
         *session = NULL;
diff --git a/hal/voice_extn/voice_extn.h b/hal/voice_extn/voice_extn.h
index 15e5248..4a04adb 100644
--- a/hal/voice_extn/voice_extn.h
+++ b/hal/voice_extn/voice_extn.h
@@ -32,7 +32,6 @@
 void voice_extn_get_parameters(const struct audio_device *adev,
                                struct str_parms *query,
                                struct str_parms *reply);
-int voice_extn_is_in_call_rec_stream(struct stream_in *in, bool *in_call_rec);
 int voice_extn_is_call_state_active(struct audio_device *adev,
                                     bool *is_call_active);
 int voice_extn_get_active_session_id(struct audio_device *adev,
@@ -83,11 +82,6 @@
     return -ENOSYS;
 }
 
-static int voice_extn_is_in_call_rec_stream(struct stream_in *in __unused, bool *in_call_rec __unused)
-{
-    return -ENOSYS;
-}
-
 static int voice_extn_get_active_session_id(struct audio_device *adev __unused,
                                             uint32_t *session_id __unused)
 {
diff --git a/policy_hal/AudioPolicyManager.cpp b/policy_hal/AudioPolicyManager.cpp
index ec48a71..65bad3c 100644
--- a/policy_hal/AudioPolicyManager.cpp
+++ b/policy_hal/AudioPolicyManager.cpp
@@ -1560,10 +1560,11 @@
             }
         }
 
-        //check if it's multi-channel AAC (includes sub formats) and FLAC format
+        //check if it's multi-channel AAC (includes sub formats), FLAC and VORBIS format
         if ((popcount(offloadInfo.channel_mask) > 2) &&
             (((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC) ||
-            ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_FLAC))) {
+            ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_FLAC) ||
+            ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_VORBIS))) {
             ALOGD("offload disabled for multi-channel AAC and FLAC format");
             return false;
         }
@@ -1605,11 +1606,16 @@
         }
     } else if (offloadInfo.duration_us < OFFLOAD_DEFAULT_MIN_DURATION_SECS * 1000000) {
         ALOGD("copl: Offload denied by duration < default min(=%u)", OFFLOAD_DEFAULT_MIN_DURATION_SECS);
-        //duration checks only valid for MP3/AAC formats,
+        //duration checks only valid for MP3/AAC/VORBIS/WMA/ALAC/APE formats,
         //do not check duration for other audio formats, e.g. dolby AAC/AC3 and amrwb+ formats
         if ((offloadInfo.format == AUDIO_FORMAT_MP3) ||
             ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC) ||
             ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_FLAC) ||
+            ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_VORBIS) ||
+            ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_WMA) ||
+            ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_WMA_PRO) ||
+            ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_ALAC) ||
+            ((offloadInfo.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_APE) ||
             pcmOffload)
             return false;
     }
diff --git a/post_proc/Android.mk b/post_proc/Android.mk
index 6ed1416..be70166 100644
--- a/post_proc/Android.mk
+++ b/post_proc/Android.mk
@@ -13,23 +13,58 @@
 	bass_boost.c \
 	virtualizer.c \
 	reverb.c \
-	effect_api.c
+	effect_api.c \
+	effect_util.c \
+        hw_accelerator.c
 
 LOCAL_CFLAGS+= -O2 -fvisibility=hidden
 
+ifneq ($(strip $(AUDIO_FEATURE_DISABLED_DTS_EAGLE)),true)
+    LOCAL_CFLAGS += -DDTS_EAGLE
+endif
+
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
 	liblog \
-	libtinyalsa
+	libtinyalsa \
+	libdl
 
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_MODULE_RELATIVE_PATH := soundfx
 LOCAL_MODULE:= libqcompostprocbundle
 
+LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
 LOCAL_C_INCLUDES := \
 	external/tinyalsa/include \
         $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include \
 	$(call include-path-for, audio-effects)
 
 include $(BUILD_SHARED_LIBRARY)
+
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HW_ACCELERATED_EFFECTS)),true)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := EffectsHwAcc.cpp
+
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-effects)
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libeffects
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS += -O2 -fvisibility=hidden
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_DTS_EAGLE)), true)
+LOCAL_CFLAGS += -DHW_ACC_HPX
+endif
+
+LOCAL_MODULE:= libhwacceffectswrapper
+
+include $(BUILD_STATIC_LIBRARY)
+endif
diff --git a/post_proc/EffectsHwAcc.cpp b/post_proc/EffectsHwAcc.cpp
new file mode 100644
index 0000000..0e4c55a
--- /dev/null
+++ b/post_proc/EffectsHwAcc.cpp
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "EffectsHwAcc"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <media/EffectsFactoryApi.h>
+#include <audio_effects/effect_hwaccelerator.h>
+#include "EffectsHwAcc.h"
+
+namespace android {
+
+#define FRAME_SIZE(format)   ((format == AUDIO_FORMAT_PCM_24_BIT_PACKED) ? \
+                              3 /* bytes for 24 bit */ : \
+                              (format == AUDIO_FORMAT_PCM_16_BIT) ? \
+                               sizeof(uint16_t) : sizeof(uint8_t))
+// ----------------------------------------------------------------------------
+EffectsHwAcc::EffectsBufferProvider::EffectsBufferProvider()
+             : AudioBufferProvider(), mEffectsHandle(NULL),
+               mInputBuffer(NULL), mOutputBuffer(NULL),
+               mInputBufferFrameCountOffset(0)
+{
+}
+
+EffectsHwAcc::EffectsBufferProvider::~EffectsBufferProvider()
+{
+    ALOGV(" deleting HwAccEffBufferProvider");
+
+    if (mEffectsHandle)
+        EffectRelease(mEffectsHandle);
+    if (mInputBuffer)
+        free(mInputBuffer);
+    if (mOutputBuffer)
+        free(mOutputBuffer);
+}
+
+status_t EffectsHwAcc::EffectsBufferProvider::getNextBuffer(
+                       AudioBufferProvider::Buffer *pBuffer,
+                       int64_t pts)
+{
+    ALOGV("EffectsBufferProvider::getNextBuffer");
+
+    size_t reqInputFrameCount, frameCount, offset;
+    size_t reqOutputFrameCount = pBuffer->frameCount;
+    int ret = 0;
+
+    if (mTrackBufferProvider != NULL) {
+        while (1) {
+            reqInputFrameCount = ((reqOutputFrameCount *
+                                   mEffectsConfig.inputCfg.samplingRate)/
+                                   mEffectsConfig.outputCfg.samplingRate) +
+                                   (((reqOutputFrameCount *
+                                     mEffectsConfig.inputCfg.samplingRate)%
+                                     mEffectsConfig.outputCfg.samplingRate) ? 1 : 0);
+            ALOGV("InputFrameCount: %d, OutputFrameCount: %d, InputBufferFrameCountOffset: %d",
+                  reqInputFrameCount, reqOutputFrameCount,
+                  mInputBufferFrameCountOffset);
+            frameCount = reqInputFrameCount - mInputBufferFrameCountOffset;
+            offset = mInputBufferFrameCountOffset *
+                     FRAME_SIZE(mEffectsConfig.inputCfg.format) *
+                     popcount(mEffectsConfig.inputCfg.channels);
+            while (frameCount) {
+                pBuffer->frameCount = frameCount;
+                ret = mTrackBufferProvider->getNextBuffer(pBuffer, pts);
+                if (ret == OK) {
+                    int bytesInBuffer = pBuffer->frameCount *
+                                        FRAME_SIZE(mEffectsConfig.inputCfg.format) *
+                                        popcount(mEffectsConfig.inputCfg.channels);
+                    memcpy((char *)mInputBuffer+offset, pBuffer->i8, bytesInBuffer);
+                    frameCount -= pBuffer->frameCount;
+                    mInputBufferFrameCountOffset += pBuffer->frameCount;
+                    offset += bytesInBuffer;
+                    mTrackBufferProvider->releaseBuffer(pBuffer);
+                } else
+                    break;
+            }
+            if (ret == OK) {
+                mEffectsConfig.inputCfg.buffer.frameCount = reqInputFrameCount;
+                mEffectsConfig.inputCfg.buffer.raw = (void *)mInputBuffer;
+                mEffectsConfig.outputCfg.buffer.frameCount = reqOutputFrameCount;
+                mEffectsConfig.outputCfg.buffer.raw = (void *)mOutputBuffer;
+
+                ret = (*mEffectsHandle)->process(mEffectsHandle,
+                                              &mEffectsConfig.inputCfg.buffer,
+                                              &mEffectsConfig.outputCfg.buffer);
+                if (ret == -ENODATA) {
+                    ALOGV("Continue to provide more data for initial buffering");
+                    mInputBufferFrameCountOffset -= reqInputFrameCount;
+                    continue;
+                }
+                if (ret > 0)
+                    mInputBufferFrameCountOffset -= reqInputFrameCount;
+                pBuffer->raw = (void *)mOutputBuffer;
+                pBuffer->frameCount = reqOutputFrameCount;
+            }
+            return ret;
+        }
+    } else {
+        ALOGE("EffBufferProvider::getNextBuffer() error: NULL track buffer provider");
+        return NO_INIT;
+    }
+}
+
+void EffectsHwAcc::EffectsBufferProvider::releaseBuffer(
+                                          AudioBufferProvider::Buffer *pBuffer)
+{
+    ALOGV("EffBufferProvider::releaseBuffer()");
+    if (this->mTrackBufferProvider != NULL) {
+        pBuffer->frameCount = 0;
+        pBuffer->raw = NULL;
+    } else {
+        ALOGE("HwAccEffectsBufferProvider::releaseBuffer() error: NULL track buffer provider");
+    }
+}
+
+EffectsHwAcc::EffectsHwAcc(uint32_t sampleRate)
+             : mEnabled(false), mFd(-1), mBufferProvider(NULL),
+               mInputSampleRate(sampleRate), mOutputSampleRate(sampleRate)
+{
+}
+
+EffectsHwAcc::~EffectsHwAcc()
+{
+    ALOGV("deleting EffectsHwAcc");
+
+    if (mBufferProvider)
+        delete mBufferProvider;
+}
+
+void EffectsHwAcc::setSampleRate(uint32_t inpSR, uint32_t outSR)
+{
+    mInputSampleRate = inpSR;
+    mOutputSampleRate = outSR;
+}
+
+void EffectsHwAcc::unprepareEffects(AudioBufferProvider **bufferProvider)
+{
+    ALOGV("EffectsHwAcc::unprepareEffects");
+
+    EffectsBufferProvider *pHwAccbp = mBufferProvider;
+    if (mBufferProvider != NULL) {
+        ALOGV(" deleting h/w accelerator EffectsBufferProvider");
+        int cmdStatus, status;
+        uint32_t replySize = sizeof(int);
+
+        replySize = sizeof(int);
+        status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
+                                              EFFECT_CMD_DISABLE,
+                                              0 /*cmdSize*/, NULL /*pCmdData*/,
+                                              &replySize, &cmdStatus /*pReplyData*/);
+        if ((status != 0) || (cmdStatus != 0))
+            ALOGE("error %d while enabling hw acc effects", status);
+
+        *bufferProvider = pHwAccbp->mTrackBufferProvider;
+        delete mBufferProvider;
+
+        mBufferProvider = NULL;
+    } else {
+        ALOGV(" nothing to do, no h/w accelerator effects to delete");
+    }
+    mEnabled = false;
+}
+
+status_t EffectsHwAcc::prepareEffects(AudioBufferProvider **bufferProvider,
+                                      int sessionId,
+                                      audio_channel_mask_t channelMask,
+                                      int frameCount)
+{
+    ALOGV("EffectsHwAcc::prepareAccEffects");
+
+    // discard the previous hw acc effects if there was one
+    unprepareEffects(bufferProvider);
+
+    EffectsBufferProvider* pHwAccbp = new EffectsBufferProvider();
+    int32_t status;
+    int cmdStatus;
+    uint32_t replySize;
+    uint32_t size = (sizeof(effect_param_t) + 2 * sizeof(int32_t) - 1) /
+                    (sizeof(uint32_t) + 1);
+    uint32_t buf32[size];
+    effect_param_t *param = (effect_param_t *)buf32;
+
+    uint32_t i, numEffects = 0;
+    effect_descriptor_t hwAccFxDesc;
+    int ret = EffectQueryNumberEffects(&numEffects);
+    if (ret != 0) {
+        ALOGE("AudioMixer() error %d querying number of effects", ret);
+        goto noEffectsForActiveTrack;
+    }
+    ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
+
+    for (i = 0 ; i < numEffects ; i++) {
+        if (EffectQueryEffect(i, &hwAccFxDesc) == 0) {
+            if (memcmp(&hwAccFxDesc.type, EFFECT_UIID_HWACCELERATOR,
+                       sizeof(effect_uuid_t)) == 0) {
+                ALOGI("found effect \"%s\" from %s",
+                        hwAccFxDesc.name, hwAccFxDesc.implementor);
+                break;
+            }
+        }
+    }
+    if (i == numEffects) {
+        ALOGW("H/W accelerated effects library not found");
+        goto noEffectsForActiveTrack;
+    }
+    if (EffectCreate(&hwAccFxDesc.uuid, sessionId, -1 /*ioId not relevant here*/,
+                     &pHwAccbp->mEffectsHandle) != 0) {
+        ALOGE("prepareEffects fails: error creating effect");
+        goto noEffectsForActiveTrack;
+    }
+
+    // channel input configuration will be overridden per-track
+    pHwAccbp->mEffectsConfig.inputCfg.channels = channelMask;
+    pHwAccbp->mEffectsConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+    pHwAccbp->mEffectsConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    pHwAccbp->mEffectsConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    pHwAccbp->mEffectsConfig.inputCfg.samplingRate = mInputSampleRate;
+    pHwAccbp->mEffectsConfig.outputCfg.samplingRate = mOutputSampleRate;
+    pHwAccbp->mEffectsConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+    pHwAccbp->mEffectsConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
+    pHwAccbp->mEffectsConfig.outputCfg.buffer.frameCount = frameCount;
+    pHwAccbp->mEffectsConfig.inputCfg.mask = EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS |
+                                             EFFECT_CONFIG_FORMAT | EFFECT_CONFIG_ACC_MODE;
+    pHwAccbp->mEffectsConfig.outputCfg.mask = pHwAccbp->mEffectsConfig.inputCfg.mask;
+
+    // Configure hw acc effects
+    replySize = sizeof(int);
+    status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
+                                          EFFECT_CMD_SET_CONFIG,
+                                          sizeof(effect_config_t) /*cmdSize*/,
+                                          &pHwAccbp->mEffectsConfig /*pCmdData*/,
+                                          &replySize, &cmdStatus /*pReplyData*/);
+    if ((status != 0) || (cmdStatus != 0)) {
+        ALOGE("error %d while configuring h/w acc effects", status);
+        goto noEffectsForActiveTrack;
+    }
+    replySize = sizeof(int);
+    status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
+                                          EFFECT_CMD_HW_ACC,
+                                          sizeof(frameCount) /*cmdSize*/,
+                                          &frameCount /*pCmdData*/,
+                                          &replySize,
+                                          &cmdStatus /*pReplyData*/);
+    if ((status != 0) || (cmdStatus != 0)) {
+        ALOGE("error %d while enabling h/w acc effects", status);
+       goto noEffectsForActiveTrack;
+    }
+    replySize = sizeof(int);
+    status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
+                                          EFFECT_CMD_ENABLE,
+                                          0 /*cmdSize*/, NULL /*pCmdData*/,
+                                          &replySize, &cmdStatus /*pReplyData*/);
+    if ((status != 0) || (cmdStatus != 0)) {
+        ALOGE("error %d while enabling h/w acc effects", status);
+        goto noEffectsForActiveTrack;
+    }
+
+    param->psize = sizeof(int32_t);
+    *(int32_t *)param->data = HW_ACCELERATOR_FD;
+    param->vsize = sizeof(int32_t);
+    replySize = sizeof(effect_param_t) +
+                ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) +
+                param->vsize;
+    status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
+                                          EFFECT_CMD_GET_PARAM,
+                                          sizeof(effect_param_t) + param->psize,
+                                          param, &replySize, param);
+    if ((param->status != 0) || (*(int32_t *)(param->data + sizeof(int32_t)) <= 0)) {
+            ALOGE("error %d while enabling h/w acc effects", status);
+            goto noEffectsForActiveTrack;
+    }
+    mFd = *(int32_t *)(param->data + sizeof(int32_t));
+
+    pHwAccbp->mInputBuffer = calloc(6*frameCount,
+                                    /* 6 times buffering to account for an input of
+                                       192kHz to an output of 32kHz - may be a least
+                                       sampling rate of rendering device */
+                                    FRAME_SIZE(pHwAccbp->mEffectsConfig.inputCfg.format) *
+                                    popcount(channelMask));
+    if (!pHwAccbp->mInputBuffer)
+        goto noEffectsForActiveTrack;
+
+    pHwAccbp->mOutputBuffer = calloc(frameCount,
+                                     FRAME_SIZE(pHwAccbp->mEffectsConfig.outputCfg.format) *
+                                     popcount(AUDIO_CHANNEL_OUT_STEREO));
+    if (!pHwAccbp->mOutputBuffer) {
+        free(pHwAccbp->mInputBuffer);
+        goto noEffectsForActiveTrack;
+    }
+    // initialization successful:
+    // - keep track of the real buffer provider in case it was set before
+    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
+    mBufferProvider = pHwAccbp;
+    *bufferProvider = pHwAccbp;
+
+    mEnabled = true;
+    return NO_ERROR;
+
+noEffectsForActiveTrack:
+    delete pHwAccbp;
+    mBufferProvider = NULL;
+    return NO_INIT;
+}
+
+void EffectsHwAcc::setBufferProvider(AudioBufferProvider **bufferProvider,
+                                     AudioBufferProvider **trackBufferProvider)
+{
+    ALOGV("setBufferProvider");
+    if (mBufferProvider &&
+        (mBufferProvider->mTrackBufferProvider != *bufferProvider)) {
+        *trackBufferProvider = mBufferProvider;
+        mBufferProvider->mTrackBufferProvider = *bufferProvider;
+    }
+}
+
+#ifdef HW_ACC_HPX
+void EffectsHwAcc::updateHPXState(uint32_t state)
+{
+    EffectsBufferProvider *pHwAccbp = mBufferProvider;
+    if (pHwAccbp) {
+        ALOGV("updateHPXState: %d", state);
+        int cmdStatus, status;
+        uint32_t replySize = sizeof(int);
+        uint32_t data = state;
+        uint32_t size = (sizeof(effect_param_t) + 2 * sizeof(int32_t));
+        uint32_t buf32[size];
+        effect_param_t *param = (effect_param_t *)buf32;
+
+        param->psize = sizeof(int32_t);
+        *(int32_t *)param->data = HW_ACCELERATOR_HPX_STATE;
+        param->vsize = sizeof(int32_t);
+        memcpy((param->data + param->psize), &data, param->vsize);
+        status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
+                                          EFFECT_CMD_SET_PARAM,
+                                          sizeof(effect_param_t) + param->psize +
+                                          param->vsize,
+                                          param, &replySize, &cmdStatus);
+
+        if ((status != 0) || (cmdStatus != 0))
+            ALOGE("error %d while updating HW ACC HPX BYPASS state", status);
+    }
+}
+#endif
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/post_proc/EffectsHwAcc.h b/post_proc/EffectsHwAcc.h
new file mode 100644
index 0000000..6420a9b
--- /dev/null
+++ b/post_proc/EffectsHwAcc.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_EFFECTS_HW_ACC_H
+#define ANDROID_EFFECTS_HW_ACC_H
+
+#include <media/AudioBufferProvider.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+class EffectsHwAcc {
+public:
+    EffectsHwAcc(uint32_t sampleRate);
+    virtual ~EffectsHwAcc();
+
+    virtual void setSampleRate(uint32_t inpSR, uint32_t outSR);
+    virtual void unprepareEffects(AudioBufferProvider **trackBufferProvider);
+    virtual status_t prepareEffects(AudioBufferProvider **trackBufferProvider,
+                            int sessionId, audio_channel_mask_t channelMask,
+                            int frameCount);
+    virtual void setBufferProvider(AudioBufferProvider **bufferProvider,
+                           AudioBufferProvider **trackBufferProvider);
+#ifdef HW_ACC_HPX
+    virtual void updateHPXState(uint32_t state);
+#endif
+
+    /* AudioBufferProvider that wraps a track AudioBufferProvider by a call to
+       h/w accelerated effect */
+    class EffectsBufferProvider : public AudioBufferProvider {
+    public:
+        EffectsBufferProvider();
+        virtual ~EffectsBufferProvider();
+
+        virtual status_t getNextBuffer(Buffer* buffer, int64_t pts);
+        virtual void releaseBuffer(Buffer* buffer);
+
+        AudioBufferProvider* mTrackBufferProvider;
+        effect_handle_t    mEffectsHandle;
+        effect_config_t    mEffectsConfig;
+
+        void *mInputBuffer;
+        void *mOutputBuffer;
+        uint32_t mInputBufferFrameCountOffset;
+    };
+
+    bool mEnabled;
+    int32_t mFd;
+
+    EffectsBufferProvider* mBufferProvider;
+
+private:
+    uint32_t mInputSampleRate;
+    uint32_t mOutputSampleRate;
+};
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_EFFECTS_HW_ACC_H
diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c
index e2c6d9a..ad1e7c9 100644
--- a/post_proc/bass_boost.c
+++ b/post_proc/bass_boost.c
@@ -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
@@ -17,14 +17,17 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "offload_effect_bass_boost"
-#define LOG_NDEBUG 0
+#define LOG_TAG "offload_effect_bass"
+//#define LOG_NDEBUG 0
 
 #include <cutils/list.h>
 #include <cutils/log.h>
+#include <cutils/properties.h>
 #include <tinyalsa/asoundlib.h>
 #include <sound/audio_effects.h>
 #include <audio_effects/effect_bassboost.h>
+#include <stdlib.h>
+#include <dlfcn.h>
 
 #include "effect_api.h"
 #include "bass_boost.h"
@@ -41,41 +44,44 @@
         "The Android Open Source Project",
 };
 
+#define LIB_ACDB_LOADER "libacdbloader.so"
+#define PBE_CONF_APP_ID 0x00011134
+
+enum {
+        AUDIO_DEVICE_CAL_TYPE = 0,
+        AUDIO_STREAM_CAL_TYPE,
+};
+
+typedef struct acdb_audio_cal_cfg {
+        uint32_t persist;
+        uint32_t snd_dev_id;
+        uint32_t dev_id;
+        int32_t acdb_dev_id;
+        uint32_t app_type;
+        uint32_t topo_id;
+        uint32_t sampling_rate;
+        uint32_t cal_type;
+        uint32_t module_id;
+        uint32_t param_id;
+} acdb_audio_cal_cfg_t;
+
+typedef int (*acdb_get_audio_cal_t) (void *, void *, uint32_t*);
+static int pbe_load_config(struct pbe_params *params);
+
 /*
- * Bassboost operations
+ * Bass operations
  */
-
-int bassboost_get_strength(bassboost_context_t *context)
+int bass_get_parameter(effect_context_t *context, effect_param_t *p,
+                       uint32_t *size)
 {
-    ALOGV("%s: ctxt %p, strength: %d", __func__,
-                      context,  context->strength);
-    return context->strength;
-}
-
-int bassboost_set_strength(bassboost_context_t *context, uint32_t strength)
-{
-    ALOGV("%s: ctxt %p, strength: %d", __func__, context, strength);
-    context->strength = strength;
-
-    offload_bassboost_set_strength(&(context->offload_bass), strength);
-    if (context->ctl)
-        offload_bassboost_send_params(context->ctl, context->offload_bass,
-                                      OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
-                                      OFFLOAD_SEND_BASSBOOST_STRENGTH);
-    return 0;
-}
-
-int bassboost_get_parameter(effect_context_t *context, effect_param_t *p,
-                            uint32_t *size)
-{
-    bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+    bass_context_t *bass_ctxt = (bass_context_t *)context;
     int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
     int32_t *param_tmp = (int32_t *)p->data;
     int32_t param = *param_tmp++;
     void *value = p->data + voffset;
     int i;
 
-    ALOGV("%s: ctxt %p, param %d", __func__, bass_ctxt, param);
+    ALOGV("%s", __func__);
 
     p->status = 0;
 
@@ -101,11 +107,19 @@
 
     switch (param) {
     case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
-        *(uint32_t *)value = 1;
+        ALOGV("%s: BASSBOOST_PARAM_STRENGTH_SUPPORTED", __func__);
+        if (bass_ctxt->active_index == BASS_BOOST)
+            *(uint32_t *)value = 1;
+        else
+            *(uint32_t *)value = 0;
         break;
 
     case BASSBOOST_PARAM_STRENGTH:
-        *(int16_t *)value = bassboost_get_strength(bass_ctxt);
+        ALOGV("%s: BASSBOOST_PARAM_STRENGTH", __func__);
+        if (bass_ctxt->active_index == BASS_BOOST)
+            *(int16_t *)value = bassboost_get_strength(&(bass_ctxt->bassboost_ctxt));
+        else
+            *(int16_t *)value = 0;
         break;
 
     default:
@@ -116,24 +130,34 @@
     return 0;
 }
 
-int bassboost_set_parameter(effect_context_t *context, effect_param_t *p,
-                            uint32_t size)
+int bass_set_parameter(effect_context_t *context, effect_param_t *p,
+                       uint32_t size __unused)
 {
-    bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+    bass_context_t *bass_ctxt = (bass_context_t *)context;
     int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
     void *value = p->data + voffset;
     int32_t *param_tmp = (int32_t *)p->data;
     int32_t param = *param_tmp++;
     uint32_t strength;
 
-    ALOGV("%s: ctxt %p, param %d", __func__, bass_ctxt, param);
+    ALOGV("%s", __func__);
 
     p->status = 0;
 
     switch (param) {
     case BASSBOOST_PARAM_STRENGTH:
-        strength = (uint32_t)(*(int16_t *)value);
-        bassboost_set_strength(bass_ctxt, strength);
+        ALOGV("%s BASSBOOST_PARAM_STRENGTH", __func__);
+        if (bass_ctxt->active_index == BASS_BOOST) {
+            strength = (uint32_t)(*(int16_t *)value);
+            bassboost_set_strength(&(bass_ctxt->bassboost_ctxt), strength);
+        } else {
+            /* stength supported only for BB and not for PBE, but do not
+             * return error for unsupported case, as it fails cts test
+             */
+            ALOGD("%s ignore set strength, index %d",
+                  __func__, bass_ctxt->active_index);
+            break;
+        }
         break;
     default:
         p->status = -EINVAL;
@@ -143,43 +167,188 @@
     return 0;
 }
 
+int bass_set_device(effect_context_t *context, uint32_t device)
+{
+    bass_context_t *bass_ctxt = (bass_context_t *)context;
+
+    if (device == AUDIO_DEVICE_OUT_SPEAKER) {
+        bass_ctxt->active_index = BASS_PBE;
+        ALOGV("%s: set PBE mode, device: %x", __func__, device);
+    } else if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+        device == AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+        device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) {
+        ALOGV("%s: set BB mode, device: %x", __func__, device);
+        bass_ctxt->active_index = BASS_BOOST;
+    } else {
+        ALOGI("%s: disabled by device: %x", __func__, device);
+        bass_ctxt->active_index = BASS_INVALID;
+    }
+
+    bassboost_set_device((effect_context_t *)&(bass_ctxt->bassboost_ctxt), device);
+    pbe_set_device((effect_context_t *)&(bass_ctxt->pbe_ctxt), device);
+
+    return 0;
+}
+
+int bass_reset(effect_context_t *context)
+{
+    bass_context_t *bass_ctxt = (bass_context_t *)context;
+
+    bassboost_reset((effect_context_t *)&(bass_ctxt->bassboost_ctxt));
+    pbe_reset((effect_context_t *)&(bass_ctxt->pbe_ctxt));
+
+    return 0;
+}
+
+int bass_init(effect_context_t *context)
+{
+    bass_context_t *bass_ctxt = (bass_context_t *)context;
+
+    // convery i/o channel config to sub effects
+    bass_ctxt->bassboost_ctxt.common.config = context->config;
+    bass_ctxt->pbe_ctxt.common.config = context->config;
+
+    ALOGV("%s", __func__);
+
+    bass_ctxt->active_index = BASS_BOOST;
+
+
+    bassboost_init((effect_context_t *)&(bass_ctxt->bassboost_ctxt));
+    pbe_init((effect_context_t *)&(bass_ctxt->pbe_ctxt));
+
+    return 0;
+}
+
+int bass_enable(effect_context_t *context)
+{
+    bass_context_t *bass_ctxt = (bass_context_t *)context;
+
+    ALOGV("%s", __func__);
+
+    bassboost_enable((effect_context_t *)&(bass_ctxt->bassboost_ctxt));
+    pbe_enable((effect_context_t *)&(bass_ctxt->pbe_ctxt));
+
+    return 0;
+}
+
+int bass_disable(effect_context_t *context)
+{
+    bass_context_t *bass_ctxt = (bass_context_t *)context;
+
+    ALOGV("%s", __func__);
+
+    bassboost_disable((effect_context_t *)&(bass_ctxt->bassboost_ctxt));
+    pbe_disable((effect_context_t *)&(bass_ctxt->pbe_ctxt));
+
+    return 0;
+}
+
+int bass_start(effect_context_t *context, output_context_t *output)
+{
+    bass_context_t *bass_ctxt = (bass_context_t *)context;
+
+    ALOGV("%s", __func__);
+
+    bassboost_start((effect_context_t *)&(bass_ctxt->bassboost_ctxt), output);
+    pbe_start((effect_context_t *)&(bass_ctxt->pbe_ctxt), output);
+
+    return 0;
+}
+
+int bass_stop(effect_context_t *context, output_context_t *output)
+{
+    bass_context_t *bass_ctxt = (bass_context_t *)context;
+
+    ALOGV("%s", __func__);
+
+    bassboost_stop((effect_context_t *)&(bass_ctxt->bassboost_ctxt), output);
+    pbe_stop((effect_context_t *)&(bass_ctxt->pbe_ctxt), output);
+
+    return 0;
+}
+
+int bass_set_mode(effect_context_t *context,  int32_t hw_acc_fd)
+{
+    bass_context_t *bass_ctxt = (bass_context_t *)context;
+
+    ALOGV("%s", __func__);
+
+    bassboost_set_mode((effect_context_t *)&(bass_ctxt->bassboost_ctxt), hw_acc_fd);
+    pbe_set_mode((effect_context_t *)&(bass_ctxt->pbe_ctxt), hw_acc_fd);
+
+    return 0;
+}
+
+#undef LOG_TAG
+#define LOG_TAG "offload_effect_bb"
+/*
+ * Bassboost operations
+ */
+
+int bassboost_get_strength(bassboost_context_t *context)
+{
+    ALOGV("%s: ctxt %p, strength: %d", __func__,
+                      context,  context->strength);
+    return context->strength;
+}
+
+int bassboost_set_strength(bassboost_context_t *context, uint32_t strength)
+{
+    ALOGV("%s: ctxt %p, strength: %d", __func__, context, strength);
+    context->strength = strength;
+
+    offload_bassboost_set_strength(&(context->offload_bass), strength);
+    if (context->ctl)
+        offload_bassboost_send_params(context->ctl, &context->offload_bass,
+                                      OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
+                                      OFFLOAD_SEND_BASSBOOST_STRENGTH);
+    if (context->hw_acc_fd > 0)
+        hw_acc_bassboost_send_params(context->hw_acc_fd,
+                                     &context->offload_bass,
+                                     OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
+                                     OFFLOAD_SEND_BASSBOOST_STRENGTH);
+    return 0;
+}
+
 int bassboost_set_device(effect_context_t *context, uint32_t device)
 {
     bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
 
     ALOGV("%s: ctxt %p, device 0x%x", __func__, bass_ctxt, device);
     bass_ctxt->device = device;
-    if((device == AUDIO_DEVICE_OUT_SPEAKER) ||
-       (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) ||
-       (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) ||
-#ifdef AFE_PROXY_ENABLED
-       (device == AUDIO_DEVICE_OUT_PROXY) ||
-#endif
-       (device == AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
-       (device == AUDIO_DEVICE_OUT_USB_ACCESSORY) ||
-       (device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET)) {
-        if (!bass_ctxt->temp_disabled) {
-            if (effect_is_active(&bass_ctxt->common)) {
-                offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false);
-                if (bass_ctxt->ctl)
-                    offload_bassboost_send_params(bass_ctxt->ctl,
-                                                  bass_ctxt->offload_bass,
-                                                  OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
-            }
-            bass_ctxt->temp_disabled = true;
-        }
-        ALOGI("%s: ctxt %p, disabled based on device", __func__, bass_ctxt);
-    } else {
+    if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET ||
+        device == AUDIO_DEVICE_OUT_WIRED_HEADPHONE ||
+        device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) {
         if (bass_ctxt->temp_disabled) {
             if (effect_is_active(&bass_ctxt->common)) {
                 offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true);
                 if (bass_ctxt->ctl)
                     offload_bassboost_send_params(bass_ctxt->ctl,
-                                                  bass_ctxt->offload_bass,
+                                                  &bass_ctxt->offload_bass,
                                                   OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+                if (bass_ctxt->hw_acc_fd > 0)
+                    hw_acc_bassboost_send_params(bass_ctxt->hw_acc_fd,
+                                                 &bass_ctxt->offload_bass,
+                                                 OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
             }
             bass_ctxt->temp_disabled = false;
         }
+    } else {
+        if (!bass_ctxt->temp_disabled) {
+            if (effect_is_active(&bass_ctxt->common)) {
+                offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false);
+                if (bass_ctxt->ctl)
+                    offload_bassboost_send_params(bass_ctxt->ctl,
+                                                  &bass_ctxt->offload_bass,
+                                                  OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+                if (bass_ctxt->hw_acc_fd > 0)
+                    hw_acc_bassboost_send_params(bass_ctxt->hw_acc_fd,
+                                                 &bass_ctxt->offload_bass,
+                                                 OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+            }
+            bass_ctxt->temp_disabled = true;
+        }
+        ALOGI("%s: ctxt %p, disabled based on device", __func__, bass_ctxt);
     }
     offload_bassboost_set_device(&(bass_ctxt->offload_bass), device);
     return 0;
@@ -216,6 +385,7 @@
 
     set_config(context, &context->config);
 
+    bass_ctxt->hw_acc_fd = -1;
     bass_ctxt->temp_disabled = false;
     memset(&(bass_ctxt->offload_bass), 0, sizeof(struct bass_boost_params));
 
@@ -233,9 +403,14 @@
         offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true);
         if (bass_ctxt->ctl && bass_ctxt->strength)
             offload_bassboost_send_params(bass_ctxt->ctl,
-                                          bass_ctxt->offload_bass,
+                                          &bass_ctxt->offload_bass,
                                           OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
                                           OFFLOAD_SEND_BASSBOOST_STRENGTH);
+        if ((bass_ctxt->hw_acc_fd > 0) && (bass_ctxt->strength))
+            hw_acc_bassboost_send_params(bass_ctxt->hw_acc_fd,
+                                         &bass_ctxt->offload_bass,
+                                         OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
+                                         OFFLOAD_SEND_BASSBOOST_STRENGTH);
     }
     return 0;
 }
@@ -249,8 +424,12 @@
         offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false);
         if (bass_ctxt->ctl)
             offload_bassboost_send_params(bass_ctxt->ctl,
-                                          bass_ctxt->offload_bass,
+                                          &bass_ctxt->offload_bass,
                                           OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+        if (bass_ctxt->hw_acc_fd > 0)
+            hw_acc_bassboost_send_params(bass_ctxt->hw_acc_fd,
+                                         &bass_ctxt->offload_bass,
+                                         OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
     }
     return 0;
 }
@@ -262,19 +441,278 @@
     ALOGV("%s: ctxt %p, ctl %p, strength %d", __func__, bass_ctxt,
                                    output->ctl, bass_ctxt->strength);
     bass_ctxt->ctl = output->ctl;
-    if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)))
+    if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) {
         if (bass_ctxt->ctl)
-            offload_bassboost_send_params(bass_ctxt->ctl, bass_ctxt->offload_bass,
+            offload_bassboost_send_params(bass_ctxt->ctl, &bass_ctxt->offload_bass,
                                           OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
                                           OFFLOAD_SEND_BASSBOOST_STRENGTH);
+        if (bass_ctxt->hw_acc_fd > 0)
+            hw_acc_bassboost_send_params(bass_ctxt->hw_acc_fd,
+                                         &bass_ctxt->offload_bass,
+                                         OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
+                                         OFFLOAD_SEND_BASSBOOST_STRENGTH);
+    }
     return 0;
 }
 
-int bassboost_stop(effect_context_t *context, output_context_t *output)
+int bassboost_stop(effect_context_t *context, output_context_t *output __unused)
 {
     bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
 
     ALOGV("%s: ctxt %p", __func__, bass_ctxt);
+    if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)) &&
+        bass_ctxt->ctl) {
+        struct bass_boost_params bassboost;
+        bassboost.enable_flag = false;
+        offload_bassboost_send_params(bass_ctxt->ctl, &bassboost,
+                                      OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+    }
     bass_ctxt->ctl = NULL;
     return 0;
 }
+
+int bassboost_set_mode(effect_context_t *context, int32_t hw_acc_fd)
+{
+    bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, bass_ctxt);
+    bass_ctxt->hw_acc_fd = hw_acc_fd;
+    if ((bass_ctxt->hw_acc_fd > 0) &&
+        (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))))
+        hw_acc_bassboost_send_params(bass_ctxt->hw_acc_fd,
+                                     &bass_ctxt->offload_bass,
+                                     OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
+                                     OFFLOAD_SEND_BASSBOOST_STRENGTH);
+    return 0;
+}
+
+#undef LOG_TAG
+#define LOG_TAG "offload_effect_pbe"
+/*
+ * PBE operations
+ */
+
+int pbe_set_device(effect_context_t *context, uint32_t device)
+{
+    pbe_context_t *pbe_ctxt = (pbe_context_t *)context;
+    char          propValue[PROPERTY_VALUE_MAX];
+    bool          pbe_enabled_by_prop = false;
+
+    ALOGV("%s: device: %d", __func__, device);
+    pbe_ctxt->device = device;
+
+    if (property_get("audio.safx.pbe.enabled", propValue, NULL)) {
+        pbe_enabled_by_prop = atoi(propValue) ||
+                              !strncmp("true", propValue, 4);
+    }
+
+    if (device == AUDIO_DEVICE_OUT_SPEAKER && pbe_enabled_by_prop == true) {
+        if (pbe_ctxt->temp_disabled) {
+            if (effect_is_active(&pbe_ctxt->common)) {
+                offload_pbe_set_enable_flag(&(pbe_ctxt->offload_pbe), true);
+                if (pbe_ctxt->ctl)
+                    offload_pbe_send_params(pbe_ctxt->ctl,
+                                        &pbe_ctxt->offload_pbe,
+                                        OFFLOAD_SEND_PBE_ENABLE_FLAG |
+                                        OFFLOAD_SEND_PBE_CONFIG);
+                if (pbe_ctxt->hw_acc_fd > 0)
+                    hw_acc_pbe_send_params(pbe_ctxt->hw_acc_fd,
+                                        &pbe_ctxt->offload_pbe,
+                                        OFFLOAD_SEND_PBE_ENABLE_FLAG |
+                                        OFFLOAD_SEND_PBE_CONFIG);
+            }
+            pbe_ctxt->temp_disabled = false;
+        }
+    } else {
+        if (!pbe_ctxt->temp_disabled) {
+            if (effect_is_active(&pbe_ctxt->common)) {
+                offload_pbe_set_enable_flag(&(pbe_ctxt->offload_pbe), false);
+                if (pbe_ctxt->ctl)
+                    offload_pbe_send_params(pbe_ctxt->ctl,
+                                        &pbe_ctxt->offload_pbe,
+                                        OFFLOAD_SEND_PBE_ENABLE_FLAG);
+                if (pbe_ctxt->hw_acc_fd > 0)
+                    hw_acc_pbe_send_params(pbe_ctxt->hw_acc_fd,
+                                        &pbe_ctxt->offload_pbe,
+                                        OFFLOAD_SEND_PBE_ENABLE_FLAG);
+            }
+            pbe_ctxt->temp_disabled = true;
+        }
+    }
+    offload_pbe_set_device(&(pbe_ctxt->offload_pbe), device);
+    return 0;
+}
+
+int pbe_reset(effect_context_t *context)
+{
+    pbe_context_t *pbe_ctxt = (pbe_context_t *)context;
+
+    return 0;
+}
+
+int pbe_init(effect_context_t *context)
+{
+    pbe_context_t *pbe_ctxt = (pbe_context_t *)context;
+
+    ALOGV("%s", __func__);
+    context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+    context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+    context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    context->config.inputCfg.samplingRate = 44100;
+    context->config.inputCfg.bufferProvider.getBuffer = NULL;
+    context->config.inputCfg.bufferProvider.releaseBuffer = NULL;
+    context->config.inputCfg.bufferProvider.cookie = NULL;
+    context->config.inputCfg.mask = EFFECT_CONFIG_ALL;
+    context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+    context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+    context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    context->config.outputCfg.samplingRate = 44100;
+    context->config.outputCfg.bufferProvider.getBuffer = NULL;
+    context->config.outputCfg.bufferProvider.releaseBuffer = NULL;
+    context->config.outputCfg.bufferProvider.cookie = NULL;
+    context->config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+    set_config(context, &context->config);
+
+    pbe_ctxt->hw_acc_fd = -1;
+    pbe_ctxt->temp_disabled = false;
+    memset(&(pbe_ctxt->offload_pbe), 0, sizeof(struct pbe_params));
+    pbe_load_config(&(pbe_ctxt->offload_pbe));
+
+    return 0;
+}
+
+int pbe_enable(effect_context_t *context)
+{
+    pbe_context_t *pbe_ctxt = (pbe_context_t *)context;
+
+    ALOGV("%s", __func__);
+
+    if (!offload_pbe_get_enable_flag(&(pbe_ctxt->offload_pbe)) &&
+        !(pbe_ctxt->temp_disabled)) {
+        offload_pbe_set_enable_flag(&(pbe_ctxt->offload_pbe), true);
+        if (pbe_ctxt->ctl)
+            offload_pbe_send_params(pbe_ctxt->ctl,
+                                    &pbe_ctxt->offload_pbe,
+                                    OFFLOAD_SEND_PBE_ENABLE_FLAG |
+                                    OFFLOAD_SEND_PBE_CONFIG);
+        if (pbe_ctxt->hw_acc_fd > 0)
+            hw_acc_pbe_send_params(pbe_ctxt->hw_acc_fd,
+                                   &pbe_ctxt->offload_pbe,
+                                   OFFLOAD_SEND_PBE_ENABLE_FLAG |
+                                   OFFLOAD_SEND_PBE_CONFIG);
+    }
+    return 0;
+}
+
+int pbe_disable(effect_context_t *context)
+{
+    pbe_context_t *pbe_ctxt = (pbe_context_t *)context;
+
+    ALOGV("%s", __func__);
+    if (offload_pbe_get_enable_flag(&(pbe_ctxt->offload_pbe))) {
+        offload_pbe_set_enable_flag(&(pbe_ctxt->offload_pbe), false);
+        if (pbe_ctxt->ctl)
+            offload_pbe_send_params(pbe_ctxt->ctl,
+                                    &pbe_ctxt->offload_pbe,
+                                    OFFLOAD_SEND_PBE_ENABLE_FLAG);
+        if (pbe_ctxt->hw_acc_fd > 0)
+            hw_acc_pbe_send_params(pbe_ctxt->hw_acc_fd,
+                                   &pbe_ctxt->offload_pbe,
+                                   OFFLOAD_SEND_PBE_ENABLE_FLAG);
+    }
+    return 0;
+}
+
+int pbe_start(effect_context_t *context, output_context_t *output)
+{
+    pbe_context_t *pbe_ctxt = (pbe_context_t *)context;
+
+    ALOGV("%s", __func__);
+    pbe_ctxt->ctl = output->ctl;
+    ALOGV("output->ctl: %p", output->ctl);
+    if (offload_pbe_get_enable_flag(&(pbe_ctxt->offload_pbe))) {
+        if (pbe_ctxt->ctl)
+            offload_pbe_send_params(pbe_ctxt->ctl, &pbe_ctxt->offload_pbe,
+                                    OFFLOAD_SEND_PBE_ENABLE_FLAG |
+                                    OFFLOAD_SEND_PBE_CONFIG);
+        if (pbe_ctxt->hw_acc_fd > 0)
+            hw_acc_pbe_send_params(pbe_ctxt->hw_acc_fd,
+                                   &pbe_ctxt->offload_pbe,
+                                   OFFLOAD_SEND_PBE_ENABLE_FLAG |
+                                   OFFLOAD_SEND_PBE_CONFIG);
+    }
+    return 0;
+}
+
+int pbe_stop(effect_context_t *context, output_context_t *output  __unused)
+{
+    pbe_context_t *pbe_ctxt = (pbe_context_t *)context;
+
+    ALOGV("%s", __func__);
+    pbe_ctxt->ctl = NULL;
+    return 0;
+}
+
+int pbe_set_mode(effect_context_t *context, int32_t hw_acc_fd)
+{
+    pbe_context_t *pbe_ctxt = (pbe_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, pbe_ctxt);
+    pbe_ctxt->hw_acc_fd = hw_acc_fd;
+    if ((pbe_ctxt->hw_acc_fd > 0) &&
+        (offload_pbe_get_enable_flag(&(pbe_ctxt->offload_pbe))))
+        hw_acc_pbe_send_params(pbe_ctxt->hw_acc_fd,
+                               &pbe_ctxt->offload_pbe,
+                               OFFLOAD_SEND_PBE_ENABLE_FLAG |
+                               OFFLOAD_SEND_PBE_CONFIG);
+    return 0;
+}
+
+static int pbe_load_config(struct pbe_params *params)
+{
+    int                  ret = 0;
+    uint32_t             len = 0;
+    uint32_t             propValue = 0;
+    uint32_t             pbe_app_type = PBE_CONF_APP_ID;
+    char                 propValueStr[PROPERTY_VALUE_MAX];
+    void                 *acdb_handle = NULL;
+    acdb_get_audio_cal_t acdb_get_audio_cal = NULL;
+    acdb_audio_cal_cfg_t cal_cfg = {0};
+
+    acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
+    if (acdb_handle == NULL) {
+        ALOGE("%s error opening library %s", __func__, LIB_ACDB_LOADER);
+        return -EFAULT;
+    }
+
+    acdb_get_audio_cal = (acdb_get_audio_cal_t)dlsym(acdb_handle,
+                                  "acdb_loader_get_audio_cal_v2");
+    if (acdb_get_audio_cal == NULL) {
+        dlclose(acdb_handle);
+        ALOGE("%s error resolving acdb func symbols", __func__);
+        return -EFAULT;
+    }
+    if (property_get("audio.safx.pbe.app.type", propValueStr, "0")) {
+        propValue = atoll(propValueStr);
+        if (propValue != 0) {
+            pbe_app_type = propValue;
+        }
+    }
+    ALOGD("%s pbe_app_type = 0x%.8x", __func__, pbe_app_type);
+
+    cal_cfg.persist              = 1;
+    cal_cfg.cal_type             = AUDIO_STREAM_CAL_TYPE;
+    cal_cfg.app_type             = pbe_app_type;
+    cal_cfg.module_id            = PBE_CONF_MODULE_ID;
+    cal_cfg.param_id             = PBE_CONF_PARAM_ID;
+
+    len = sizeof(params->config);
+    ret = acdb_get_audio_cal((void *)&cal_cfg, (void*)&(params->config), &len);
+    ALOGD("%s ret = %d, len = %u", __func__, ret, len);
+    if (ret == 0)
+        params->cfg_len = len;
+
+    dlclose(acdb_handle);
+    return ret;
+}
diff --git a/post_proc/bass_boost.h b/post_proc/bass_boost.h
index 430a07d..8bf51d3 100644
--- a/post_proc/bass_boost.h
+++ b/post_proc/bass_boost.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
@@ -22,6 +22,13 @@
 
 #include "bundle.h"
 
+enum {
+    BASS_INVALID = -1,
+    BASS_BOOST = 0,      // index of bassboost
+    BASS_PBE,        // index of PBE
+    BASS_COUNT       // totol number of bass type
+};
+
 extern const effect_descriptor_t bassboost_descriptor;
 
 typedef struct bassboost_context_s {
@@ -31,19 +38,61 @@
 
     // Offload vars
     struct mixer_ctl *ctl;
+    int hw_acc_fd;
     bool temp_disabled;
     uint32_t device;
     struct bass_boost_params offload_bass;
 } bassboost_context_t;
 
-int bassboost_get_parameter(effect_context_t *context, effect_param_t *p,
-                            uint32_t *size);
+typedef struct pbe_context_s {
+    effect_context_t common;
 
-int bassboost_set_parameter(effect_context_t *context, effect_param_t *p,
-                            uint32_t size);
+    // Offload vars
+    struct mixer_ctl *ctl;
+    int hw_acc_fd;
+    bool temp_disabled;
+    uint32_t device;
+    struct pbe_params offload_pbe;
+} pbe_context_t;
+
+typedef struct bass_context_s {
+    effect_context_t    common;
+    bassboost_context_t bassboost_ctxt;
+    pbe_context_t       pbe_ctxt;
+    int                 active_index;
+} bass_context_t;
+
+int bass_get_parameter(effect_context_t *context, effect_param_t *p,
+                       uint32_t *size);
+
+int bass_set_parameter(effect_context_t *context, effect_param_t *p,
+                       uint32_t size);
+
+int bass_set_device(effect_context_t *context,  uint32_t device);
+
+int bass_set_mode(effect_context_t *context,  int32_t hw_acc_fd);
+
+int bass_reset(effect_context_t *context);
+
+int bass_init(effect_context_t *context);
+
+int bass_enable(effect_context_t *context);
+
+int bass_disable(effect_context_t *context);
+
+int bass_start(effect_context_t *context, output_context_t *output);
+
+int bass_stop(effect_context_t *context, output_context_t *output);
+
+
+int bassboost_get_strength(bassboost_context_t *context);
+
+int bassboost_set_strength(bassboost_context_t *context, uint32_t strength);
 
 int bassboost_set_device(effect_context_t *context,  uint32_t device);
 
+int bassboost_set_mode(effect_context_t *context,  int32_t hw_acc_fd);
+
 int bassboost_reset(effect_context_t *context);
 
 int bassboost_init(effect_context_t *context);
@@ -56,4 +105,20 @@
 
 int bassboost_stop(effect_context_t *context, output_context_t *output);
 
+int pbe_set_device(effect_context_t *context,  uint32_t device);
+
+int pbe_set_mode(effect_context_t *context,  int32_t hw_acc_fd);
+
+int pbe_reset(effect_context_t *context);
+
+int pbe_init(effect_context_t *context);
+
+int pbe_enable(effect_context_t *context);
+
+int pbe_disable(effect_context_t *context);
+
+int pbe_start(effect_context_t *context, output_context_t *output);
+
+int pbe_stop(effect_context_t *context, output_context_t *output);
+
 #endif /* OFFLOAD_EFFECT_BASS_BOOST_H_ */
diff --git a/post_proc/bundle.c b/post_proc/bundle.c
index 0db2e37..e38a41c 100644
--- a/post_proc/bundle.c
+++ b/post_proc/bundle.c
@@ -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
@@ -15,10 +15,28 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
+ * This file was modified by DTS, Inc. The portions of the
+ * code modified by DTS, Inc are copyrighted and
+ * licensed separately, as follows:
+ *
+ * (C) 2014 DTS, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 #define LOG_TAG "offload_effect_bundle"
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <cutils/list.h>
 #include <cutils/log.h>
@@ -27,11 +45,16 @@
 #include <hardware/audio_effect.h>
 
 #include "bundle.h"
+#include "hw_accelerator.h"
 #include "equalizer.h"
 #include "bass_boost.h"
 #include "virtualizer.h"
 #include "reverb.h"
 
+#ifdef DTS_EAGLE
+#include "effect_util.h"
+#endif
+
 enum {
     EFFECT_STATE_UNINITIALIZED,
     EFFECT_STATE_INITIALIZED,
@@ -46,6 +69,7 @@
         &ins_env_reverb_descriptor,
         &aux_preset_reverb_descriptor,
         &ins_preset_reverb_descriptor,
+        &hw_accelerator_descriptor,
         NULL,
 };
 
@@ -190,6 +214,10 @@
 
     ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
 
+#ifdef DTS_EAGLE
+    create_effect_state_node(pcm_id);
+#endif
+
     if (lib_init() != 0)
         return init_status;
 
@@ -217,6 +245,7 @@
     if (!out_ctxt->mixer) {
         ALOGE("Failed to open mixer");
         out_ctxt->ctl = NULL;
+        out_ctxt->ref_ctl = NULL;
         ret = -EINVAL;
         free(out_ctxt);
         goto exit;
@@ -230,6 +259,7 @@
             free(out_ctxt);
             goto exit;
         }
+        out_ctxt->ref_ctl = out_ctxt->ctl;
     }
 
     list_init(&out_ctxt->effects_list);
@@ -285,6 +315,10 @@
 
     list_remove(&out_ctxt->outputs_list_node);
 
+#ifdef DTS_EAGLE
+    remove_effect_state_node(pcm_id);
+#endif
+
     free(out_ctxt);
 
 exit:
@@ -292,6 +326,131 @@
     return ret;
 }
 
+__attribute__ ((visibility ("default")))
+int offload_effects_bundle_set_hpx_state(bool hpx_state)
+{
+    int ret = 0;
+    struct listnode *node;
+
+    ALOGV("%s hpx state: %d", __func__, hpx_state);
+
+    if (lib_init() != 0)
+        return init_status;
+
+    pthread_mutex_lock(&lock);
+
+    if (hpx_state) {
+        /* set ramp down */
+        list_for_each(node, &active_outputs_list) {
+            output_context_t *out_ctxt = node_to_item(node,
+                                                      output_context_t,
+                                                      outputs_list_node);
+            struct soft_volume_params vol;
+            vol.master_gain = 0x0;
+            offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
+                              OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
+        }
+        /* wait for ramp down duration - 30msec */
+        usleep(30000);
+        /* disable effects modules */
+        list_for_each(node, &active_outputs_list) {
+            struct listnode *fx_node;
+            output_context_t *out_ctxt = node_to_item(node,
+                                                      output_context_t,
+                                                      outputs_list_node);
+            list_for_each(fx_node, &out_ctxt->effects_list) {
+                effect_context_t *fx_ctxt = node_to_item(fx_node,
+                                                         effect_context_t,
+                                                         output_node);
+                if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
+                    (fx_ctxt->ops.stop != NULL))
+                    fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
+            }
+            out_ctxt->ctl = NULL;
+        }
+        /* set the channel mixer */
+        list_for_each(node, &active_outputs_list) {
+            /* send command to set channel mixer */
+        }
+        /* enable hpx modules */
+        list_for_each(node, &active_outputs_list) {
+            output_context_t *out_ctxt = node_to_item(node,
+                                                      output_context_t,
+                                                      outputs_list_node);
+            offload_hpx_send_params(out_ctxt->ref_ctl,
+                                    OFFLOAD_SEND_HPX_STATE_ON);
+        }
+        /* wait for transition state - 50msec */
+        usleep(50000);
+        /* set ramp up */
+        list_for_each(node, &active_outputs_list) {
+            output_context_t *out_ctxt = node_to_item(node,
+                                                      output_context_t,
+                                                      outputs_list_node);
+            struct soft_volume_params vol;
+            vol.master_gain = 0x2000;
+            offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
+                              OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
+        }
+    } else {
+        /* set ramp down */
+        list_for_each(node, &active_outputs_list) {
+            output_context_t *out_ctxt = node_to_item(node,
+                                                      output_context_t,
+                                                      outputs_list_node);
+            struct soft_volume_params vol;
+            vol.master_gain = 0x0;
+            offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
+                              OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
+        }
+        /* wait for ramp down duration - 30msec */
+        usleep(30000);
+        /* disable effects modules */
+        list_for_each(node, &active_outputs_list) {
+            output_context_t *out_ctxt = node_to_item(node,
+                                                      output_context_t,
+                                                      outputs_list_node);
+            offload_hpx_send_params(out_ctxt->ref_ctl,
+                                    OFFLOAD_SEND_HPX_STATE_OFF);
+        }
+        /* set the channel mixer */
+        list_for_each(node, &active_outputs_list) {
+            /* send command to set channel mixer */
+        }
+        /* enable effects modules */
+        list_for_each(node, &active_outputs_list) {
+            struct listnode *fx_node;
+            output_context_t *out_ctxt = node_to_item(node,
+                                                      output_context_t,
+                                                      outputs_list_node);
+            out_ctxt->ctl = out_ctxt->ref_ctl;
+            list_for_each(fx_node, &out_ctxt->effects_list) {
+                effect_context_t *fx_ctxt = node_to_item(fx_node,
+                                                         effect_context_t,
+                                                         output_node);
+                if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
+                    (fx_ctxt->ops.start != NULL))
+                    fx_ctxt->ops.start(fx_ctxt, out_ctxt);
+            }
+        }
+        /* wait for transition state - 50msec */
+        usleep(50000);
+        /* set ramp up */
+        list_for_each(node, &active_outputs_list) {
+            output_context_t *out_ctxt = node_to_item(node,
+                                                      output_context_t,
+                                                      outputs_list_node);
+            struct soft_volume_params vol;
+            vol.master_gain = 0x2000;
+            offload_transition_soft_volume_send_params(out_ctxt->ref_ctl, vol,
+                              OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER);
+        }
+    }
+
+exit:
+    pthread_mutex_unlock(&lock);
+    return ret;
+}
 
 /*
  * Effect operations
@@ -351,6 +510,7 @@
         context->ops.set_parameter = equalizer_set_parameter;
         context->ops.get_parameter = equalizer_get_parameter;
         context->ops.set_device = equalizer_set_device;
+        context->ops.set_hw_acc_mode = equalizer_set_mode;
         context->ops.enable = equalizer_enable;
         context->ops.disable = equalizer_disable;
         context->ops.start = equalizer_start;
@@ -360,24 +520,26 @@
         eq_ctxt->ctl = NULL;
     } else if (memcmp(uuid, &bassboost_descriptor.uuid,
                sizeof(effect_uuid_t)) == 0) {
-        bassboost_context_t *bass_ctxt = (bassboost_context_t *)
-                                         calloc(1, sizeof(bassboost_context_t));
+        bass_context_t *bass_ctxt = (bass_context_t *)
+                                         calloc(1, sizeof(bass_context_t));
         if (bass_ctxt == NULL) {
             return -ENOMEM;
         }
         context = (effect_context_t *)bass_ctxt;
-        context->ops.init = bassboost_init;
-        context->ops.reset = bassboost_reset;
-        context->ops.set_parameter = bassboost_set_parameter;
-        context->ops.get_parameter = bassboost_get_parameter;
-        context->ops.set_device = bassboost_set_device;
-        context->ops.enable = bassboost_enable;
-        context->ops.disable = bassboost_disable;
-        context->ops.start = bassboost_start;
-        context->ops.stop = bassboost_stop;
+        context->ops.init = bass_init;
+        context->ops.reset = bass_reset;
+        context->ops.set_parameter = bass_set_parameter;
+        context->ops.get_parameter = bass_get_parameter;
+        context->ops.set_device = bass_set_device;
+        context->ops.set_hw_acc_mode = bass_set_mode;
+        context->ops.enable = bass_enable;
+        context->ops.disable = bass_disable;
+        context->ops.start = bass_start;
+        context->ops.stop = bass_stop;
 
         context->desc = &bassboost_descriptor;
-        bass_ctxt->ctl = NULL;
+        bass_ctxt->bassboost_ctxt.ctl = NULL;
+        bass_ctxt->pbe_ctxt.ctl = NULL;
     } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
                sizeof(effect_uuid_t)) == 0) {
         virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
@@ -391,6 +553,7 @@
         context->ops.set_parameter = virtualizer_set_parameter;
         context->ops.get_parameter = virtualizer_get_parameter;
         context->ops.set_device = virtualizer_set_device;
+        context->ops.set_hw_acc_mode = virtualizer_set_mode;
         context->ops.enable = virtualizer_enable;
         context->ops.disable = virtualizer_disable;
         context->ops.start = virtualizer_start;
@@ -417,6 +580,7 @@
         context->ops.set_parameter = reverb_set_parameter;
         context->ops.get_parameter = reverb_get_parameter;
         context->ops.set_device = reverb_set_device;
+        context->ops.set_hw_acc_mode = reverb_set_mode;
         context->ops.enable = reverb_enable;
         context->ops.disable = reverb_disable;
         context->ops.start = reverb_start;
@@ -429,7 +593,7 @@
         } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
                    sizeof(effect_uuid_t)) == 0) {
             context->desc = &ins_env_reverb_descriptor;
-            reverb_preset_init(reverb_ctxt);
+            reverb_insert_init(reverb_ctxt);
         } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
                    sizeof(effect_uuid_t)) == 0) {
             context->desc = &aux_preset_reverb_descriptor;
@@ -440,6 +604,27 @@
             reverb_preset_init(reverb_ctxt);
         }
         reverb_ctxt->ctl = NULL;
+    } else if (memcmp(uuid, &hw_accelerator_descriptor.uuid,
+               sizeof(effect_uuid_t)) == 0) {
+        hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)
+                                   calloc(1, sizeof(hw_accelerator_context_t));
+        if (hw_acc_ctxt == NULL) {
+            ALOGE("h/w acc context allocation failed");
+            return -ENOMEM;
+        }
+        context = (effect_context_t *)hw_acc_ctxt;
+        context->ops.init = hw_accelerator_init;
+        context->ops.reset = hw_accelerator_reset;
+        context->ops.set_parameter = hw_accelerator_set_parameter;
+        context->ops.get_parameter = hw_accelerator_get_parameter;
+        context->ops.set_device = hw_accelerator_set_device;
+        context->ops.set_hw_acc_mode = hw_accelerator_set_mode;
+        context->ops.enable = hw_accelerator_enable;
+        context->ops.disable = hw_accelerator_disable;
+        context->ops.release = hw_accelerator_release;
+        context->ops.process = hw_accelerator_process;
+
+        context->desc = &hw_accelerator_descriptor;
     } else {
         return -EINVAL;
     }
@@ -527,14 +712,15 @@
  */
 
 /* Stub function for effect interface: never called for offloaded effects */
+/* called for hw accelerated effects */
 int effect_process(effect_handle_t self,
-                       audio_buffer_t *inBuffer,
-                       audio_buffer_t *outBuffer)
+                       audio_buffer_t *inBuffer __unused,
+                       audio_buffer_t *outBuffer __unused)
 {
     effect_context_t * context = (effect_context_t *)self;
     int status = 0;
 
-    ALOGW("%s: ctxt %p, Called ?????", __func__, context);
+    ALOGV("%s", __func__);
 
     pthread_mutex_lock(&lock);
     if (!effect_exists(context)) {
@@ -547,6 +733,8 @@
         goto exit;
     }
 
+    if (context->ops.process)
+        status = context->ops.process(context, inBuffer, outBuffer);
 exit:
     pthread_mutex_unlock(&lock);
     return status;
@@ -598,7 +786,7 @@
             status = -EINVAL;
             goto exit;
         }
-        if (!context->offload_enabled) {
+        if (!context->offload_enabled && !context->hw_acc_enabled) {
             status = -EINVAL;
             goto exit;
         }
@@ -648,7 +836,7 @@
                   cmdSize, *replySize);
             goto exit;
         }
-        if (!context->offload_enabled) {
+        if (!context->offload_enabled && !context->hw_acc_enabled) {
             status = -EINVAL;
             goto exit;
         }
@@ -723,7 +911,20 @@
 
         } break;
 
+    case EFFECT_CMD_HW_ACC: {
+        ALOGV("EFFECT_CMD_HW_ACC cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
+              cmdSize, pCmdData, *replySize, pReplyData);
+        if (cmdSize != sizeof(uint32_t) || pCmdData == NULL
+                || pReplyData == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        uint32_t value = *(uint32_t *)pCmdData;
+        if (context->ops.set_hw_acc_mode)
+            context->ops.set_hw_acc_mode(context, value);
 
+        context->hw_acc_enabled = (value > 0) ? true : false;
+        break;
+    }
     default:
         if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
             status = context->ops.command(context, cmdCode, cmdSize,
diff --git a/post_proc/bundle.h b/post_proc/bundle.h
index cbe7dba..06da991 100644
--- a/post_proc/bundle.h
+++ b/post_proc/bundle.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -48,6 +48,7 @@
     int pcm_device_id;
     struct mixer *mixer;
     struct mixer_ctl *ctl;
+    struct mixer_ctl *ref_ctl;
 };
 
 /* effect specific operations.
@@ -66,6 +67,7 @@
     int (*set_parameter)(effect_context_t *context, effect_param_t *param, uint32_t size);
     int (*get_parameter)(effect_context_t *context, effect_param_t *param, uint32_t *size);
     int (*set_device)(effect_context_t *context, uint32_t device);
+    int (*set_hw_acc_mode)(effect_context_t *context, int32_t value);
     int (*command)(effect_context_t *context, uint32_t cmdCode, uint32_t cmdSize,
             void *pCmdData, uint32_t *replySize, void *pReplyData);
 };
@@ -82,6 +84,7 @@
     audio_io_handle_t out_handle;
     uint32_t state;
     bool offload_enabled;
+    bool hw_acc_enabled;
     effect_ops_t ops;
 };
 
diff --git a/post_proc/effect_api.c b/post_proc/effect_api.c
index 971b67f..e15db17 100644
--- a/post_proc/effect_api.c
+++ b/post_proc/effect_api.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, 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
@@ -25,10 +25,28 @@
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file was modified by DTS, Inc. The portions of the
+ * code modified by DTS, Inc are copyrighted and
+ * licensed separately, as follows:
+ *
+ * (C) 2014 DTS, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 #define LOG_TAG "offload_effect_api"
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 //#define VERY_VERY_VERBOSE_LOGGING
 #ifdef VERY_VERY_VERBOSE_LOGGING
 #define ALOGVV ALOGV
@@ -40,10 +58,20 @@
 #include <cutils/log.h>
 #include <tinyalsa/asoundlib.h>
 #include <sound/audio_effects.h>
+#include <sound/devdep_params.h>
+#include <linux/msm_audio.h>
 
 #include "effect_api.h"
 
+#ifdef DTS_EAGLE
+#include "effect_util.h"
+#endif
+
 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+typedef enum eff_mode {
+    OFFLOAD,
+    HW_ACCELERATOR
+} eff_mode_t;
 
 #define OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL 19
 const int map_eq_opensl_preset_2_offload_preset[] = {
@@ -71,35 +99,35 @@
 };
 
 int offload_update_mixer_and_effects_ctl(int card, int device_id,
-                                         struct mixer *mixer,
-                                         struct mixer_ctl *ctl)
+                                         struct mixer **mixer,
+                                         struct mixer_ctl **ctl)
 {
     char mixer_string[128];
 
     snprintf(mixer_string, sizeof(mixer_string),
              "%s %d", "Audio Effects Config", device_id);
     ALOGV("%s: mixer_string: %s", __func__, mixer_string);
-    mixer = mixer_open(card);
-    if (!mixer) {
+    *mixer = mixer_open(card);
+    if (!(*mixer)) {
         ALOGE("Failed to open mixer");
         ctl = NULL;
         return -EINVAL;
     } else {
-        ctl = mixer_get_ctl_by_name(mixer, mixer_string);
-        if (!ctl) {
+        *ctl = mixer_get_ctl_by_name(*mixer, mixer_string);
+        if (!(*ctl)) {
             ALOGE("mixer_get_ctl_by_name failed");
-            mixer_close(mixer);
-            mixer = NULL;
+            mixer_close(*mixer);
+            *mixer = NULL;
             return -EINVAL;
         }
     }
-    ALOGV("mixer: %p, ctl: %p", mixer, ctl);
+    ALOGV("mixer: %p, ctl: %p", *mixer, *ctl);
     return 0;
 }
 
-void offload_close_mixer(struct mixer *mixer)
+void offload_close_mixer(struct mixer **mixer)
 {
-    mixer_close(mixer);
+    mixer_close(*mixer);
 }
 
 void offload_bassboost_set_device(struct bass_boost_params *bassboost,
@@ -114,6 +142,10 @@
 {
     ALOGVV("%s: enable=%d", __func__, (int)enable);
     bassboost->enable_flag = enable;
+
+#ifdef DTS_EAGLE
+    update_effects_node(PCM_DEV_ID, EFFECT_TYPE_BB, EFFECT_ENABLE_PARAM, enable, EFFECT_NO_OP, EFFECT_NO_OP, EFFECT_NO_OP);
+#endif
 }
 
 int offload_bassboost_get_enable_flag(struct bass_boost_params *bassboost)
@@ -127,6 +159,10 @@
 {
     ALOGVV("%s: strength %d", __func__, strength);
     bassboost->strength = strength;
+
+#ifdef DTS_EAGLE
+    update_effects_node(PCM_DEV_ID, EFFECT_TYPE_BB, EFFECT_SET_PARAM, EFFECT_NO_OP, strength, EFFECT_NO_OP, EFFECT_NO_OP);
+#endif
 }
 
 void offload_bassboost_set_mode(struct bass_boost_params *bassboost,
@@ -136,23 +172,23 @@
     bassboost->mode = mode;
 }
 
-int offload_bassboost_send_params(struct mixer_ctl *ctl,
-                                  struct bass_boost_params bassboost,
-                                  unsigned param_send_flags)
+static int bassboost_send_params(eff_mode_t mode, void *ctl,
+                                  struct bass_boost_params *bassboost,
+                                 unsigned param_send_flags)
 {
     int param_values[128] = {0};
     int *p_param_values = param_values;
 
     ALOGV("%s: flags 0x%x", __func__, param_send_flags);
     *p_param_values++ = BASS_BOOST_MODULE;
-    *p_param_values++ = bassboost.device;
+    *p_param_values++ = bassboost->device;
     *p_param_values++ = 0; /* num of commands*/
     if (param_send_flags & OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG) {
         *p_param_values++ = BASS_BOOST_ENABLE;
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = BASS_BOOST_ENABLE_PARAM_LEN;
-        *p_param_values++ = bassboost.enable_flag;
+        *p_param_values++ = bassboost->enable_flag;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_BASSBOOST_STRENGTH) {
@@ -160,7 +196,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = BASS_BOOST_STRENGTH_PARAM_LEN;
-        *p_param_values++ = bassboost.strength;
+        *p_param_values++ = bassboost->strength;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_BASSBOOST_MODE) {
@@ -168,16 +204,114 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = BASS_BOOST_MODE_PARAM_LEN;
-        *p_param_values++ = bassboost.mode;
+        *p_param_values++ = bassboost->mode;
         param_values[2] += 1;
     }
 
-    if (param_values[2] && ctl)
-        mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+    if ((mode == OFFLOAD) && param_values[2] && ctl) {
+        mixer_ctl_set_array((struct mixer_ctl *)ctl, param_values,
+                            ARRAY_SIZE(param_values));
+    } else if ((mode == HW_ACCELERATOR) && param_values[2] &&
+               ctl && *(int *)ctl) {
+        if (ioctl(*(int *)ctl, AUDIO_EFFECTS_SET_PP_PARAMS, param_values) < 0)
+            ALOGE("%s: sending h/w acc effects params fail[%d]", __func__, errno);
+    }
 
     return 0;
 }
 
+int offload_bassboost_send_params(struct mixer_ctl *ctl,
+                                  struct bass_boost_params *bassboost,
+                                  unsigned param_send_flags)
+{
+    return bassboost_send_params(OFFLOAD, (void *)ctl, bassboost,
+                                 param_send_flags);
+}
+
+int hw_acc_bassboost_send_params(int fd, struct bass_boost_params *bassboost,
+                                 unsigned param_send_flags)
+{
+    return bassboost_send_params(HW_ACCELERATOR, (void *)&fd,
+                                 bassboost, param_send_flags);
+}
+
+void offload_pbe_set_device(struct pbe_params *pbe,
+                            uint32_t device)
+{
+    ALOGV("%s: device=%d", __func__, device);
+    pbe->device = device;
+}
+
+void offload_pbe_set_enable_flag(struct pbe_params *pbe,
+                                 bool enable)
+{
+    ALOGV("%s: enable=%d", __func__, enable);
+    pbe->enable_flag = enable;
+}
+
+int offload_pbe_get_enable_flag(struct pbe_params *pbe)
+{
+    ALOGV("%s: enabled=%d", __func__, pbe->enable_flag);
+    return pbe->enable_flag;
+}
+
+static int pbe_send_params(eff_mode_t mode, void *ctl,
+                            struct pbe_params *pbe,
+                            unsigned param_send_flags)
+{
+    int param_values[128] = {0};
+    int i, *p_param_values = param_values, *cfg = NULL;
+
+    ALOGV("%s: enabled=%d", __func__, pbe->enable_flag);
+    *p_param_values++ = PBE_MODULE;
+    *p_param_values++ = pbe->device;
+    *p_param_values++ = 0; /* num of commands*/
+    if (param_send_flags & OFFLOAD_SEND_PBE_ENABLE_FLAG) {
+        *p_param_values++ = PBE_ENABLE;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = PBE_ENABLE_PARAM_LEN;
+        *p_param_values++ = pbe->enable_flag;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_PBE_CONFIG) {
+        *p_param_values++ = PBE_CONFIG;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = pbe->cfg_len;
+        cfg = (int *)&pbe->config;
+        for (i = 0; i < (int)pbe->cfg_len ; i+= sizeof(*p_param_values))
+            *p_param_values++ = *cfg++;
+        param_values[2] += 1;
+    }
+
+    if ((mode == OFFLOAD) && param_values[2] && ctl) {
+        mixer_ctl_set_array((struct mixer_ctl *)ctl, param_values,
+                            ARRAY_SIZE(param_values));
+    } else if ((mode == HW_ACCELERATOR) && param_values[2] &&
+               ctl && *(int *)ctl) {
+        if (ioctl(*(int *)ctl, AUDIO_EFFECTS_SET_PP_PARAMS, param_values) < 0)
+            ALOGE("%s: sending h/w acc effects params fail[%d]", __func__, errno);
+    }
+
+    return 0;
+}
+
+int offload_pbe_send_params(struct mixer_ctl *ctl,
+                                  struct pbe_params *pbe,
+                                  unsigned param_send_flags)
+{
+    return pbe_send_params(OFFLOAD, (void *)ctl, pbe,
+                                 param_send_flags);
+}
+
+int hw_acc_pbe_send_params(int fd, struct pbe_params *pbe,
+                                 unsigned param_send_flags)
+{
+    return pbe_send_params(HW_ACCELERATOR, (void *)&fd,
+                                 pbe, param_send_flags);
+}
+
 void offload_virtualizer_set_device(struct virtualizer_params *virtualizer,
                                     uint32_t device)
 {
@@ -190,6 +324,10 @@
 {
     ALOGVV("%s: enable=%d", __func__, (int)enable);
     virtualizer->enable_flag = enable;
+
+#ifdef DTS_EAGLE
+    update_effects_node(PCM_DEV_ID, EFFECT_TYPE_VIRT, EFFECT_ENABLE_PARAM, enable, EFFECT_NO_OP, EFFECT_NO_OP, EFFECT_NO_OP);
+#endif
 }
 
 int offload_virtualizer_get_enable_flag(struct virtualizer_params *virtualizer)
@@ -203,6 +341,10 @@
 {
     ALOGVV("%s: strength %d", __func__, strength);
     virtualizer->strength = strength;
+
+#ifdef DTS_EAGLE
+    update_effects_node(PCM_DEV_ID, EFFECT_TYPE_VIRT, EFFECT_SET_PARAM, EFFECT_NO_OP, strength, EFFECT_NO_OP, EFFECT_NO_OP);
+#endif
 }
 
 void offload_virtualizer_set_out_type(struct virtualizer_params *virtualizer,
@@ -219,23 +361,23 @@
     virtualizer->gain_adjust = gain_adjust;
 }
 
-int offload_virtualizer_send_params(struct mixer_ctl *ctl,
-                                    struct virtualizer_params virtualizer,
-                                    unsigned param_send_flags)
+static int virtualizer_send_params(eff_mode_t mode, void *ctl,
+                                    struct virtualizer_params *virtualizer,
+                                   unsigned param_send_flags)
 {
     int param_values[128] = {0};
     int *p_param_values = param_values;
 
     ALOGV("%s: flags 0x%x", __func__, param_send_flags);
     *p_param_values++ = VIRTUALIZER_MODULE;
-    *p_param_values++ = virtualizer.device;
+    *p_param_values++ = virtualizer->device;
     *p_param_values++ = 0; /* num of commands*/
     if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG) {
         *p_param_values++ = VIRTUALIZER_ENABLE;
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = VIRTUALIZER_ENABLE_PARAM_LEN;
-        *p_param_values++ = virtualizer.enable_flag;
+        *p_param_values++ = virtualizer->enable_flag;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_STRENGTH) {
@@ -243,7 +385,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = VIRTUALIZER_STRENGTH_PARAM_LEN;
-        *p_param_values++ = virtualizer.strength;
+        *p_param_values++ = virtualizer->strength;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE) {
@@ -251,7 +393,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = VIRTUALIZER_OUT_TYPE_PARAM_LEN;
-        *p_param_values++ = virtualizer.out_type;
+        *p_param_values++ = virtualizer->out_type;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_GAIN_ADJUST) {
@@ -259,16 +401,38 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = VIRTUALIZER_GAIN_ADJUST_PARAM_LEN;
-        *p_param_values++ = virtualizer.gain_adjust;
+        *p_param_values++ = virtualizer->gain_adjust;
         param_values[2] += 1;
     }
 
-    if (param_values[2] && ctl)
-        mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+    if ((mode == OFFLOAD) && param_values[2] && ctl) {
+        mixer_ctl_set_array((struct mixer_ctl *)ctl, param_values,
+                            ARRAY_SIZE(param_values));
+    } else if ((mode == HW_ACCELERATOR) && param_values[2] &&
+               ctl && *(int *)ctl) {
+        if (ioctl(*(int *)ctl, AUDIO_EFFECTS_SET_PP_PARAMS, param_values) < 0)
+            ALOGE("%s: sending h/w acc effects params fail[%d]", __func__, errno);
+    }
 
     return 0;
 }
 
+int offload_virtualizer_send_params(struct mixer_ctl *ctl,
+                                    struct virtualizer_params *virtualizer,
+                                    unsigned param_send_flags)
+{
+    return virtualizer_send_params(OFFLOAD, (void *)ctl, virtualizer,
+                                   param_send_flags);
+}
+
+int hw_acc_virtualizer_send_params(int fd,
+                                   struct virtualizer_params *virtualizer,
+                                   unsigned param_send_flags)
+{
+    return virtualizer_send_params(HW_ACCELERATOR, (void *)&fd,
+                                   virtualizer, param_send_flags);
+}
+
 void offload_eq_set_device(struct eq_params *eq, uint32_t device)
 {
     ALOGVV("%s: device 0x%x", __func__, device);
@@ -279,6 +443,10 @@
 {
     ALOGVV("%s: enable=%d", __func__, (int)enable);
     eq->enable_flag = enable;
+
+#ifdef DTS_EAGLE
+    update_effects_node(PCM_DEV_ID, EFFECT_TYPE_EQ, EFFECT_ENABLE_PARAM, enable, EFFECT_NO_OP, EFFECT_NO_OP, EFFECT_NO_OP);
+#endif
 }
 
 int offload_eq_get_enable_flag(struct eq_params *eq)
@@ -308,30 +476,34 @@
         eq->per_band_cfg[i].gain_millibels = band_gain_list[i] * 100;
         eq->per_band_cfg[i].quality_factor = Q8_UNITY;
     }
+
+#ifdef DTS_EAGLE
+        update_effects_node(PCM_DEV_ID, EFFECT_TYPE_EQ, EFFECT_SET_PARAM, EFFECT_NO_OP, EFFECT_NO_OP, i, band_gain_list[i] * 100);
+#endif
 }
 
-int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params eq,
-                           unsigned param_send_flags)
+static int eq_send_params(eff_mode_t mode, void *ctl, struct eq_params *eq,
+                          unsigned param_send_flags)
 {
     int param_values[128] = {0};
     int *p_param_values = param_values;
     uint32_t i;
 
     ALOGV("%s: flags 0x%x", __func__, param_send_flags);
-    if ((eq.config.preset_id < -1) ||
-            ((param_send_flags & OFFLOAD_SEND_EQ_PRESET) && (eq.config.preset_id == -1))) {
+    if ((eq->config.preset_id < -1) ||
+            ((param_send_flags & OFFLOAD_SEND_EQ_PRESET) && (eq->config.preset_id == -1))) {
         ALOGV("No Valid preset to set");
         return 0;
     }
     *p_param_values++ = EQ_MODULE;
-    *p_param_values++ = eq.device;
+    *p_param_values++ = eq->device;
     *p_param_values++ = 0; /* num of commands*/
     if (param_send_flags & OFFLOAD_SEND_EQ_ENABLE_FLAG) {
         *p_param_values++ = EQ_ENABLE;
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = EQ_ENABLE_PARAM_LEN;
-        *p_param_values++ = eq.enable_flag;
+        *p_param_values++ = eq->enable_flag;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_EQ_PRESET) {
@@ -339,9 +511,9 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = EQ_CONFIG_PARAM_LEN;
-        *p_param_values++ = eq.config.eq_pregain;
+        *p_param_values++ = eq->config.eq_pregain;
         *p_param_values++ =
-                     map_eq_opensl_preset_2_offload_preset[eq.config.preset_id];
+                     map_eq_opensl_preset_2_offload_preset[eq->config.preset_id];
         *p_param_values++ = 0;
         param_values[2] += 1;
     }
@@ -350,26 +522,45 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = EQ_CONFIG_PARAM_LEN +
-                            eq.config.num_bands * EQ_CONFIG_PER_BAND_PARAM_LEN;
-        *p_param_values++ = eq.config.eq_pregain;
+                            eq->config.num_bands * EQ_CONFIG_PER_BAND_PARAM_LEN;
+        *p_param_values++ = eq->config.eq_pregain;
         *p_param_values++ = CUSTOM_OPENSL_PRESET;
-        *p_param_values++ = eq.config.num_bands;
-        for (i=0; i<eq.config.num_bands; i++) {
-            *p_param_values++ = eq.per_band_cfg[i].band_idx;
-            *p_param_values++ = eq.per_band_cfg[i].filter_type;
-	    *p_param_values++ = eq.per_band_cfg[i].freq_millihertz;
-            *p_param_values++ = eq.per_band_cfg[i].gain_millibels;
-            *p_param_values++ = eq.per_band_cfg[i].quality_factor;
+        *p_param_values++ = eq->config.num_bands;
+        for (i=0; i<eq->config.num_bands; i++) {
+            *p_param_values++ = eq->per_band_cfg[i].band_idx;
+            *p_param_values++ = eq->per_band_cfg[i].filter_type;
+	    *p_param_values++ = eq->per_band_cfg[i].freq_millihertz;
+            *p_param_values++ = eq->per_band_cfg[i].gain_millibels;
+            *p_param_values++ = eq->per_band_cfg[i].quality_factor;
         }
         param_values[2] += 1;
     }
 
-    if (param_values[2] && ctl)
-        mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+    if ((mode == OFFLOAD) && param_values[2] && ctl) {
+        mixer_ctl_set_array((struct mixer_ctl *)ctl, param_values,
+                            ARRAY_SIZE(param_values));
+    } else if ((mode == HW_ACCELERATOR) && param_values[2] &&
+               ctl && *(int *)ctl) {
+        if (ioctl(*(int *)ctl, AUDIO_EFFECTS_SET_PP_PARAMS, param_values) < 0)
+            ALOGE("%s: sending h/w acc effects params fail[%d]", __func__, errno);
+    }
 
     return 0;
 }
 
+int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params *eq,
+                           unsigned param_send_flags)
+{
+    return eq_send_params(OFFLOAD, (void *)ctl, eq, param_send_flags);
+}
+
+int hw_acc_eq_send_params(int fd, struct eq_params *eq,
+                          unsigned param_send_flags)
+{
+    return eq_send_params(HW_ACCELERATOR, (void *)&fd, eq,
+                          param_send_flags);
+}
+
 void offload_reverb_set_device(struct reverb_params *reverb, uint32_t device)
 {
     ALOGVV("%s: device 0x%x", __func__, device);
@@ -479,16 +670,16 @@
     reverb->density = density;
 }
 
-int offload_reverb_send_params(struct mixer_ctl *ctl,
-                               struct reverb_params reverb,
-                               unsigned param_send_flags)
+static int reverb_send_params(eff_mode_t mode, void *ctl,
+                               struct reverb_params *reverb,
+                              unsigned param_send_flags)
 {
     int param_values[128] = {0};
     int *p_param_values = param_values;
 
     ALOGV("%s: flags 0x%x", __func__, param_send_flags);
     *p_param_values++ = REVERB_MODULE;
-    *p_param_values++ = reverb.device;
+    *p_param_values++ = reverb->device;
     *p_param_values++ = 0; /* num of commands*/
 
     if (param_send_flags & OFFLOAD_SEND_REVERB_ENABLE_FLAG) {
@@ -496,7 +687,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_ENABLE_PARAM_LEN;
-        *p_param_values++ = reverb.enable_flag;
+        *p_param_values++ = reverb->enable_flag;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_MODE) {
@@ -504,7 +695,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_MODE_PARAM_LEN;
-        *p_param_values++ = reverb.mode;
+        *p_param_values++ = reverb->mode;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_PRESET) {
@@ -512,7 +703,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_PRESET_PARAM_LEN;
-        *p_param_values++ = reverb.preset;
+        *p_param_values++ = reverb->preset;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_WET_MIX) {
@@ -520,7 +711,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_WET_MIX_PARAM_LEN;
-        *p_param_values++ = reverb.wet_mix;
+        *p_param_values++ = reverb->wet_mix;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_GAIN_ADJUST) {
@@ -528,7 +719,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_GAIN_ADJUST_PARAM_LEN;
-        *p_param_values++ = reverb.gain_adjust;
+        *p_param_values++ = reverb->gain_adjust;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_ROOM_LEVEL) {
@@ -536,7 +727,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_ROOM_LEVEL_PARAM_LEN;
-        *p_param_values++ = reverb.room_level;
+        *p_param_values++ = reverb->room_level;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL) {
@@ -544,7 +735,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_ROOM_HF_LEVEL_PARAM_LEN;
-        *p_param_values++ = reverb.room_hf_level;
+        *p_param_values++ = reverb->room_hf_level;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_DECAY_TIME) {
@@ -552,7 +743,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_DECAY_TIME_PARAM_LEN;
-        *p_param_values++ = reverb.decay_time;
+        *p_param_values++ = reverb->decay_time;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_DECAY_HF_RATIO) {
@@ -560,7 +751,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_DECAY_HF_RATIO_PARAM_LEN;
-        *p_param_values++ = reverb.decay_hf_ratio;
+        *p_param_values++ = reverb->decay_hf_ratio;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL) {
@@ -568,7 +759,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_REFLECTIONS_LEVEL_PARAM_LEN;
-        *p_param_values++ = reverb.reflections_level;
+        *p_param_values++ = reverb->reflections_level;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY) {
@@ -576,7 +767,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_REFLECTIONS_DELAY_PARAM_LEN;
-        *p_param_values++ = reverb.reflections_delay;
+        *p_param_values++ = reverb->reflections_delay;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_LEVEL) {
@@ -584,7 +775,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_LEVEL_PARAM_LEN;
-        *p_param_values++ = reverb.level;
+        *p_param_values++ = reverb->level;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_DELAY) {
@@ -592,7 +783,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_DELAY_PARAM_LEN;
-        *p_param_values++ = reverb.delay;
+        *p_param_values++ = reverb->delay;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_DIFFUSION) {
@@ -600,7 +791,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_DIFFUSION_PARAM_LEN;
-        *p_param_values++ = reverb.diffusion;
+        *p_param_values++ = reverb->diffusion;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_DENSITY) {
@@ -608,7 +799,92 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_DENSITY_PARAM_LEN;
-        *p_param_values++ = reverb.density;
+        *p_param_values++ = reverb->density;
+        param_values[2] += 1;
+    }
+
+    if ((mode == OFFLOAD) && param_values[2] && ctl) {
+        mixer_ctl_set_array((struct mixer_ctl *)ctl, param_values,
+                            ARRAY_SIZE(param_values));
+    } else if ((mode == HW_ACCELERATOR) && param_values[2] &&
+               ctl && *(int *)ctl) {
+        if (ioctl(*(int *)ctl, AUDIO_EFFECTS_SET_PP_PARAMS, param_values) < 0)
+            ALOGE("%s: sending h/w acc effects params fail[%d]", __func__, errno);
+    }
+
+    return 0;
+}
+
+int offload_reverb_send_params(struct mixer_ctl *ctl,
+                               struct reverb_params *reverb,
+                               unsigned param_send_flags)
+{
+    return reverb_send_params(OFFLOAD, (void *)ctl, reverb,
+                              param_send_flags);
+}
+
+int hw_acc_reverb_send_params(int fd, struct reverb_params *reverb,
+                              unsigned param_send_flags)
+{
+    return reverb_send_params(HW_ACCELERATOR, (void *)&fd,
+                              reverb, param_send_flags);
+}
+
+void offload_soft_volume_set_enable(struct soft_volume_params *vol, bool enable)
+{
+    ALOGV("%s", __func__);
+    vol->enable_flag = enable;
+}
+
+void offload_soft_volume_set_gain_master(struct soft_volume_params *vol, int gain)
+{
+    ALOGV("%s", __func__);
+    vol->master_gain = gain;
+}
+
+void offload_soft_volume_set_gain_2ch(struct soft_volume_params *vol,
+                                      int l_gain, int r_gain)
+{
+    ALOGV("%s", __func__);
+    vol->left_gain = l_gain;
+    vol->right_gain = r_gain;
+}
+
+int offload_soft_volume_send_params(struct mixer_ctl *ctl,
+                                    struct soft_volume_params vol,
+                                    unsigned param_send_flags)
+{
+    int param_values[128] = {0};
+    int *p_param_values = param_values;
+    uint32_t i;
+
+    ALOGV("%s", __func__);
+    *p_param_values++ = SOFT_VOLUME_MODULE;
+    *p_param_values++ = 0;
+    *p_param_values++ = 0; /* num of commands*/
+    if (param_send_flags & OFFLOAD_SEND_SOFT_VOLUME_ENABLE_FLAG) {
+        *p_param_values++ = SOFT_VOLUME_ENABLE;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = SOFT_VOLUME_ENABLE_PARAM_LEN;
+        *p_param_values++ = vol.enable_flag;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_SOFT_VOLUME_GAIN_MASTER) {
+        *p_param_values++ = SOFT_VOLUME_GAIN_MASTER;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = SOFT_VOLUME_GAIN_MASTER_PARAM_LEN;
+        *p_param_values++ = vol.master_gain;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_SOFT_VOLUME_GAIN_2CH) {
+        *p_param_values++ = SOFT_VOLUME_GAIN_2CH;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = SOFT_VOLUME_GAIN_2CH_PARAM_LEN;
+        *p_param_values++ = vol.left_gain;
+        *p_param_values++ = vol.right_gain;
         param_values[2] += 1;
     }
 
@@ -617,3 +893,109 @@
 
     return 0;
 }
+
+void offload_transition_soft_volume_set_enable(struct soft_volume_params *vol,
+                                               bool enable)
+{
+    ALOGV("%s", __func__);
+    vol->enable_flag = enable;
+}
+
+void offload_transition_soft_volume_set_gain_master(struct soft_volume_params *vol,
+                                                    int gain)
+{
+    ALOGV("%s", __func__);
+    vol->master_gain = gain;
+}
+
+void offload_transition_soft_volume_set_gain_2ch(struct soft_volume_params *vol,
+                                                 int l_gain, int r_gain)
+{
+    ALOGV("%s", __func__);
+    vol->left_gain = l_gain;
+    vol->right_gain = r_gain;
+}
+
+int offload_transition_soft_volume_send_params(struct mixer_ctl *ctl,
+                                               struct soft_volume_params vol,
+                                               unsigned param_send_flags)
+{
+    int param_values[128] = {0};
+    int *p_param_values = param_values;
+    uint32_t i;
+
+    ALOGV("%s", __func__);
+    *p_param_values++ = SOFT_VOLUME2_MODULE;
+    *p_param_values++ = 0;
+    *p_param_values++ = 0; /* num of commands*/
+    if (param_send_flags & OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_ENABLE_FLAG) {
+        *p_param_values++ = SOFT_VOLUME2_ENABLE;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = SOFT_VOLUME2_ENABLE_PARAM_LEN;
+        *p_param_values++ = vol.enable_flag;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER) {
+        *p_param_values++ = SOFT_VOLUME2_GAIN_MASTER;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = SOFT_VOLUME2_GAIN_MASTER_PARAM_LEN;
+        *p_param_values++ = vol.master_gain;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_2CH) {
+        *p_param_values++ = SOFT_VOLUME2_GAIN_2CH;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = SOFT_VOLUME2_GAIN_2CH_PARAM_LEN;
+        *p_param_values++ = vol.left_gain;
+        *p_param_values++ = vol.right_gain;
+        param_values[2] += 1;
+    }
+
+    if (param_values[2] && ctl)
+        mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+
+    return 0;
+}
+
+static int hpx_send_params(eff_mode_t mode, void *ctl,
+                           unsigned param_send_flags)
+{
+    int param_values[128] = {0};
+    int *p_param_values = param_values;
+    uint32_t i;
+
+    ALOGV("%s", __func__);
+    if (!ctl) {
+        ALOGE("%s: ctl is NULL, return invalid", __func__);
+        return -EINVAL;
+    }
+
+    if (param_send_flags & OFFLOAD_SEND_HPX_STATE_OFF) {
+        *p_param_values++ = DTS_EAGLE_MODULE_ENABLE;
+        *p_param_values++ = 0; /* hpx off*/
+    } else if (param_send_flags & OFFLOAD_SEND_HPX_STATE_ON) {
+        *p_param_values++ = DTS_EAGLE_MODULE_ENABLE;
+        *p_param_values++ = 1; /* hpx on*/
+    }
+
+    if (mode == OFFLOAD)
+        mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+    else {
+        if (ioctl(*(int *)ctl, AUDIO_EFFECTS_SET_PP_PARAMS, param_values) < 0)
+            ALOGE("%s: sending h/w acc hpx state params fail[%d]", __func__, errno);
+    }
+    return 0;
+}
+
+int offload_hpx_send_params(struct mixer_ctl *ctl, unsigned param_send_flags)
+{
+    return hpx_send_params(OFFLOAD, (void *)ctl, param_send_flags);
+}
+
+int hw_acc_hpx_send_params(int fd, unsigned param_send_flags)
+{
+    return hpx_send_params(HW_ACCELERATOR, (void *)&fd, param_send_flags);
+}
diff --git a/post_proc/effect_api.h b/post_proc/effect_api.h
index 342c606..ce0503a 100644
--- a/post_proc/effect_api.h
+++ b/post_proc/effect_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, 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
@@ -30,11 +30,30 @@
 #ifndef OFFLOAD_EFFECT_API_H_
 #define OFFLOAD_EFFECT_API_H_
 
-int offload_update_mixer_and_effects_ctl(int card, int device_id,
-                                         struct mixer *mixer,
-                                         struct mixer_ctl *ctl);
-void offload_close_mixer(struct mixer *mixer);
+#if __cplusplus
+extern "C" {
+#endif
 
+int offload_update_mixer_and_effects_ctl(int card, int device_id,
+                                         struct mixer **mixer,
+                                         struct mixer_ctl **ctl);
+void offload_close_mixer(struct mixer **mixer);
+
+
+#define OFFLOAD_SEND_PBE_ENABLE_FLAG      (1 << 0)
+#define OFFLOAD_SEND_PBE_CONFIG           (OFFLOAD_SEND_PBE_ENABLE_FLAG << 1)
+void offload_pbe_set_device(struct pbe_params *pbe,
+                            uint32_t device);
+void offload_pbe_set_enable_flag(struct pbe_params *pbe,
+                                 bool enable);
+int offload_pbe_get_enable_flag(struct pbe_params *pbe);
+
+int offload_pbe_send_params(struct mixer_ctl *ctl,
+                            struct pbe_params *pbe,
+                            unsigned param_send_flags);
+int hw_acc_pbe_send_params(int fd,
+                           struct pbe_params *pbe,
+                           unsigned param_send_flags);
 #define OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG      (1 << 0)
 #define OFFLOAD_SEND_BASSBOOST_STRENGTH         \
                                           (OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG << 1)
@@ -50,8 +69,11 @@
 void offload_bassboost_set_mode(struct bass_boost_params *bassboost,
                                 int mode);
 int offload_bassboost_send_params(struct mixer_ctl *ctl,
-                                  struct bass_boost_params bassboost,
+                                  struct bass_boost_params *bassboost,
                                   unsigned param_send_flags);
+int hw_acc_bassboost_send_params(int fd,
+                                 struct bass_boost_params *bassboost,
+                                 unsigned param_send_flags);
 
 #define OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG    (1 << 0)
 #define OFFLOAD_SEND_VIRTUALIZER_STRENGTH       \
@@ -72,8 +94,11 @@
 void offload_virtualizer_set_gain_adjust(struct virtualizer_params *virtualizer,
                                          int gain_adjust);
 int offload_virtualizer_send_params(struct mixer_ctl *ctl,
-                                  struct virtualizer_params virtualizer,
+                                  struct virtualizer_params *virtualizer,
                                   unsigned param_send_flags);
+int hw_acc_virtualizer_send_params(int fd,
+                                   struct virtualizer_params *virtualizer,
+                                   unsigned param_send_flags);
 
 #define OFFLOAD_SEND_EQ_ENABLE_FLAG             (1 << 0)
 #define OFFLOAD_SEND_EQ_PRESET                  \
@@ -87,8 +112,10 @@
 void offload_eq_set_bands_level(struct eq_params *eq, int num_bands,
                                 const uint16_t *band_freq_list,
                                 int *band_gain_list);
-int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params eq,
+int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params *eq,
                            unsigned param_send_flags);
+int hw_acc_eq_send_params(int fd, struct eq_params *eq,
+                          unsigned param_send_flags);
 
 #define OFFLOAD_SEND_REVERB_ENABLE_FLAG         (1 << 0)
 #define OFFLOAD_SEND_REVERB_MODE                \
@@ -145,7 +172,49 @@
 void offload_reverb_set_diffusion(struct reverb_params *reverb, int diffusion);
 void offload_reverb_set_density(struct reverb_params *reverb, int density);
 int offload_reverb_send_params(struct mixer_ctl *ctl,
-                               struct reverb_params reverb,
+                               struct reverb_params *reverb,
                                unsigned param_send_flags);
+int hw_acc_reverb_send_params(int fd,
+                              struct reverb_params *reverb,
+                              unsigned param_send_flags);
+
+#define OFFLOAD_SEND_SOFT_VOLUME_ENABLE_FLAG         (1 << 0)
+#define OFFLOAD_SEND_SOFT_VOLUME_GAIN_2CH             \
+                                          (OFFLOAD_SEND_SOFT_VOLUME_ENABLE_FLAG << 1)
+#define OFFLOAD_SEND_SOFT_VOLUME_GAIN_MASTER          \
+                                          (OFFLOAD_SEND_SOFT_VOLUME_GAIN_2CH << 1)
+void offload_soft_volume_set_enable(struct soft_volume_params *vol,
+                                    bool enable);
+void offload_soft_volume_set_gain_master(struct soft_volume_params *vol,
+                                         int gain);
+void offload_soft_volume_set_gain_2ch(struct soft_volume_params *vol,
+                                      int l_gain, int r_gain);
+int offload_soft_volume_send_params(struct mixer_ctl *ctl,
+                                    struct soft_volume_params vol,
+                                    unsigned param_send_flags);
+
+#define OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_ENABLE_FLAG         (1 << 0)
+#define OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_2CH             \
+                                  (OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_ENABLE_FLAG << 1)
+#define OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER          \
+                                  (OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_2CH << 1)
+void offload_transition_soft_volume_set_enable(struct soft_volume_params *vol,
+                                               bool enable);
+void offload_transition_soft_volume_set_gain_master(struct soft_volume_params *vol,
+                                                    int gain);
+void offload_transition_soft_volume_set_gain_2ch(struct soft_volume_params *vol,
+                                                 int l_gain, int r_gain);
+int offload_transition_soft_volume_send_params(struct mixer_ctl *ctl,
+                                               struct soft_volume_params vol,
+                                               unsigned param_send_flags);
+
+#define OFFLOAD_SEND_HPX_STATE_ON       (1 << 0)
+#define OFFLOAD_SEND_HPX_STATE_OFF      (OFFLOAD_SEND_HPX_STATE_ON << 1)
+int offload_hpx_send_params(struct mixer_ctl *ctl, unsigned param_send_flags);
+int hw_acc_hpx_send_params(int fd, unsigned param_send_flags);
+
+#if __cplusplus
+} //extern "C"
+#endif
 
 #endif /*OFFLOAD_EFFECT_API_H_*/
diff --git a/post_proc/effect_util.c b/post_proc/effect_util.c
new file mode 100644
index 0000000..8f7a604
--- /dev/null
+++ b/post_proc/effect_util.c
@@ -0,0 +1,210 @@
+/*
+ *  (C) 2014 DTS, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/Log.h>
+#include <stdlib.h>
+#include "effect_util.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "effect_util"
+
+/*#define LOG_NDEBUG 0*/
+
+enum {
+    EQUALIZER,
+    VIRTUALIZER,
+    BASSBOOST,
+};
+
+static const char *paramList[10] = {
+                              "eq_enable",
+                              "virt_enable",
+                              "bb_enable",
+                              "eq_param_level0",
+                              "eq_param_level1",
+                              "eq_param_level2",
+                              "eq_param_level3",
+                              "eq_param_level4",
+                              "virt_param_strength",
+                              "bassboost_param_strength"
+};
+
+#define EFFECT_FILE "/data/misc/dts/effect"
+#define MAX_LENGTH_OF_INTEGER_IN_STRING 13
+
+#ifdef DTS_EAGLE
+void create_effect_state_node(int device_id)
+{
+    char prop[PROPERTY_VALUE_MAX];
+    int fd;
+    char buf[1024];
+    char path[PATH_MAX];
+    char value[MAX_LENGTH_OF_INTEGER_IN_STRING];
+
+    property_get("use.dts_eagle", prop, "0");
+    if (!strncmp("true", prop, sizeof("true")) || atoi(prop)) {
+        ALOGV("create_effect_node for - device_id: %d", device_id);
+        strlcpy(path, EFFECT_FILE, sizeof(path));
+        snprintf(value, sizeof(value), "%d", device_id);
+        strlcat(path, value, sizeof(path));
+        if ((fd=open(path, O_RDONLY)) < 0) {
+            ALOGV("No File exist");
+        } else {
+            ALOGV("A file with the same name exist. So, not creating again");
+            return;
+        }
+        if ((fd=creat(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
+            ALOGE("opening effect state node failed returned");
+            return;
+        }
+        chmod(path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH);
+        snprintf(buf, sizeof(buf), "eq_enable=%d;virt_enable=%d;bb_enable=%d;eq_param_level0=%d;eq_param_level1=%d;eq_param_level2=%d;eq_param_level3=%d;eq_param_level4=%d;virt_param_strength=%d;bassboost_param_strength=%d", 0,0,0,0,0,0,0,0,0,0);
+        int n = write(fd, buf, strlen(buf));
+        ALOGV("number of bytes written: %d", n);
+        close(fd);
+    }
+}
+
+void update_effects_node(int device_id, int effect_type, int enable_or_set, int enable_disable, int strength, int eq_band, int eq_level)
+{
+    char prop[PROPERTY_VALUE_MAX];
+    char buf[1024];
+    int fd = 0;
+    int paramValue = 0;
+    char path[PATH_MAX];
+    char value[MAX_LENGTH_OF_INTEGER_IN_STRING];
+    char parameterValue[MAX_LENGTH_OF_INTEGER_IN_STRING];
+    int keyParamIndex = -1; //index in the paramlist array which has to be updated
+    char *s1, *s2;
+    char resultBuf[1024];
+    int index1 = -1;
+  //ALOGV("value of device_id and effect_type is %d and %d", device_id, effect_type);
+    property_get("use.dts_eagle", prop, "0");
+    if (!strncmp("true", prop, sizeof("true")) || atoi(prop)) {
+        strlcpy(path, EFFECT_FILE, sizeof(path));
+        snprintf(value, sizeof(value), "%d", device_id);
+        strlcat(path, value, sizeof(path));
+        switch (effect_type)
+        {
+        case EQUALIZER:
+            if (enable_or_set) {
+                keyParamIndex = 0;
+                paramValue = enable_disable;
+        } else {
+            switch (eq_band) {
+            case 0:
+                keyParamIndex = 3;
+                break;
+            case 1:
+                keyParamIndex = 4;
+                break;
+            case 2:
+                keyParamIndex = 5;
+                break;
+            case 3:
+                keyParamIndex = 6;
+                break;
+            case 4:
+                keyParamIndex = 7;
+                break;
+            default:
+                break;
+            }
+            paramValue = eq_level;
+        }
+        break;
+        case VIRTUALIZER:
+            if(enable_or_set) {
+                keyParamIndex = 1;
+                paramValue = enable_disable;
+            } else {
+                 keyParamIndex = 8;
+                 paramValue = strength;
+            }
+            break;
+        case BASSBOOST:
+            if (enable_or_set) {
+                keyParamIndex = 2;
+                paramValue = enable_disable;
+            } else {
+                keyParamIndex = 9;
+                paramValue = strength;
+            }
+            break;
+         default:
+            break;
+        }
+        if(keyParamIndex !=-1) {
+            FILE *fp;
+            fp = fopen(path,"r");
+            if (fp != NULL) {
+                memset(buf, 0, 1024);
+                memset(resultBuf, 0, 1024);
+                if (fgets(buf, 1024, fp) != NULL) {
+                    s1 = strstr(buf, paramList[keyParamIndex]);
+                    s2 = strstr(s1,";");
+                    index1 = s1 - buf;
+                    strncpy(resultBuf, buf, index1);
+                    strncat(resultBuf, paramList[keyParamIndex], sizeof(resultBuf)-strlen(resultBuf)-1);
+                    strncat(resultBuf, "=", sizeof(resultBuf)-strlen(resultBuf)-1);
+                    snprintf(parameterValue, sizeof(parameterValue), "%d", paramValue);
+                    strncat(resultBuf, parameterValue, sizeof(resultBuf)-strlen(resultBuf)-1);
+                    if (s2)
+                        strncat(resultBuf, s2, sizeof(resultBuf)-strlen(resultBuf)-1);
+                    fclose(fp);
+                    if ((fd=open(path, O_TRUNC|O_WRONLY)) < 0) {
+                       ALOGV("opening file for writing failed");
+                       return;
+                    }
+                    int n = write(fd, resultBuf, strlen(resultBuf));
+                    close(fd);
+                    ALOGV("number of bytes written: %d", n);
+                } else {
+                    ALOGV("file could not be read");
+                    fclose(fp);
+                }
+            } else
+                ALOGV("file could not be opened");
+        }
+    }
+}
+
+void remove_effect_state_node(int device_id)
+{
+    char prop[PROPERTY_VALUE_MAX];
+    int fd;
+    char path[PATH_MAX];
+    char value[MAX_LENGTH_OF_INTEGER_IN_STRING];
+
+    property_get("use.dts_eagle", prop, "0");
+    if (!strncmp("true", prop, sizeof("true")) || atoi(prop)) {
+        ALOGV("remove_state_notifier_node: device_id - %d", device_id);
+        strlcpy(path, EFFECT_FILE, sizeof(path));
+        snprintf(value, sizeof(value), "%d", device_id);
+        strlcat(path, value, sizeof(path));
+        if ((fd=open(path, O_RDONLY)) < 0) {
+            ALOGV("open effect state node failed");
+        } else {
+            ALOGV("open effect state node successful");
+            ALOGV("Remove the file");
+            close(fd);
+            remove(path);
+        }
+    }
+}
+#endif
diff --git a/post_proc/effect_util.h b/post_proc/effect_util.h
new file mode 100644
index 0000000..38bd9bd
--- /dev/null
+++ b/post_proc/effect_util.h
@@ -0,0 +1,47 @@
+/*
+ *  (C) 2014 DTS, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef EFFECT_UTIL_H_
+#define EFFECT_UTIL_H_
+
+#ifdef DTS_EAGLE
+
+#include <cutils/properties.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+enum {
+    EFFECT_TYPE_EQ = 0,
+    EFFECT_TYPE_VIRT,
+    EFFECT_TYPE_BB,
+};
+
+enum {
+    EFFECT_SET_PARAM = 0,
+    EFFECT_ENABLE_PARAM,
+};
+
+
+#define EFFECT_NO_OP 0
+#define PCM_DEV_ID 9
+
+void create_effect_state_node(int device_id);
+void update_effects_node(int device_id, int effect_type, int enable_or_set, int enable_disable, int strength, int band, int level);
+void remove_effect_state_node(int device_id);
+
+#endif /*DTS_EAGLE*/
+
+#endif /*EFFECT_UTIL_H_*/
diff --git a/post_proc/equalizer.c b/post_proc/equalizer.c
index 7355ead..c2ae326 100644
--- a/post_proc/equalizer.c
+++ b/post_proc/equalizer.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -18,7 +18,7 @@
  */
 
 #define LOG_TAG "offload_effect_equalizer"
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <cutils/list.h>
 #include <cutils/log.h>
@@ -110,9 +110,13 @@
                                equalizer_band_presets_freq,
                                context->band_levels);
     if (context->ctl)
-        offload_eq_send_params(context->ctl, context->offload_eq,
+        offload_eq_send_params(context->ctl, &context->offload_eq,
                                OFFLOAD_SEND_EQ_ENABLE_FLAG |
                                OFFLOAD_SEND_EQ_BANDS_LEVEL);
+    if (context->hw_acc_fd > 0)
+        hw_acc_eq_send_params(context->hw_acc_fd, &context->offload_eq,
+                              OFFLOAD_SEND_EQ_ENABLE_FLAG |
+                              OFFLOAD_SEND_EQ_BANDS_LEVEL);
     return 0;
 }
 
@@ -167,9 +171,13 @@
                                equalizer_band_presets_freq,
                                context->band_levels);
     if(context->ctl)
-        offload_eq_send_params(context->ctl, context->offload_eq,
+        offload_eq_send_params(context->ctl, &context->offload_eq,
                                OFFLOAD_SEND_EQ_ENABLE_FLAG |
                                OFFLOAD_SEND_EQ_PRESET);
+    if(context->hw_acc_fd > 0)
+        hw_acc_eq_send_params(context->hw_acc_fd, &context->offload_eq,
+                              OFFLOAD_SEND_EQ_ENABLE_FLAG |
+                              OFFLOAD_SEND_EQ_PRESET);
     return 0;
 }
 
@@ -336,7 +344,7 @@
 }
 
 int equalizer_set_parameter(effect_context_t *context, effect_param_t *p,
-                            uint32_t size)
+                            uint32_t size __unused)
 {
     equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
     int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
@@ -437,6 +445,7 @@
 
     set_config(context, &context->config);
 
+    eq_ctxt->hw_acc_fd = -1;
     memset(&(eq_ctxt->offload_eq), 0, sizeof(struct eq_params));
     offload_eq_set_preset(&(eq_ctxt->offload_eq), INVALID_PRESET);
 
@@ -452,9 +461,13 @@
     if (!offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) {
         offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), true);
         if (eq_ctxt->ctl)
-            offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq,
+            offload_eq_send_params(eq_ctxt->ctl, &eq_ctxt->offload_eq,
                                    OFFLOAD_SEND_EQ_ENABLE_FLAG |
                                    OFFLOAD_SEND_EQ_BANDS_LEVEL);
+        if (eq_ctxt->hw_acc_fd > 0)
+            hw_acc_eq_send_params(eq_ctxt->hw_acc_fd, &eq_ctxt->offload_eq,
+                                  OFFLOAD_SEND_EQ_ENABLE_FLAG |
+                                  OFFLOAD_SEND_EQ_BANDS_LEVEL);
     }
     return 0;
 }
@@ -467,8 +480,11 @@
     if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) {
         offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), false);
         if (eq_ctxt->ctl)
-            offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq,
+            offload_eq_send_params(eq_ctxt->ctl, &eq_ctxt->offload_eq,
                                    OFFLOAD_SEND_EQ_ENABLE_FLAG);
+        if (eq_ctxt->hw_acc_fd > 0)
+            hw_acc_eq_send_params(eq_ctxt->hw_acc_fd, &eq_ctxt->offload_eq,
+                                  OFFLOAD_SEND_EQ_ENABLE_FLAG);
     }
     return 0;
 }
@@ -479,19 +495,44 @@
 
     ALOGV("%s: ctxt %p, ctl %p", __func__, eq_ctxt, output->ctl);
     eq_ctxt->ctl = output->ctl;
-    if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq)))
+    if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) {
         if (eq_ctxt->ctl)
-            offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq,
+            offload_eq_send_params(eq_ctxt->ctl, &eq_ctxt->offload_eq,
                                    OFFLOAD_SEND_EQ_ENABLE_FLAG |
                                    OFFLOAD_SEND_EQ_BANDS_LEVEL);
+        if (eq_ctxt->hw_acc_fd > 0)
+            hw_acc_eq_send_params(eq_ctxt->hw_acc_fd, &eq_ctxt->offload_eq,
+                                  OFFLOAD_SEND_EQ_ENABLE_FLAG |
+                                  OFFLOAD_SEND_EQ_BANDS_LEVEL);
+    }
     return 0;
 }
 
-int equalizer_stop(effect_context_t *context, output_context_t *output)
+int equalizer_stop(effect_context_t *context, output_context_t *output __unused)
 {
     equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
 
     ALOGV("%s: ctxt %p", __func__, eq_ctxt);
+    if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq)) &&
+        eq_ctxt->ctl) {
+        struct eq_params eq;
+        eq.enable_flag = false;
+        offload_eq_send_params(eq_ctxt->ctl, &eq, OFFLOAD_SEND_EQ_ENABLE_FLAG);
+    }
     eq_ctxt->ctl = NULL;
     return 0;
 }
+
+int equalizer_set_mode(effect_context_t *context, int32_t hw_acc_fd)
+{
+    equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, eq_ctxt);
+    eq_ctxt->hw_acc_fd = hw_acc_fd;
+    if ((eq_ctxt->hw_acc_fd > 0) &&
+        (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))))
+        hw_acc_eq_send_params(eq_ctxt->hw_acc_fd, &eq_ctxt->offload_eq,
+                              OFFLOAD_SEND_EQ_ENABLE_FLAG |
+                              OFFLOAD_SEND_EQ_BANDS_LEVEL);
+    return 0;
+}
diff --git a/post_proc/equalizer.h b/post_proc/equalizer.h
index 19af186..7fec058 100644
--- a/post_proc/equalizer.h
+++ b/post_proc/equalizer.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -36,6 +36,7 @@
 
     // Offload vars
     struct mixer_ctl *ctl;
+    int hw_acc_fd;
     uint32_t device;
     struct eq_params offload_eq;
 } equalizer_context_t;
@@ -48,6 +49,8 @@
 
 int equalizer_set_device(effect_context_t *context,  uint32_t device);
 
+int equalizer_set_mode(effect_context_t *context,  int32_t hw_acc_fd);
+
 int equalizer_reset(effect_context_t *context);
 
 int equalizer_init(effect_context_t *context);
diff --git a/post_proc/hw_accelerator.c b/post_proc/hw_accelerator.c
new file mode 100644
index 0000000..fd95db0
--- /dev/null
+++ b/post_proc/hw_accelerator.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "hw_accelerator_effect"
+/*#define LOG_NDEBUG 0*/
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <fcntl.h>
+#include <tinyalsa/asoundlib.h>
+#include <sound/audio_effects.h>
+#include <audio_effects/effect_hwaccelerator.h>
+
+#include "effect_api.h"
+#include "hw_accelerator.h"
+
+
+/* hw_accelerator UUID: 7d1580bd-297f-4683-9239-e475b6d1d69f */
+const effect_descriptor_t hw_accelerator_descriptor = {
+        EFFECT_UIID_HWACCELERATOR__,
+        {0x7d1580bd, 0x297f, 0x4683, 0x9239, {0xe4, 0x75, 0xb6, 0xd1, 0xd6, 0x9f}}, // uuid
+        EFFECT_CONTROL_API_VERSION,
+        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_DEVICE_IND),
+        0, /* TODO */
+        1,
+        "HwAccelerated Library",
+        "QTI",
+};
+
+int hw_accelerator_get_parameter(effect_context_t *context,
+                                 effect_param_t *p, uint32_t *size)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+    int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+    int32_t *param_tmp = (int32_t *)p->data;
+    int32_t param = *param_tmp++;
+    void *value = p->data + voffset;
+    int i;
+
+    ALOGV("%s: ctxt %p, param %d", __func__, hw_acc_ctxt, param);
+
+    p->status = 0;
+
+    switch (param) {
+    case HW_ACCELERATOR_FD:
+        if (p->vsize < sizeof(int32_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(int32_t);
+        break;
+    default:
+        p->status = -EINVAL;
+    }
+
+    *size = sizeof(effect_param_t) + voffset + p->vsize;
+
+    if (p->status != 0)
+        return 0;
+
+    switch (param) {
+    case HW_ACCELERATOR_FD:
+        ALOGV("%s: HW_ACCELERATOR_FD", __func__);
+        *(int32_t *)value = hw_acc_ctxt->fd;
+        break;
+
+    default:
+        p->status = -EINVAL;
+        break;
+    }
+
+    return 0;
+}
+
+int hw_accelerator_set_parameter(effect_context_t *context, effect_param_t *p,
+                            uint32_t size)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+    int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+    void *value = p->data + voffset;
+    int32_t *param_tmp = (int32_t *)p->data;
+    int32_t param = *param_tmp++;
+
+    ALOGV("%s: ctxt %p, param %d", __func__, hw_acc_ctxt, param);
+
+    p->status = 0;
+
+    switch (param) {
+    case HW_ACCELERATOR_HPX_STATE: {
+        int hpxState = (uint32_t)(*(int32_t *)value);
+        if (hpxState)
+            hw_acc_hpx_send_params(hw_acc_ctxt->fd, OFFLOAD_SEND_HPX_STATE_ON);
+        else
+            hw_acc_hpx_send_params(hw_acc_ctxt->fd, OFFLOAD_SEND_HPX_STATE_OFF);
+        break;
+    }
+    default:
+        p->status = -EINVAL;
+        break;
+    }
+
+    return 0;
+}
+
+int hw_accelerator_set_device(effect_context_t *context, uint32_t device)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, hw_acc_ctxt);
+    hw_acc_ctxt->device = device;
+    return 0;
+}
+
+int hw_accelerator_init(effect_context_t *context)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, hw_acc_ctxt);
+    context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+    context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_7POINT1;
+    context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    context->config.inputCfg.samplingRate = 44100;
+    context->config.inputCfg.bufferProvider.getBuffer = NULL;
+    context->config.inputCfg.bufferProvider.releaseBuffer = NULL;
+    context->config.inputCfg.bufferProvider.cookie = NULL;
+    context->config.inputCfg.mask = EFFECT_CONFIG_ALL;
+
+    context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+    context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+    context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    context->config.outputCfg.samplingRate = 44100;
+    context->config.outputCfg.bufferProvider.getBuffer = NULL;
+    context->config.outputCfg.bufferProvider.releaseBuffer = NULL;
+    context->config.outputCfg.bufferProvider.cookie = NULL;
+    context->config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+    set_config(context, &context->config);
+
+    hw_acc_ctxt->fd = -1;
+    memset(&(hw_acc_ctxt->cfg), 0, sizeof(struct msm_hwacc_effects_config));
+
+    return 0;
+}
+
+int hw_accelerator_reset(effect_context_t *context)
+{
+    ALOGV("%s", __func__);
+    return 0;
+}
+
+int hw_accelerator_set_mode(effect_context_t *context, int32_t frame_count)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, hw_acc_ctxt);
+    hw_acc_ctxt->cfg.output.sample_rate = context->config.inputCfg.samplingRate;
+    hw_acc_ctxt->cfg.input.sample_rate = context->config.outputCfg.samplingRate;
+
+    hw_acc_ctxt->cfg.output.num_channels = popcount(context->config.inputCfg.channels);
+    hw_acc_ctxt->cfg.input.num_channels = popcount(context->config.outputCfg.channels);
+
+    hw_acc_ctxt->cfg.output.bits_per_sample = 8 *
+                                audio_bytes_per_sample(context->config.inputCfg.format);
+    hw_acc_ctxt->cfg.input.bits_per_sample = 8 *
+                                audio_bytes_per_sample(context->config.outputCfg.format);
+
+    ALOGV("write: sample_rate: %d, channel: %d, bit_width: %d",
+           hw_acc_ctxt->cfg.output.sample_rate, hw_acc_ctxt->cfg.output.num_channels,
+           hw_acc_ctxt->cfg.output.bits_per_sample);
+    ALOGV("read: sample_rate: %d, channel: %d, bit_width: %d",
+           hw_acc_ctxt->cfg.input.sample_rate, hw_acc_ctxt->cfg.input.num_channels,
+           hw_acc_ctxt->cfg.input.bits_per_sample);
+
+    hw_acc_ctxt->cfg.output.num_buf = 4;
+    hw_acc_ctxt->cfg.input.num_buf = 2;
+
+    hw_acc_ctxt->cfg.output.buf_size = frame_count *
+                    hw_acc_ctxt->cfg.output.num_channels *
+                    audio_bytes_per_sample(context->config.inputCfg.format) *
+                    ((hw_acc_ctxt->cfg.output.sample_rate/hw_acc_ctxt->cfg.input.sample_rate) +
+                     (hw_acc_ctxt->cfg.output.sample_rate%hw_acc_ctxt->cfg.input.sample_rate ? 1 : 0));
+    hw_acc_ctxt->cfg.input.buf_size = frame_count *
+                    hw_acc_ctxt->cfg.input.num_channels *
+                    audio_bytes_per_sample(context->config.outputCfg.format);
+
+    hw_acc_ctxt->cfg.meta_mode_enabled = 0;
+    /* TODO: overwrite this for effects using custom topology*/
+    hw_acc_ctxt->cfg.overwrite_topology = 0;
+    hw_acc_ctxt->cfg.topology = 0;
+
+    return 0;
+}
+
+int hw_accelerator_enable(effect_context_t *context)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, hw_acc_ctxt);
+    hw_acc_ctxt->fd = open("/dev/msm_hweffects", O_RDWR | O_NONBLOCK);
+    /* open driver */
+    if (hw_acc_ctxt->fd < 0) {
+         ALOGE("Audio Effects driver open failed");
+         return -EFAULT;
+    }
+    /* set config */
+    if (ioctl(hw_acc_ctxt->fd, AUDIO_SET_EFFECTS_CONFIG, &hw_acc_ctxt->cfg) < 0) {
+        ALOGE("setting audio effects drivers config failed");
+        if (close(hw_acc_ctxt->fd) < 0)
+            ALOGE("releasing hardware accelerated effects driver failed");
+        hw_acc_ctxt->fd = -1;
+        return -EFAULT;
+    }
+    /* start */
+    if (ioctl(hw_acc_ctxt->fd,  AUDIO_START, 0) < 0) {
+        ALOGE("audio effects drivers prepare failed");
+        if (close(hw_acc_ctxt->fd) < 0)
+            ALOGE("releasing hardware accelerated effects driver failed");
+        hw_acc_ctxt->fd = -1;
+        return -EFAULT;
+    }
+    return 0;
+}
+
+int hw_accelerator_disable(effect_context_t *context)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, hw_acc_ctxt);
+    if (hw_acc_ctxt->fd > 0)
+        if (close(hw_acc_ctxt->fd) < 0)
+            ALOGE("releasing hardware accelerated effects driver failed");
+    hw_acc_ctxt->fd = -1;
+    return 0;
+}
+
+int hw_accelerator_release(effect_context_t *context)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, hw_acc_ctxt);
+    if (hw_acc_ctxt->fd > 0)
+        if (close(hw_acc_ctxt->fd) < 0)
+            ALOGE("releasing hardware accelerated effects driver failed");
+    hw_acc_ctxt->fd = -1;
+    return 0;
+}
+
+int hw_accelerator_process(effect_context_t *context, audio_buffer_t *in_buf,
+                           audio_buffer_t *out_buf)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+    struct msm_hwacc_buf_cfg buf_cfg;
+    struct msm_hwacc_buf_avail buf_avail;
+    int ret = 0;
+
+    ALOGV("%s: ctxt %p", __func__, hw_acc_ctxt);
+    if (in_buf == NULL || in_buf->raw == NULL ||
+        out_buf == NULL || out_buf->raw == NULL)
+        return -EINVAL;
+
+    buf_cfg.output_len = in_buf->frameCount *
+                         audio_bytes_per_sample(context->config.inputCfg.format) *
+                         hw_acc_ctxt->cfg.output.num_channels;
+    buf_cfg.input_len = out_buf->frameCount *
+                         audio_bytes_per_sample(context->config.outputCfg.format) *
+                         hw_acc_ctxt->cfg.input.num_channels;
+
+    if (ioctl(hw_acc_ctxt->fd, AUDIO_EFFECTS_GET_BUF_AVAIL, &buf_avail) < 0) {
+        ALOGE("AUDIO_EFFECTS_GET_BUF_AVAIL failed");
+        return -ENOMEM;
+    }
+
+    if (!hw_acc_ctxt->intial_buffer_done) {
+        if (ioctl(hw_acc_ctxt->fd, AUDIO_EFFECTS_SET_BUF_LEN, &buf_cfg) < 0) {
+            ALOGE("AUDIO_EFFECTS_BUF_CFG failed");
+            return -EFAULT;
+        }
+        if (ioctl(hw_acc_ctxt->fd, AUDIO_EFFECTS_WRITE, (char *)in_buf->raw) < 0) {
+            ALOGE("AUDIO_EFFECTS_WRITE failed");
+            return -EFAULT;
+        }
+        ALOGV("Request for more data");
+        hw_acc_ctxt->intial_buffer_done = true;
+        return -ENODATA;
+    }
+    if (buf_avail.output_num_avail > 1) {
+        if (ioctl(hw_acc_ctxt->fd, AUDIO_EFFECTS_SET_BUF_LEN, &buf_cfg) < 0) {
+            ALOGE("AUDIO_EFFECTS_BUF_CFG failed");
+            return -EFAULT;
+        }
+        if (ioctl(hw_acc_ctxt->fd, AUDIO_EFFECTS_WRITE, (char *)in_buf->raw) < 0) {
+            ALOGE("AUDIO_EFFECTS_WRITE failed");
+            return -EFAULT;
+        }
+        ret = in_buf->frameCount;
+    }
+    if (ioctl(hw_acc_ctxt->fd, AUDIO_EFFECTS_READ, (char *)out_buf->raw) < 0) {
+        ALOGE("AUDIO_EFFECTS_READ failed");
+        return -EFAULT;
+    }
+
+    return ret;
+}
diff --git a/post_proc/hw_accelerator.h b/post_proc/hw_accelerator.h
new file mode 100644
index 0000000..6387da8
--- /dev/null
+++ b/post_proc/hw_accelerator.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HW_ACCELERATOR_EFFECT_H_
+#define HW_ACCELERATOR_EFFECT_H_
+
+#include "bundle.h"
+
+#include <linux/msm_audio.h>
+
+#define HWACCELERATOR_OUTPUT_CHANNELS AUDIO_CHANNEL_OUT_STEREO
+
+extern const effect_descriptor_t hw_accelerator_descriptor;
+
+typedef struct hw_accelerator_context_s {
+    effect_context_t common;
+
+    int fd;
+    uint32_t device;
+    bool intial_buffer_done;
+    struct msm_hwacc_effects_config cfg;
+} hw_accelerator_context_t;
+
+int hw_accelerator_get_parameter(effect_context_t *context,
+                                 effect_param_t *p, uint32_t *size);
+
+int hw_accelerator_set_parameter(effect_context_t *context,
+                                 effect_param_t *p, uint32_t size);
+
+int hw_accelerator_set_device(effect_context_t *context,  uint32_t device);
+
+int hw_accelerator_reset(effect_context_t *context);
+
+int hw_accelerator_init(effect_context_t *context);
+
+int hw_accelerator_enable(effect_context_t *context);
+
+int hw_accelerator_disable(effect_context_t *context);
+
+int hw_accelerator_release(effect_context_t *context);
+
+int hw_accelerator_set_mode(effect_context_t *context,  int32_t frame_count);
+
+int hw_accelerator_process(effect_context_t *context, audio_buffer_t *in,
+                           audio_buffer_t *out);
+
+#endif /* HW_ACCELERATOR_EFFECT_H_ */
diff --git a/post_proc/reverb.c b/post_proc/reverb.c
index 77ae303..b256e53 100644
--- a/post_proc/reverb.c
+++ b/post_proc/reverb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013 - 2014, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -18,7 +18,7 @@
  */
 
 #define LOG_TAG "offload_effect_reverb"
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <cutils/list.h>
 #include <cutils/log.h>
@@ -102,6 +102,14 @@
     context->preset = false;
 }
 
+void reverb_insert_init(reverb_context_t *context)
+{
+    context->auxiliary = false;
+    context->preset = true;
+    context->cur_preset = REVERB_PRESET_LAST + 1;
+    context->next_preset = REVERB_DEFAULT_PRESET;
+}
+
 void reverb_preset_init(reverb_context_t *context)
 {
     context->auxiliary = false;
@@ -125,9 +133,13 @@
     context->reverb_settings.roomLevel = room_level;
     offload_reverb_set_room_level(&(context->offload_reverb), room_level);
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_ROOM_LEVEL);
+    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_ROOM_LEVEL);
 }
 
 int16_t reverb_get_room_hf_level(reverb_context_t *context)
@@ -143,9 +155,13 @@
     context->reverb_settings.roomHFLevel = room_hf_level;
     offload_reverb_set_room_hf_level(&(context->offload_reverb), room_hf_level);
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL);
+    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_ROOM_HF_LEVEL);
 }
 
 uint32_t reverb_get_decay_time(reverb_context_t *context)
@@ -161,9 +177,13 @@
     context->reverb_settings.decayTime = decay_time;
     offload_reverb_set_decay_time(&(context->offload_reverb), decay_time);
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_DECAY_TIME);
+    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_DECAY_TIME);
 }
 
 int16_t reverb_get_decay_hf_ratio(reverb_context_t *context)
@@ -179,9 +199,13 @@
     context->reverb_settings.decayHFRatio = decay_hf_ratio;
     offload_reverb_set_decay_hf_ratio(&(context->offload_reverb), decay_hf_ratio);
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_DECAY_HF_RATIO);
+    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_DECAY_HF_RATIO);
 }
 
 int16_t reverb_get_reverb_level(reverb_context_t *context)
@@ -197,9 +221,13 @@
     context->reverb_settings.reverbLevel = reverb_level;
     offload_reverb_set_reverb_level(&(context->offload_reverb), reverb_level);
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_LEVEL);
+    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_LEVEL);
 }
 
 int16_t reverb_get_diffusion(reverb_context_t *context)
@@ -215,9 +243,13 @@
     context->reverb_settings.diffusion = diffusion;
     offload_reverb_set_diffusion(&(context->offload_reverb), diffusion);
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_DIFFUSION);
+    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_DIFFUSION);
 }
 
 int16_t reverb_get_density(reverb_context_t *context)
@@ -233,9 +265,13 @@
     context->reverb_settings.density = density;
     offload_reverb_set_density(&(context->offload_reverb), density);
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_DENSITY);
+    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_DENSITY);
 }
 
 void reverb_set_preset(reverb_context_t *context, int16_t preset)
@@ -249,9 +285,13 @@
     offload_reverb_set_enable_flag(&(context->offload_reverb), enable);
 
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        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,
+                                  OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                  OFFLOAD_SEND_REVERB_PRESET);
 }
 
 void reverb_set_all_properties(reverb_context_t *context,
@@ -266,7 +306,7 @@
     context->reverb_settings.diffusion = reverb_settings->diffusion;
     context->reverb_settings.density = reverb_settings->density;
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_ROOM_LEVEL |
                                    OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL |
@@ -275,6 +315,16 @@
                                    OFFLOAD_SEND_REVERB_LEVEL |
                                    OFFLOAD_SEND_REVERB_DIFFUSION |
                                    OFFLOAD_SEND_REVERB_DENSITY);
+    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_ROOM_LEVEL |
+                                  OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL |
+                                  OFFLOAD_SEND_REVERB_DECAY_TIME |
+                                  OFFLOAD_SEND_REVERB_DECAY_HF_RATIO |
+                                  OFFLOAD_SEND_REVERB_LEVEL |
+                                  OFFLOAD_SEND_REVERB_DIFFUSION |
+                                  OFFLOAD_SEND_REVERB_DENSITY);
 }
 
 void reverb_load_preset(reverb_context_t *context)
@@ -433,7 +483,7 @@
 }
 
 int reverb_set_parameter(effect_context_t *context, effect_param_t *p,
-                         uint32_t size)
+                         uint32_t size __unused)
 {
     reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
     int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
@@ -549,6 +599,7 @@
 
     set_config(context, &context->config);
 
+    reverb_ctxt->hw_acc_fd = -1;
     memset(&(reverb_ctxt->reverb_settings), 0, sizeof(reverb_settings_t));
     memset(&(reverb_ctxt->offload_reverb), 0, sizeof(struct reverb_params));
 
@@ -579,8 +630,12 @@
         offload_reverb_set_enable_flag(&(reverb_ctxt->offload_reverb), false);
         if (reverb_ctxt->ctl)
             offload_reverb_send_params(reverb_ctxt->ctl,
-                                       reverb_ctxt->offload_reverb,
+                                       &reverb_ctxt->offload_reverb,
                                        OFFLOAD_SEND_REVERB_ENABLE_FLAG);
+        if (reverb_ctxt->hw_acc_fd > 0)
+            hw_acc_reverb_send_params(reverb_ctxt->hw_acc_fd,
+                                      &reverb_ctxt->offload_reverb,
+                                      OFFLOAD_SEND_REVERB_ENABLE_FLAG);
     }
     return 0;
 }
@@ -593,21 +648,48 @@
     reverb_ctxt->ctl = output->ctl;
     if (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))) {
         if (reverb_ctxt->ctl && reverb_ctxt->preset) {
-            offload_reverb_send_params(reverb_ctxt->ctl, reverb_ctxt->offload_reverb,
+            offload_reverb_send_params(reverb_ctxt->ctl, &reverb_ctxt->offload_reverb,
                                        OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                        OFFLOAD_SEND_REVERB_PRESET);
         }
+        if ((reverb_ctxt->hw_acc_fd > 0) && reverb_ctxt->preset) {
+            hw_acc_reverb_send_params(reverb_ctxt->hw_acc_fd,
+                                      &reverb_ctxt->offload_reverb,
+                                      OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                      OFFLOAD_SEND_REVERB_PRESET);
+        }
     }
 
     return 0;
 }
 
-int reverb_stop(effect_context_t *context, output_context_t *output)
+int reverb_stop(effect_context_t *context, output_context_t *output __unused)
 {
     reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
 
     ALOGV("%s: ctxt %p", __func__, reverb_ctxt);
+    if (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb)) &&
+        reverb_ctxt->ctl) {
+        struct reverb_params reverb;
+        reverb.enable_flag = false;
+        offload_reverb_send_params(reverb_ctxt->ctl, &reverb,
+                                   OFFLOAD_SEND_REVERB_ENABLE_FLAG);
+    }
     reverb_ctxt->ctl = NULL;
     return 0;
 }
 
+int reverb_set_mode(effect_context_t *context, int32_t hw_acc_fd)
+{
+    reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, reverb_ctxt);
+    reverb_ctxt->hw_acc_fd = hw_acc_fd;
+    if ((reverb_ctxt->hw_acc_fd > 0) &&
+        (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))))
+        hw_acc_reverb_send_params(reverb_ctxt->hw_acc_fd,
+                                  &reverb_ctxt->offload_reverb,
+                                  OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
+                                  OFFLOAD_SEND_BASSBOOST_STRENGTH);
+    return 0;
+}
diff --git a/post_proc/reverb.h b/post_proc/reverb.h
index 63192eb..991151e 100644
--- a/post_proc/reverb.h
+++ b/post_proc/reverb.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -47,6 +47,7 @@
 
     // Offload vars
     struct mixer_ctl *ctl;
+    int hw_acc_fd;
     bool auxiliary;
     bool preset;
     uint16_t cur_preset;
@@ -61,6 +62,8 @@
 
 void reverb_preset_init(reverb_context_t *context);
 
+void reverb_insert_init(reverb_context_t *context);
+
 int reverb_get_parameter(effect_context_t *context, effect_param_t *p,
                             uint32_t *size);
 
@@ -69,6 +72,8 @@
 
 int reverb_set_device(effect_context_t *context,  uint32_t device);
 
+int reverb_set_mode(effect_context_t *context,  int32_t hw_acc_fd);
+
 int reverb_reset(effect_context_t *context);
 
 int reverb_init(effect_context_t *context);
diff --git a/post_proc/virtualizer.c b/post_proc/virtualizer.c
index 9ed1ac5..2748568 100644
--- a/post_proc/virtualizer.c
+++ b/post_proc/virtualizer.c
@@ -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
@@ -18,7 +18,7 @@
  */
 
 #define LOG_TAG "offload_effect_virtualizer"
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <cutils/list.h>
 #include <cutils/log.h>
@@ -58,12 +58,208 @@
 
     offload_virtualizer_set_strength(&(context->offload_virt), strength);
     if (context->ctl)
-        offload_virtualizer_send_params(context->ctl, context->offload_virt,
+        offload_virtualizer_send_params(context->ctl, &context->offload_virt,
                                         OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
                                         OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
+    if (context->hw_acc_fd > 0)
+        hw_acc_virtualizer_send_params(context->hw_acc_fd,
+                                       &context->offload_virt,
+                                       OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
+                                       OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
     return 0;
 }
 
+/*
+ *  Check if an audio device is supported by this implementation
+ *
+ *  [in]
+ *  device    device that is intented for processing (e.g. for binaural vs transaural)
+ *  [out]
+ *  false     device is not applicable for effect
+ *  true      device is applicable for effect
+ */
+bool virtualizer_is_device_supported(audio_devices_t device) {
+    switch (device) {
+    case AUDIO_DEVICE_OUT_SPEAKER:
+    case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+    case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+#ifdef AFE_PROXY_ENABLED
+    case AUDIO_DEVICE_OUT_PROXY:
+#endif
+    case AUDIO_DEVICE_OUT_AUX_DIGITAL:
+    case AUDIO_DEVICE_OUT_USB_ACCESSORY:
+    case AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET:
+        return false;
+    default :
+        return true;
+    }
+}
+
+/*
+ *  Check if a channel mask + audio device is supported by this implementation
+ *
+ *  [in]
+ *  channel_mask channel mask of input buffer
+ *  device       device that is intented for processing (e.g. for binaural vs transaural)
+ *  [out]
+ *  false        if the configuration is not supported or it is unknown
+ *  true         if the configuration is supported
+ */
+bool virtualizer_is_configuration_supported(audio_channel_mask_t channel_mask,
+        audio_devices_t device) {
+    uint32_t channelCount = audio_channel_count_from_out_mask(channel_mask);
+    if ((channelCount == 0) || (channelCount > 2)) {
+        return false;
+    }
+
+    return virtualizer_is_device_supported(device);
+}
+
+/*
+ *  Force the virtualization mode to that of the given audio device
+ *
+ *  [in]
+ *  context       effect engine context
+ *  forced_device device whose virtualization mode we'll always use
+ *  [out]
+ *  -EINVAL       if the device is not supported or is unknown
+ *  0             if the device is supported and the virtualization mode forced
+ */
+int virtualizer_force_virtualization_mode(virtualizer_context_t *context,
+        audio_devices_t forced_device) {
+    virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+    int status = 0;
+    bool use_virt = false;
+    int is_virt_enabled =
+        offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt));
+
+    ALOGV("%s: ctxt %p, forcedDev=0x%x enabled=%d tmpDisabled=%d", __func__, virt_ctxt,
+            forced_device, is_virt_enabled, virt_ctxt->temp_disabled);
+
+    if (virtualizer_is_device_supported(forced_device) == false) {
+        if (forced_device != AUDIO_DEVICE_NONE) {
+            //forced device is not supported, make it behave as a reset of forced mode
+            forced_device = AUDIO_DEVICE_NONE;
+            // but return an error
+            status = -EINVAL;
+        }
+    }
+
+    if (forced_device == AUDIO_DEVICE_NONE) {
+        // disabling forced virtualization mode:
+        // verify whether the virtualization should be enabled or disabled
+        if (virtualizer_is_device_supported(virt_ctxt->device)) {
+            use_virt = (is_virt_enabled == true);
+        }
+        virt_ctxt->forced_device = AUDIO_DEVICE_NONE;
+    } else {
+        // forcing virtualization mode:
+        // TODO: we assume device is supported, so hard coded a fixed one.
+        virt_ctxt->forced_device = AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+        // TODO: only enable for a supported mode, when the effect is enabled
+        use_virt = (is_virt_enabled == true);
+    }
+
+    if (use_virt) {
+        if (virt_ctxt->temp_disabled == true) {
+            if (effect_is_active(&virt_ctxt->common)) {
+                offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
+                if (virt_ctxt->ctl)
+                    offload_virtualizer_send_params(virt_ctxt->ctl,
+                                                    &virt_ctxt->offload_virt,
+                                                    OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+                if (virt_ctxt->hw_acc_fd > 0)
+                    hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+                                                   &virt_ctxt->offload_virt,
+                                                   OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+            }
+            ALOGV("%s: re-enable VIRTUALIZER", __func__);
+            virt_ctxt->temp_disabled = false;
+        } else {
+            ALOGV("%s: leaving VIRTUALIZER enabled", __func__);
+        }
+    } else {
+        if (virt_ctxt->temp_disabled == false) {
+            if (effect_is_active(&virt_ctxt->common)) {
+                offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
+                if (virt_ctxt->ctl)
+                    offload_virtualizer_send_params(virt_ctxt->ctl,
+                                                    &virt_ctxt->offload_virt,
+                                                    OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+                if (virt_ctxt->hw_acc_fd > 0)
+                    hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+                                                   &virt_ctxt->offload_virt,
+                                                   OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+            }
+            ALOGV("%s: disable VIRTUALIZER", __func__);
+            virt_ctxt->temp_disabled = true;
+        } else {
+            ALOGV("%s: leaving VIRTUALIZER disabled", __func__);
+        }
+    }
+
+    ALOGV("after %s: ctxt %p, enabled=%d tmpDisabled=%d", __func__, virt_ctxt,
+            is_virt_enabled, virt_ctxt->temp_disabled);
+
+    return status;
+}
+
+/*
+ *  Get the virtual speaker angles for a channel mask + audio device configuration
+ *  which is guaranteed to be supported by this implementation
+ *
+ *  [in]
+ *  channel_mask   the channel mask of the input to virtualize
+ *  device         the type of device that affects the processing (e.g. for binaural vs transaural)
+ *  [in/out]
+ *  speaker_angles the array of integer where each speaker angle is written as a triplet in the
+ *                 following format:
+ *                  int32_t a bit mask with a single value selected for each speaker, following
+ *                  the convention of the audio_channel_mask_t type
+ *                  int32_t a value in degrees expressing the speaker azimuth, where 0 is in front
+ *                  of the user, 180 behind, -90 to the left, 90 to the right of the user
+ *                  int32_t a value in degrees expressing the speaker elevation, where 0 is the
+ *                  horizontal plane, +90 is directly above the user, -90 below
+ *
+ */
+void virtualizer_get_speaker_angles(audio_channel_mask_t channel_mask __unused,
+        audio_devices_t device __unused, int32_t *speaker_angles) {
+    // the channel count is guaranteed to be 1 or 2
+    // the device is guaranteed to be of type headphone
+    // this virtualizer is always 2in with speakers at -90 and 90deg of azimuth, 0deg of elevation
+    *speaker_angles++ = (int32_t) AUDIO_CHANNEL_OUT_FRONT_LEFT;
+    *speaker_angles++ = -90; // azimuth
+    *speaker_angles++ = 0;   // elevation
+    *speaker_angles++ = (int32_t) AUDIO_CHANNEL_OUT_FRONT_RIGHT;
+    *speaker_angles++ = 90;  // azimuth
+    *speaker_angles   = 0;   // elevation
+}
+
+/*
+ *  Retrieve the current device whose processing mode is used by this effect
+ *
+ *  [out]
+ *  AUDIO_DEVICE_NONE if the effect is not virtualizing
+ *  or the device type if the effect is virtualizing
+ */
+audio_devices_t virtualizer_get_virtualization_mode(virtualizer_context_t *context) {
+    virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+    audio_devices_t device = AUDIO_DEVICE_NONE;
+
+    if ((offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)))
+            && (virt_ctxt->temp_disabled == false)) {
+        if (virt_ctxt->forced_device != AUDIO_DEVICE_NONE) {
+            // virtualization mode is forced, return that device
+            device = virt_ctxt->forced_device;
+        } else {
+            // no forced mode, return the current device
+            device = virt_ctxt->device;
+        }
+    }
+    ALOGV("%s: returning 0x%x", __func__, device);
+    return device;
+}
+
 int virtualizer_get_parameter(effect_context_t *context, effect_param_t *p,
                               uint32_t *size)
 {
@@ -89,6 +285,15 @@
            p->status = -EINVAL;
         p->vsize = sizeof(int16_t);
         break;
+    case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES:
+        // return value size can only be interpreted as relative to input value,
+        // deferring validity check to below
+        break;
+    case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE:
+        if (p->vsize != sizeof(uint32_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(uint32_t);
+        break;
     default:
         p->status = -EINVAL;
     }
@@ -107,6 +312,31 @@
         *(int16_t *)value = virtualizer_get_strength(virt_ctxt);
         break;
 
+    case VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES:
+    {
+        const audio_channel_mask_t channel_mask = (audio_channel_mask_t) *param_tmp++;
+        const audio_devices_t device = (audio_devices_t) *param_tmp;
+        uint32_t channel_cnt = audio_channel_count_from_out_mask(channel_mask);
+
+        if (p->vsize < 3 * channel_cnt * sizeof(int32_t)){
+            p->status = -EINVAL;
+            break;
+        }
+        // verify the configuration is supported
+        if(virtualizer_is_configuration_supported(channel_mask, device)) {
+            // configuration is supported, get the angles
+            virtualizer_get_speaker_angles(channel_mask, device, (int32_t *)value);
+        } else {
+            p->status = -EINVAL;
+        }
+
+        break;
+    }
+
+    case VIRTUALIZER_PARAM_VIRTUALIZATION_MODE:
+        *(uint32_t *)value  = (uint32_t) virtualizer_get_virtualization_mode(virt_ctxt);
+        break;
+
     default:
         p->status = -EINVAL;
         break;
@@ -116,7 +346,7 @@
 }
 
 int virtualizer_set_parameter(effect_context_t *context, effect_param_t *p,
-                              uint32_t size)
+                              uint32_t size __unused)
 {
     virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
     int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
@@ -134,6 +364,14 @@
         strength = (uint32_t)(*(int16_t *)value);
         virtualizer_set_strength(virt_ctxt, strength);
         break;
+    case VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE:
+    {
+        const audio_devices_t device = *(audio_devices_t *)value;
+        if (0 != virtualizer_force_virtualization_mode(virt_ctxt, device)) {
+            p->status = -EINVAL;
+        }
+        break;
+    }
     default:
         p->status = -EINVAL;
         break;
@@ -148,38 +386,44 @@
 
     ALOGV("%s: ctxt %p, device: 0x%x", __func__, virt_ctxt, device);
     virt_ctxt->device = device;
-    if((device == AUDIO_DEVICE_OUT_SPEAKER) ||
-       (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) ||
-       (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) ||
-#ifdef AFE_PROXY_ENABLED
-       (device == AUDIO_DEVICE_OUT_PROXY) ||
-#endif
-       (device == AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
-       (device == AUDIO_DEVICE_OUT_USB_ACCESSORY) ||
-       (device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET)) {
-        if (!virt_ctxt->temp_disabled) {
-            if (effect_is_active(&virt_ctxt->common)) {
-                offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
-                if (virt_ctxt->ctl)
-                    offload_virtualizer_send_params(virt_ctxt->ctl,
-                                                    virt_ctxt->offload_virt,
-                                                    OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+
+    if (virt_ctxt->forced_device == AUDIO_DEVICE_NONE) {
+        // default case unless configuration is forced
+        if (virtualizer_is_device_supported(device) == false) {
+            if (!virt_ctxt->temp_disabled) {
+                if (effect_is_active(&virt_ctxt->common)) {
+                    offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
+                    if (virt_ctxt->ctl)
+                        offload_virtualizer_send_params(virt_ctxt->ctl,
+                                                        &virt_ctxt->offload_virt,
+                                                        OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+                    if (virt_ctxt->hw_acc_fd > 0)
+                        hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+                                                       &virt_ctxt->offload_virt,
+                                                       OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+                }
+                virt_ctxt->temp_disabled = true;
+                ALOGI("%s: ctxt %p, disabled based on device", __func__, virt_ctxt);
             }
-            virt_ctxt->temp_disabled = true;
-            ALOGI("%s: ctxt %p, disabled based on device", __func__, virt_ctxt);
-        }
-    } else {
-        if (virt_ctxt->temp_disabled) {
-            if (effect_is_active(&virt_ctxt->common)) {
-                offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
-                if (virt_ctxt->ctl)
-                    offload_virtualizer_send_params(virt_ctxt->ctl,
-                                                    virt_ctxt->offload_virt,
-                                                    OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+        } else {
+            if (virt_ctxt->temp_disabled) {
+                if (effect_is_active(&virt_ctxt->common)) {
+                    offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
+                    if (virt_ctxt->ctl)
+                        offload_virtualizer_send_params(virt_ctxt->ctl,
+                                                        &virt_ctxt->offload_virt,
+                                                        OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+                    if (virt_ctxt->hw_acc_fd > 0)
+                        hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+                                                       &virt_ctxt->offload_virt,
+                                                       OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+                }
+                virt_ctxt->temp_disabled = false;
             }
-            virt_ctxt->temp_disabled = false;
         }
     }
+    // else virtualization mode is forced to a certain device, nothing to do
+
     offload_virtualizer_set_device(&(virt_ctxt->offload_virt), device);
     return 0;
 }
@@ -216,6 +460,9 @@
     set_config(context, &context->config);
 
     virt_ctxt->temp_disabled = false;
+    virt_ctxt->hw_acc_fd = -1;
+    virt_ctxt->forced_device = AUDIO_DEVICE_NONE;
+    virt_ctxt->device = AUDIO_DEVICE_NONE;
     memset(&(virt_ctxt->offload_virt), 0, sizeof(struct virtualizer_params));
 
     return 0;
@@ -232,9 +479,14 @@
         offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
         if (virt_ctxt->ctl && virt_ctxt->strength)
             offload_virtualizer_send_params(virt_ctxt->ctl,
-                                          virt_ctxt->offload_virt,
+                                          &virt_ctxt->offload_virt,
                                           OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
-                                          OFFLOAD_SEND_BASSBOOST_STRENGTH);
+                                          OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
+        if ((virt_ctxt->hw_acc_fd > 0) && virt_ctxt->strength)
+            hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+                                           &virt_ctxt->offload_virt,
+                                           OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
+                                           OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
     }
     return 0;
 }
@@ -248,8 +500,12 @@
         offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
         if (virt_ctxt->ctl)
             offload_virtualizer_send_params(virt_ctxt->ctl,
-                                          virt_ctxt->offload_virt,
+                                          &virt_ctxt->offload_virt,
                                           OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+        if (virt_ctxt->hw_acc_fd > 0)
+            hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+                                           &virt_ctxt->offload_virt,
+                                           OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
     }
     return 0;
 }
@@ -260,19 +516,47 @@
 
     ALOGV("%s: ctxt %p, ctl %p", __func__, virt_ctxt, output->ctl);
     virt_ctxt->ctl = output->ctl;
-    if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)))
+    if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) {
         if (virt_ctxt->ctl)
-            offload_virtualizer_send_params(virt_ctxt->ctl, virt_ctxt->offload_virt,
+            offload_virtualizer_send_params(virt_ctxt->ctl, &virt_ctxt->offload_virt,
                                           OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
                                           OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
+        if (virt_ctxt->hw_acc_fd > 0)
+            hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+                                           &virt_ctxt->offload_virt,
+                                           OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
+                                           OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
+    }
     return 0;
 }
 
-int virtualizer_stop(effect_context_t *context, output_context_t *output)
+int virtualizer_stop(effect_context_t *context, output_context_t *output __unused)
 {
     virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
 
     ALOGV("%s: ctxt %p", __func__, virt_ctxt);
+    if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)) &&
+        virt_ctxt->ctl) {
+        struct virtualizer_params virt;
+        virt.enable_flag = false;
+        offload_virtualizer_send_params(virt_ctxt->ctl, &virt,
+                                        OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+    }
     virt_ctxt->ctl = NULL;
     return 0;
 }
+
+int virtualizer_set_mode(effect_context_t *context, int32_t hw_acc_fd)
+{
+    virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, virt_ctxt);
+    virt_ctxt->hw_acc_fd = hw_acc_fd;
+    if ((virt_ctxt->hw_acc_fd > 0) &&
+        (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))))
+        hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+                                       &virt_ctxt->offload_virt,
+                                       OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
+                                       OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
+    return 0;
+}
diff --git a/post_proc/virtualizer.h b/post_proc/virtualizer.h
index 4a5005f..b5293fb 100644
--- a/post_proc/virtualizer.h
+++ b/post_proc/virtualizer.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
@@ -31,8 +31,10 @@
 
     // Offload vars
     struct mixer_ctl *ctl;
+    int hw_acc_fd;
     bool temp_disabled;
-    uint32_t device;
+    audio_devices_t forced_device;
+    audio_devices_t device;
     struct virtualizer_params offload_virt;
 } virtualizer_context_t;
 
@@ -44,6 +46,8 @@
 
 int virtualizer_set_device(effect_context_t *context,  uint32_t device);
 
+int virtualizer_set_mode(effect_context_t *context,  int32_t hw_acc_fd);
+
 int virtualizer_reset(effect_context_t *context);
 
 int virtualizer_init(effect_context_t *context);
diff --git a/visualizer/Android.mk b/visualizer/Android.mk
index 393eec3..87d4987 100644
--- a/visualizer/Android.mk
+++ b/visualizer/Android.mk
@@ -24,6 +24,7 @@
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
 	liblog \
+	libdl \
 	libtinyalsa
 
 LOCAL_MODULE_RELATIVE_PATH := soundfx
diff --git a/visualizer/offload_visualizer.c b/visualizer/offload_visualizer.c
index 94c44a5..d363b77 100644
--- a/visualizer/offload_visualizer.c
+++ b/visualizer/offload_visualizer.c
@@ -22,6 +22,7 @@
 #include <string.h>
 #include <time.h>
 #include <sys/prctl.h>
+#include <dlfcn.h>
 
 #include <cutils/list.h>
 #include <cutils/log.h>
@@ -29,6 +30,15 @@
 #include <tinyalsa/asoundlib.h>
 #include <audio_effects/effect_visualizer.h>
 
+#define LIB_ACDB_LOADER "libacdbloader.so"
+#define ACDB_DEV_TYPE_OUT 1
+#define AFE_PROXY_ACDB_ID 45
+
+static void* acdb_handle;
+
+typedef void (*acdb_send_audio_cal_t)(int, int);
+
+acdb_send_audio_cal_t acdb_send_audio_cal;
 
 enum {
     EFFECT_STATE_UNINITIALIZED,
@@ -294,6 +304,9 @@
     const char *proxy_ctl_name = "AFE_PCM_RX Audio Mixer MultiMedia4";
     struct mixer_ctl *ctl;
 
+    if (value && acdb_send_audio_cal)
+        acdb_send_audio_cal(AFE_PROXY_ACDB_ID, ACDB_DEV_TYPE_OUT);
+
     ctl = mixer_get_ctl_by_name(mixer, proxy_ctl_name);
     if (ctl == NULL) {
         ALOGW("%s: could not get %s ctl", __func__, proxy_ctl_name);
@@ -614,6 +627,19 @@
 
     set_config(context, &context->config);
 
+    if (acdb_handle == NULL) {
+        acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
+        if (acdb_handle == NULL) {
+            ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER);
+        } else {
+            acdb_send_audio_cal = (acdb_send_audio_cal_t)dlsym(acdb_handle,
+                                                    "acdb_loader_send_audio_cal");
+            if (!acdb_send_audio_cal)
+                ALOGE("%s: Could not find the symbol acdb_send_audio_cal from %s",
+                      __func__, LIB_ACDB_LOADER);
+            }
+    }
+
     return 0;
 }