post_proc: Support effects in DSP for tunnel mode playback

Add interface to support configuring equlaizer, bass boost,
virtualizer and reverb effects in DSP for tunnel mode of
playback.

Change-Id: I9a93ad6136c4de06df5136967908b4e888dae44f
diff --git a/Android.mk b/Android.mk
index 0e94762..424bbe1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -11,6 +11,7 @@
 include $(MY_LOCAL_PATH)/policy_hal/Android.mk
 include $(MY_LOCAL_PATH)/visualizer/Android.mk
 include $(MY_LOCAL_PATH)/audiod/Android.mk
+include $(MY_LOCAL_PATH)/post_proc/Android.mk
 endif
 
 endif
diff --git a/post_proc/Android.mk b/post_proc/Android.mk
new file mode 100644
index 0000000..b6966e6
--- /dev/null
+++ b/post_proc/Android.mk
@@ -0,0 +1,31 @@
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	bundle.c \
+	equalizer.c \
+	bass_boost.c \
+	virtualizer.c \
+	reverb.c \
+	effect_api.c
+
+LOCAL_CFLAGS+= -O2 -fvisibility=hidden
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	liblog \
+	libtinyalsa
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
+LOCAL_MODULE:= libqcompostprocbundle
+
+LOCAL_C_INCLUDES := \
+	external/tinyalsa/include \
+	kernel/include/sound \
+	$(call include-path-for, audio-effects)
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c
new file mode 100644
index 0000000..c64ba6b
--- /dev/null
+++ b/post_proc/bass_boost.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "offload_effect_bass_boost"
+#define LOG_NDEBUG 0
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <audio_effects.h>
+#include <audio_effects/effect_bassboost.h>
+
+#include "effect_api.h"
+#include "bass_boost.h"
+
+/* Offload bassboost UUID: 2c4a8c24-1581-487f-94f6-0002a5d5c51b */
+const effect_descriptor_t bassboost_descriptor = {
+        {0x0634f220, 0xddd4, 0x11db, 0xa0fc, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }},
+        {0x2c4a8c24, 0x1581, 0x487f, 0x94f6, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
+        EFFECT_CONTROL_API_VERSION,
+        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_HW_ACC_TUNNEL),
+        0, /* TODO */
+        1,
+        "MSM offload bassboost",
+        "The Android Open Source Project",
+};
+
+/*
+ * Bassboost operations
+ */
+
+int bassboost_get_strength(bassboost_context_t *context)
+{
+    ALOGV("%s: strength: %d", __func__, context->strength);
+    return context->strength;
+}
+
+int bassboost_set_strength(bassboost_context_t *context, uint32_t strength)
+{
+    ALOGV("%s: strength: %d", __func__, strength);
+    context->strength = strength;
+
+    offload_bassboost_set_strength(&(context->offload_bass), strength);
+    if (context->ctl)
+        offload_bassboost_send_params(context->ctl, context->offload_bass,
+                                      OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
+                                      OFFLOAD_SEND_BASSBOOST_STRENGTH);
+    return 0;
+}
+
+int bassboost_get_parameter(effect_context_t *context, effect_param_t *p,
+                            uint32_t *size)
+{
+    bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+    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__);
+        *(uint32_t *)value = 1;
+        break;
+
+    case BASSBOOST_PARAM_STRENGTH:
+	ALOGV("%s: BASSBOOST_PARAM_STRENGTH", __func__);
+        *(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)
+{
+    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", __func__);
+
+    p->status = 0;
+
+    switch (param) {
+    case BASSBOOST_PARAM_STRENGTH:
+	ALOGV("%s BASSBOOST_PARAM_STRENGTH", __func__);
+        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: device: %d", __func__, 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)) {
+        if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) {
+            offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false);
+            bass_ctxt->temp_disabled = true;
+        }
+    } else {
+        if (!offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)) &&
+            bass_ctxt->temp_disabled) {
+            offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true);
+            bass_ctxt->temp_disabled = false;
+        }
+    }
+    offload_bassboost_set_device(&(bass_ctxt->offload_bass), device);
+    return 0;
+}
+
+int bassboost_reset(effect_context_t *context)
+{
+    bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+    return 0;
+}
+
+int bassboost_init(effect_context_t *context)
+{
+    bassboost_context_t *bass_ctxt = (bassboost_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);
+
+    bass_ctxt->temp_disabled = false;
+    memset(&(bass_ctxt->offload_bass), 0, sizeof(struct bass_boost_params));
+
+    return 0;
+}
+
+int bassboost_enable(effect_context_t *context)
+{
+    bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+    ALOGV("%s", __func__);
+
+    if (!offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)))
+        offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true);
+    return 0;
+}
+
+int bassboost_disable(effect_context_t *context)
+{
+    bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+    ALOGV("%s", __func__);
+    if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) {
+        offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false);
+        if (bass_ctxt->ctl)
+            offload_bassboost_send_params(bass_ctxt->ctl,
+                                          bass_ctxt->offload_bass,
+                                          OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+    }
+    return 0;
+}
+
+int bassboost_start(effect_context_t *context, output_context_t *output)
+{
+    bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+    ALOGV("%s", __func__);
+    bass_ctxt->ctl = output->ctl;
+    ALOGV("output->ctl: %p", output->ctl);
+    return 0;
+}
+
+int bassboost_stop(effect_context_t *context, output_context_t *output)
+{
+    bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+    ALOGV("%s", __func__);
+    bass_ctxt->ctl = NULL;
+    return 0;
+}
diff --git a/post_proc/bass_boost.h b/post_proc/bass_boost.h
new file mode 100644
index 0000000..430a07d
--- /dev/null
+++ b/post_proc/bass_boost.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OFFLOAD_EFFECT_BASS_BOOST_H_
+#define OFFLOAD_EFFECT_BASS_BOOST_H_
+
+#include "bundle.h"
+
+extern const effect_descriptor_t bassboost_descriptor;
+
+typedef struct bassboost_context_s {
+    effect_context_t common;
+
+    int strength;
+
+    // Offload vars
+    struct mixer_ctl *ctl;
+    bool temp_disabled;
+    uint32_t device;
+    struct bass_boost_params offload_bass;
+} bassboost_context_t;
+
+int bassboost_get_parameter(effect_context_t *context, effect_param_t *p,
+                            uint32_t *size);
+
+int bassboost_set_parameter(effect_context_t *context, effect_param_t *p,
+                            uint32_t size);
+
+int bassboost_set_device(effect_context_t *context,  uint32_t device);
+
+int bassboost_reset(effect_context_t *context);
+
+int bassboost_init(effect_context_t *context);
+
+int bassboost_enable(effect_context_t *context);
+
+int bassboost_disable(effect_context_t *context);
+
+int bassboost_start(effect_context_t *context, output_context_t *output);
+
+int bassboost_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
new file mode 100644
index 0000000..8e2bce8
--- /dev/null
+++ b/post_proc/bundle.c
@@ -0,0 +1,755 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "offload_effect_bundle"
+#define LOG_NDEBUG 0
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <system/thread_defs.h>
+#include <tinyalsa/asoundlib.h>
+#include <hardware/audio_effect.h>
+
+#include "bundle.h"
+#include "equalizer.h"
+#include "bass_boost.h"
+#include "virtualizer.h"
+#include "reverb.h"
+
+enum {
+    EFFECT_STATE_UNINITIALIZED,
+    EFFECT_STATE_INITIALIZED,
+    EFFECT_STATE_ACTIVE,
+};
+
+const effect_descriptor_t *descriptors[] = {
+        &equalizer_descriptor,
+        &bassboost_descriptor,
+        &virtualizer_descriptor,
+        &aux_env_reverb_descriptor,
+        &ins_env_reverb_descriptor,
+        &aux_preset_reverb_descriptor,
+        &ins_preset_reverb_descriptor,
+        NULL,
+};
+
+pthread_once_t once = PTHREAD_ONCE_INIT;
+int init_status;
+/*
+ * list of created effects.
+ * Updated by offload_effects_bundle_hal_start_output()
+ * and offload_effects_bundle_hal_stop_output()
+ */
+struct listnode created_effects_list;
+/*
+ * list of active output streams.
+ * Updated by offload_effects_bundle_hal_start_output()
+ * and offload_effects_bundle_hal_stop_output()
+ */
+struct listnode active_outputs_list;
+/*
+ * lock must be held when modifying or accessing
+ * created_effects_list or active_outputs_list
+ */
+pthread_mutex_t lock;
+
+
+/*
+ *  Local functions
+ */
+static void init_once() {
+    list_init(&created_effects_list);
+    list_init(&active_outputs_list);
+
+    pthread_mutex_init(&lock, NULL);
+
+    init_status = 0;
+}
+
+int lib_init()
+{
+    pthread_once(&once, init_once);
+    return init_status;
+}
+
+bool effect_exists(effect_context_t *context)
+{
+    struct listnode *node;
+
+    list_for_each(node, &created_effects_list) {
+        effect_context_t *fx_ctxt = node_to_item(node,
+                                                 effect_context_t,
+                                                 effects_list_node);
+        if (fx_ctxt == context) {
+            return true;
+        }
+    }
+    return false;
+}
+
+output_context_t *get_output(audio_io_handle_t output)
+{
+    struct listnode *node;
+
+    list_for_each(node, &active_outputs_list) {
+        output_context_t *out_ctxt = node_to_item(node,
+                                                  output_context_t,
+                                                  outputs_list_node);
+        if (out_ctxt->handle == output)
+            return out_ctxt;
+    }
+    return NULL;
+}
+
+void add_effect_to_output(output_context_t * output, effect_context_t *context)
+{
+    struct listnode *fx_node;
+
+    list_for_each(fx_node, &output->effects_list) {
+        effect_context_t *fx_ctxt = node_to_item(fx_node,
+                                                 effect_context_t,
+                                                 output_node);
+        if (fx_ctxt == context)
+            return;
+    }
+    list_add_tail(&output->effects_list, &context->output_node);
+    if (context->ops.start)
+        context->ops.start(context, output);
+
+}
+
+void remove_effect_from_output(output_context_t * output,
+                               effect_context_t *context)
+{
+    struct listnode *fx_node;
+
+    list_for_each(fx_node, &output->effects_list) {
+        effect_context_t *fx_ctxt = node_to_item(fx_node,
+                                                 effect_context_t,
+                                                 output_node);
+        if (fx_ctxt == context) {
+            if (context->ops.stop)
+                context->ops.stop(context, output);
+            list_remove(&context->output_node);
+            return;
+        }
+    }
+}
+
+bool effects_enabled()
+{
+    struct listnode *out_node;
+
+    list_for_each(out_node, &active_outputs_list) {
+        struct listnode *fx_node;
+        output_context_t *out_ctxt = node_to_item(out_node,
+                                                  output_context_t,
+                                                  outputs_list_node);
+
+        list_for_each(fx_node, &out_ctxt->effects_list) {
+            effect_context_t *fx_ctxt = node_to_item(fx_node,
+                                                     effect_context_t,
+                                                     output_node);
+            if ((fx_ctxt->state == EFFECT_STATE_ACTIVE) &&
+                (fx_ctxt->ops.process != NULL))
+                return true;
+        }
+    }
+    return false;
+}
+
+
+/*
+ * Interface from audio HAL
+ */
+__attribute__ ((visibility ("default")))
+int offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id)
+{
+    int ret = 0;
+    struct listnode *node;
+    char mixer_string[128];
+
+    ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
+
+    if (lib_init() != 0)
+        return init_status;
+
+    pthread_mutex_lock(&lock);
+    if (get_output(output) != NULL) {
+        ALOGW("%s output already started", __func__);
+        ret = -ENOSYS;
+        goto exit;
+    }
+
+    output_context_t *out_ctxt = (output_context_t *)
+                                 malloc(sizeof(output_context_t));
+    out_ctxt->handle = output;
+    out_ctxt->pcm_device_id = pcm_id;
+
+    /* populate the mixer control to send offload parameters */
+    snprintf(mixer_string, sizeof(mixer_string),
+             "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id);
+    out_ctxt->mixer = mixer_open(MIXER_CARD);
+    if (!out_ctxt->mixer) {
+        ALOGE("Failed to open mixer");
+        out_ctxt->ctl = NULL;
+        ret = -EINVAL;
+        goto exit;
+    } else {
+        out_ctxt->ctl = mixer_get_ctl_by_name(out_ctxt->mixer, mixer_string);
+        if (!out_ctxt->ctl) {
+            ALOGE("mixer_get_ctl_by_name failed");
+            mixer_close(out_ctxt->mixer);
+            out_ctxt->mixer = NULL;
+            ret = -EINVAL;
+            goto exit;
+        }
+    }
+
+    list_init(&out_ctxt->effects_list);
+
+    list_for_each(node, &created_effects_list) {
+        effect_context_t *fx_ctxt = node_to_item(node,
+                                                 effect_context_t,
+                                                 effects_list_node);
+        if (fx_ctxt->out_handle == output) {
+            if (fx_ctxt->ops.start)
+                fx_ctxt->ops.start(fx_ctxt, out_ctxt);
+            list_add_tail(&out_ctxt->effects_list, &fx_ctxt->output_node);
+        }
+    }
+    list_add_tail(&active_outputs_list, &out_ctxt->outputs_list_node);
+exit:
+    pthread_mutex_unlock(&lock);
+    return ret;
+}
+
+__attribute__ ((visibility ("default")))
+int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id)
+{
+    int ret;
+    struct listnode *node;
+    struct listnode *fx_node;
+    output_context_t *out_ctxt;
+
+    ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
+
+    if (lib_init() != 0)
+        return init_status;
+
+    pthread_mutex_lock(&lock);
+
+    out_ctxt = get_output(output);
+    if (out_ctxt == NULL) {
+        ALOGW("%s output not started", __func__);
+        ret = -ENOSYS;
+        goto exit;
+    }
+
+    if (out_ctxt->mixer)
+        mixer_close(out_ctxt->mixer);
+
+    list_for_each(fx_node, &out_ctxt->effects_list) {
+        effect_context_t *fx_ctxt = node_to_item(fx_node,
+                                                 effect_context_t,
+                                                 output_node);
+        if (fx_ctxt->ops.stop)
+            fx_ctxt->ops.stop(fx_ctxt, out_ctxt);
+    }
+
+    list_remove(&out_ctxt->outputs_list_node);
+
+    free(out_ctxt);
+
+exit:
+    pthread_mutex_unlock(&lock);
+    return ret;
+}
+
+
+/*
+ * Effect operations
+ */
+int set_config(effect_context_t *context, effect_config_t *config)
+{
+    context->config = *config;
+
+    if (context->ops.reset)
+        context->ops.reset(context);
+
+    return 0;
+}
+
+void get_config(effect_context_t *context, effect_config_t *config)
+{
+    *config = context->config;
+}
+
+
+/*
+ * Effect Library Interface Implementation
+ */
+int effect_lib_create(const effect_uuid_t *uuid,
+                         int32_t sessionId,
+                         int32_t ioId,
+                         effect_handle_t *pHandle) {
+    int ret;
+    int i;
+
+    ALOGV("%s: sessionId: %d, ioId: %d", __func__, sessionId, ioId);
+    if (lib_init() != 0)
+        return init_status;
+
+    if (pHandle == NULL || uuid == NULL)
+        return -EINVAL;
+
+    for (i = 0; descriptors[i] != NULL; i++) {
+        if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0)
+            break;
+    }
+
+    if (descriptors[i] == NULL)
+        return -EINVAL;
+
+    effect_context_t *context;
+    if (memcmp(uuid, &equalizer_descriptor.uuid,
+        sizeof(effect_uuid_t)) == 0) {
+        equalizer_context_t *eq_ctxt = (equalizer_context_t *)
+                                       calloc(1, sizeof(equalizer_context_t));
+        context = (effect_context_t *)eq_ctxt;
+        context->ops.init = equalizer_init;
+        context->ops.reset = equalizer_reset;
+        context->ops.set_parameter = equalizer_set_parameter;
+        context->ops.get_parameter = equalizer_get_parameter;
+        context->ops.set_device = equalizer_set_device;
+        context->ops.enable = equalizer_enable;
+        context->ops.disable = equalizer_disable;
+        context->ops.start = equalizer_start;
+        context->ops.stop = equalizer_stop;
+
+        context->desc = &equalizer_descriptor;
+        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));
+        context = (effect_context_t *)bass_ctxt;
+        context->ops.init = bassboost_init;
+        context->ops.reset = bassboost_reset;
+        context->ops.set_parameter = bassboost_set_parameter;
+        context->ops.get_parameter = bassboost_get_parameter;
+        context->ops.set_device = bassboost_set_device;
+        context->ops.enable = bassboost_enable;
+        context->ops.disable = bassboost_disable;
+        context->ops.start = bassboost_start;
+        context->ops.stop = bassboost_stop;
+
+        context->desc = &bassboost_descriptor;
+        bass_ctxt->ctl = NULL;
+    } else if (memcmp(uuid, &virtualizer_descriptor.uuid,
+               sizeof(effect_uuid_t)) == 0) {
+        virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)
+                                           calloc(1, sizeof(virtualizer_context_t));
+        context = (effect_context_t *)virt_ctxt;
+        context->ops.init = virtualizer_init;
+        context->ops.reset = virtualizer_reset;
+        context->ops.set_parameter = virtualizer_set_parameter;
+        context->ops.get_parameter = virtualizer_get_parameter;
+        context->ops.set_device = virtualizer_set_device;
+        context->ops.enable = virtualizer_enable;
+        context->ops.disable = virtualizer_disable;
+        context->ops.start = virtualizer_start;
+        context->ops.stop = virtualizer_stop;
+
+        context->desc = &virtualizer_descriptor;
+        virt_ctxt->ctl = NULL;
+    } else if ((memcmp(uuid, &aux_env_reverb_descriptor.uuid,
+                sizeof(effect_uuid_t)) == 0) ||
+               (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
+                sizeof(effect_uuid_t)) == 0) ||
+               (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
+                sizeof(effect_uuid_t)) == 0) ||
+               (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
+                sizeof(effect_uuid_t)) == 0)) {
+        reverb_context_t *reverb_ctxt = (reverb_context_t *)
+                                        calloc(1, sizeof(reverb_context_t));
+        context = (effect_context_t *)reverb_ctxt;
+        context->ops.init = reverb_init;
+        context->ops.reset = reverb_reset;
+        context->ops.set_parameter = reverb_set_parameter;
+        context->ops.get_parameter = reverb_get_parameter;
+        context->ops.set_device = reverb_set_device;
+        context->ops.enable = reverb_enable;
+        context->ops.disable = reverb_disable;
+        context->ops.start = reverb_start;
+        context->ops.stop = reverb_stop;
+
+        if (memcmp(uuid, &aux_env_reverb_descriptor.uuid,
+                   sizeof(effect_uuid_t)) == 0) {
+            context->desc = &aux_env_reverb_descriptor;
+            reverb_auxiliary_init(reverb_ctxt);
+        } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
+                   sizeof(effect_uuid_t)) == 0) {
+            context->desc = &ins_env_reverb_descriptor;
+            reverb_preset_init(reverb_ctxt);
+        } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
+                   sizeof(effect_uuid_t)) == 0) {
+            context->desc = &aux_preset_reverb_descriptor;
+            reverb_auxiliary_init(reverb_ctxt);
+        } else if (memcmp(uuid, &ins_preset_reverb_descriptor.uuid,
+                   sizeof(effect_uuid_t)) == 0) {
+            context->desc = &ins_preset_reverb_descriptor;
+            reverb_preset_init(reverb_ctxt);
+        }
+        reverb_ctxt->ctl = NULL;
+    } else {
+        return -EINVAL;
+    }
+
+    context->itfe = &effect_interface;
+    context->state = EFFECT_STATE_UNINITIALIZED;
+    context->out_handle = (audio_io_handle_t)ioId;
+
+    ret = context->ops.init(context);
+    if (ret < 0) {
+        ALOGW("%s init failed", __func__);
+        free(context);
+        return ret;
+    }
+
+    context->state = EFFECT_STATE_INITIALIZED;
+
+    pthread_mutex_lock(&lock);
+    list_add_tail(&created_effects_list, &context->effects_list_node);
+    output_context_t *out_ctxt = get_output(ioId);
+    if (out_ctxt != NULL)
+        add_effect_to_output(out_ctxt, context);
+    pthread_mutex_unlock(&lock);
+
+    *pHandle = (effect_handle_t)context;
+
+    ALOGV("%s created context %p", __func__, context);
+
+    return 0;
+
+}
+
+int effect_lib_release(effect_handle_t handle)
+{
+    effect_context_t *context = (effect_context_t *)handle;
+    int status;
+
+    if (lib_init() != 0)
+        return init_status;
+
+    ALOGV("%s context %p", __func__, handle);
+    pthread_mutex_lock(&lock);
+    status = -EINVAL;
+    if (effect_exists(context)) {
+        output_context_t *out_ctxt = get_output(context->out_handle);
+        if (out_ctxt != NULL)
+            remove_effect_from_output(out_ctxt, context);
+        list_remove(&context->effects_list_node);
+        if (context->ops.release)
+            context->ops.release(context);
+        free(context);
+        status = 0;
+    }
+    pthread_mutex_unlock(&lock);
+
+    return status;
+}
+
+int effect_lib_get_descriptor(const effect_uuid_t *uuid,
+                              effect_descriptor_t *descriptor)
+{
+    int i;
+
+    if (lib_init() != 0)
+        return init_status;
+
+    if (descriptor == NULL || uuid == NULL) {
+        ALOGV("%s called with NULL pointer", __func__);
+        return -EINVAL;
+    }
+
+    for (i = 0; descriptors[i] != NULL; i++) {
+        if (memcmp(uuid, &descriptors[i]->uuid, sizeof(effect_uuid_t)) == 0) {
+            *descriptor = *descriptors[i];
+            return 0;
+        }
+    }
+
+    return  -EINVAL;
+}
+
+
+/*
+ * Effect Control Interface Implementation
+ */
+
+/* Stub function for effect interface: never called for offloaded effects */
+int effect_process(effect_handle_t self,
+                       audio_buffer_t *inBuffer,
+                       audio_buffer_t *outBuffer)
+{
+    effect_context_t * context = (effect_context_t *)self;
+    int status = 0;
+
+    ALOGW("%s Called ?????", __func__);
+
+    pthread_mutex_lock(&lock);
+    if (!effect_exists(context)) {
+        status = -EINVAL;
+        goto exit;
+    }
+
+    if (context->state != EFFECT_STATE_ACTIVE) {
+        status = -EINVAL;
+        goto exit;
+    }
+
+exit:
+    pthread_mutex_unlock(&lock);
+    return status;
+}
+
+int effect_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
+                   void *pCmdData, uint32_t *replySize, void *pReplyData)
+{
+
+    effect_context_t * context = (effect_context_t *)self;
+    int retsize;
+    int status = 0;
+
+    pthread_mutex_lock(&lock);
+
+    if (!effect_exists(context)) {
+        status = -EINVAL;
+        goto exit;
+    }
+
+    if (context == NULL || context->state == EFFECT_STATE_UNINITIALIZED) {
+        status = -EINVAL;
+        goto exit;
+    }
+
+    switch (cmdCode) {
+    case EFFECT_CMD_INIT:
+        if (pReplyData == NULL || *replySize != sizeof(int)) {
+            status = -EINVAL;
+            goto exit;
+        }
+        if (context->ops.init)
+            *(int *) pReplyData = context->ops.init(context);
+        else
+            *(int *) pReplyData = 0;
+        break;
+    case EFFECT_CMD_SET_CONFIG:
+        if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
+                || pReplyData == NULL || *replySize != sizeof(int)) {
+            status = -EINVAL;
+            goto exit;
+        }
+        *(int *) pReplyData = set_config(context, (effect_config_t *) pCmdData);
+        break;
+    case EFFECT_CMD_GET_CONFIG:
+        if (pReplyData == NULL ||
+            *replySize != sizeof(effect_config_t)) {
+            status = -EINVAL;
+            goto exit;
+        }
+        if (!context->offload_enabled) {
+            status = -EINVAL;
+            goto exit;
+        }
+
+        get_config(context, (effect_config_t *)pReplyData);
+        break;
+    case EFFECT_CMD_RESET:
+        if (context->ops.reset)
+            context->ops.reset(context);
+        break;
+    case EFFECT_CMD_ENABLE:
+        if (pReplyData == NULL || *replySize != sizeof(int)) {
+            status = -EINVAL;
+            goto exit;
+        }
+        if (context->state != EFFECT_STATE_INITIALIZED) {
+            status = -ENOSYS;
+            goto exit;
+        }
+        context->state = EFFECT_STATE_ACTIVE;
+        if (context->ops.enable)
+            context->ops.enable(context);
+        ALOGV("%s EFFECT_CMD_ENABLE", __func__);
+        *(int *)pReplyData = 0;
+        break;
+    case EFFECT_CMD_DISABLE:
+        if (pReplyData == NULL || *replySize != sizeof(int)) {
+            status = -EINVAL;
+            goto exit;
+        }
+        if (context->state != EFFECT_STATE_ACTIVE) {
+            status = -ENOSYS;
+            goto exit;
+        }
+        context->state = EFFECT_STATE_INITIALIZED;
+        if (context->ops.disable)
+            context->ops.disable(context);
+        ALOGV("%s EFFECT_CMD_DISABLE", __func__);
+        *(int *)pReplyData = 0;
+        break;
+    case EFFECT_CMD_GET_PARAM: {
+        if (pCmdData == NULL ||
+            cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
+            pReplyData == NULL ||
+            *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
+                               sizeof(uint16_t))) {
+            status = -EINVAL;
+            ALOGV("EFFECT_CMD_GET_PARAM invalid command cmdSize %d *replySize %d",
+                  cmdSize, *replySize);
+            goto exit;
+        }
+        if (!context->offload_enabled) {
+            status = -EINVAL;
+            goto exit;
+        }
+        effect_param_t *q = (effect_param_t *)pCmdData;
+        memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + q->psize);
+        effect_param_t *p = (effect_param_t *)pReplyData;
+        if (context->ops.get_parameter)
+            context->ops.get_parameter(context, p, replySize);
+        } break;
+    case EFFECT_CMD_SET_PARAM: {
+        if (pCmdData == NULL ||
+            cmdSize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) +
+                            sizeof(uint16_t)) ||
+            pReplyData == NULL || *replySize != sizeof(int32_t)) {
+            status = -EINVAL;
+            ALOGV("EFFECT_CMD_SET_PARAM invalid command cmdSize %d *replySize %d",
+                  cmdSize, *replySize);
+            goto exit;
+        }
+        *(int32_t *)pReplyData = 0;
+        effect_param_t *p = (effect_param_t *)pCmdData;
+        if (context->ops.set_parameter)
+            *(int32_t *)pReplyData = context->ops.set_parameter(context, p,
+                                                                *replySize);
+
+        } break;
+    case EFFECT_CMD_SET_DEVICE: {
+        uint32_t device;
+        ALOGV("\t EFFECT_CMD_SET_DEVICE start");
+        if (pCmdData == NULL || cmdSize < sizeof(uint32_t)) {
+            status = -EINVAL;
+            ALOGV("EFFECT_CMD_SET_DEVICE invalid command cmdSize %d", cmdSize);
+            goto exit;
+        }
+        device = *(uint32_t *)pCmdData;
+        if (context->ops.set_device)
+            context->ops.set_device(context, device);
+        } break;
+    case EFFECT_CMD_SET_VOLUME:
+    case EFFECT_CMD_SET_AUDIO_MODE:
+        break;
+
+    case EFFECT_CMD_OFFLOAD: {
+        output_context_t *out_ctxt;
+
+        if (cmdSize != sizeof(effect_offload_param_t) || pCmdData == NULL
+                || pReplyData == NULL || *replySize != sizeof(int)) {
+            ALOGV("%s EFFECT_CMD_OFFLOAD bad format", __func__);
+            status = -EINVAL;
+            break;
+        }
+
+        effect_offload_param_t* offload_param = (effect_offload_param_t*)pCmdData;
+
+        ALOGV("%s EFFECT_CMD_OFFLOAD offload %d output %d", __func__,
+              offload_param->isOffload, offload_param->ioHandle);
+
+        *(int *)pReplyData = 0;
+
+        context->offload_enabled = offload_param->isOffload;
+        if (context->out_handle == offload_param->ioHandle)
+            break;
+
+        out_ctxt = get_output(context->out_handle);
+        if (out_ctxt != NULL)
+            remove_effect_from_output(out_ctxt, context);
+
+        context->out_handle = offload_param->ioHandle;
+        out_ctxt = get_output(context->out_handle);
+        if (out_ctxt != NULL)
+            add_effect_to_output(out_ctxt, context);
+
+        } break;
+
+
+    default:
+        if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
+            status = context->ops.command(context, cmdCode, cmdSize,
+                                          pCmdData, replySize, pReplyData);
+        else {
+            ALOGW("%s invalid command %d", __func__, cmdCode);
+            status = -EINVAL;
+        }
+        break;
+    }
+
+exit:
+    pthread_mutex_unlock(&lock);
+
+    return status;
+}
+
+/* Effect Control Interface Implementation: get_descriptor */
+int effect_get_descriptor(effect_handle_t   self,
+                          effect_descriptor_t *descriptor)
+{
+    effect_context_t *context = (effect_context_t *)self;
+
+    if (!effect_exists(context) || (descriptor == NULL))
+        return -EINVAL;
+
+    *descriptor = *context->desc;
+
+    return 0;
+}
+
+
+/* effect_handle_t interface implementation for offload effects */
+const struct effect_interface_s effect_interface = {
+    effect_process,
+    effect_command,
+    effect_get_descriptor,
+    NULL,
+};
+
+__attribute__ ((visibility ("default")))
+audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
+    tag : AUDIO_EFFECT_LIBRARY_TAG,
+    version : EFFECT_LIBRARY_API_VERSION,
+    name : "Offload Effects Bundle Library",
+    implementor : "The Linux Foundation",
+    create_effect : effect_lib_create,
+    release_effect : effect_lib_release,
+    get_descriptor : effect_lib_get_descriptor,
+};
diff --git a/post_proc/bundle.h b/post_proc/bundle.h
new file mode 100644
index 0000000..a8e0f93
--- /dev/null
+++ b/post_proc/bundle.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OFFLOAD_EFFECT_BUNDLE_H
+#define OFFLOAD_EFFECT_BUNDLE_H
+
+#include <tinyalsa/asoundlib.h>
+#include <audio_effects.h>
+#include "effect_api.h"
+
+/* Retry for delay for mixer open */
+#define RETRY_NUMBER 10
+#define RETRY_US 500000
+
+#define MIXER_CARD 0
+#define SOUND_CARD 0
+
+extern const struct effect_interface_s effect_interface;
+
+typedef struct output_context_s output_context_t;
+typedef struct effect_ops_s effect_ops_t;
+typedef struct effect_context_s effect_context_t;
+
+struct output_context_s {
+    /* node in active_outputs_list */
+    struct listnode outputs_list_node;
+    /* io handle */
+    audio_io_handle_t handle;
+    /* list of effects attached to this output */
+    struct listnode effects_list;
+    /* pcm device id */
+    int pcm_device_id;
+    struct mixer *mixer;
+    struct mixer_ctl *ctl;
+};
+
+/* effect specific operations.
+ * Only the init() and process() operations must be defined.
+ * Others are optional.
+ */
+struct effect_ops_s {
+    int (*init)(effect_context_t *context);
+    int (*release)(effect_context_t *context);
+    int (*reset)(effect_context_t *context);
+    int (*enable)(effect_context_t *context);
+    int (*start)(effect_context_t *context, output_context_t *output);
+    int (*stop)(effect_context_t *context, output_context_t *output);
+    int (*disable)(effect_context_t *context);
+    int (*process)(effect_context_t *context, audio_buffer_t *in, audio_buffer_t *out);
+    int (*set_parameter)(effect_context_t *context, effect_param_t *param, uint32_t size);
+    int (*get_parameter)(effect_context_t *context, effect_param_t *param, uint32_t *size);
+    int (*set_device)(effect_context_t *context, uint32_t device);
+    int (*command)(effect_context_t *context, uint32_t cmdCode, uint32_t cmdSize,
+            void *pCmdData, uint32_t *replySize, void *pReplyData);
+};
+
+struct effect_context_s {
+    const struct effect_interface_s *itfe;
+    /* node in created_effects_list */
+    struct listnode effects_list_node;
+    /* node in output_context_t.effects_list */
+    struct listnode output_node;
+    effect_config_t config;
+    const effect_descriptor_t *desc;
+    /* io handle of the output the effect is attached to */
+    audio_io_handle_t out_handle;
+    uint32_t state;
+    bool offload_enabled;
+    effect_ops_t ops;
+};
+
+int set_config(effect_context_t *context, effect_config_t *config);
+
+#endif /* OFFLOAD_EFFECT_BUNDLE_H */
diff --git a/post_proc/effect_api.c b/post_proc/effect_api.c
new file mode 100644
index 0000000..a2e4f45
--- /dev/null
+++ b/post_proc/effect_api.c
@@ -0,0 +1,612 @@
+/*
+ * Copyright (c) 2013, 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 "offload_effect_api"
+#define LOG_NDEBUG 0
+
+#include <stdbool.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <audio_effects.h>
+
+#include "effect_api.h"
+
+#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+
+#define OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL 19
+const int map_eq_opensl_preset_2_offload_preset[] = {
+    OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL,   /* Normal Preset */
+    OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+1, /* Classical Preset */
+    OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+2, /* Dance Preset */
+    OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+3, /* Flat Preset */
+    OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+4, /* Folk Preset */
+    OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+5, /* Heavy Metal Preset */
+    OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+6, /* Hip Hop Preset */
+    OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+7, /* Jazz Preset */
+    OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+8, /* Pop Preset */
+    OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+9, /* Rock Preset */
+    OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL+10 /* FX Booster */
+};
+
+const int map_reverb_opensl_preset_2_offload_preset
+                  [NUM_OSL_REVERB_PRESETS_SUPPORTED][2] = {
+    {1, 15},
+    {2, 16},
+    {3, 17},
+    {4, 18},
+    {5, 3},
+    {6, 20}
+};
+
+int offload_update_mixer_and_effects_ctl(int card, int device_id,
+                                         struct mixer *mixer,
+                                         struct mixer_ctl *ctl)
+{
+    char mixer_string[128];
+
+    snprintf(mixer_string, sizeof(mixer_string),
+             "%s %d", "Audio Effects Config", device_id);
+    ALOGV("%s: mixer_string: %s", __func__, mixer_string);
+    mixer = mixer_open(card);
+    if (!mixer) {
+        ALOGE("Failed to open mixer");
+        ctl = NULL;
+        return -EINVAL;
+    } else {
+        ctl = mixer_get_ctl_by_name(mixer, mixer_string);
+        if (!ctl) {
+            ALOGE("mixer_get_ctl_by_name failed");
+            mixer_close(mixer);
+            mixer = NULL;
+            return -EINVAL;
+        }
+    }
+    ALOGV("mixer: %p, ctl: %p", mixer, ctl);
+    return 0;
+}
+
+void offload_close_mixer(struct mixer *mixer)
+{
+    mixer_close(mixer);
+}
+
+void offload_bassboost_set_device(struct bass_boost_params *bassboost,
+                                  uint32_t device)
+{
+    ALOGV("%s", __func__);
+    bassboost->device = device;
+}
+
+void offload_bassboost_set_enable_flag(struct bass_boost_params *bassboost,
+                                       bool enable)
+{
+    ALOGV("%s", __func__);
+    bassboost->enable_flag = enable;
+}
+
+int offload_bassboost_get_enable_flag(struct bass_boost_params *bassboost)
+{
+    ALOGV("%s", __func__);
+    return bassboost->enable_flag;
+}
+
+void offload_bassboost_set_strength(struct bass_boost_params *bassboost,
+                                    int strength)
+{
+    ALOGV("%s", __func__);
+    bassboost->strength = strength;
+}
+
+void offload_bassboost_set_mode(struct bass_boost_params *bassboost,
+                                int mode)
+{
+    ALOGV("%s", __func__);
+    bassboost->mode = mode;
+}
+
+int offload_bassboost_send_params(struct mixer_ctl *ctl,
+                                  struct bass_boost_params bassboost,
+                                  unsigned param_send_flags)
+{
+    int param_values[128] = {0};
+    int *p_param_values = param_values;
+
+    ALOGV("%s", __func__);
+    *p_param_values++ = BASS_BOOST_MODULE;
+    *p_param_values++ = bassboost.device;
+    *p_param_values++ = 0; /* num of commands*/
+    if (param_send_flags & OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG) {
+        *p_param_values++ = BASS_BOOST_ENABLE;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = BASS_BOOST_ENABLE_PARAM_LEN;
+        *p_param_values++ = bassboost.enable_flag;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_BASSBOOST_STRENGTH) {
+        *p_param_values++ = BASS_BOOST_STRENGTH;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = BASS_BOOST_STRENGTH_PARAM_LEN;
+        *p_param_values++ = bassboost.strength;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_BASSBOOST_MODE) {
+        *p_param_values++ = BASS_BOOST_MODE;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = BASS_BOOST_MODE_PARAM_LEN;
+        *p_param_values++ = bassboost.mode;
+        param_values[2] += 1;
+    }
+
+    if (param_values[2] && ctl)
+        mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+
+    return 0;
+}
+
+void offload_virtualizer_set_device(struct virtualizer_params *virtualizer,
+                                    uint32_t device)
+{
+    ALOGV("%s", __func__);
+    virtualizer->device = device;
+}
+
+void offload_virtualizer_set_enable_flag(struct virtualizer_params *virtualizer,
+                                         bool enable)
+{
+    ALOGV("%s", __func__);
+    virtualizer->enable_flag = enable;
+}
+
+int offload_virtualizer_get_enable_flag(struct virtualizer_params *virtualizer)
+{
+    ALOGV("%s", __func__);
+    return virtualizer->enable_flag;
+}
+
+void offload_virtualizer_set_strength(struct virtualizer_params *virtualizer,
+                                      int strength)
+{
+    ALOGV("%s", __func__);
+    virtualizer->strength = strength;
+}
+
+void offload_virtualizer_set_out_type(struct virtualizer_params *virtualizer,
+                                      int out_type)
+{
+    ALOGV("%s", __func__);
+    virtualizer->out_type = out_type;
+}
+
+void offload_virtualizer_set_gain_adjust(struct virtualizer_params *virtualizer,
+                                         int gain_adjust)
+{
+    ALOGV("%s", __func__);
+    virtualizer->gain_adjust = gain_adjust;
+}
+
+int offload_virtualizer_send_params(struct mixer_ctl *ctl,
+                                    struct virtualizer_params virtualizer,
+                                    unsigned param_send_flags)
+{
+    int param_values[128] = {0};
+    int *p_param_values = param_values;
+
+    ALOGV("%s", __func__);
+    *p_param_values++ = VIRTUALIZER_MODULE;
+    *p_param_values++ = virtualizer.device;
+    *p_param_values++ = 0; /* num of commands*/
+    if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG) {
+        *p_param_values++ = VIRTUALIZER_ENABLE;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = VIRTUALIZER_ENABLE_PARAM_LEN;
+        *p_param_values++ = virtualizer.enable_flag;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_STRENGTH) {
+        *p_param_values++ = VIRTUALIZER_STRENGTH;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = VIRTUALIZER_STRENGTH_PARAM_LEN;
+        *p_param_values++ = virtualizer.strength;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE) {
+        *p_param_values++ = VIRTUALIZER_OUT_TYPE;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = VIRTUALIZER_OUT_TYPE_PARAM_LEN;
+        *p_param_values++ = virtualizer.out_type;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_GAIN_ADJUST) {
+        *p_param_values++ = VIRTUALIZER_GAIN_ADJUST;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = VIRTUALIZER_GAIN_ADJUST_PARAM_LEN;
+        *p_param_values++ = virtualizer.gain_adjust;
+        param_values[2] += 1;
+    }
+
+    if (param_values[2] && ctl)
+        mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+
+    return 0;
+}
+
+void offload_eq_set_device(struct eq_params *eq, uint32_t device)
+{
+    ALOGV("%s", __func__);
+    eq->device = device;
+}
+
+void offload_eq_set_enable_flag(struct eq_params *eq, bool enable)
+{
+    ALOGV("%s", __func__);
+    eq->enable_flag = enable;
+}
+
+int offload_eq_get_enable_flag(struct eq_params *eq)
+{
+    ALOGV("%s", __func__);
+    return eq->enable_flag;
+}
+
+void offload_eq_set_preset(struct eq_params *eq, int preset)
+{
+    ALOGV("%s", __func__);
+    eq->config.preset_id = preset;
+    eq->config.eq_pregain = Q27_UNITY;
+}
+
+void offload_eq_set_bands_level(struct eq_params *eq, int num_bands,
+                                const uint16_t *band_freq_list,
+                                int *band_gain_list)
+{
+    int i;
+    ALOGV("%s", __func__);
+    eq->config.num_bands = num_bands;
+    for (i=0; i<num_bands; i++) {
+        eq->per_band_cfg[i].band_idx = i;
+        eq->per_band_cfg[i].filter_type = EQ_BAND_BOOST;
+        eq->per_band_cfg[i].freq_millihertz = band_freq_list[i] * 1000;
+        eq->per_band_cfg[i].gain_millibels = band_gain_list[i] * 100;
+        eq->per_band_cfg[i].quality_factor = Q8_UNITY;
+    }
+}
+
+int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params eq,
+                           unsigned param_send_flags)
+{
+    int param_values[128] = {0};
+    int *p_param_values = param_values;
+    uint32_t i;
+
+    ALOGV("%s", __func__);
+    if (eq.config.preset_id < -1 ) {
+        ALOGV("No Valid preset to set");
+        return 0;
+    }
+    *p_param_values++ = EQ_MODULE;
+    *p_param_values++ = eq.device;
+    *p_param_values++ = 0; /* num of commands*/
+    if (param_send_flags & OFFLOAD_SEND_EQ_ENABLE_FLAG) {
+        *p_param_values++ = EQ_ENABLE;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = EQ_ENABLE_PARAM_LEN;
+        *p_param_values++ = eq.enable_flag;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_EQ_PRESET) {
+        *p_param_values++ = EQ_CONFIG;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = EQ_CONFIG_PARAM_LEN;
+        *p_param_values++ = eq.config.eq_pregain;
+        *p_param_values++ =
+                     map_eq_opensl_preset_2_offload_preset[eq.config.preset_id];
+        *p_param_values++ = 0;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_EQ_BANDS_LEVEL) {
+        *p_param_values++ = EQ_CONFIG;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = EQ_CONFIG_PARAM_LEN +
+                            eq.config.num_bands * EQ_CONFIG_PER_BAND_PARAM_LEN;
+        *p_param_values++ = eq.config.eq_pregain;
+        *p_param_values++ = CUSTOM_OPENSL_PRESET;
+        *p_param_values++ = eq.config.num_bands;
+        for (i=0; i<eq.config.num_bands; i++) {
+            *p_param_values++ = eq.per_band_cfg[i].band_idx;
+            *p_param_values++ = eq.per_band_cfg[i].filter_type;
+	    *p_param_values++ = eq.per_band_cfg[i].freq_millihertz;
+            *p_param_values++ = eq.per_band_cfg[i].gain_millibels;
+            *p_param_values++ = eq.per_band_cfg[i].quality_factor;
+        }
+        param_values[2] += 1;
+    }
+
+    if (param_values[2] && ctl)
+        mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+
+    return 0;
+}
+
+void offload_reverb_set_device(struct reverb_params *reverb, uint32_t device)
+{
+    ALOGV("%s", __func__);
+    reverb->device = device;
+}
+
+void offload_reverb_set_enable_flag(struct reverb_params *reverb, bool enable)
+{
+    ALOGV("%s", __func__);
+    reverb->enable_flag = enable;
+}
+
+int offload_reverb_get_enable_flag(struct reverb_params *reverb)
+{
+    ALOGV("%s", __func__);
+    return reverb->enable_flag;
+}
+
+void offload_reverb_set_mode(struct reverb_params *reverb, int mode)
+{
+    ALOGV("%s", __func__);
+    reverb->mode = mode;
+}
+
+void offload_reverb_set_preset(struct reverb_params *reverb, int preset)
+{
+    ALOGV("%s", __func__);
+    if (preset && (preset <= NUM_OSL_REVERB_PRESETS_SUPPORTED))
+        reverb->preset = map_reverb_opensl_preset_2_offload_preset[preset][1];
+}
+
+void offload_reverb_set_wet_mix(struct reverb_params *reverb, int wet_mix)
+{
+    ALOGV("%s", __func__);
+    reverb->wet_mix = wet_mix;
+}
+
+void offload_reverb_set_gain_adjust(struct reverb_params *reverb,
+                                    int gain_adjust)
+{
+    ALOGV("%s", __func__);
+    reverb->gain_adjust = gain_adjust;
+}
+
+void offload_reverb_set_room_level(struct reverb_params *reverb, int room_level)
+{
+    ALOGV("%s", __func__);
+    reverb->room_level = room_level;
+}
+
+void offload_reverb_set_room_hf_level(struct reverb_params *reverb,
+                                      int room_hf_level)
+{
+    ALOGV("%s", __func__);
+    reverb->room_hf_level = room_hf_level;
+}
+
+void offload_reverb_set_decay_time(struct reverb_params *reverb, int decay_time)
+{
+    ALOGV("%s", __func__);
+    reverb->decay_time = decay_time;
+}
+
+void offload_reverb_set_decay_hf_ratio(struct reverb_params *reverb,
+                                       int decay_hf_ratio)
+{
+    ALOGV("%s", __func__);
+    reverb->decay_hf_ratio = decay_hf_ratio;
+}
+
+void offload_reverb_set_reflections_level(struct reverb_params *reverb,
+                                          int reflections_level)
+{
+    ALOGV("%s", __func__);
+    reverb->reflections_level = reflections_level;
+}
+
+void offload_reverb_set_reflections_delay(struct reverb_params *reverb,
+                                          int reflections_delay)
+{
+    ALOGV("%s", __func__);
+    reverb->reflections_delay = reflections_delay;
+}
+
+void offload_reverb_set_reverb_level(struct reverb_params *reverb,
+                                     int reverb_level)
+{
+    ALOGV("%s", __func__);
+    reverb->level = reverb_level;
+}
+
+void offload_reverb_set_delay(struct reverb_params *reverb, int delay)
+{
+    ALOGV("%s", __func__);
+    reverb->delay = delay;
+}
+
+void offload_reverb_set_diffusion(struct reverb_params *reverb, int diffusion)
+{
+    ALOGV("%s", __func__);
+    reverb->diffusion = diffusion;
+}
+
+void offload_reverb_set_density(struct reverb_params *reverb, int density)
+{
+    ALOGV("%s", __func__);
+    reverb->density = density;
+}
+
+int offload_reverb_send_params(struct mixer_ctl *ctl,
+                               struct reverb_params reverb,
+                               unsigned param_send_flags)
+{
+    int param_values[128] = {0};
+    int *p_param_values = param_values;
+
+    ALOGV("%s", __func__);
+    *p_param_values++ = REVERB_MODULE;
+    *p_param_values++ = reverb.device;
+    *p_param_values++ = 0; /* num of commands*/
+
+    if (param_send_flags & OFFLOAD_SEND_REVERB_ENABLE_FLAG) {
+        *p_param_values++ = REVERB_ENABLE;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = REVERB_ENABLE_PARAM_LEN;
+        *p_param_values++ = reverb.enable_flag;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_REVERB_MODE) {
+        *p_param_values++ = REVERB_MODE;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = REVERB_MODE_PARAM_LEN;
+        *p_param_values++ = reverb.mode;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_REVERB_PRESET) {
+        *p_param_values++ = REVERB_PRESET;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = REVERB_PRESET_PARAM_LEN;
+        *p_param_values++ = reverb.preset;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_REVERB_WET_MIX) {
+        *p_param_values++ = REVERB_WET_MIX;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = REVERB_WET_MIX_PARAM_LEN;
+        *p_param_values++ = reverb.wet_mix;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_REVERB_GAIN_ADJUST) {
+        *p_param_values++ = REVERB_GAIN_ADJUST;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = REVERB_GAIN_ADJUST_PARAM_LEN;
+        *p_param_values++ = reverb.gain_adjust;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_REVERB_ROOM_LEVEL) {
+        *p_param_values++ = REVERB_ROOM_LEVEL;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = REVERB_ROOM_LEVEL_PARAM_LEN;
+        *p_param_values++ = reverb.room_level;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL) {
+        *p_param_values++ = REVERB_ROOM_HF_LEVEL;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = REVERB_ROOM_HF_LEVEL_PARAM_LEN;
+        *p_param_values++ = reverb.room_hf_level;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_REVERB_DECAY_TIME) {
+        *p_param_values++ = REVERB_DECAY_TIME;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = REVERB_DECAY_TIME_PARAM_LEN;
+        *p_param_values++ = reverb.decay_time;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_REVERB_DECAY_HF_RATIO) {
+        *p_param_values++ = REVERB_DECAY_HF_RATIO;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = REVERB_DECAY_HF_RATIO_PARAM_LEN;
+        *p_param_values++ = reverb.decay_hf_ratio;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL) {
+        *p_param_values++ = REVERB_REFLECTIONS_LEVEL;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = REVERB_REFLECTIONS_LEVEL_PARAM_LEN;
+        *p_param_values++ = reverb.reflections_level;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY) {
+        *p_param_values++ = REVERB_REFLECTIONS_DELAY;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = REVERB_REFLECTIONS_DELAY_PARAM_LEN;
+        *p_param_values++ = reverb.reflections_delay;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_REVERB_LEVEL) {
+        *p_param_values++ = REVERB_LEVEL;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = REVERB_LEVEL_PARAM_LEN;
+        *p_param_values++ = reverb.level;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_REVERB_DELAY) {
+        *p_param_values++ = REVERB_DELAY;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = REVERB_DELAY_PARAM_LEN;
+        *p_param_values++ = reverb.delay;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_REVERB_DIFFUSION) {
+        *p_param_values++ = REVERB_DIFFUSION;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = REVERB_DIFFUSION_PARAM_LEN;
+        *p_param_values++ = reverb.diffusion;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_REVERB_DENSITY) {
+        *p_param_values++ = REVERB_DENSITY;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = REVERB_DENSITY_PARAM_LEN;
+        *p_param_values++ = reverb.density;
+        param_values[2] += 1;
+    }
+
+    if (param_values[2] && ctl)
+        mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+
+    return 0;
+}
diff --git a/post_proc/effect_api.h b/post_proc/effect_api.h
new file mode 100644
index 0000000..342c606
--- /dev/null
+++ b/post_proc/effect_api.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of The Linux Foundation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef OFFLOAD_EFFECT_API_H_
+#define OFFLOAD_EFFECT_API_H_
+
+int offload_update_mixer_and_effects_ctl(int card, int device_id,
+                                         struct mixer *mixer,
+                                         struct mixer_ctl *ctl);
+void offload_close_mixer(struct mixer *mixer);
+
+#define OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG      (1 << 0)
+#define OFFLOAD_SEND_BASSBOOST_STRENGTH         \
+                                          (OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG << 1)
+#define OFFLOAD_SEND_BASSBOOST_MODE             \
+                                          (OFFLOAD_SEND_BASSBOOST_STRENGTH << 1)
+void offload_bassboost_set_device(struct bass_boost_params *bassboost,
+                                  uint32_t device);
+void offload_bassboost_set_enable_flag(struct bass_boost_params *bassboost,
+                                       bool enable);
+int offload_bassboost_get_enable_flag(struct bass_boost_params *bassboost);
+void offload_bassboost_set_strength(struct bass_boost_params *bassboost,
+                                    int strength);
+void offload_bassboost_set_mode(struct bass_boost_params *bassboost,
+                                int mode);
+int offload_bassboost_send_params(struct mixer_ctl *ctl,
+                                  struct bass_boost_params bassboost,
+                                  unsigned param_send_flags);
+
+#define OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG    (1 << 0)
+#define OFFLOAD_SEND_VIRTUALIZER_STRENGTH       \
+                                          (OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG << 1)
+#define OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE       \
+                                          (OFFLOAD_SEND_VIRTUALIZER_STRENGTH << 1)
+#define OFFLOAD_SEND_VIRTUALIZER_GAIN_ADJUST    \
+                                          (OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE << 1)
+void offload_virtualizer_set_device(struct virtualizer_params *virtualizer,
+                                    uint32_t device);
+void offload_virtualizer_set_enable_flag(struct virtualizer_params *virtualizer,
+                                         bool enable);
+int offload_virtualizer_get_enable_flag(struct virtualizer_params *virtualizer);
+void offload_virtualizer_set_strength(struct virtualizer_params *virtualizer,
+                                      int strength);
+void offload_virtualizer_set_out_type(struct virtualizer_params *virtualizer,
+                                      int out_type);
+void offload_virtualizer_set_gain_adjust(struct virtualizer_params *virtualizer,
+                                         int gain_adjust);
+int offload_virtualizer_send_params(struct mixer_ctl *ctl,
+                                  struct virtualizer_params virtualizer,
+                                  unsigned param_send_flags);
+
+#define OFFLOAD_SEND_EQ_ENABLE_FLAG             (1 << 0)
+#define OFFLOAD_SEND_EQ_PRESET                  \
+                                          (OFFLOAD_SEND_EQ_ENABLE_FLAG << 1)
+#define OFFLOAD_SEND_EQ_BANDS_LEVEL             \
+                                          (OFFLOAD_SEND_EQ_PRESET << 1)
+void offload_eq_set_device(struct eq_params *eq, uint32_t device);
+void offload_eq_set_enable_flag(struct eq_params *eq, bool enable);
+int offload_eq_get_enable_flag(struct eq_params *eq);
+void offload_eq_set_preset(struct eq_params *eq, int preset);
+void offload_eq_set_bands_level(struct eq_params *eq, int num_bands,
+                                const uint16_t *band_freq_list,
+                                int *band_gain_list);
+int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params eq,
+                           unsigned param_send_flags);
+
+#define OFFLOAD_SEND_REVERB_ENABLE_FLAG         (1 << 0)
+#define OFFLOAD_SEND_REVERB_MODE                \
+                                          (OFFLOAD_SEND_REVERB_ENABLE_FLAG << 1)
+#define OFFLOAD_SEND_REVERB_PRESET              \
+                                          (OFFLOAD_SEND_REVERB_MODE << 1)
+#define OFFLOAD_SEND_REVERB_WET_MIX             \
+                                          (OFFLOAD_SEND_REVERB_PRESET << 1)
+#define OFFLOAD_SEND_REVERB_GAIN_ADJUST	        \
+                                          (OFFLOAD_SEND_REVERB_WET_MIX << 1)
+#define OFFLOAD_SEND_REVERB_ROOM_LEVEL	        \
+                                          (OFFLOAD_SEND_REVERB_GAIN_ADJUST << 1)
+#define OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL       \
+                                          (OFFLOAD_SEND_REVERB_ROOM_LEVEL << 1)
+#define OFFLOAD_SEND_REVERB_DECAY_TIME          \
+                                          (OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL << 1)
+#define OFFLOAD_SEND_REVERB_DECAY_HF_RATIO      \
+                                          (OFFLOAD_SEND_REVERB_DECAY_TIME << 1)
+#define OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL   \
+                                          (OFFLOAD_SEND_REVERB_DECAY_HF_RATIO << 1)
+#define OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY   \
+                                          (OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL << 1)
+#define OFFLOAD_SEND_REVERB_LEVEL               \
+                                          (OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY << 1)
+#define OFFLOAD_SEND_REVERB_DELAY               \
+                                          (OFFLOAD_SEND_REVERB_LEVEL << 1)
+#define OFFLOAD_SEND_REVERB_DIFFUSION           \
+                                          (OFFLOAD_SEND_REVERB_DELAY << 1)
+#define OFFLOAD_SEND_REVERB_DENSITY             \
+                                          (OFFLOAD_SEND_REVERB_DIFFUSION << 1)
+void offload_reverb_set_device(struct reverb_params *reverb, uint32_t device);
+void offload_reverb_set_enable_flag(struct reverb_params *reverb, bool enable);
+int offload_reverb_get_enable_flag(struct reverb_params *reverb);
+void offload_reverb_set_mode(struct reverb_params *reverb, int mode);
+void offload_reverb_set_preset(struct reverb_params *reverb, int preset);
+void offload_reverb_set_wet_mix(struct reverb_params *reverb, int wet_mix);
+void offload_reverb_set_gain_adjust(struct reverb_params *reverb,
+                                    int gain_adjust);
+void offload_reverb_set_room_level(struct reverb_params *reverb,
+                                   int room_level);
+void offload_reverb_set_room_hf_level(struct reverb_params *reverb,
+                                      int room_hf_level);
+void offload_reverb_set_decay_time(struct reverb_params *reverb,
+                                   int decay_time);
+void offload_reverb_set_decay_hf_ratio(struct reverb_params *reverb,
+                                       int decay_hf_ratio);
+void offload_reverb_set_reflections_level(struct reverb_params *reverb,
+                                          int reflections_level);
+void offload_reverb_set_reflections_delay(struct reverb_params *reverb,
+                                          int reflections_delay);
+void offload_reverb_set_reverb_level(struct reverb_params *reverb,
+                                     int reverb_level);
+void offload_reverb_set_delay(struct reverb_params *reverb, int delay);
+void offload_reverb_set_diffusion(struct reverb_params *reverb, int diffusion);
+void offload_reverb_set_density(struct reverb_params *reverb, int density);
+int offload_reverb_send_params(struct mixer_ctl *ctl,
+                               struct reverb_params reverb,
+                               unsigned param_send_flags);
+
+#endif /*OFFLOAD_EFFECT_API_H_*/
diff --git a/post_proc/equalizer.c b/post_proc/equalizer.c
new file mode 100644
index 0000000..e31d2b9
--- /dev/null
+++ b/post_proc/equalizer.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "offload_effect_equalizer"
+#define LOG_NDEBUG 0
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <audio_effects.h>
+#include <audio_effects/effect_equalizer.h>
+
+#include "effect_api.h"
+#include "equalizer.h"
+
+/* Offload equalizer UUID: a0dac280-401c-11e3-9379-0002a5d5c51b */
+const effect_descriptor_t equalizer_descriptor = {
+        {0x0bed4300, 0xddd6, 0x11db, 0x8f34, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type
+        {0xa0dac280, 0x401c, 0x11e3, 0x9379, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
+        EFFECT_CONTROL_API_VERSION,
+        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_HW_ACC_TUNNEL),
+        0, /* TODO */
+        1,
+        "MSM offload equalizer",
+        "The Android Open Source Project",
+};
+
+static const char *equalizer_preset_names[] = {
+                                        "Normal",
+                                        "Classical",
+                                        "Dance",
+                                        "Flat",
+                                        "Folk",
+                                        "Heavy Metal",
+                                        "Hip Hop",
+                                        "Jazz",
+                                        "Pop",
+                                        "Rock"
+					};
+
+static const uint32_t equalizer_band_freq_range[NUM_EQ_BANDS][2] = {
+                                       {30000, 120000},
+                                       {120001, 460000},
+                                       {460001, 1800000},
+                                       {1800001, 7000000},
+                                       {7000001, 20000000}};
+
+static const uint16_t equalizer_band_presets_level[] = {
+                                        3, 0, 0, 0, 3,      /* Normal Preset */
+                                        5, 3, -2, 4, 4,     /* Classical Preset */
+                                        6, 0, 2, 4, 1,      /* Dance Preset */
+                                        0, 0, 0, 0, 0,      /* Flat Preset */
+                                        3, 0, 0, 2, -1,     /* Folk Preset */
+                                        4, 1, 9, 3, 0,      /* Heavy Metal Preset */
+                                        5, 3, 0, 1, 3,      /* Hip Hop Preset */
+                                        4, 2, -2, 2, 5,     /* Jazz Preset */
+                                       -1, 2, 5, 1, -2,     /* Pop Preset */
+                                        5, 3, -1, 3, 5};    /* Rock Preset */
+
+const uint16_t equalizer_band_presets_freq[NUM_EQ_BANDS] = {
+                                        60,      /* Frequencies in Hz */
+                                        230,
+                                        910,
+                                        3600,
+                                        14000
+};
+
+/*
+ * Equalizer operations
+ */
+
+int equalizer_get_band_level(equalizer_context_t *context, int32_t band)
+{
+    ALOGV("%s: band: %d level: %d", __func__, band,
+           context->band_levels[band] * 100);
+    return context->band_levels[band] * 100;
+}
+
+int equalizer_set_band_level(equalizer_context_t *context, int32_t band,
+                             int32_t level)
+{
+    ALOGV("%s: band: %d, level: %d", __func__, band, level);
+    if (level > 0) {
+        level = (int)((level+50)/100);
+    } else {
+        level = (int)((level-50)/100);
+    }
+    context->band_levels[band] = level;
+    context->preset = PRESET_CUSTOM;
+
+    offload_eq_set_preset(&(context->offload_eq), PRESET_CUSTOM);
+    offload_eq_set_bands_level(&(context->offload_eq),
+                               NUM_EQ_BANDS,
+                               equalizer_band_presets_freq,
+                               context->band_levels);
+    if (context->ctl)
+        offload_eq_send_params(context->ctl, context->offload_eq,
+                               OFFLOAD_SEND_EQ_ENABLE_FLAG |
+                               OFFLOAD_SEND_EQ_BANDS_LEVEL);
+    return 0;
+}
+
+int equalizer_get_center_frequency(equalizer_context_t *context, int32_t band)
+{
+    ALOGV("%s: band: %d", __func__, band);
+    return (equalizer_band_freq_range[band][0] +
+            equalizer_band_freq_range[band][1]) / 2;
+}
+
+int equalizer_get_band_freq_range(equalizer_context_t *context, int32_t band,
+                                  uint32_t *low, uint32_t *high)
+{
+    ALOGV("%s: band: %d", __func__, band);
+    *low = equalizer_band_freq_range[band][0];
+    *high = equalizer_band_freq_range[band][1];
+   return 0;
+}
+
+int equalizer_get_band(equalizer_context_t *context, uint32_t freq)
+{
+    int i;
+
+    ALOGV("%s: freq: %d", __func__, freq);
+    for(i = 0; i < NUM_EQ_BANDS; i++) {
+        if (freq <= equalizer_band_freq_range[i][1]) {
+            return i;
+        }
+    }
+    return NUM_EQ_BANDS - 1;
+}
+
+int equalizer_get_preset(equalizer_context_t *context)
+{
+    ALOGV("%s: preset: %d", __func__, context->preset);
+    return context->preset;
+}
+
+int equalizer_set_preset(equalizer_context_t *context, int preset)
+{
+    int i;
+
+    ALOGV("%s: preset: %d", __func__, preset);
+    context->preset = preset;
+    for (i=0; i<NUM_EQ_BANDS; i++)
+        context->band_levels[i] =
+                 equalizer_band_presets_level[i + preset * NUM_EQ_BANDS];
+
+    offload_eq_set_preset(&(context->offload_eq), preset);
+    offload_eq_set_bands_level(&(context->offload_eq),
+                               NUM_EQ_BANDS,
+                               equalizer_band_presets_freq,
+                               context->band_levels);
+    if(context->ctl)
+        offload_eq_send_params(context->ctl, context->offload_eq,
+                               OFFLOAD_SEND_EQ_ENABLE_FLAG |
+                               OFFLOAD_SEND_EQ_PRESET);
+    return 0;
+}
+
+const char * equalizer_get_preset_name(equalizer_context_t *context,
+                                       int32_t preset)
+{
+    ALOGV("%s: preset: %s", __func__, equalizer_preset_names[preset]);
+    if (preset == PRESET_CUSTOM) {
+        return "Custom";
+    } else {
+        return equalizer_preset_names[preset];
+    }
+}
+
+int equalizer_get_num_presets(equalizer_context_t *context)
+{
+    ALOGV("%s: presets_num: %d", __func__,
+           sizeof(equalizer_preset_names)/sizeof(char *));
+    return sizeof(equalizer_preset_names)/sizeof(char *);
+}
+
+int equalizer_get_parameter(effect_context_t *context, effect_param_t *p,
+                            uint32_t *size)
+{
+    equalizer_context_t *eq_ctxt = (equalizer_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++;
+    int32_t param2;
+    char *name;
+    void *value = p->data + voffset;
+    int i;
+
+    ALOGV("%s", __func__);
+
+    p->status = 0;
+
+    switch (param) {
+    case EQ_PARAM_NUM_BANDS:
+    case EQ_PARAM_CUR_PRESET:
+    case EQ_PARAM_GET_NUM_OF_PRESETS:
+    case EQ_PARAM_BAND_LEVEL:
+    case EQ_PARAM_GET_BAND:
+        if (p->vsize < sizeof(int16_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(int16_t);
+        break;
+
+    case EQ_PARAM_LEVEL_RANGE:
+        if (p->vsize < 2 * sizeof(int16_t))
+            p->status = -EINVAL;
+        p->vsize = 2 * sizeof(int16_t);
+        break;
+    case EQ_PARAM_BAND_FREQ_RANGE:
+       if (p->vsize < 2 * sizeof(int32_t))
+            p->status = -EINVAL;
+        p->vsize = 2 * sizeof(int32_t);
+        break;
+
+   case EQ_PARAM_CENTER_FREQ:
+        if (p->vsize < sizeof(int32_t))
+            p->status = -EINVAL;
+        p->vsize = sizeof(int32_t);
+        break;
+
+    case EQ_PARAM_GET_PRESET_NAME:
+        break;
+
+    case EQ_PARAM_PROPERTIES:
+        if (p->vsize < (2 + NUM_EQ_BANDS) * sizeof(uint16_t))
+            p->status = -EINVAL;
+        p->vsize = (2 + NUM_EQ_BANDS) * sizeof(uint16_t);
+        break;
+
+    default:
+        p->status = -EINVAL;
+    }
+
+    *size = sizeof(effect_param_t) + voffset + p->vsize;
+
+    if (p->status != 0)
+        return 0;
+
+    switch (param) {
+    case EQ_PARAM_NUM_BANDS:
+	ALOGV("%s: EQ_PARAM_NUM_BANDS", __func__);
+        *(uint16_t *)value = (uint16_t)NUM_EQ_BANDS;
+        break;
+
+    case EQ_PARAM_LEVEL_RANGE:
+	ALOGV("%s: EQ_PARAM_LEVEL_RANGE", __func__);
+        *(int16_t *)value = -1500;
+        *((int16_t *)value + 1) = 1500;
+        break;
+
+    case EQ_PARAM_BAND_LEVEL:
+	ALOGV("%s: EQ_PARAM_BAND_LEVEL", __func__);
+        param2 = *param_tmp;
+        if (param2 >= NUM_EQ_BANDS) {
+            p->status = -EINVAL;
+            break;
+        }
+        *(int16_t *)value = (int16_t)equalizer_get_band_level(eq_ctxt, param2);
+        break;
+
+    case EQ_PARAM_CENTER_FREQ:
+	ALOGV("%s: EQ_PARAM_CENTER_FREQ", __func__);
+        param2 = *param_tmp;
+        if (param2 >= NUM_EQ_BANDS) {
+           p->status = -EINVAL;
+            break;
+        }
+        *(int32_t *)value = equalizer_get_center_frequency(eq_ctxt, param2);
+        break;
+
+    case EQ_PARAM_BAND_FREQ_RANGE:
+	ALOGV("%s: EQ_PARAM_BAND_FREQ_RANGE", __func__);
+        param2 = *param_tmp;
+        if (param2 >= NUM_EQ_BANDS) {
+            p->status = -EINVAL;
+           break;
+        }
+       equalizer_get_band_freq_range(eq_ctxt, param2, (uint32_t *)value,
+                                     ((uint32_t *)value + 1));
+        break;
+
+    case EQ_PARAM_GET_BAND:
+	ALOGV("%s: EQ_PARAM_GET_BAND", __func__);
+        param2 = *param_tmp;
+        *(uint16_t *)value = (uint16_t)equalizer_get_band(eq_ctxt, param2);
+        break;
+
+    case EQ_PARAM_CUR_PRESET:
+	ALOGV("%s: EQ_PARAM_CUR_PRESET", __func__);
+        *(uint16_t *)value = (uint16_t)equalizer_get_preset(eq_ctxt);
+        break;
+
+    case EQ_PARAM_GET_NUM_OF_PRESETS:
+	ALOGV("%s: EQ_PARAM_GET_NUM_OF_PRESETS", __func__);
+        *(uint16_t *)value = (uint16_t)equalizer_get_num_presets(eq_ctxt);
+        break;
+
+    case EQ_PARAM_GET_PRESET_NAME:
+	ALOGV("%s: EQ_PARAM_GET_PRESET_NAME", __func__);
+        param2 = *param_tmp;
+	ALOGV("param2: %d", param2);
+        if (param2 >= equalizer_get_num_presets(eq_ctxt)) {
+            p->status = -EINVAL;
+            break;
+        }
+        name = (char *)value;
+        strlcpy(name, equalizer_get_preset_name(eq_ctxt, param2), p->vsize - 1);
+        name[p->vsize - 1] = 0;
+        p->vsize = strlen(name) + 1;
+        break;
+
+    case EQ_PARAM_PROPERTIES: {
+	ALOGV("%s: EQ_PARAM_PROPERTIES", __func__);
+        int16_t *prop = (int16_t *)value;
+        prop[0] = (int16_t)equalizer_get_preset(eq_ctxt);
+        prop[1] = (int16_t)NUM_EQ_BANDS;
+        for (i = 0; i < NUM_EQ_BANDS; i++) {
+            prop[2 + i] = (int16_t)equalizer_get_band_level(eq_ctxt, i);
+        }
+    } break;
+
+    default:
+        p->status = -EINVAL;
+        break;
+    }
+
+    return 0;
+}
+
+int equalizer_set_parameter(effect_context_t *context, effect_param_t *p,
+                            uint32_t size)
+{
+    equalizer_context_t *eq_ctxt = (equalizer_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++;
+    int32_t preset;
+    int32_t band;
+    int32_t level;
+    int i;
+
+    ALOGV("%s", __func__);
+
+    p->status = 0;
+
+    switch (param) {
+    case EQ_PARAM_CUR_PRESET:
+	ALOGV("EQ_PARAM_CUR_PRESET");
+        preset = (int32_t)(*(uint16_t *)value);
+
+        if ((preset >= equalizer_get_num_presets(eq_ctxt)) || (preset < 0)) {
+           p->status = -EINVAL;
+            break;
+        }
+        equalizer_set_preset(eq_ctxt, preset);
+        break;
+    case EQ_PARAM_BAND_LEVEL:
+	ALOGV("EQ_PARAM_BAND_LEVEL");
+        band =  *param_tmp;
+        level = (int32_t)(*(int16_t *)value);
+        if (band >= NUM_EQ_BANDS) {
+           p->status = -EINVAL;
+            break;
+        }
+        equalizer_set_band_level(eq_ctxt, band, level);
+        break;
+    case EQ_PARAM_PROPERTIES: {
+	ALOGV("EQ_PARAM_PROPERTIES");
+        int16_t *prop = (int16_t *)value;
+        if ((int)prop[0] >= equalizer_get_num_presets(eq_ctxt)) {
+            p->status = -EINVAL;
+            break;
+        }
+        if (prop[0] >= 0) {
+            equalizer_set_preset(eq_ctxt, (int)prop[0]);
+        } else {
+            if ((int)prop[1] != NUM_EQ_BANDS) {
+                p->status = -EINVAL;
+                break;
+            }
+            for (i = 0; i < NUM_EQ_BANDS; i++) {
+               equalizer_set_band_level(eq_ctxt, i, (int)prop[2 + i]);
+            }
+        }
+    } break;
+    default:
+        p->status = -EINVAL;
+        break;
+    }
+
+    return 0;
+}
+
+int equalizer_set_device(effect_context_t *context,  uint32_t device)
+{
+    ALOGV("%s: device: %d", __func__, device);
+    equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+    eq_ctxt->device = device;
+    offload_eq_set_device(&(eq_ctxt->offload_eq), device);
+    return 0;
+}
+
+int equalizer_reset(effect_context_t *context)
+{
+    equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+    return 0;
+}
+
+int equalizer_init(effect_context_t *context)
+{
+    ALOGV("%s", __func__);
+    equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+    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);
+
+    memset(&(eq_ctxt->offload_eq), 0, sizeof(struct eq_params));
+    offload_eq_set_preset(&(eq_ctxt->offload_eq), INVALID_PRESET);
+
+    return 0;
+}
+
+int equalizer_enable(effect_context_t *context)
+{
+    equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+    ALOGV("%s", __func__);
+
+    if (!offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) {
+        offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), true);
+        if (eq_ctxt->ctl)
+            offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq,
+                                   OFFLOAD_SEND_EQ_ENABLE_FLAG |
+                                   OFFLOAD_SEND_EQ_BANDS_LEVEL);
+    }
+    return 0;
+}
+
+int equalizer_disable(effect_context_t *context)
+{
+    equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+    ALOGV("%s", __func__);
+    if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) {
+        offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), false);
+        if (eq_ctxt->ctl)
+            offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq,
+                                   OFFLOAD_SEND_EQ_ENABLE_FLAG);
+    }
+    return 0;
+}
+
+int equalizer_start(effect_context_t *context, output_context_t *output)
+{
+    equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+    ALOGV("%s: %p", __func__, output->ctl);
+    eq_ctxt->ctl = output->ctl;
+    return 0;
+}
+
+int equalizer_stop(effect_context_t *context, output_context_t *output)
+{
+    equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+    ALOGV("%s", __func__);
+    eq_ctxt->ctl = NULL;
+    return 0;
+}
diff --git a/post_proc/equalizer.h b/post_proc/equalizer.h
new file mode 100644
index 0000000..19af186
--- /dev/null
+++ b/post_proc/equalizer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OFFLOAD_EQUALIZER_H_
+#define OFFLOAD_EQUALIZER_H_
+
+#include "bundle.h"
+
+#define NUM_EQ_BANDS              5
+#define INVALID_PRESET		 -2
+#define PRESET_CUSTOM		 -1
+
+extern const effect_descriptor_t equalizer_descriptor;
+
+typedef struct equalizer_context_s {
+    effect_context_t common;
+
+    int preset;
+    int band_levels[NUM_EQ_BANDS];
+
+    // Offload vars
+    struct mixer_ctl *ctl;
+    uint32_t device;
+    struct eq_params offload_eq;
+} equalizer_context_t;
+
+int equalizer_get_parameter(effect_context_t *context, effect_param_t *p,
+                            uint32_t *size);
+
+int equalizer_set_parameter(effect_context_t *context, effect_param_t *p,
+                            uint32_t size);
+
+int equalizer_set_device(effect_context_t *context,  uint32_t device);
+
+int equalizer_reset(effect_context_t *context);
+
+int equalizer_init(effect_context_t *context);
+
+int equalizer_enable(effect_context_t *context);
+
+int equalizer_disable(effect_context_t *context);
+
+int equalizer_start(effect_context_t *context, output_context_t *output);
+
+int equalizer_stop(effect_context_t *context, output_context_t *output);
+
+#endif /*OFFLOAD_EQUALIZER_H_*/
diff --git a/post_proc/reverb.c b/post_proc/reverb.c
new file mode 100644
index 0000000..4fc8c83
--- /dev/null
+++ b/post_proc/reverb.c
@@ -0,0 +1,612 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "offload_effect_reverb"
+#define LOG_NDEBUG 0
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <audio_effects.h>
+#include <audio_effects/effect_environmentalreverb.h>
+#include <audio_effects/effect_presetreverb.h>
+
+#include "effect_api.h"
+#include "reverb.h"
+
+/* Offload auxiliary environmental reverb UUID: 79a18026-18fd-4185-8233-0002a5d5c51b */
+const effect_descriptor_t aux_env_reverb_descriptor = {
+        { 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, { 0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e } },
+        { 0x79a18026, 0x18fd, 0x4185, 0x8233, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } },
+        EFFECT_CONTROL_API_VERSION,
+        (EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_HW_ACC_TUNNEL),
+        0, /* TODO */
+        1,
+        "MSM offload Auxiliary Environmental Reverb",
+        "The Android Open Source Project",
+};
+
+/* Offload insert environmental reverb UUID: eb64ea04-973b-43d2-8f5e-0002a5d5c51b */
+const effect_descriptor_t ins_env_reverb_descriptor = {
+        {0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}},
+        {0xeb64ea04, 0x973b, 0x43d2, 0x8f5e, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        EFFECT_CONTROL_API_VERSION,
+        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST | EFFECT_FLAG_HW_ACC_TUNNEL),
+        0, /* TODO */
+        1,
+        "MSM offload Insert Environmental Reverb",
+        "The Android Open Source Project",
+};
+
+// Offload auxiliary preset reverb UUID: 6987be09-b142-4b41-9056-0002a5d5c51b */
+const effect_descriptor_t aux_preset_reverb_descriptor = {
+        {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        {0x6987be09, 0xb142, 0x4b41, 0x9056, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        EFFECT_CONTROL_API_VERSION,
+        (EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_HW_ACC_TUNNEL),
+        0, /* TODO */
+        1,
+        "MSM offload Auxiliary Preset Reverb",
+        "The Android Open Source Project",
+};
+
+// Offload insert preset reverb UUID: aa2bebf6-47cf-4613-9bca-0002a5d5c51b */
+const effect_descriptor_t ins_preset_reverb_descriptor = {
+        {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        {0xaa2bebf6, 0x47cf, 0x4613, 0x9bca, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        EFFECT_CONTROL_API_VERSION,
+        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST | EFFECT_FLAG_HW_ACC_TUNNEL),
+        0, /* TODO */
+        1,
+        "MSM offload Insert Preset Reverb",
+        "The Android Open Source Project",
+};
+
+static const reverb_settings_t reverb_presets[] = {
+        // REVERB_PRESET_NONE: values are unused
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+        // REVERB_PRESET_SMALLROOM
+        {-400, -600, 1100, 830, -400, 5, 500, 10, 1000, 1000},
+        // REVERB_PRESET_MEDIUMROOM
+        {-400, -600, 1300, 830, -1000, 20, -200, 20, 1000, 1000},
+        // REVERB_PRESET_LARGEROOM
+        {-400, -600, 1500, 830, -1600, 5, -1000, 40, 1000, 1000},
+        // REVERB_PRESET_MEDIUMHALL
+        {-400, -600, 1800, 700, -1300, 15, -800, 30, 1000, 1000},
+        // REVERB_PRESET_LARGEHALL
+        {-400, -600, 1800, 700, -2000, 30, -1400, 60, 1000, 1000},
+        // REVERB_PRESET_PLATE
+        {-400, -200, 1300, 900, 0, 2, 0, 10, 1000, 750},
+};
+
+
+void reverb_auxiliary_init(reverb_context_t *context)
+{
+    context->auxiliary = true;
+    context->preset = false;
+}
+
+void reverb_preset_init(reverb_context_t *context)
+{
+    context->auxiliary = false;
+    context->preset = true;
+    context->cur_preset = REVERB_PRESET_LAST + 1;
+    context->next_preset = REVERB_DEFAULT_PRESET;
+}
+
+/*
+ * Reverb operations
+ */
+int16_t reverb_get_room_level(reverb_context_t *context)
+{
+    ALOGV("%s: room level: %d", __func__, context->reverb_settings.roomLevel);
+    return context->reverb_settings.roomLevel;
+}
+
+void reverb_set_room_level(reverb_context_t *context, int16_t room_level)
+{
+    ALOGV("%s: room level: %d", __func__, room_level);
+    context->reverb_settings.roomLevel = room_level;
+    offload_reverb_set_room_level(&(context->offload_reverb), room_level);
+    if (context->ctl)
+        offload_reverb_send_params(context->ctl, context->offload_reverb,
+                                   OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                   OFFLOAD_SEND_REVERB_ROOM_LEVEL);
+}
+
+int16_t reverb_get_room_hf_level(reverb_context_t *context)
+{
+    ALOGV("%s: room hf level: %d", __func__,
+          context->reverb_settings.roomHFLevel);
+    return context->reverb_settings.roomHFLevel;
+}
+
+void reverb_set_room_hf_level(reverb_context_t *context, int16_t room_hf_level)
+{
+    ALOGV("%s: room hf level: %d", __func__, room_hf_level);
+    context->reverb_settings.roomHFLevel = room_hf_level;
+    offload_reverb_set_room_hf_level(&(context->offload_reverb), room_hf_level);
+    if (context->ctl)
+        offload_reverb_send_params(context->ctl, context->offload_reverb,
+                                   OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                   OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL);
+}
+
+uint32_t reverb_get_decay_time(reverb_context_t *context)
+{
+    ALOGV("%s: decay time: %d", __func__, context->reverb_settings.decayTime);
+    return context->reverb_settings.decayTime;
+}
+
+void reverb_set_decay_time(reverb_context_t *context, uint32_t decay_time)
+{
+    ALOGV("%s: decay_time: %d", __func__, decay_time);
+    context->reverb_settings.decayTime = decay_time;
+    offload_reverb_set_decay_time(&(context->offload_reverb), decay_time);
+    if (context->ctl)
+        offload_reverb_send_params(context->ctl, context->offload_reverb,
+                                   OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                   OFFLOAD_SEND_REVERB_DECAY_TIME);
+}
+
+int16_t reverb_get_decay_hf_ratio(reverb_context_t *context)
+{
+    ALOGV("%s: decay hf ratio: %d", __func__,
+          context->reverb_settings.decayHFRatio);
+    return context->reverb_settings.decayHFRatio;
+}
+
+void reverb_set_decay_hf_ratio(reverb_context_t *context, int16_t decay_hf_ratio)
+{
+    ALOGV("%s: decay_hf_ratio: %d", __func__, decay_hf_ratio);
+    context->reverb_settings.decayHFRatio = decay_hf_ratio;
+    offload_reverb_set_decay_hf_ratio(&(context->offload_reverb), decay_hf_ratio);
+    if (context->ctl)
+        offload_reverb_send_params(context->ctl, context->offload_reverb,
+                                   OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                   OFFLOAD_SEND_REVERB_DECAY_HF_RATIO);
+}
+
+int16_t reverb_get_reverb_level(reverb_context_t *context)
+{
+    ALOGV("%s: reverb level: %d", __func__, context->reverb_settings.reverbLevel);
+    return context->reverb_settings.reverbLevel;
+}
+
+void reverb_set_reverb_level(reverb_context_t *context, int16_t reverb_level)
+{
+    ALOGV("%s: reverb level: %d", __func__, reverb_level);
+    context->reverb_settings.reverbLevel = reverb_level;
+    offload_reverb_set_reverb_level(&(context->offload_reverb), reverb_level);
+    if (context->ctl)
+        offload_reverb_send_params(context->ctl, context->offload_reverb,
+                                   OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                   OFFLOAD_SEND_REVERB_LEVEL);
+}
+
+int16_t reverb_get_diffusion(reverb_context_t *context)
+{
+    ALOGV("%s: diffusion: %d", __func__, context->reverb_settings.diffusion);
+    return context->reverb_settings.diffusion;
+}
+
+void reverb_set_diffusion(reverb_context_t *context, int16_t diffusion)
+{
+    ALOGV("%s: diffusion: %d", __func__, diffusion);
+    context->reverb_settings.diffusion = diffusion;
+    offload_reverb_set_diffusion(&(context->offload_reverb), diffusion);
+    if (context->ctl)
+        offload_reverb_send_params(context->ctl, context->offload_reverb,
+                                   OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                   OFFLOAD_SEND_REVERB_DIFFUSION);
+}
+
+int16_t reverb_get_density(reverb_context_t *context)
+{
+    ALOGV("%s: density: %d", __func__, context->reverb_settings.density);
+    return context->reverb_settings.density;
+}
+
+void reverb_set_density(reverb_context_t *context, int16_t density)
+{
+    ALOGV("%s: density: %d", __func__, density);
+    context->reverb_settings.density = density;
+    offload_reverb_set_density(&(context->offload_reverb), density);
+    if (context->ctl)
+        offload_reverb_send_params(context->ctl, context->offload_reverb,
+                                   OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                   OFFLOAD_SEND_REVERB_DENSITY);
+}
+
+void reverb_set_preset(reverb_context_t *context, int16_t preset)
+{
+    ALOGV("%s: preset: %d", __func__, preset);
+    context->next_preset = preset;
+    offload_reverb_set_preset(&(context->offload_reverb), preset);
+    if (context->ctl)
+        offload_reverb_send_params(context->ctl, context->offload_reverb,
+                                   OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                   OFFLOAD_SEND_REVERB_PRESET);
+}
+
+void reverb_set_all_properties(reverb_context_t *context,
+                               reverb_settings_t *reverb_settings)
+{
+    ALOGV("%s", __func__);
+    context->reverb_settings.roomLevel = reverb_settings->roomLevel;
+    context->reverb_settings.roomHFLevel = reverb_settings->roomHFLevel;
+    context->reverb_settings.decayTime = reverb_settings->decayTime;
+    context->reverb_settings.decayHFRatio = reverb_settings->decayHFRatio;
+    context->reverb_settings.reverbLevel = reverb_settings->reverbLevel;
+    context->reverb_settings.diffusion = reverb_settings->diffusion;
+    context->reverb_settings.density = reverb_settings->density;
+    if (context->ctl)
+        offload_reverb_send_params(context->ctl, context->offload_reverb,
+                                   OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                   OFFLOAD_SEND_REVERB_ROOM_LEVEL |
+                                   OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL |
+                                   OFFLOAD_SEND_REVERB_DECAY_TIME |
+                                   OFFLOAD_SEND_REVERB_DECAY_HF_RATIO |
+                                   OFFLOAD_SEND_REVERB_LEVEL |
+                                   OFFLOAD_SEND_REVERB_DIFFUSION |
+                                   OFFLOAD_SEND_REVERB_DENSITY);
+}
+
+void reverb_load_preset(reverb_context_t *context)
+{
+    context->cur_preset = context->next_preset;
+
+    if (context->cur_preset != REVERB_PRESET_NONE) {
+        const reverb_settings_t *preset = &reverb_presets[context->cur_preset];
+        reverb_set_room_level(context, preset->roomLevel);
+        reverb_set_room_hf_level(context, preset->roomHFLevel);
+        reverb_set_decay_time(context, preset->decayTime);
+        reverb_set_decay_hf_ratio(context, preset->decayHFRatio);
+        reverb_set_reverb_level(context, preset->reverbLevel);
+        reverb_set_diffusion(context, preset->diffusion);
+        reverb_set_density(context, preset->density);
+    }
+}
+
+int reverb_get_parameter(effect_context_t *context, effect_param_t *p,
+                         uint32_t *size)
+{
+    reverb_context_t *reverb_ctxt = (reverb_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;
+    reverb_settings_t *reverb_settings;
+    int i;
+
+    ALOGV("%s", __func__);
+
+    p->status = 0;
+
+    if (reverb_ctxt->preset) {
+        if (param != REVERB_PARAM_PRESET || p->vsize < sizeof(uint16_t))
+            return -EINVAL;
+        *(uint16_t *)value = reverb_ctxt->next_preset;
+        ALOGV("get REVERB_PARAM_PRESET, preset %d", reverb_ctxt->next_preset);
+    }
+    switch (param) {
+    case REVERB_PARAM_ROOM_LEVEL:
+        if (p->vsize < sizeof(uint16_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(uint16_t);
+        break;
+    case REVERB_PARAM_ROOM_HF_LEVEL:
+        if (p->vsize < sizeof(uint16_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(uint16_t);
+        break;
+    case REVERB_PARAM_DECAY_TIME:
+        if (p->vsize < sizeof(uint32_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(uint32_t);
+        break;
+    case REVERB_PARAM_DECAY_HF_RATIO:
+        if (p->vsize < sizeof(uint16_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(uint16_t);
+        break;
+    case REVERB_PARAM_REFLECTIONS_LEVEL:
+        if (p->vsize < sizeof(uint16_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(uint16_t);
+        break;
+    case REVERB_PARAM_REFLECTIONS_DELAY:
+        if (p->vsize < sizeof(uint32_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(uint32_t);
+        break;
+    case REVERB_PARAM_REVERB_LEVEL:
+        if (p->vsize < sizeof(uint16_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(uint16_t);
+        break;
+    case REVERB_PARAM_REVERB_DELAY:
+        if (p->vsize < sizeof(uint32_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(uint32_t);
+        break;
+    case REVERB_PARAM_DIFFUSION:
+        if (p->vsize < sizeof(uint16_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(uint16_t);
+        break;
+    case REVERB_PARAM_DENSITY:
+        if (p->vsize < sizeof(uint16_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(uint16_t);
+        break;
+    case REVERB_PARAM_PROPERTIES:
+        if (p->vsize < sizeof(reverb_settings_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(reverb_settings_t);
+        break;
+    default:
+        p->status = -EINVAL;
+    }
+
+    *size = sizeof(effect_param_t) + voffset + p->vsize;
+
+    if (p->status != 0)
+        return 0;
+
+    switch (param) {
+    case REVERB_PARAM_PROPERTIES:
+	ALOGV("%s: REVERB_PARAM_PROPERTIES", __func__);
+        reverb_settings = (reverb_settings_t *)value;
+        reverb_settings->roomLevel = reverb_get_room_level(reverb_ctxt);
+        reverb_settings->roomHFLevel = reverb_get_room_hf_level(reverb_ctxt);
+        reverb_settings->decayTime = reverb_get_decay_time(reverb_ctxt);
+        reverb_settings->decayHFRatio = reverb_get_decay_hf_ratio(reverb_ctxt);
+        reverb_settings->reflectionsLevel = 0;
+        reverb_settings->reflectionsDelay = 0;
+        reverb_settings->reverbDelay = 0;
+        reverb_settings->reverbLevel = reverb_get_reverb_level(reverb_ctxt);
+        reverb_settings->diffusion = reverb_get_diffusion(reverb_ctxt);
+        reverb_settings->density = reverb_get_density(reverb_ctxt);
+        break;
+    case REVERB_PARAM_ROOM_LEVEL:
+	ALOGV("%s: REVERB_PARAM_ROOM_LEVEL", __func__);
+        *(int16_t *)value = reverb_get_room_level(reverb_ctxt);
+        break;
+    case REVERB_PARAM_ROOM_HF_LEVEL:
+	ALOGV("%s: REVERB_PARAM_ROOM_HF_LEVEL", __func__);
+        *(int16_t *)value = reverb_get_room_hf_level(reverb_ctxt);
+        break;
+    case REVERB_PARAM_DECAY_TIME:
+	ALOGV("%s: REVERB_PARAM_DECAY_TIME", __func__);
+        *(uint32_t *)value = reverb_get_decay_time(reverb_ctxt);
+        break;
+    case REVERB_PARAM_DECAY_HF_RATIO:
+	ALOGV("%s: REVERB_PARAM_DECAY_HF_RATIO", __func__);
+        *(int16_t *)value = reverb_get_decay_hf_ratio(reverb_ctxt);
+        break;
+    case REVERB_PARAM_REVERB_LEVEL:
+	ALOGV("%s: REVERB_PARAM_REVERB_LEVEL", __func__);
+        *(int16_t *)value = reverb_get_reverb_level(reverb_ctxt);
+        break;
+    case REVERB_PARAM_DIFFUSION:
+	ALOGV("%s: REVERB_PARAM_DIFFUSION", __func__);
+        *(int16_t *)value = reverb_get_diffusion(reverb_ctxt);
+        break;
+    case REVERB_PARAM_DENSITY:
+	ALOGV("%s: REVERB_PARAM_DENSITY", __func__);
+        *(int16_t *)value = reverb_get_density(reverb_ctxt);
+        break;
+    case REVERB_PARAM_REFLECTIONS_LEVEL:
+	ALOGV("%s: REVERB_PARAM_REFLECTIONS_LEVEL", __func__);
+        *(uint16_t *)value = 0;
+        break;
+    case REVERB_PARAM_REFLECTIONS_DELAY:
+	ALOGV("%s: REVERB_PARAM_REFLECTIONS_DELAY", __func__);
+        *(uint32_t *)value = 0;
+        break;
+    case REVERB_PARAM_REVERB_DELAY:
+	ALOGV("%s: REVERB_PARAM_REVERB_DELAY", __func__);
+        *(uint32_t *)value = 0;
+        break;
+    default:
+        p->status = -EINVAL;
+        break;
+    }
+
+    return 0;
+}
+
+int reverb_set_parameter(effect_context_t *context, effect_param_t *p,
+                         uint32_t size)
+{
+    reverb_context_t *reverb_ctxt = (reverb_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++;
+    reverb_settings_t *reverb_settings;
+    int16_t level;
+    int16_t ratio;
+    uint32_t time;
+
+    ALOGV("%s", __func__);
+
+    p->status = 0;
+
+    if (reverb_ctxt->preset) {
+        if (param != REVERB_PARAM_PRESET)
+            return -EINVAL;
+        uint16_t preset = *(uint16_t *)value;
+        ALOGV("set REVERB_PARAM_PRESET, preset %d", preset);
+        if (preset > REVERB_PRESET_LAST) {
+            return -EINVAL;
+        }
+        reverb_set_preset(reverb_ctxt, preset);
+    }
+    switch (param) {
+    case REVERB_PARAM_PROPERTIES:
+	ALOGV("%s: REVERB_PARAM_PROPERTIES", __func__);
+        reverb_settings = (reverb_settings_t *)value;
+        break;
+    case REVERB_PARAM_ROOM_LEVEL:
+	ALOGV("%s: REVERB_PARAM_ROOM_LEVEL", __func__);
+        level = *(int16_t *)value;
+        reverb_set_room_level(reverb_ctxt, level);
+        break;
+    case REVERB_PARAM_ROOM_HF_LEVEL:
+	ALOGV("%s: REVERB_PARAM_ROOM_HF_LEVEL", __func__);
+        level = *(int16_t *)value;
+        reverb_set_room_hf_level(reverb_ctxt, level);
+        break;
+    case REVERB_PARAM_DECAY_TIME:
+	ALOGV("%s: REVERB_PARAM_DECAY_TIME", __func__);
+        time = *(uint32_t *)value;
+        reverb_set_decay_time(reverb_ctxt, time);
+        break;
+    case REVERB_PARAM_DECAY_HF_RATIO:
+	ALOGV("%s: REVERB_PARAM_DECAY_HF_RATIO", __func__);
+        ratio = *(int16_t *)value;
+        reverb_set_decay_hf_ratio(reverb_ctxt, ratio);
+        break;
+    case REVERB_PARAM_REVERB_LEVEL:
+	ALOGV("%s: REVERB_PARAM_REVERB_LEVEL", __func__);
+        level = *(int16_t *)value;
+        reverb_set_reverb_level(reverb_ctxt, level);
+        break;
+    case REVERB_PARAM_DIFFUSION:
+	ALOGV("%s: REVERB_PARAM_DIFFUSION", __func__);
+        ratio = *(int16_t *)value;
+        reverb_set_diffusion(reverb_ctxt, ratio);
+        break;
+    case REVERB_PARAM_DENSITY:
+	ALOGV("%s: REVERB_PARAM_DENSITY", __func__);
+        ratio = *(int16_t *)value;
+        reverb_set_density(reverb_ctxt, ratio);
+        break;
+    case REVERB_PARAM_REFLECTIONS_LEVEL:
+    case REVERB_PARAM_REFLECTIONS_DELAY:
+    case REVERB_PARAM_REVERB_DELAY:
+        break;
+    default:
+        p->status = -EINVAL;
+        break;
+    }
+
+    return 0;
+}
+
+int reverb_set_device(effect_context_t *context, uint32_t device)
+{
+    reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+    ALOGV("%s: device: %d", __func__, device);
+    reverb_ctxt->device = device;
+    offload_reverb_set_device(&(reverb_ctxt->offload_reverb), device);
+    return 0;
+}
+
+int reverb_reset(effect_context_t *context)
+{
+    reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+    return 0;
+}
+
+int reverb_init(effect_context_t *context)
+{
+    reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+    context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+    /*
+       FIXME: channel mode is mono for auxiliary. is it needed for offload ?
+              If so, this set config needs to be updated accordingly
+    */
+    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);
+
+    memset(&(reverb_ctxt->reverb_settings), 0, sizeof(reverb_settings_t));
+    memset(&(reverb_ctxt->offload_reverb), 0, sizeof(struct reverb_params));
+
+    if (reverb_ctxt->preset &&
+        reverb_ctxt->next_preset != reverb_ctxt->cur_preset)
+        reverb_load_preset(reverb_ctxt);
+
+    return 0;
+}
+
+int reverb_enable(effect_context_t *context)
+{
+    reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+    ALOGV("%s", __func__);
+
+    if (!offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb)))
+        offload_reverb_set_enable_flag(&(reverb_ctxt->offload_reverb), true);
+    return 0;
+}
+
+int reverb_disable(effect_context_t *context)
+{
+    reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+    ALOGV("%s", __func__);
+    if (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))) {
+        offload_reverb_set_enable_flag(&(reverb_ctxt->offload_reverb), false);
+        if (reverb_ctxt->ctl)
+            offload_reverb_send_params(reverb_ctxt->ctl,
+                                       reverb_ctxt->offload_reverb,
+                                       OFFLOAD_SEND_REVERB_ENABLE_FLAG);
+    }
+    return 0;
+}
+
+int reverb_start(effect_context_t *context, output_context_t *output)
+{
+    reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+    ALOGV("%s", __func__);
+    reverb_ctxt->ctl = output->ctl;
+    return 0;
+}
+
+int reverb_stop(effect_context_t *context, output_context_t *output)
+{
+    reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+    ALOGV("%s", __func__);
+    reverb_ctxt->ctl = NULL;
+    return 0;
+}
+
diff --git a/post_proc/reverb.h b/post_proc/reverb.h
new file mode 100644
index 0000000..63192eb
--- /dev/null
+++ b/post_proc/reverb.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OFFLOAD_REVERB_H_
+#define OFFLOAD_REVERB_H_
+
+#include "bundle.h"
+
+#define REVERB_DEFAULT_PRESET REVERB_PRESET_NONE
+
+extern const effect_descriptor_t aux_env_reverb_descriptor;
+extern const effect_descriptor_t ins_env_reverb_descriptor;
+extern const effect_descriptor_t aux_preset_reverb_descriptor;
+extern const effect_descriptor_t ins_preset_reverb_descriptor;
+
+typedef struct reverb_settings_s {
+    int16_t     roomLevel;
+    int16_t     roomHFLevel;
+    uint32_t    decayTime;
+    int16_t     decayHFRatio;
+    int16_t     reflectionsLevel;
+    uint32_t    reflectionsDelay;
+    int16_t     reverbLevel;
+    uint32_t    reverbDelay;
+    int16_t     diffusion;
+    int16_t     density;
+} reverb_settings_t;
+
+typedef struct reverb_context_s {
+    effect_context_t common;
+
+    // Offload vars
+    struct mixer_ctl *ctl;
+    bool auxiliary;
+    bool preset;
+    uint16_t cur_preset;
+    uint16_t next_preset;
+    reverb_settings_t reverb_settings;
+    uint32_t device;
+    struct reverb_params offload_reverb;
+} reverb_context_t;
+
+
+void reverb_auxiliary_init(reverb_context_t *context);
+
+void reverb_preset_init(reverb_context_t *context);
+
+int reverb_get_parameter(effect_context_t *context, effect_param_t *p,
+                            uint32_t *size);
+
+int reverb_set_parameter(effect_context_t *context, effect_param_t *p,
+                            uint32_t size);
+
+int reverb_set_device(effect_context_t *context,  uint32_t device);
+
+int reverb_reset(effect_context_t *context);
+
+int reverb_init(effect_context_t *context);
+
+int reverb_enable(effect_context_t *context);
+
+int reverb_disable(effect_context_t *context);
+
+int reverb_start(effect_context_t *context, output_context_t *output);
+
+int reverb_stop(effect_context_t *context, output_context_t *output);
+
+#endif /* OFFLOAD_REVERB_H_ */
diff --git a/post_proc/virtualizer.c b/post_proc/virtualizer.c
new file mode 100644
index 0000000..2f0ca6b
--- /dev/null
+++ b/post_proc/virtualizer.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "offload_effect_virtualizer"
+#define LOG_NDEBUG 0
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <tinyalsa/asoundlib.h>
+#include <audio_effects.h>
+#include <audio_effects/effect_virtualizer.h>
+
+#include "effect_api.h"
+#include "virtualizer.h"
+
+/* Offload Virtualizer UUID: 509a4498-561a-4bea-b3b1-0002a5d5c51b */
+const effect_descriptor_t virtualizer_descriptor = {
+        {0x37cc2c00, 0xdddd, 0x11db, 0x8577, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+        {0x509a4498, 0x561a, 0x4bea, 0xb3b1, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
+        EFFECT_CONTROL_API_VERSION,
+        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_HW_ACC_TUNNEL),
+        0, /* TODO */
+        1,
+        "MSM offload virtualizer",
+        "The Android Open Source Project",
+};
+
+/*
+ * Virtualizer operations
+ */
+
+int virtualizer_get_strength(virtualizer_context_t *context)
+{
+    ALOGV("%s: strength: %d", __func__, context->strength);
+    return context->strength;
+}
+
+int virtualizer_set_strength(virtualizer_context_t *context, uint32_t strength)
+{
+    ALOGV("%s: strength: %d", __func__, strength);
+    context->strength = strength;
+
+    offload_virtualizer_set_strength(&(context->offload_virt), strength);
+    if (context->ctl)
+        offload_virtualizer_send_params(context->ctl, context->offload_virt,
+                                        OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
+                                        OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
+    return 0;
+}
+
+int virtualizer_get_parameter(effect_context_t *context, effect_param_t *p,
+                              uint32_t *size)
+{
+    virtualizer_context_t *virt_ctxt = (virtualizer_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 VIRTUALIZER_PARAM_STRENGTH_SUPPORTED:
+        if (p->vsize < sizeof(uint32_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(uint32_t);
+        break;
+    case VIRTUALIZER_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 VIRTUALIZER_PARAM_STRENGTH_SUPPORTED:
+	ALOGV("%s: VIRTUALIZER_PARAM_STRENGTH_SUPPORTED", __func__);
+        *(uint32_t *)value = 1;
+        break;
+
+    case VIRTUALIZER_PARAM_STRENGTH:
+	ALOGV("%s: VIRTUALIZER_PARAM_STRENGTH", __func__);
+        *(int16_t *)value = virtualizer_get_strength(virt_ctxt);
+        break;
+
+    default:
+        p->status = -EINVAL;
+        break;
+    }
+
+    return 0;
+}
+
+int virtualizer_set_parameter(effect_context_t *context, effect_param_t *p,
+                              uint32_t size)
+{
+    virtualizer_context_t *virt_ctxt = (virtualizer_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 VIRTUALIZER_PARAM_STRENGTH:
+	ALOGV("%s VIRTUALIZER_PARAM_STRENGTH", __func__);
+        strength = (uint32_t)(*(int16_t *)value);
+        virtualizer_set_strength(virt_ctxt, strength);
+        break;
+    default:
+        p->status = -EINVAL;
+        break;
+    }
+
+    return 0;
+}
+
+int virtualizer_set_device(effect_context_t *context, uint32_t device)
+{
+    virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+    ALOGV("%s: device: %d", __func__, device);
+    virt_ctxt->device = device;
+    if((device == AUDIO_DEVICE_OUT_SPEAKER) ||
+       (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) ||
+       (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) {
+        if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) {
+            offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
+            virt_ctxt->temp_disabled = true;
+        }
+    } else {
+        if (!offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)) &&
+            virt_ctxt->temp_disabled) {
+            offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
+            virt_ctxt->temp_disabled = false;
+        }
+    }
+    offload_virtualizer_set_device(&(virt_ctxt->offload_virt), device);
+    return 0;
+}
+
+int virtualizer_reset(effect_context_t *context)
+{
+    virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+    return 0;
+}
+
+int virtualizer_init(effect_context_t *context)
+{
+    ALOGV("%s", __func__);
+    virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+    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);
+
+    memset(&(virt_ctxt->offload_virt), 0, sizeof(struct virtualizer_params));
+
+    return 0;
+}
+
+int virtualizer_enable(effect_context_t *context)
+{
+    virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+    ALOGV("%s", __func__);
+
+    if (!offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)))
+        offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
+    return 0;
+}
+
+int virtualizer_disable(effect_context_t *context)
+{
+    virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+    ALOGV("%s", __func__);
+    if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) {
+        offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
+        if (virt_ctxt->ctl)
+            offload_virtualizer_send_params(virt_ctxt->ctl,
+                                          virt_ctxt->offload_virt,
+                                          OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+    }
+    return 0;
+}
+
+int virtualizer_start(effect_context_t *context, output_context_t *output)
+{
+    virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+    ALOGV("%s", __func__);
+    virt_ctxt->ctl = output->ctl;
+    return 0;
+}
+
+int virtualizer_stop(effect_context_t *context, output_context_t *output)
+{
+    virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+    ALOGV("%s", __func__);
+    virt_ctxt->ctl = NULL;
+    return 0;
+}
diff --git a/post_proc/virtualizer.h b/post_proc/virtualizer.h
new file mode 100644
index 0000000..4a5005f
--- /dev/null
+++ b/post_proc/virtualizer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OFFLOAD_VIRTUALIZER_H_
+#define OFFLOAD_VIRTUALIZER_H_
+
+#include "bundle.h"
+
+extern const effect_descriptor_t virtualizer_descriptor;
+
+typedef struct virtualizer_context_s {
+    effect_context_t common;
+
+    int strength;
+
+    // Offload vars
+    struct mixer_ctl *ctl;
+    bool temp_disabled;
+    uint32_t device;
+    struct virtualizer_params offload_virt;
+} virtualizer_context_t;
+
+int virtualizer_get_parameter(effect_context_t *context, effect_param_t *p,
+                            uint32_t *size);
+
+int virtualizer_set_parameter(effect_context_t *context, effect_param_t *p,
+                            uint32_t size);
+
+int virtualizer_set_device(effect_context_t *context,  uint32_t device);
+
+int virtualizer_reset(effect_context_t *context);
+
+int virtualizer_init(effect_context_t *context);
+
+int virtualizer_enable(effect_context_t *context);
+
+int virtualizer_disable(effect_context_t *context);
+
+int virtualizer_start(effect_context_t *context, output_context_t *output);
+
+int virtualizer_stop(effect_context_t *context, output_context_t *output);
+
+#endif /* OFFLOAD_VIRTUALIZER_H_ */