Merge "hal: Fix calibration for external speakers."
diff --git a/Android.mk b/Android.mk
index 6d0ec5f..6e129a1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,4 +1,4 @@
-ifneq ($(filter mpq8092 msm8960 msm8226 msm8x26 msm8610 msm8974 msm8x74 apq8084 msm8916 msm8994 msm8992 msm8909 msm8996,$(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 c0cff58..99b6b39 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -32,7 +32,7 @@
 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
@@ -194,6 +194,11 @@
     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
+
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
 	libcutils \
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index ff485e5..688e265 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -91,6 +91,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
@@ -332,7 +343,7 @@
                                                      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);
@@ -535,6 +546,7 @@
    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);
 }
 
 void audio_extn_get_parameters(const struct audio_device *adev,
@@ -547,6 +559,7 @@
     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);
 
     kv_pairs = str_parms_to_str(reply);
     ALOGD_IF(kv_pairs != NULL, "%s: returns %s", __func__, kv_pairs);
diff --git a/hal/audio_extn/dts_eagle.c b/hal/audio_extn/dts_eagle.c
index 83c3506..52d7abb 100644
--- a/hal/audio_extn/dts_eagle.c
+++ b/hal/audio_extn/dts_eagle.c
@@ -150,20 +150,16 @@
     if (strncmp("true", prop, sizeof("true")))
         return;
     int fd, n = 0;
-    if ((fd = open(FADE_NOTIFY_FILE, O_RDONLY)) < 0)
-        ALOGV("No fade node");
-    else {
-        ALOGV("fade node exists, remove it before creating it");
-        close(fd);
-        remove(FADE_NOTIFY_FILE);
+    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);
     }
-    fd = creat(FADE_NOTIFY_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
     char *str = need_data ? "need" : "have";
-    if (fd < 0) {
-        ALOGE("DTS_EAGLE_HAL (%s): opening fade notifier node failed", __func__);
-        return;
-    }
-    chmod(FADE_NOTIFY_FILE, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH);
     n = write(fd, str, strlen(str));
     close(fd);
     if (n > 0)
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_hw.c b/hal/audio_hw.c
index c2d3400..138bd3c 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -190,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",
@@ -285,7 +287,9 @@
         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_WMA ||
+        format == AUDIO_FORMAT_WMA_PRO)
            return true;
 
     return false;
@@ -308,6 +312,12 @@
     case AUDIO_FORMAT_FLAC:
         id = SND_AUDIOCODEC_FLAC;
         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);
     }
@@ -660,6 +670,7 @@
         if (usecase->type != PCM_PLAYBACK &&
                 usecase != uc_info &&
                 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],
@@ -739,14 +750,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;
         }
@@ -803,7 +815,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;
@@ -1796,6 +1808,52 @@
         }
     }
 
+    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);
+    }
+
     ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_SAMPLE_RATE, value, sizeof(value));
     if(ret >= 0)
         is_meta_data_params = true;
@@ -2131,6 +2189,7 @@
         }
         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;
 
@@ -3363,7 +3422,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;
@@ -3383,8 +3442,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);
 
@@ -3405,7 +3464,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;
@@ -3471,6 +3530,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,
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index d0e01e5..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
@@ -115,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,
@@ -342,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/msm8916/hw_info.c b/hal/msm8916/hw_info.c
index 689e834..69c9341 100644
--- a/hal/msm8916/hw_info.c
+++ b/hal/msm8916/hw_info.c
@@ -216,8 +216,32 @@
         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__);
     }
 }
 
@@ -232,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 deec058..043615d 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
@@ -36,6 +36,7 @@
 #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"
@@ -49,6 +50,7 @@
 #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"
@@ -187,6 +189,7 @@
     bool slowtalk;
     bool hd_voice;
     bool ec_ref_enabled;
+    bool is_wsa_speaker;
     /* Audio calibration related functions */
     void                       *acdb_handle;
     int                        voice_feature_set;
@@ -207,6 +210,14 @@
     bool edid_valid;
 };
 
+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},
@@ -281,6 +292,7 @@
     [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",
@@ -288,6 +300,7 @@
     [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",
@@ -383,6 +396,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,
@@ -390,6 +404,7 @@
     [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,
@@ -487,6 +502,7 @@
     {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)},
@@ -494,6 +510,7 @@
     {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)},
@@ -668,6 +685,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)
 {
@@ -789,6 +832,28 @@
         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));
@@ -1170,6 +1235,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;
         }
@@ -1196,6 +1262,7 @@
     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"))) {
@@ -1235,6 +1302,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;
@@ -1309,6 +1377,25 @@
     }
     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();
@@ -1413,11 +1500,19 @@
 
 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;
 }
 
@@ -1966,7 +2061,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;
@@ -2019,7 +2117,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)
@@ -3187,8 +3290,15 @@
     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 = "SLIM_0_RX Format";
+        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) {
@@ -3891,3 +4001,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 dfb976d..03a02bf 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -58,12 +58,14 @@
     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,
@@ -219,17 +221,6 @@
 #define PLAYBACK_OFFLOAD_DEVICE 9
 
 #ifdef MULTIPLE_OFFLOAD_ENABLED
-#ifdef PLATFORM_APQ8084
-#define PLAYBACK_OFFLOAD_DEVICE2 17
-#define PLAYBACK_OFFLOAD_DEVICE3 18
-#define PLAYBACK_OFFLOAD_DEVICE4 34
-#define PLAYBACK_OFFLOAD_DEVICE5 35
-#define PLAYBACK_OFFLOAD_DEVICE6 36
-#define PLAYBACK_OFFLOAD_DEVICE7 37
-#define PLAYBACK_OFFLOAD_DEVICE8 38
-#define PLAYBACK_OFFLOAD_DEVICE9 39
-#endif
-#if defined (PLATFORM_MSM8994)
 #define PLAYBACK_OFFLOAD_DEVICE2 17
 #define PLAYBACK_OFFLOAD_DEVICE3 18
 #define PLAYBACK_OFFLOAD_DEVICE4 37
@@ -239,7 +230,6 @@
 #define PLAYBACK_OFFLOAD_DEVICE8 41
 #define PLAYBACK_OFFLOAD_DEVICE9 42
 #endif
-#endif
 
 #define COMPRESS_VOIP_CALL_PCM_DEVICE 3
 
@@ -253,7 +243,8 @@
 #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
@@ -310,4 +301,12 @@
  */
 #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 4c798b6..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
@@ -1153,3 +1153,9 @@
 {
     return 0;
 }
+
+int platform_set_audio_device_interface(const char * device_name __unused,
+                                        const char *intf_name __unused)
+{
+    return -ENOSYS;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index d34a733..24e23e6 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -44,9 +44,13 @@
 #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"
@@ -242,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},
@@ -637,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},
@@ -988,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));
 
@@ -1028,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.",
@@ -3366,10 +3444,15 @@
         ALOGE("%s: Invalid channel mapping used", __func__);
         return -EINVAL;
     }
-    strlcpy(mixer_ctl_name, "Playback Channel Map", sizeof(mixer_ctl_name));
+
+    /*
+     * 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(device_num, sizeof(device_num), "%d", snd_id);
-        strncat(mixer_ctl_name, device_num, 13);
+        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);
@@ -3659,3 +3742,54 @@
 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 7deb6da..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
@@ -280,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
@@ -288,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
 
@@ -360,4 +374,12 @@
  */
 #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 3e81d68..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
@@ -109,4 +109,5 @@
 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 a176177..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
@@ -46,6 +46,7 @@
     BITWIDTH,
     PCM_ID,
     BACKEND_NAME,
+    INTERFACE_NAME,
 } section_t;
 
 typedef void (* section_process_fn)(const XML_Char **attr);
@@ -54,6 +55,7 @@
 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[] = {
@@ -62,6 +64,7 @@
     [BITWIDTH] = process_bit_width,
     [PCM_ID] = process_pcm_id,
     [BACKEND_NAME] = process_backend_name,
+    [INTERFACE_NAME] = process_interface_name,
 };
 
 static section_t section;
@@ -83,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>
  */
 
@@ -237,6 +245,34 @@
     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)
 {
@@ -252,9 +288,12 @@
         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) && (section != BITWIDTH)) {
-            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;
         }
 
@@ -284,6 +323,8 @@
         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 5bc0a4e..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,
@@ -293,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__);
     }
 
diff --git a/hal/voice.h b/hal/voice.h
index 5038dfa..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
diff --git a/hal/voice_extn/compress_voip.c b/hal/voice_extn/compress_voip.c
index e8ba1f9..14af6fc 100644
--- a/hal/voice_extn/compress_voip.c
+++ b/hal/voice_extn/compress_voip.c
@@ -697,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;
@@ -704,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 00068fe..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__);
     }
@@ -346,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,
@@ -375,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/post_proc/Android.mk b/post_proc/Android.mk
index 880838a..be70166 100644
--- a/post_proc/Android.mk
+++ b/post_proc/Android.mk
@@ -26,7 +26,8 @@
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
 	liblog \
-	libtinyalsa
+	libtinyalsa \
+	libdl
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c
index 57cf8ef..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_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,6 +44,243 @@
         "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);
+
+/*
+ * Bass operations
+ */
+int bass_get_parameter(effect_context_t *context, effect_param_t *p,
+                       uint32_t *size)
+{
+    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", __func__);
+
+    p->status = 0;
+
+    switch (param) {
+    case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
+        if (p->vsize < sizeof(uint32_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(uint32_t);
+        break;
+    case BASSBOOST_PARAM_STRENGTH:
+        if (p->vsize < sizeof(int16_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(int16_t);
+        break;
+    default:
+        p->status = -EINVAL;
+    }
+
+    *size = sizeof(effect_param_t) + voffset + p->vsize;
+
+    if (p->status != 0)
+        return 0;
+
+    switch (param) {
+    case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
+        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:
+        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:
+        p->status = -EINVAL;
+        break;
+    }
+
+    return 0;
+}
+
+int bass_set_parameter(effect_context_t *context, effect_param_t *p,
+                       uint32_t size __unused)
+{
+    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", __func__);
+
+    p->status = 0;
+
+    switch (param) {
+    case BASSBOOST_PARAM_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;
+        break;
+    }
+
+    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
  */
@@ -70,99 +310,30 @@
     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;
-    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);
-
-    p->status = 0;
-
-    switch (param) {
-    case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
-        if (p->vsize < sizeof(uint32_t))
-           p->status = -EINVAL;
-        p->vsize = sizeof(uint32_t);
-        break;
-    case BASSBOOST_PARAM_STRENGTH:
-        if (p->vsize < sizeof(int16_t))
-           p->status = -EINVAL;
-        p->vsize = sizeof(int16_t);
-        break;
-    default:
-        p->status = -EINVAL;
-    }
-
-    *size = sizeof(effect_param_t) + voffset + p->vsize;
-
-    if (p->status != 0)
-        return 0;
-
-    switch (param) {
-    case BASSBOOST_PARAM_STRENGTH_SUPPORTED:
-        *(uint32_t *)value = 1;
-        break;
-
-    case BASSBOOST_PARAM_STRENGTH:
-        *(int16_t *)value = bassboost_get_strength(bass_ctxt);
-        break;
-
-    default:
-        p->status = -EINVAL;
-        break;
-    }
-
-    return 0;
-}
-
-int bassboost_set_parameter(effect_context_t *context, effect_param_t *p,
-                            uint32_t size __unused)
-{
-    bassboost_context_t *bass_ctxt = (bassboost_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);
-
-    p->status = 0;
-
-    switch (param) {
-    case BASSBOOST_PARAM_STRENGTH:
-        strength = (uint32_t)(*(int16_t *)value);
-        bassboost_set_strength(bass_ctxt, strength);
-        break;
-    default:
-        p->status = -EINVAL;
-        break;
-    }
-
-    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 (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,
+                                                  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);
@@ -178,21 +349,6 @@
             bass_ctxt->temp_disabled = true;
         }
         ALOGI("%s: ctxt %p, disabled based on device", __func__, bass_ctxt);
-    } else {
-        if (bass_ctxt->temp_disabled) {
-            if (effect_is_active(&bass_ctxt->common)) {
-                offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true);
-                if (bass_ctxt->ctl)
-                    offload_bassboost_send_params(bass_ctxt->ctl,
-                                                  &bass_ctxt->offload_bass,
-                                                  OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
-                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;
-        }
     }
     offload_bassboost_set_device(&(bass_ctxt->offload_bass), device);
     return 0;
@@ -329,3 +485,234 @@
                                      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 6f0e61b..8bf51d3 100644
--- a/post_proc/bass_boost.h
+++ b/post_proc/bass_boost.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
@@ -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 {
@@ -37,11 +44,50 @@
     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);
 
@@ -59,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 606c66b..e38a41c 100644
--- a/post_proc/bundle.c
+++ b/post_proc/bundle.c
@@ -520,25 +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.set_hw_acc_mode = bassboost_set_mode;
-        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 *)
@@ -847,8 +848,6 @@
         } break;
     case EFFECT_CMD_SET_PARAM: {
         if (pCmdData == NULL ||
-            cmdSize > (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
-                            sizeof(uint32_t)) ||
             cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
                             sizeof(uint16_t)) ||
             pReplyData == NULL || *replySize != sizeof(int32_t)) {
diff --git a/post_proc/effect_api.c b/post_proc/effect_api.c
index 7c1968e..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
@@ -114,7 +114,7 @@
         return -EINVAL;
     } else {
         *ctl = mixer_get_ctl_by_name(*mixer, mixer_string);
-        if (!ctl) {
+        if (!(*ctl)) {
             ALOGE("mixer_get_ctl_by_name failed");
             mixer_close(*mixer);
             *mixer = NULL;
@@ -235,6 +235,83 @@
                                  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)
 {
@@ -891,6 +968,11 @@
     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*/
@@ -899,7 +981,7 @@
         *p_param_values++ = 1; /* hpx on*/
     }
 
-    if ((mode == OFFLOAD) && ctl)
+    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)
diff --git a/post_proc/effect_api.h b/post_proc/effect_api.h
index e05924a..ce0503a 100644
--- a/post_proc/effect_api.h
+++ b/post_proc/effect_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.
 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -39,6 +39,21 @@
                                          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)