post_proc: add PBE effect for speaker

Enable PBE for speaker device.

Change-Id: I1a48dff038baf63376f1d4b355888159cf69ba81
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..14d6c97 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) 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..a89b02b 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 *)
diff --git a/post_proc/effect_api.c b/post_proc/effect_api.c
index 7c1968e..c850fa5 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
@@ -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)
 {
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)