post_proc: Add support for non-tunnel DSP audio effects

Add hw accelerator module to send PCM data to DSP and get
back the effects processed data.

Expose a wrapper library for AudioFlinger to be able use the new
module to apply the DSP audio effects.

Change-Id: I6ee30c11f04a97b35f12201fb61b8cd901921e68
Signed-off-by: Alexy Joseph <alexyj@codeaurora.org>
diff --git a/post_proc/Android.mk b/post_proc/Android.mk
index 720d3dd..e253159 100644
--- a/post_proc/Android.mk
+++ b/post_proc/Android.mk
@@ -14,7 +14,8 @@
 	virtualizer.c \
 	reverb.c \
 	effect_api.c \
-	effect_util.c
+	effect_util.c \
+        hw_accelerator.c
 
 LOCAL_CFLAGS+= -O2 -fvisibility=hidden
 
@@ -32,9 +33,33 @@
 LOCAL_MODULE_RELATIVE_PATH := soundfx
 LOCAL_MODULE:= libqcompostprocbundle
 
+LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
 LOCAL_C_INCLUDES := \
 	external/tinyalsa/include \
         $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include \
 	$(call include-path-for, audio-effects)
 
 include $(BUILD_SHARED_LIBRARY)
+
+
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_HW_ACCELERATED_EFFECTS)),true)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := EffectsHwAcc.cpp
+
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-effects)
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libeffects
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS += -O2 -fvisibility=hidden
+
+LOCAL_MODULE:= libhwacceffectswrapper
+
+include $(BUILD_STATIC_LIBRARY)
+endif
diff --git a/post_proc/EffectsHwAcc.cpp b/post_proc/EffectsHwAcc.cpp
new file mode 100644
index 0000000..d88a199
--- /dev/null
+++ b/post_proc/EffectsHwAcc.cpp
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "EffectsHwAcc"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <media/EffectsFactoryApi.h>
+#include <audio_effects/effect_hwaccelerator.h>
+#include "EffectsHwAcc.h"
+
+namespace android {
+
+#define FRAME_SIZE(format)   ((format == AUDIO_FORMAT_PCM_24_BIT_PACKED) ? \
+                              3 /* bytes for 24 bit */ : \
+                              (format == AUDIO_FORMAT_PCM_16_BIT) ? \
+                               sizeof(uint16_t) : sizeof(uint8_t))
+// ----------------------------------------------------------------------------
+EffectsHwAcc::EffectsBufferProvider::EffectsBufferProvider()
+             : AudioBufferProvider(), mEffectsHandle(NULL),
+               mInputBuffer(NULL), mOutputBuffer(NULL),
+               mInputBufferFrameCountOffset(0)
+{
+}
+
+EffectsHwAcc::EffectsBufferProvider::~EffectsBufferProvider()
+{
+    ALOGV(" deleting HwAccEffBufferProvider");
+
+    if (mEffectsHandle)
+        EffectRelease(mEffectsHandle);
+    if (mInputBuffer)
+        free(mInputBuffer);
+    if (mOutputBuffer)
+        free(mOutputBuffer);
+}
+
+status_t EffectsHwAcc::EffectsBufferProvider::getNextBuffer(
+                       AudioBufferProvider::Buffer *pBuffer,
+                       int64_t pts)
+{
+    ALOGV("EffectsBufferProvider::getNextBuffer");
+
+    size_t reqInputFrameCount, frameCount, offset;
+    size_t reqOutputFrameCount = pBuffer->frameCount;
+    int ret = 0;
+
+    if (mTrackBufferProvider != NULL) {
+        while (1) {
+            reqInputFrameCount = ((reqOutputFrameCount *
+                                   mEffectsConfig.inputCfg.samplingRate)/
+                                   mEffectsConfig.outputCfg.samplingRate) +
+                                   (((reqOutputFrameCount *
+                                     mEffectsConfig.inputCfg.samplingRate)%
+                                     mEffectsConfig.outputCfg.samplingRate) ? 1 : 0);
+            ALOGV("InputFrameCount: %d, OutputFrameCount: %d, InputBufferFrameCountOffset: %d",
+                  reqInputFrameCount, reqOutputFrameCount,
+                  mInputBufferFrameCountOffset);
+            frameCount = reqInputFrameCount - mInputBufferFrameCountOffset;
+            offset = mInputBufferFrameCountOffset *
+                     FRAME_SIZE(mEffectsConfig.inputCfg.format) *
+                     popcount(mEffectsConfig.inputCfg.channels);
+            while (frameCount) {
+                pBuffer->frameCount = frameCount;
+                ret = mTrackBufferProvider->getNextBuffer(pBuffer, pts);
+                if (ret == OK) {
+                    int bytesInBuffer = pBuffer->frameCount *
+                                        FRAME_SIZE(mEffectsConfig.inputCfg.format) *
+                                        popcount(mEffectsConfig.inputCfg.channels);
+                    memcpy((char *)mInputBuffer+offset, pBuffer->i8, bytesInBuffer);
+                    frameCount -= pBuffer->frameCount;
+                    mInputBufferFrameCountOffset += pBuffer->frameCount;
+                    offset += bytesInBuffer;
+                    mTrackBufferProvider->releaseBuffer(pBuffer);
+                } else
+                    break;
+            }
+            if (ret == OK) {
+                mEffectsConfig.inputCfg.buffer.frameCount = reqInputFrameCount;
+                mEffectsConfig.inputCfg.buffer.raw = (void *)mInputBuffer;
+                mEffectsConfig.outputCfg.buffer.frameCount = reqOutputFrameCount;
+                mEffectsConfig.outputCfg.buffer.raw = (void *)mOutputBuffer;
+
+                ret = (*mEffectsHandle)->process(mEffectsHandle,
+                                              &mEffectsConfig.inputCfg.buffer,
+                                              &mEffectsConfig.outputCfg.buffer);
+                if (ret == -ENODATA) {
+                    ALOGV("Continue to provide more data for initial buffering");
+                    mInputBufferFrameCountOffset -= reqInputFrameCount;
+                    continue;
+                }
+                if (ret > 0)
+                    mInputBufferFrameCountOffset -= reqInputFrameCount;
+                pBuffer->raw = (void *)mOutputBuffer;
+                pBuffer->frameCount = reqOutputFrameCount;
+            }
+            return ret;
+        }
+    } else {
+        ALOGE("EffBufferProvider::getNextBuffer() error: NULL track buffer provider");
+        return NO_INIT;
+    }
+}
+
+void EffectsHwAcc::EffectsBufferProvider::releaseBuffer(
+                                          AudioBufferProvider::Buffer *pBuffer)
+{
+    ALOGV("EffBufferProvider::releaseBuffer()");
+    if (this->mTrackBufferProvider != NULL) {
+        pBuffer->frameCount = 0;
+        pBuffer->raw = NULL;
+    } else {
+        ALOGE("HwAccEffectsBufferProvider::releaseBuffer() error: NULL track buffer provider");
+    }
+}
+
+EffectsHwAcc::EffectsHwAcc(uint32_t sampleRate)
+             : mEnabled(false), mFd(-1), mBufferProvider(NULL),
+               mInputSampleRate(sampleRate), mOutputSampleRate(sampleRate)
+{
+}
+
+EffectsHwAcc::~EffectsHwAcc()
+{
+    ALOGV("deleting EffectsHwAcc");
+
+    if (mBufferProvider)
+        delete mBufferProvider;
+}
+
+void EffectsHwAcc::setSampleRate(uint32_t inpSR, uint32_t outSR)
+{
+    mInputSampleRate = inpSR;
+    mOutputSampleRate = outSR;
+}
+
+void EffectsHwAcc::unprepareEffects(AudioBufferProvider **bufferProvider)
+{
+    ALOGV("EffectsHwAcc::unprepareEffects");
+
+    EffectsBufferProvider *pHwAccbp = mBufferProvider;
+    if (mBufferProvider != NULL) {
+        ALOGV(" deleting h/w accelerator EffectsBufferProvider");
+        int cmdStatus, status;
+        uint32_t replySize = sizeof(int);
+
+        replySize = sizeof(int);
+        status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
+                                              EFFECT_CMD_DISABLE,
+                                              0 /*cmdSize*/, NULL /*pCmdData*/,
+                                              &replySize, &cmdStatus /*pReplyData*/);
+        if ((status != 0) || (cmdStatus != 0))
+            ALOGE("error %d while enabling hw acc effects", status);
+
+        *bufferProvider = pHwAccbp->mTrackBufferProvider;
+        delete mBufferProvider;
+
+        mBufferProvider = NULL;
+    } else {
+        ALOGV(" nothing to do, no h/w accelerator effects to delete");
+    }
+    mEnabled = false;
+}
+
+status_t EffectsHwAcc::prepareEffects(AudioBufferProvider **bufferProvider,
+                                      int sessionId,
+                                      audio_channel_mask_t channelMask,
+                                      int frameCount)
+{
+    ALOGV("EffectsHwAcc::prepareAccEffects");
+
+    // discard the previous hw acc effects if there was one
+    unprepareEffects(bufferProvider);
+
+    EffectsBufferProvider* pHwAccbp = new EffectsBufferProvider();
+    int32_t status;
+    int cmdStatus;
+    uint32_t replySize;
+    uint32_t size = (sizeof(effect_param_t) + 2 * sizeof(int32_t) - 1) /
+                    (sizeof(uint32_t) + 1);
+    uint32_t buf32[size];
+    effect_param_t *param = (effect_param_t *)buf32;
+
+    uint32_t i, numEffects = 0;
+    effect_descriptor_t hwAccFxDesc;
+    int ret = EffectQueryNumberEffects(&numEffects);
+    if (ret != 0) {
+        ALOGE("AudioMixer() error %d querying number of effects", ret);
+        goto noEffectsForActiveTrack;
+    }
+    ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
+
+    for (i = 0 ; i < numEffects ; i++) {
+        if (EffectQueryEffect(i, &hwAccFxDesc) == 0) {
+            if (memcmp(&hwAccFxDesc.type, EFFECT_UIID_HWACCELERATOR,
+                       sizeof(effect_uuid_t)) == 0) {
+                ALOGI("found effect \"%s\" from %s",
+                        hwAccFxDesc.name, hwAccFxDesc.implementor);
+                break;
+            }
+        }
+    }
+    if (i == numEffects) {
+        ALOGW("H/W accelerated effects library not found");
+        goto noEffectsForActiveTrack;
+    }
+    if (EffectCreate(&hwAccFxDesc.uuid, sessionId, -1 /*ioId not relevant here*/,
+                     &pHwAccbp->mEffectsHandle) != 0) {
+        ALOGE("prepareEffects fails: error creating effect");
+        goto noEffectsForActiveTrack;
+    }
+
+    // channel input configuration will be overridden per-track
+    pHwAccbp->mEffectsConfig.inputCfg.channels = channelMask;
+    pHwAccbp->mEffectsConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+    pHwAccbp->mEffectsConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    pHwAccbp->mEffectsConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    pHwAccbp->mEffectsConfig.inputCfg.samplingRate = mInputSampleRate;
+    pHwAccbp->mEffectsConfig.outputCfg.samplingRate = mOutputSampleRate;
+    pHwAccbp->mEffectsConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+    pHwAccbp->mEffectsConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE;
+    pHwAccbp->mEffectsConfig.outputCfg.buffer.frameCount = frameCount;
+    pHwAccbp->mEffectsConfig.inputCfg.mask = EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS |
+                                             EFFECT_CONFIG_FORMAT | EFFECT_CONFIG_ACC_MODE;
+    pHwAccbp->mEffectsConfig.outputCfg.mask = pHwAccbp->mEffectsConfig.inputCfg.mask;
+
+    // Configure hw acc effects
+    replySize = sizeof(int);
+    status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
+                                          EFFECT_CMD_SET_CONFIG,
+                                          sizeof(effect_config_t) /*cmdSize*/,
+                                          &pHwAccbp->mEffectsConfig /*pCmdData*/,
+                                          &replySize, &cmdStatus /*pReplyData*/);
+    if ((status != 0) || (cmdStatus != 0)) {
+        ALOGE("error %d while configuring h/w acc effects", status);
+        goto noEffectsForActiveTrack;
+    }
+    replySize = sizeof(int);
+    status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
+                                          EFFECT_CMD_HW_ACC,
+                                          sizeof(frameCount) /*cmdSize*/,
+                                          &frameCount /*pCmdData*/,
+                                          &replySize,
+                                          &cmdStatus /*pReplyData*/);
+    if ((status != 0) || (cmdStatus != 0)) {
+        ALOGE("error %d while enabling h/w acc effects", status);
+       goto noEffectsForActiveTrack;
+    }
+    replySize = sizeof(int);
+    status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
+                                          EFFECT_CMD_ENABLE,
+                                          0 /*cmdSize*/, NULL /*pCmdData*/,
+                                          &replySize, &cmdStatus /*pReplyData*/);
+    if ((status != 0) || (cmdStatus != 0)) {
+        ALOGE("error %d while enabling h/w acc effects", status);
+        goto noEffectsForActiveTrack;
+    }
+
+    param->psize = sizeof(int32_t);
+    *(int32_t *)param->data = HW_ACCELERATOR_FD;
+    param->vsize = sizeof(int32_t);
+    replySize = sizeof(effect_param_t) +
+                ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) +
+                param->vsize;
+    status = (*pHwAccbp->mEffectsHandle)->command(pHwAccbp->mEffectsHandle,
+                                          EFFECT_CMD_GET_PARAM,
+                                          sizeof(effect_param_t) + param->psize,
+                                          param, &replySize, param);
+    if ((param->status != 0) || (*(int32_t *)(param->data + sizeof(int32_t)) <= 0)) {
+            ALOGE("error %d while enabling h/w acc effects", status);
+            goto noEffectsForActiveTrack;
+    }
+    mFd = *(int32_t *)(param->data + sizeof(int32_t));
+
+    pHwAccbp->mInputBuffer = calloc(6*frameCount,
+                                    /* 6 times buffering to account for an input of
+                                       192kHz to an output of 32kHz - may be a least
+                                       sampling rate of rendering device */
+                                    FRAME_SIZE(pHwAccbp->mEffectsConfig.inputCfg.format) *
+                                    popcount(channelMask));
+    if (!pHwAccbp->mInputBuffer)
+        goto noEffectsForActiveTrack;
+
+    pHwAccbp->mOutputBuffer = calloc(frameCount,
+                                     FRAME_SIZE(pHwAccbp->mEffectsConfig.outputCfg.format) *
+                                     popcount(AUDIO_CHANNEL_OUT_STEREO));
+    if (!pHwAccbp->mOutputBuffer) {
+        free(pHwAccbp->mInputBuffer);
+        goto noEffectsForActiveTrack;
+    }
+    // initialization successful:
+    // - keep track of the real buffer provider in case it was set before
+    pHwAccbp->mTrackBufferProvider = *bufferProvider;
+    // - we'll use the hw acc effect integrated inside this
+    //    track's buffer provider, and we'll use it as the track's buffer provider
+    mBufferProvider = pHwAccbp;
+    *bufferProvider = pHwAccbp;
+
+    mEnabled = true;
+    return NO_ERROR;
+
+noEffectsForActiveTrack:
+    delete pHwAccbp;
+    mBufferProvider = NULL;
+    return NO_INIT;
+}
+
+void EffectsHwAcc::setBufferProvider(AudioBufferProvider **bufferProvider,
+                                     AudioBufferProvider **trackBufferProvider)
+{
+    ALOGV("setBufferProvider");
+    if (mBufferProvider &&
+        (mBufferProvider->mTrackBufferProvider != *bufferProvider)) {
+        *trackBufferProvider = mBufferProvider;
+        mBufferProvider->mTrackBufferProvider = *bufferProvider;
+    }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/post_proc/EffectsHwAcc.h b/post_proc/EffectsHwAcc.h
new file mode 100644
index 0000000..919332b
--- /dev/null
+++ b/post_proc/EffectsHwAcc.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_EFFECTS_HW_ACC_H
+#define ANDROID_EFFECTS_HW_ACC_H
+
+#include <media/AudioBufferProvider.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+class EffectsHwAcc {
+public:
+    EffectsHwAcc(uint32_t sampleRate);
+    virtual ~EffectsHwAcc();
+
+    virtual void setSampleRate(uint32_t inpSR, uint32_t outSR);
+    virtual void unprepareEffects(AudioBufferProvider **trackBufferProvider);
+    virtual status_t prepareEffects(AudioBufferProvider **trackBufferProvider,
+                            int sessionId, audio_channel_mask_t channelMask,
+                            int frameCount);
+    virtual void setBufferProvider(AudioBufferProvider **bufferProvider,
+                           AudioBufferProvider **trackBufferProvider);
+    /* AudioBufferProvider that wraps a track AudioBufferProvider by a call to
+       h/w accelerated effect */
+    class EffectsBufferProvider : public AudioBufferProvider {
+    public:
+        EffectsBufferProvider();
+        virtual ~EffectsBufferProvider();
+
+        virtual status_t getNextBuffer(Buffer* buffer, int64_t pts);
+        virtual void releaseBuffer(Buffer* buffer);
+
+        AudioBufferProvider* mTrackBufferProvider;
+        effect_handle_t    mEffectsHandle;
+        effect_config_t    mEffectsConfig;
+
+        void *mInputBuffer;
+        void *mOutputBuffer;
+        uint32_t mInputBufferFrameCountOffset;
+    };
+
+    bool mEnabled;
+    int32_t mFd;
+
+    EffectsBufferProvider* mBufferProvider;
+
+private:
+    uint32_t mInputSampleRate;
+    uint32_t mOutputSampleRate;
+};
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_EFFECTS_HW_ACC_H
diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c
index e2c6d9a..57cf8ef 100644
--- a/post_proc/bass_boost.c
+++ b/post_proc/bass_boost.c
@@ -18,7 +18,7 @@
  */
 
 #define LOG_TAG "offload_effect_bass_boost"
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <cutils/list.h>
 #include <cutils/log.h>
@@ -59,9 +59,14 @@
 
     offload_bassboost_set_strength(&(context->offload_bass), strength);
     if (context->ctl)
-        offload_bassboost_send_params(context->ctl, context->offload_bass,
+        offload_bassboost_send_params(context->ctl, &context->offload_bass,
                                       OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
                                       OFFLOAD_SEND_BASSBOOST_STRENGTH);
+    if (context->hw_acc_fd > 0)
+        hw_acc_bassboost_send_params(context->hw_acc_fd,
+                                     &context->offload_bass,
+                                     OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
+                                     OFFLOAD_SEND_BASSBOOST_STRENGTH);
     return 0;
 }
 
@@ -117,7 +122,7 @@
 }
 
 int bassboost_set_parameter(effect_context_t *context, effect_param_t *p,
-                            uint32_t size)
+                            uint32_t size __unused)
 {
     bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
     int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
@@ -163,8 +168,12 @@
                 offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false);
                 if (bass_ctxt->ctl)
                     offload_bassboost_send_params(bass_ctxt->ctl,
-                                                  bass_ctxt->offload_bass,
+                                                  &bass_ctxt->offload_bass,
                                                   OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+                if (bass_ctxt->hw_acc_fd > 0)
+                    hw_acc_bassboost_send_params(bass_ctxt->hw_acc_fd,
+                                                 &bass_ctxt->offload_bass,
+                                                 OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
             }
             bass_ctxt->temp_disabled = true;
         }
@@ -175,8 +184,12 @@
                 offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true);
                 if (bass_ctxt->ctl)
                     offload_bassboost_send_params(bass_ctxt->ctl,
-                                                  bass_ctxt->offload_bass,
+                                                  &bass_ctxt->offload_bass,
                                                   OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+                if (bass_ctxt->hw_acc_fd > 0)
+                    hw_acc_bassboost_send_params(bass_ctxt->hw_acc_fd,
+                                                 &bass_ctxt->offload_bass,
+                                                 OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
             }
             bass_ctxt->temp_disabled = false;
         }
@@ -216,6 +229,7 @@
 
     set_config(context, &context->config);
 
+    bass_ctxt->hw_acc_fd = -1;
     bass_ctxt->temp_disabled = false;
     memset(&(bass_ctxt->offload_bass), 0, sizeof(struct bass_boost_params));
 
@@ -233,9 +247,14 @@
         offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), true);
         if (bass_ctxt->ctl && bass_ctxt->strength)
             offload_bassboost_send_params(bass_ctxt->ctl,
-                                          bass_ctxt->offload_bass,
+                                          &bass_ctxt->offload_bass,
                                           OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
                                           OFFLOAD_SEND_BASSBOOST_STRENGTH);
+        if ((bass_ctxt->hw_acc_fd > 0) && (bass_ctxt->strength))
+            hw_acc_bassboost_send_params(bass_ctxt->hw_acc_fd,
+                                         &bass_ctxt->offload_bass,
+                                         OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
+                                         OFFLOAD_SEND_BASSBOOST_STRENGTH);
     }
     return 0;
 }
@@ -249,8 +268,12 @@
         offload_bassboost_set_enable_flag(&(bass_ctxt->offload_bass), false);
         if (bass_ctxt->ctl)
             offload_bassboost_send_params(bass_ctxt->ctl,
-                                          bass_ctxt->offload_bass,
+                                          &bass_ctxt->offload_bass,
                                           OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+        if (bass_ctxt->hw_acc_fd > 0)
+            hw_acc_bassboost_send_params(bass_ctxt->hw_acc_fd,
+                                         &bass_ctxt->offload_bass,
+                                         OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
     }
     return 0;
 }
@@ -262,19 +285,47 @@
     ALOGV("%s: ctxt %p, ctl %p, strength %d", __func__, bass_ctxt,
                                    output->ctl, bass_ctxt->strength);
     bass_ctxt->ctl = output->ctl;
-    if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)))
+    if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))) {
         if (bass_ctxt->ctl)
-            offload_bassboost_send_params(bass_ctxt->ctl, bass_ctxt->offload_bass,
+            offload_bassboost_send_params(bass_ctxt->ctl, &bass_ctxt->offload_bass,
                                           OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
                                           OFFLOAD_SEND_BASSBOOST_STRENGTH);
+        if (bass_ctxt->hw_acc_fd > 0)
+            hw_acc_bassboost_send_params(bass_ctxt->hw_acc_fd,
+                                         &bass_ctxt->offload_bass,
+                                         OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
+                                         OFFLOAD_SEND_BASSBOOST_STRENGTH);
+    }
     return 0;
 }
 
-int bassboost_stop(effect_context_t *context, output_context_t *output)
+int bassboost_stop(effect_context_t *context, output_context_t *output __unused)
 {
     bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
 
     ALOGV("%s: ctxt %p", __func__, bass_ctxt);
+    if (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass)) &&
+        bass_ctxt->ctl) {
+        struct bass_boost_params bassboost;
+        bassboost.enable_flag = false;
+        offload_bassboost_send_params(bass_ctxt->ctl, &bassboost,
+                                      OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG);
+    }
     bass_ctxt->ctl = NULL;
     return 0;
 }
+
+int bassboost_set_mode(effect_context_t *context, int32_t hw_acc_fd)
+{
+    bassboost_context_t *bass_ctxt = (bassboost_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, bass_ctxt);
+    bass_ctxt->hw_acc_fd = hw_acc_fd;
+    if ((bass_ctxt->hw_acc_fd > 0) &&
+        (offload_bassboost_get_enable_flag(&(bass_ctxt->offload_bass))))
+        hw_acc_bassboost_send_params(bass_ctxt->hw_acc_fd,
+                                     &bass_ctxt->offload_bass,
+                                     OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
+                                     OFFLOAD_SEND_BASSBOOST_STRENGTH);
+    return 0;
+}
diff --git a/post_proc/bass_boost.h b/post_proc/bass_boost.h
index 430a07d..6f0e61b 100644
--- a/post_proc/bass_boost.h
+++ b/post_proc/bass_boost.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -31,6 +31,7 @@
 
     // Offload vars
     struct mixer_ctl *ctl;
+    int hw_acc_fd;
     bool temp_disabled;
     uint32_t device;
     struct bass_boost_params offload_bass;
@@ -44,6 +45,8 @@
 
 int bassboost_set_device(effect_context_t *context,  uint32_t device);
 
+int bassboost_set_mode(effect_context_t *context,  int32_t hw_acc_fd);
+
 int bassboost_reset(effect_context_t *context);
 
 int bassboost_init(effect_context_t *context);
diff --git a/post_proc/bundle.c b/post_proc/bundle.c
index a0a6765..871b087 100644
--- a/post_proc/bundle.c
+++ b/post_proc/bundle.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -36,7 +36,7 @@
  */
 
 #define LOG_TAG "offload_effect_bundle"
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <cutils/list.h>
 #include <cutils/log.h>
@@ -45,6 +45,7 @@
 #include <hardware/audio_effect.h>
 
 #include "bundle.h"
+#include "hw_accelerator.h"
 #include "equalizer.h"
 #include "bass_boost.h"
 #include "virtualizer.h"
@@ -68,6 +69,7 @@
         &ins_env_reverb_descriptor,
         &aux_preset_reverb_descriptor,
         &ins_preset_reverb_descriptor,
+        &hw_accelerator_descriptor,
         NULL,
 };
 
@@ -243,6 +245,7 @@
     if (!out_ctxt->mixer) {
         ALOGE("Failed to open mixer");
         out_ctxt->ctl = NULL;
+        out_ctxt->ref_ctl = NULL;
         ret = -EINVAL;
         free(out_ctxt);
         goto exit;
@@ -256,6 +259,7 @@
             free(out_ctxt);
             goto exit;
         }
+        out_ctxt->ref_ctl = out_ctxt->ctl;
     }
 
     list_init(&out_ctxt->effects_list);
@@ -322,7 +326,6 @@
     return ret;
 }
 
-
 /*
  * Effect operations
  */
@@ -381,6 +384,7 @@
         context->ops.set_parameter = equalizer_set_parameter;
         context->ops.get_parameter = equalizer_get_parameter;
         context->ops.set_device = equalizer_set_device;
+        context->ops.set_hw_acc_mode = equalizer_set_mode;
         context->ops.enable = equalizer_enable;
         context->ops.disable = equalizer_disable;
         context->ops.start = equalizer_start;
@@ -401,6 +405,7 @@
         context->ops.set_parameter = bassboost_set_parameter;
         context->ops.get_parameter = bassboost_get_parameter;
         context->ops.set_device = bassboost_set_device;
+        context->ops.set_hw_acc_mode = bassboost_set_mode;
         context->ops.enable = bassboost_enable;
         context->ops.disable = bassboost_disable;
         context->ops.start = bassboost_start;
@@ -421,6 +426,7 @@
         context->ops.set_parameter = virtualizer_set_parameter;
         context->ops.get_parameter = virtualizer_get_parameter;
         context->ops.set_device = virtualizer_set_device;
+        context->ops.set_hw_acc_mode = virtualizer_set_mode;
         context->ops.enable = virtualizer_enable;
         context->ops.disable = virtualizer_disable;
         context->ops.start = virtualizer_start;
@@ -447,6 +453,7 @@
         context->ops.set_parameter = reverb_set_parameter;
         context->ops.get_parameter = reverb_get_parameter;
         context->ops.set_device = reverb_set_device;
+        context->ops.set_hw_acc_mode = reverb_set_mode;
         context->ops.enable = reverb_enable;
         context->ops.disable = reverb_disable;
         context->ops.start = reverb_start;
@@ -459,7 +466,7 @@
         } else if (memcmp(uuid, &ins_env_reverb_descriptor.uuid,
                    sizeof(effect_uuid_t)) == 0) {
             context->desc = &ins_env_reverb_descriptor;
-            reverb_preset_init(reverb_ctxt);
+            reverb_insert_init(reverb_ctxt);
         } else if (memcmp(uuid, &aux_preset_reverb_descriptor.uuid,
                    sizeof(effect_uuid_t)) == 0) {
             context->desc = &aux_preset_reverb_descriptor;
@@ -470,6 +477,27 @@
             reverb_preset_init(reverb_ctxt);
         }
         reverb_ctxt->ctl = NULL;
+    } else if (memcmp(uuid, &hw_accelerator_descriptor.uuid,
+               sizeof(effect_uuid_t)) == 0) {
+        hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)
+                                   calloc(1, sizeof(hw_accelerator_context_t));
+        if (hw_acc_ctxt == NULL) {
+            ALOGE("h/w acc context allocation failed");
+            return -ENOMEM;
+        }
+        context = (effect_context_t *)hw_acc_ctxt;
+        context->ops.init = hw_accelerator_init;
+        context->ops.reset = hw_accelerator_reset;
+        context->ops.set_parameter = hw_accelerator_set_parameter;
+        context->ops.get_parameter = hw_accelerator_get_parameter;
+        context->ops.set_device = hw_accelerator_set_device;
+        context->ops.set_hw_acc_mode = hw_accelerator_set_mode;
+        context->ops.enable = hw_accelerator_enable;
+        context->ops.disable = hw_accelerator_disable;
+        context->ops.release = hw_accelerator_release;
+        context->ops.process = hw_accelerator_process;
+
+        context->desc = &hw_accelerator_descriptor;
     } else {
         return -EINVAL;
     }
@@ -557,6 +585,7 @@
  */
 
 /* Stub function for effect interface: never called for offloaded effects */
+/* called for hw accelerated effects */
 int effect_process(effect_handle_t self,
                        audio_buffer_t *inBuffer,
                        audio_buffer_t *outBuffer)
@@ -564,7 +593,7 @@
     effect_context_t * context = (effect_context_t *)self;
     int status = 0;
 
-    ALOGW("%s: ctxt %p, Called ?????", __func__, context);
+    ALOGV("%s", __func__);
 
     pthread_mutex_lock(&lock);
     if (!effect_exists(context)) {
@@ -577,6 +606,8 @@
         goto exit;
     }
 
+    if (context->ops.process)
+        status = context->ops.process(context, inBuffer, outBuffer);
 exit:
     pthread_mutex_unlock(&lock);
     return status;
@@ -628,7 +659,7 @@
             status = -EINVAL;
             goto exit;
         }
-        if (!context->offload_enabled) {
+        if (!context->offload_enabled && !context->hw_acc_enabled) {
             status = -EINVAL;
             goto exit;
         }
@@ -678,7 +709,7 @@
                   cmdSize, *replySize);
             goto exit;
         }
-        if (!context->offload_enabled) {
+        if (!context->offload_enabled && !context->hw_acc_enabled) {
             status = -EINVAL;
             goto exit;
         }
@@ -753,7 +784,20 @@
 
         } break;
 
+    case EFFECT_CMD_HW_ACC: {
+        ALOGV("EFFECT_CMD_HW_ACC cmdSize %d pCmdData %p, *replySize %d, pReplyData %p",
+              cmdSize, pCmdData, *replySize, pReplyData);
+        if (cmdSize != sizeof(uint32_t) || pCmdData == NULL
+                || pReplyData == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        uint32_t value = *(uint32_t *)pCmdData;
+        if (context->ops.set_hw_acc_mode)
+            context->ops.set_hw_acc_mode(context, value);
 
+        context->hw_acc_enabled = (value > 0) ? true : false;
+        break;
+    }
     default:
         if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
             status = context->ops.command(context, cmdCode, cmdSize,
diff --git a/post_proc/bundle.h b/post_proc/bundle.h
index cbe7dba..06da991 100644
--- a/post_proc/bundle.h
+++ b/post_proc/bundle.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -48,6 +48,7 @@
     int pcm_device_id;
     struct mixer *mixer;
     struct mixer_ctl *ctl;
+    struct mixer_ctl *ref_ctl;
 };
 
 /* effect specific operations.
@@ -66,6 +67,7 @@
     int (*set_parameter)(effect_context_t *context, effect_param_t *param, uint32_t size);
     int (*get_parameter)(effect_context_t *context, effect_param_t *param, uint32_t *size);
     int (*set_device)(effect_context_t *context, uint32_t device);
+    int (*set_hw_acc_mode)(effect_context_t *context, int32_t value);
     int (*command)(effect_context_t *context, uint32_t cmdCode, uint32_t cmdSize,
             void *pCmdData, uint32_t *replySize, void *pReplyData);
 };
@@ -82,6 +84,7 @@
     audio_io_handle_t out_handle;
     uint32_t state;
     bool offload_enabled;
+    bool hw_acc_enabled;
     effect_ops_t ops;
 };
 
diff --git a/post_proc/effect_api.c b/post_proc/effect_api.c
index 327ddb9..61f6f00 100644
--- a/post_proc/effect_api.c
+++ b/post_proc/effect_api.c
@@ -46,7 +46,7 @@
  */
 
 #define LOG_TAG "offload_effect_api"
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 //#define VERY_VERY_VERBOSE_LOGGING
 #ifdef VERY_VERY_VERBOSE_LOGGING
 #define ALOGVV ALOGV
@@ -59,6 +59,8 @@
 #include <tinyalsa/asoundlib.h>
 #include <sound/audio_effects.h>
 #include <sound/devdep_params.h>
+#include <linux/msm_audio.h>
+
 #include "effect_api.h"
 
 #ifdef DTS_EAGLE
@@ -66,6 +68,10 @@
 #endif
 
 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+typedef enum eff_mode {
+    OFFLOAD,
+    HW_ACCELERATOR
+} eff_mode_t;
 
 #define OFFLOAD_PRESET_START_OFFSET_FOR_OPENSL 19
 const int map_eq_opensl_preset_2_offload_preset[] = {
@@ -93,35 +99,35 @@
 };
 
 int offload_update_mixer_and_effects_ctl(int card, int device_id,
-                                         struct mixer *mixer,
-                                         struct mixer_ctl *ctl)
+                                         struct mixer **mixer,
+                                         struct mixer_ctl **ctl)
 {
     char mixer_string[128];
 
     snprintf(mixer_string, sizeof(mixer_string),
              "%s %d", "Audio Effects Config", device_id);
     ALOGV("%s: mixer_string: %s", __func__, mixer_string);
-    mixer = mixer_open(card);
-    if (!mixer) {
+    *mixer = mixer_open(card);
+    if (!(*mixer)) {
         ALOGE("Failed to open mixer");
         ctl = NULL;
         return -EINVAL;
     } else {
-        ctl = mixer_get_ctl_by_name(mixer, mixer_string);
+        *ctl = mixer_get_ctl_by_name(*mixer, mixer_string);
         if (!ctl) {
             ALOGE("mixer_get_ctl_by_name failed");
-            mixer_close(mixer);
-            mixer = NULL;
+            mixer_close(*mixer);
+            *mixer = NULL;
             return -EINVAL;
         }
     }
-    ALOGV("mixer: %p, ctl: %p", mixer, ctl);
+    ALOGV("mixer: %p, ctl: %p", *mixer, *ctl);
     return 0;
 }
 
-void offload_close_mixer(struct mixer *mixer)
+void offload_close_mixer(struct mixer **mixer)
 {
-    mixer_close(mixer);
+    mixer_close(*mixer);
 }
 
 void offload_bassboost_set_device(struct bass_boost_params *bassboost,
@@ -166,23 +172,23 @@
     bassboost->mode = mode;
 }
 
-int offload_bassboost_send_params(struct mixer_ctl *ctl,
-                                  struct bass_boost_params bassboost,
-                                  unsigned param_send_flags)
+static int bassboost_send_params(eff_mode_t mode, void *ctl,
+                                  struct bass_boost_params *bassboost,
+                                 unsigned param_send_flags)
 {
     int param_values[128] = {0};
     int *p_param_values = param_values;
 
     ALOGV("%s: flags 0x%x", __func__, param_send_flags);
     *p_param_values++ = BASS_BOOST_MODULE;
-    *p_param_values++ = bassboost.device;
+    *p_param_values++ = bassboost->device;
     *p_param_values++ = 0; /* num of commands*/
     if (param_send_flags & OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG) {
         *p_param_values++ = BASS_BOOST_ENABLE;
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = BASS_BOOST_ENABLE_PARAM_LEN;
-        *p_param_values++ = bassboost.enable_flag;
+        *p_param_values++ = bassboost->enable_flag;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_BASSBOOST_STRENGTH) {
@@ -190,7 +196,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = BASS_BOOST_STRENGTH_PARAM_LEN;
-        *p_param_values++ = bassboost.strength;
+        *p_param_values++ = bassboost->strength;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_BASSBOOST_MODE) {
@@ -198,16 +204,37 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = BASS_BOOST_MODE_PARAM_LEN;
-        *p_param_values++ = bassboost.mode;
+        *p_param_values++ = bassboost->mode;
         param_values[2] += 1;
     }
 
-    if (param_values[2] && ctl)
-        mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+    if ((mode == OFFLOAD) && param_values[2] && ctl) {
+        mixer_ctl_set_array((struct mixer_ctl *)ctl, param_values,
+                            ARRAY_SIZE(param_values));
+    } else if ((mode == HW_ACCELERATOR) && param_values[2] &&
+               ctl && *(int *)ctl) {
+        if (ioctl(*(int *)ctl, AUDIO_EFFECTS_SET_PP_PARAMS, param_values) < 0)
+            ALOGE("%s: sending h/w acc effects params fail[%d]", __func__, errno);
+    }
 
     return 0;
 }
 
+int offload_bassboost_send_params(struct mixer_ctl *ctl,
+                                  struct bass_boost_params *bassboost,
+                                  unsigned param_send_flags)
+{
+    return bassboost_send_params(OFFLOAD, (void *)ctl, bassboost,
+                                 param_send_flags);
+}
+
+int hw_acc_bassboost_send_params(int fd, struct bass_boost_params *bassboost,
+                                 unsigned param_send_flags)
+{
+    return bassboost_send_params(HW_ACCELERATOR, (void *)&fd,
+                                 bassboost, param_send_flags);
+}
+
 void offload_virtualizer_set_device(struct virtualizer_params *virtualizer,
                                     uint32_t device)
 {
@@ -257,23 +284,23 @@
     virtualizer->gain_adjust = gain_adjust;
 }
 
-int offload_virtualizer_send_params(struct mixer_ctl *ctl,
-                                    struct virtualizer_params virtualizer,
-                                    unsigned param_send_flags)
+static int virtualizer_send_params(eff_mode_t mode, void *ctl,
+                                    struct virtualizer_params *virtualizer,
+                                   unsigned param_send_flags)
 {
     int param_values[128] = {0};
     int *p_param_values = param_values;
 
     ALOGV("%s: flags 0x%x", __func__, param_send_flags);
     *p_param_values++ = VIRTUALIZER_MODULE;
-    *p_param_values++ = virtualizer.device;
+    *p_param_values++ = virtualizer->device;
     *p_param_values++ = 0; /* num of commands*/
     if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG) {
         *p_param_values++ = VIRTUALIZER_ENABLE;
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = VIRTUALIZER_ENABLE_PARAM_LEN;
-        *p_param_values++ = virtualizer.enable_flag;
+        *p_param_values++ = virtualizer->enable_flag;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_STRENGTH) {
@@ -281,7 +308,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = VIRTUALIZER_STRENGTH_PARAM_LEN;
-        *p_param_values++ = virtualizer.strength;
+        *p_param_values++ = virtualizer->strength;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_OUT_TYPE) {
@@ -289,7 +316,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = VIRTUALIZER_OUT_TYPE_PARAM_LEN;
-        *p_param_values++ = virtualizer.out_type;
+        *p_param_values++ = virtualizer->out_type;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_VIRTUALIZER_GAIN_ADJUST) {
@@ -297,16 +324,38 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = VIRTUALIZER_GAIN_ADJUST_PARAM_LEN;
-        *p_param_values++ = virtualizer.gain_adjust;
+        *p_param_values++ = virtualizer->gain_adjust;
         param_values[2] += 1;
     }
 
-    if (param_values[2] && ctl)
-        mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+    if ((mode == OFFLOAD) && param_values[2] && ctl) {
+        mixer_ctl_set_array((struct mixer_ctl *)ctl, param_values,
+                            ARRAY_SIZE(param_values));
+    } else if ((mode == HW_ACCELERATOR) && param_values[2] &&
+               ctl && *(int *)ctl) {
+        if (ioctl(*(int *)ctl, AUDIO_EFFECTS_SET_PP_PARAMS, param_values) < 0)
+            ALOGE("%s: sending h/w acc effects params fail[%d]", __func__, errno);
+    }
 
     return 0;
 }
 
+int offload_virtualizer_send_params(struct mixer_ctl *ctl,
+                                    struct virtualizer_params *virtualizer,
+                                    unsigned param_send_flags)
+{
+    return virtualizer_send_params(OFFLOAD, (void *)ctl, virtualizer,
+                                   param_send_flags);
+}
+
+int hw_acc_virtualizer_send_params(int fd,
+                                   struct virtualizer_params *virtualizer,
+                                   unsigned param_send_flags)
+{
+    return virtualizer_send_params(HW_ACCELERATOR, (void *)&fd,
+                                   virtualizer, param_send_flags);
+}
+
 void offload_eq_set_device(struct eq_params *eq, uint32_t device)
 {
     ALOGVV("%s: device 0x%x", __func__, device);
@@ -356,28 +405,28 @@
 #endif
 }
 
-int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params eq,
-                           unsigned param_send_flags)
+static int eq_send_params(eff_mode_t mode, void *ctl, struct eq_params *eq,
+                          unsigned param_send_flags)
 {
     int param_values[128] = {0};
     int *p_param_values = param_values;
     uint32_t i;
 
     ALOGV("%s: flags 0x%x", __func__, param_send_flags);
-    if ((eq.config.preset_id < -1) ||
-            ((param_send_flags & OFFLOAD_SEND_EQ_PRESET) && (eq.config.preset_id == -1))) {
+    if ((eq->config.preset_id < -1) ||
+            ((param_send_flags & OFFLOAD_SEND_EQ_PRESET) && (eq->config.preset_id == -1))) {
         ALOGV("No Valid preset to set");
         return 0;
     }
     *p_param_values++ = EQ_MODULE;
-    *p_param_values++ = eq.device;
+    *p_param_values++ = eq->device;
     *p_param_values++ = 0; /* num of commands*/
     if (param_send_flags & OFFLOAD_SEND_EQ_ENABLE_FLAG) {
         *p_param_values++ = EQ_ENABLE;
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = EQ_ENABLE_PARAM_LEN;
-        *p_param_values++ = eq.enable_flag;
+        *p_param_values++ = eq->enable_flag;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_EQ_PRESET) {
@@ -385,9 +434,9 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = EQ_CONFIG_PARAM_LEN;
-        *p_param_values++ = eq.config.eq_pregain;
+        *p_param_values++ = eq->config.eq_pregain;
         *p_param_values++ =
-                     map_eq_opensl_preset_2_offload_preset[eq.config.preset_id];
+                     map_eq_opensl_preset_2_offload_preset[eq->config.preset_id];
         *p_param_values++ = 0;
         param_values[2] += 1;
     }
@@ -396,26 +445,45 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = EQ_CONFIG_PARAM_LEN +
-                            eq.config.num_bands * EQ_CONFIG_PER_BAND_PARAM_LEN;
-        *p_param_values++ = eq.config.eq_pregain;
+                            eq->config.num_bands * EQ_CONFIG_PER_BAND_PARAM_LEN;
+        *p_param_values++ = eq->config.eq_pregain;
         *p_param_values++ = CUSTOM_OPENSL_PRESET;
-        *p_param_values++ = eq.config.num_bands;
-        for (i=0; i<eq.config.num_bands; i++) {
-            *p_param_values++ = eq.per_band_cfg[i].band_idx;
-            *p_param_values++ = eq.per_band_cfg[i].filter_type;
-	    *p_param_values++ = eq.per_band_cfg[i].freq_millihertz;
-            *p_param_values++ = eq.per_band_cfg[i].gain_millibels;
-            *p_param_values++ = eq.per_band_cfg[i].quality_factor;
+        *p_param_values++ = eq->config.num_bands;
+        for (i=0; i<eq->config.num_bands; i++) {
+            *p_param_values++ = eq->per_band_cfg[i].band_idx;
+            *p_param_values++ = eq->per_band_cfg[i].filter_type;
+	    *p_param_values++ = eq->per_band_cfg[i].freq_millihertz;
+            *p_param_values++ = eq->per_band_cfg[i].gain_millibels;
+            *p_param_values++ = eq->per_band_cfg[i].quality_factor;
         }
         param_values[2] += 1;
     }
 
-    if (param_values[2] && ctl)
-        mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+    if ((mode == OFFLOAD) && param_values[2] && ctl) {
+        mixer_ctl_set_array((struct mixer_ctl *)ctl, param_values,
+                            ARRAY_SIZE(param_values));
+    } else if ((mode == HW_ACCELERATOR) && param_values[2] &&
+               ctl && *(int *)ctl) {
+        if (ioctl(*(int *)ctl, AUDIO_EFFECTS_SET_PP_PARAMS, param_values) < 0)
+            ALOGE("%s: sending h/w acc effects params fail[%d]", __func__, errno);
+    }
 
     return 0;
 }
 
+int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params *eq,
+                           unsigned param_send_flags)
+{
+    return eq_send_params(OFFLOAD, (void *)ctl, eq, param_send_flags);
+}
+
+int hw_acc_eq_send_params(int fd, struct eq_params *eq,
+                          unsigned param_send_flags)
+{
+    return eq_send_params(HW_ACCELERATOR, (void *)&fd, eq,
+                          param_send_flags);
+}
+
 void offload_reverb_set_device(struct reverb_params *reverb, uint32_t device)
 {
     ALOGVV("%s: device 0x%x", __func__, device);
@@ -525,16 +593,16 @@
     reverb->density = density;
 }
 
-int offload_reverb_send_params(struct mixer_ctl *ctl,
-                               struct reverb_params reverb,
-                               unsigned param_send_flags)
+static int reverb_send_params(eff_mode_t mode, void *ctl,
+                               struct reverb_params *reverb,
+                              unsigned param_send_flags)
 {
     int param_values[128] = {0};
     int *p_param_values = param_values;
 
     ALOGV("%s: flags 0x%x", __func__, param_send_flags);
     *p_param_values++ = REVERB_MODULE;
-    *p_param_values++ = reverb.device;
+    *p_param_values++ = reverb->device;
     *p_param_values++ = 0; /* num of commands*/
 
     if (param_send_flags & OFFLOAD_SEND_REVERB_ENABLE_FLAG) {
@@ -542,7 +610,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_ENABLE_PARAM_LEN;
-        *p_param_values++ = reverb.enable_flag;
+        *p_param_values++ = reverb->enable_flag;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_MODE) {
@@ -550,7 +618,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_MODE_PARAM_LEN;
-        *p_param_values++ = reverb.mode;
+        *p_param_values++ = reverb->mode;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_PRESET) {
@@ -558,7 +626,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_PRESET_PARAM_LEN;
-        *p_param_values++ = reverb.preset;
+        *p_param_values++ = reverb->preset;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_WET_MIX) {
@@ -566,7 +634,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_WET_MIX_PARAM_LEN;
-        *p_param_values++ = reverb.wet_mix;
+        *p_param_values++ = reverb->wet_mix;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_GAIN_ADJUST) {
@@ -574,7 +642,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_GAIN_ADJUST_PARAM_LEN;
-        *p_param_values++ = reverb.gain_adjust;
+        *p_param_values++ = reverb->gain_adjust;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_ROOM_LEVEL) {
@@ -582,7 +650,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_ROOM_LEVEL_PARAM_LEN;
-        *p_param_values++ = reverb.room_level;
+        *p_param_values++ = reverb->room_level;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL) {
@@ -590,7 +658,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_ROOM_HF_LEVEL_PARAM_LEN;
-        *p_param_values++ = reverb.room_hf_level;
+        *p_param_values++ = reverb->room_hf_level;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_DECAY_TIME) {
@@ -598,7 +666,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_DECAY_TIME_PARAM_LEN;
-        *p_param_values++ = reverb.decay_time;
+        *p_param_values++ = reverb->decay_time;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_DECAY_HF_RATIO) {
@@ -606,7 +674,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_DECAY_HF_RATIO_PARAM_LEN;
-        *p_param_values++ = reverb.decay_hf_ratio;
+        *p_param_values++ = reverb->decay_hf_ratio;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_REFLECTIONS_LEVEL) {
@@ -614,7 +682,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_REFLECTIONS_LEVEL_PARAM_LEN;
-        *p_param_values++ = reverb.reflections_level;
+        *p_param_values++ = reverb->reflections_level;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_REFLECTIONS_DELAY) {
@@ -622,7 +690,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_REFLECTIONS_DELAY_PARAM_LEN;
-        *p_param_values++ = reverb.reflections_delay;
+        *p_param_values++ = reverb->reflections_delay;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_LEVEL) {
@@ -630,7 +698,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_LEVEL_PARAM_LEN;
-        *p_param_values++ = reverb.level;
+        *p_param_values++ = reverb->level;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_DELAY) {
@@ -638,7 +706,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_DELAY_PARAM_LEN;
-        *p_param_values++ = reverb.delay;
+        *p_param_values++ = reverb->delay;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_DIFFUSION) {
@@ -646,7 +714,7 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_DIFFUSION_PARAM_LEN;
-        *p_param_values++ = reverb.diffusion;
+        *p_param_values++ = reverb->diffusion;
         param_values[2] += 1;
     }
     if (param_send_flags & OFFLOAD_SEND_REVERB_DENSITY) {
@@ -654,7 +722,158 @@
         *p_param_values++ = CONFIG_SET;
         *p_param_values++ = 0; /* start offset if param size if greater than 128  */
         *p_param_values++ = REVERB_DENSITY_PARAM_LEN;
-        *p_param_values++ = reverb.density;
+        *p_param_values++ = reverb->density;
+        param_values[2] += 1;
+    }
+
+    if ((mode == OFFLOAD) && param_values[2] && ctl) {
+        mixer_ctl_set_array((struct mixer_ctl *)ctl, param_values,
+                            ARRAY_SIZE(param_values));
+    } else if ((mode == HW_ACCELERATOR) && param_values[2] &&
+               ctl && *(int *)ctl) {
+        if (ioctl(*(int *)ctl, AUDIO_EFFECTS_SET_PP_PARAMS, param_values) < 0)
+            ALOGE("%s: sending h/w acc effects params fail[%d]", __func__, errno);
+    }
+
+    return 0;
+}
+
+int offload_reverb_send_params(struct mixer_ctl *ctl,
+                               struct reverb_params *reverb,
+                               unsigned param_send_flags)
+{
+    return reverb_send_params(OFFLOAD, (void *)ctl, reverb,
+                              param_send_flags);
+}
+
+int hw_acc_reverb_send_params(int fd, struct reverb_params *reverb,
+                              unsigned param_send_flags)
+{
+    return reverb_send_params(HW_ACCELERATOR, (void *)&fd,
+                              reverb, param_send_flags);
+}
+
+void offload_soft_volume_set_enable(struct soft_volume_params *vol, bool enable)
+{
+    ALOGV("%s", __func__);
+    vol->enable_flag = enable;
+}
+
+void offload_soft_volume_set_gain_master(struct soft_volume_params *vol, int gain)
+{
+    ALOGV("%s", __func__);
+    vol->master_gain = gain;
+}
+
+void offload_soft_volume_set_gain_2ch(struct soft_volume_params *vol,
+                                      int l_gain, int r_gain)
+{
+    ALOGV("%s", __func__);
+    vol->left_gain = l_gain;
+    vol->right_gain = r_gain;
+}
+
+int offload_soft_volume_send_params(struct mixer_ctl *ctl,
+                                    struct soft_volume_params vol,
+                                    unsigned param_send_flags)
+{
+    int param_values[128] = {0};
+    int *p_param_values = param_values;
+    uint32_t i;
+
+    ALOGV("%s", __func__);
+    *p_param_values++ = SOFT_VOLUME_MODULE;
+    *p_param_values++ = 0;
+    *p_param_values++ = 0; /* num of commands*/
+    if (param_send_flags & OFFLOAD_SEND_SOFT_VOLUME_ENABLE_FLAG) {
+        *p_param_values++ = SOFT_VOLUME_ENABLE;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = SOFT_VOLUME_ENABLE_PARAM_LEN;
+        *p_param_values++ = vol.enable_flag;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_SOFT_VOLUME_GAIN_MASTER) {
+        *p_param_values++ = SOFT_VOLUME_GAIN_MASTER;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = SOFT_VOLUME_GAIN_MASTER_PARAM_LEN;
+        *p_param_values++ = vol.master_gain;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_SOFT_VOLUME_GAIN_2CH) {
+        *p_param_values++ = SOFT_VOLUME_GAIN_2CH;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = SOFT_VOLUME_GAIN_2CH_PARAM_LEN;
+        *p_param_values++ = vol.left_gain;
+        *p_param_values++ = vol.right_gain;
+        param_values[2] += 1;
+    }
+
+    if (param_values[2] && ctl)
+        mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));
+
+    return 0;
+}
+
+void offload_transition_soft_volume_set_enable(struct soft_volume_params *vol,
+                                               bool enable)
+{
+    ALOGV("%s", __func__);
+    vol->enable_flag = enable;
+}
+
+void offload_transition_soft_volume_set_gain_master(struct soft_volume_params *vol,
+                                                    int gain)
+{
+    ALOGV("%s", __func__);
+    vol->master_gain = gain;
+}
+
+void offload_transition_soft_volume_set_gain_2ch(struct soft_volume_params *vol,
+                                                 int l_gain, int r_gain)
+{
+    ALOGV("%s", __func__);
+    vol->left_gain = l_gain;
+    vol->right_gain = r_gain;
+}
+
+int offload_transition_soft_volume_send_params(struct mixer_ctl *ctl,
+                                               struct soft_volume_params vol,
+                                               unsigned param_send_flags)
+{
+    int param_values[128] = {0};
+    int *p_param_values = param_values;
+    uint32_t i;
+
+    ALOGV("%s", __func__);
+    *p_param_values++ = SOFT_VOLUME2_MODULE;
+    *p_param_values++ = 0;
+    *p_param_values++ = 0; /* num of commands*/
+    if (param_send_flags & OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_ENABLE_FLAG) {
+        *p_param_values++ = SOFT_VOLUME2_ENABLE;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = SOFT_VOLUME2_ENABLE_PARAM_LEN;
+        *p_param_values++ = vol.enable_flag;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER) {
+        *p_param_values++ = SOFT_VOLUME2_GAIN_MASTER;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = SOFT_VOLUME2_GAIN_MASTER_PARAM_LEN;
+        *p_param_values++ = vol.master_gain;
+        param_values[2] += 1;
+    }
+    if (param_send_flags & OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_2CH) {
+        *p_param_values++ = SOFT_VOLUME2_GAIN_2CH;
+        *p_param_values++ = CONFIG_SET;
+        *p_param_values++ = 0; /* start offset if param size if greater than 128  */
+        *p_param_values++ = SOFT_VOLUME2_GAIN_2CH_PARAM_LEN;
+        *p_param_values++ = vol.left_gain;
+        *p_param_values++ = vol.right_gain;
         param_values[2] += 1;
     }
 
diff --git a/post_proc/effect_api.h b/post_proc/effect_api.h
index 342c606..d3b1d81 100644
--- a/post_proc/effect_api.h
+++ b/post_proc/effect_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -30,10 +30,14 @@
 #ifndef OFFLOAD_EFFECT_API_H_
 #define OFFLOAD_EFFECT_API_H_
 
+#if __cplusplus
+extern "C" {
+#endif
+
 int offload_update_mixer_and_effects_ctl(int card, int device_id,
-                                         struct mixer *mixer,
-                                         struct mixer_ctl *ctl);
-void offload_close_mixer(struct mixer *mixer);
+                                         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         \
@@ -50,8 +54,11 @@
 void offload_bassboost_set_mode(struct bass_boost_params *bassboost,
                                 int mode);
 int offload_bassboost_send_params(struct mixer_ctl *ctl,
-                                  struct bass_boost_params bassboost,
+                                  struct bass_boost_params *bassboost,
                                   unsigned param_send_flags);
+int hw_acc_bassboost_send_params(int fd,
+                                 struct bass_boost_params *bassboost,
+                                 unsigned param_send_flags);
 
 #define OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG    (1 << 0)
 #define OFFLOAD_SEND_VIRTUALIZER_STRENGTH       \
@@ -72,8 +79,11 @@
 void offload_virtualizer_set_gain_adjust(struct virtualizer_params *virtualizer,
                                          int gain_adjust);
 int offload_virtualizer_send_params(struct mixer_ctl *ctl,
-                                  struct virtualizer_params virtualizer,
+                                  struct virtualizer_params *virtualizer,
                                   unsigned param_send_flags);
+int hw_acc_virtualizer_send_params(int fd,
+                                   struct virtualizer_params *virtualizer,
+                                   unsigned param_send_flags);
 
 #define OFFLOAD_SEND_EQ_ENABLE_FLAG             (1 << 0)
 #define OFFLOAD_SEND_EQ_PRESET                  \
@@ -87,8 +97,10 @@
 void offload_eq_set_bands_level(struct eq_params *eq, int num_bands,
                                 const uint16_t *band_freq_list,
                                 int *band_gain_list);
-int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params eq,
+int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params *eq,
                            unsigned param_send_flags);
+int hw_acc_eq_send_params(int fd, struct eq_params *eq,
+                          unsigned param_send_flags);
 
 #define OFFLOAD_SEND_REVERB_ENABLE_FLAG         (1 << 0)
 #define OFFLOAD_SEND_REVERB_MODE                \
@@ -145,7 +157,43 @@
 void offload_reverb_set_diffusion(struct reverb_params *reverb, int diffusion);
 void offload_reverb_set_density(struct reverb_params *reverb, int density);
 int offload_reverb_send_params(struct mixer_ctl *ctl,
-                               struct reverb_params reverb,
+                               struct reverb_params *reverb,
                                unsigned param_send_flags);
+int hw_acc_reverb_send_params(int fd,
+                              struct reverb_params *reverb,
+                              unsigned param_send_flags);
+
+#define OFFLOAD_SEND_SOFT_VOLUME_ENABLE_FLAG         (1 << 0)
+#define OFFLOAD_SEND_SOFT_VOLUME_GAIN_2CH             \
+                                          (OFFLOAD_SEND_SOFT_VOLUME_ENABLE_FLAG << 1)
+#define OFFLOAD_SEND_SOFT_VOLUME_GAIN_MASTER          \
+                                          (OFFLOAD_SEND_SOFT_VOLUME_GAIN_2CH << 1)
+void offload_soft_volume_set_enable(struct soft_volume_params *vol,
+                                    bool enable);
+void offload_soft_volume_set_gain_master(struct soft_volume_params *vol,
+                                         int gain);
+void offload_soft_volume_set_gain_2ch(struct soft_volume_params *vol,
+                                      int l_gain, int r_gain);
+int offload_soft_volume_send_params(struct mixer_ctl *ctl,
+                                    struct soft_volume_params vol,
+                                    unsigned param_send_flags);
+
+#define OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_ENABLE_FLAG         (1 << 0)
+#define OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_2CH             \
+                                  (OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_ENABLE_FLAG << 1)
+#define OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_MASTER          \
+                                  (OFFLOAD_SEND_TRANSITION_SOFT_VOLUME_GAIN_2CH << 1)
+void offload_transition_soft_volume_set_enable(struct soft_volume_params *vol,
+                                               bool enable);
+void offload_transition_soft_volume_set_gain_master(struct soft_volume_params *vol,
+                                                    int gain);
+void offload_transition_soft_volume_set_gain_2ch(struct soft_volume_params *vol,
+                                                 int l_gain, int r_gain);
+int offload_transition_soft_volume_send_params(struct mixer_ctl *ctl,
+                                               struct soft_volume_params vol,
+                                               unsigned param_send_flags);
+#if __cplusplus
+} //extern "C"
+#endif
 
 #endif /*OFFLOAD_EFFECT_API_H_*/
diff --git a/post_proc/equalizer.c b/post_proc/equalizer.c
index 7355ead..c2ae326 100644
--- a/post_proc/equalizer.c
+++ b/post_proc/equalizer.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -18,7 +18,7 @@
  */
 
 #define LOG_TAG "offload_effect_equalizer"
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <cutils/list.h>
 #include <cutils/log.h>
@@ -110,9 +110,13 @@
                                equalizer_band_presets_freq,
                                context->band_levels);
     if (context->ctl)
-        offload_eq_send_params(context->ctl, context->offload_eq,
+        offload_eq_send_params(context->ctl, &context->offload_eq,
                                OFFLOAD_SEND_EQ_ENABLE_FLAG |
                                OFFLOAD_SEND_EQ_BANDS_LEVEL);
+    if (context->hw_acc_fd > 0)
+        hw_acc_eq_send_params(context->hw_acc_fd, &context->offload_eq,
+                              OFFLOAD_SEND_EQ_ENABLE_FLAG |
+                              OFFLOAD_SEND_EQ_BANDS_LEVEL);
     return 0;
 }
 
@@ -167,9 +171,13 @@
                                equalizer_band_presets_freq,
                                context->band_levels);
     if(context->ctl)
-        offload_eq_send_params(context->ctl, context->offload_eq,
+        offload_eq_send_params(context->ctl, &context->offload_eq,
                                OFFLOAD_SEND_EQ_ENABLE_FLAG |
                                OFFLOAD_SEND_EQ_PRESET);
+    if(context->hw_acc_fd > 0)
+        hw_acc_eq_send_params(context->hw_acc_fd, &context->offload_eq,
+                              OFFLOAD_SEND_EQ_ENABLE_FLAG |
+                              OFFLOAD_SEND_EQ_PRESET);
     return 0;
 }
 
@@ -336,7 +344,7 @@
 }
 
 int equalizer_set_parameter(effect_context_t *context, effect_param_t *p,
-                            uint32_t size)
+                            uint32_t size __unused)
 {
     equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
     int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
@@ -437,6 +445,7 @@
 
     set_config(context, &context->config);
 
+    eq_ctxt->hw_acc_fd = -1;
     memset(&(eq_ctxt->offload_eq), 0, sizeof(struct eq_params));
     offload_eq_set_preset(&(eq_ctxt->offload_eq), INVALID_PRESET);
 
@@ -452,9 +461,13 @@
     if (!offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) {
         offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), true);
         if (eq_ctxt->ctl)
-            offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq,
+            offload_eq_send_params(eq_ctxt->ctl, &eq_ctxt->offload_eq,
                                    OFFLOAD_SEND_EQ_ENABLE_FLAG |
                                    OFFLOAD_SEND_EQ_BANDS_LEVEL);
+        if (eq_ctxt->hw_acc_fd > 0)
+            hw_acc_eq_send_params(eq_ctxt->hw_acc_fd, &eq_ctxt->offload_eq,
+                                  OFFLOAD_SEND_EQ_ENABLE_FLAG |
+                                  OFFLOAD_SEND_EQ_BANDS_LEVEL);
     }
     return 0;
 }
@@ -467,8 +480,11 @@
     if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) {
         offload_eq_set_enable_flag(&(eq_ctxt->offload_eq), false);
         if (eq_ctxt->ctl)
-            offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq,
+            offload_eq_send_params(eq_ctxt->ctl, &eq_ctxt->offload_eq,
                                    OFFLOAD_SEND_EQ_ENABLE_FLAG);
+        if (eq_ctxt->hw_acc_fd > 0)
+            hw_acc_eq_send_params(eq_ctxt->hw_acc_fd, &eq_ctxt->offload_eq,
+                                  OFFLOAD_SEND_EQ_ENABLE_FLAG);
     }
     return 0;
 }
@@ -479,19 +495,44 @@
 
     ALOGV("%s: ctxt %p, ctl %p", __func__, eq_ctxt, output->ctl);
     eq_ctxt->ctl = output->ctl;
-    if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq)))
+    if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))) {
         if (eq_ctxt->ctl)
-            offload_eq_send_params(eq_ctxt->ctl, eq_ctxt->offload_eq,
+            offload_eq_send_params(eq_ctxt->ctl, &eq_ctxt->offload_eq,
                                    OFFLOAD_SEND_EQ_ENABLE_FLAG |
                                    OFFLOAD_SEND_EQ_BANDS_LEVEL);
+        if (eq_ctxt->hw_acc_fd > 0)
+            hw_acc_eq_send_params(eq_ctxt->hw_acc_fd, &eq_ctxt->offload_eq,
+                                  OFFLOAD_SEND_EQ_ENABLE_FLAG |
+                                  OFFLOAD_SEND_EQ_BANDS_LEVEL);
+    }
     return 0;
 }
 
-int equalizer_stop(effect_context_t *context, output_context_t *output)
+int equalizer_stop(effect_context_t *context, output_context_t *output __unused)
 {
     equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
 
     ALOGV("%s: ctxt %p", __func__, eq_ctxt);
+    if (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq)) &&
+        eq_ctxt->ctl) {
+        struct eq_params eq;
+        eq.enable_flag = false;
+        offload_eq_send_params(eq_ctxt->ctl, &eq, OFFLOAD_SEND_EQ_ENABLE_FLAG);
+    }
     eq_ctxt->ctl = NULL;
     return 0;
 }
+
+int equalizer_set_mode(effect_context_t *context, int32_t hw_acc_fd)
+{
+    equalizer_context_t *eq_ctxt = (equalizer_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, eq_ctxt);
+    eq_ctxt->hw_acc_fd = hw_acc_fd;
+    if ((eq_ctxt->hw_acc_fd > 0) &&
+        (offload_eq_get_enable_flag(&(eq_ctxt->offload_eq))))
+        hw_acc_eq_send_params(eq_ctxt->hw_acc_fd, &eq_ctxt->offload_eq,
+                              OFFLOAD_SEND_EQ_ENABLE_FLAG |
+                              OFFLOAD_SEND_EQ_BANDS_LEVEL);
+    return 0;
+}
diff --git a/post_proc/equalizer.h b/post_proc/equalizer.h
index 19af186..7fec058 100644
--- a/post_proc/equalizer.h
+++ b/post_proc/equalizer.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -36,6 +36,7 @@
 
     // Offload vars
     struct mixer_ctl *ctl;
+    int hw_acc_fd;
     uint32_t device;
     struct eq_params offload_eq;
 } equalizer_context_t;
@@ -48,6 +49,8 @@
 
 int equalizer_set_device(effect_context_t *context,  uint32_t device);
 
+int equalizer_set_mode(effect_context_t *context,  int32_t hw_acc_fd);
+
 int equalizer_reset(effect_context_t *context);
 
 int equalizer_init(effect_context_t *context);
diff --git a/post_proc/hw_accelerator.c b/post_proc/hw_accelerator.c
new file mode 100644
index 0000000..b49337a
--- /dev/null
+++ b/post_proc/hw_accelerator.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "hw_accelerator_effect"
+/*#define LOG_NDEBUG 0*/
+
+#include <cutils/list.h>
+#include <cutils/log.h>
+#include <fcntl.h>
+#include <tinyalsa/asoundlib.h>
+#include <sound/audio_effects.h>
+#include <audio_effects/effect_hwaccelerator.h>
+
+#include "effect_api.h"
+#include "hw_accelerator.h"
+
+
+/* hw_accelerator UUID: 7d1580bd-297f-4683-9239-e475b6d1d69f */
+const effect_descriptor_t hw_accelerator_descriptor = {
+        EFFECT_UIID_HWACCELERATOR__,
+        {0x7d1580bd, 0x297f, 0x4683, 0x9239, {0xe4, 0x75, 0xb6, 0xd1, 0xd6, 0x9f}}, // uuid
+        EFFECT_CONTROL_API_VERSION,
+        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_DEVICE_IND),
+        0, /* TODO */
+        1,
+        "HwAccelerated Library",
+        "QTI",
+};
+
+int hw_accelerator_get_parameter(effect_context_t *context,
+                                 effect_param_t *p, uint32_t *size)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+    int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+    int32_t *param_tmp = (int32_t *)p->data;
+    int32_t param = *param_tmp++;
+    void *value = p->data + voffset;
+    int i;
+
+    ALOGV("%s: ctxt %p, param %d", __func__, hw_acc_ctxt, param);
+
+    p->status = 0;
+
+    switch (param) {
+    case HW_ACCELERATOR_FD:
+        if (p->vsize < sizeof(int32_t))
+           p->status = -EINVAL;
+        p->vsize = sizeof(int32_t);
+        break;
+    default:
+        p->status = -EINVAL;
+    }
+
+    *size = sizeof(effect_param_t) + voffset + p->vsize;
+
+    if (p->status != 0)
+        return 0;
+
+    switch (param) {
+    case HW_ACCELERATOR_FD:
+        ALOGV("%s: HW_ACCELERATOR_FD", __func__);
+        *(int32_t *)value = hw_acc_ctxt->fd;
+        break;
+
+    default:
+        p->status = -EINVAL;
+        break;
+    }
+
+    return 0;
+}
+
+int hw_accelerator_set_parameter(effect_context_t *context, effect_param_t *p,
+                            uint32_t size)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+    int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+    void *value = p->data + voffset;
+    int32_t *param_tmp = (int32_t *)p->data;
+    int32_t param = *param_tmp++;
+
+    ALOGV("%s: ctxt %p, param %d", __func__, hw_acc_ctxt, param);
+
+    p->status = 0;
+
+    switch (param) {
+    /* Placeholder for effects to use set param */
+    default:
+        p->status = -EINVAL;
+        break;
+    }
+
+    return 0;
+}
+
+int hw_accelerator_set_device(effect_context_t *context, uint32_t device)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, hw_acc_ctxt);
+    hw_acc_ctxt->device = device;
+    return 0;
+}
+
+int hw_accelerator_init(effect_context_t *context)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, hw_acc_ctxt);
+    context->config.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+    context->config.inputCfg.channels = AUDIO_CHANNEL_OUT_7POINT1;
+    context->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    context->config.inputCfg.samplingRate = 44100;
+    context->config.inputCfg.bufferProvider.getBuffer = NULL;
+    context->config.inputCfg.bufferProvider.releaseBuffer = NULL;
+    context->config.inputCfg.bufferProvider.cookie = NULL;
+    context->config.inputCfg.mask = EFFECT_CONFIG_ALL;
+
+    context->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+    context->config.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+    context->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    context->config.outputCfg.samplingRate = 44100;
+    context->config.outputCfg.bufferProvider.getBuffer = NULL;
+    context->config.outputCfg.bufferProvider.releaseBuffer = NULL;
+    context->config.outputCfg.bufferProvider.cookie = NULL;
+    context->config.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+    set_config(context, &context->config);
+
+    hw_acc_ctxt->fd = -1;
+    memset(&(hw_acc_ctxt->cfg), 0, sizeof(struct msm_hwacc_effects_config));
+
+    return 0;
+}
+
+int hw_accelerator_reset(effect_context_t *context)
+{
+    ALOGV("%s", __func__);
+    return 0;
+}
+
+int hw_accelerator_set_mode(effect_context_t *context, int32_t frame_count)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, hw_acc_ctxt);
+    hw_acc_ctxt->cfg.output.sample_rate = context->config.inputCfg.samplingRate;
+    hw_acc_ctxt->cfg.input.sample_rate = context->config.outputCfg.samplingRate;
+
+    hw_acc_ctxt->cfg.output.num_channels = popcount(context->config.inputCfg.channels);
+    hw_acc_ctxt->cfg.input.num_channels = popcount(context->config.outputCfg.channels);
+
+    hw_acc_ctxt->cfg.output.bits_per_sample = 8 *
+                                audio_bytes_per_sample(context->config.inputCfg.format);
+    hw_acc_ctxt->cfg.input.bits_per_sample = 8 *
+                                audio_bytes_per_sample(context->config.outputCfg.format);
+
+    ALOGV("write: sample_rate: %d, channel: %d, bit_width: %d",
+           hw_acc_ctxt->cfg.output.sample_rate, hw_acc_ctxt->cfg.output.num_channels,
+           hw_acc_ctxt->cfg.output.bits_per_sample);
+    ALOGV("read: sample_rate: %d, channel: %d, bit_width: %d",
+           hw_acc_ctxt->cfg.input.sample_rate, hw_acc_ctxt->cfg.input.num_channels,
+           hw_acc_ctxt->cfg.input.bits_per_sample);
+
+    hw_acc_ctxt->cfg.output.num_buf = 4;
+    hw_acc_ctxt->cfg.input.num_buf = 2;
+
+    hw_acc_ctxt->cfg.output.buf_size = frame_count *
+                    hw_acc_ctxt->cfg.output.num_channels *
+                    audio_bytes_per_sample(context->config.inputCfg.format) *
+                    ((hw_acc_ctxt->cfg.output.sample_rate/hw_acc_ctxt->cfg.input.sample_rate) +
+                     (hw_acc_ctxt->cfg.output.sample_rate%hw_acc_ctxt->cfg.input.sample_rate ? 1 : 0));
+    hw_acc_ctxt->cfg.input.buf_size = frame_count *
+                    hw_acc_ctxt->cfg.input.num_channels *
+                    audio_bytes_per_sample(context->config.outputCfg.format);
+
+    hw_acc_ctxt->cfg.meta_mode_enabled = 0;
+    /* TODO: overwrite this for effects using custom topology*/
+    hw_acc_ctxt->cfg.overwrite_topology = 0;
+    hw_acc_ctxt->cfg.topology = 0;
+
+    return 0;
+}
+
+int hw_accelerator_enable(effect_context_t *context)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, hw_acc_ctxt);
+    hw_acc_ctxt->fd = open("/dev/msm_hweffects", O_RDWR | O_NONBLOCK);
+    /* open driver */
+    if (hw_acc_ctxt->fd < 0) {
+         ALOGE("Audio Effects driver open failed");
+         return -EFAULT;
+    }
+    /* set config */
+    if (ioctl(hw_acc_ctxt->fd, AUDIO_SET_EFFECTS_CONFIG, &hw_acc_ctxt->cfg) < 0) {
+        ALOGE("setting audio effects drivers config failed");
+        if (close(hw_acc_ctxt->fd) < 0)
+            ALOGE("releasing hardware accelerated effects driver failed");
+        hw_acc_ctxt->fd = -1;
+        return -EFAULT;
+    }
+    /* start */
+    if (ioctl(hw_acc_ctxt->fd,  AUDIO_START, 0) < 0) {
+        ALOGE("audio effects drivers prepare failed");
+        if (close(hw_acc_ctxt->fd) < 0)
+            ALOGE("releasing hardware accelerated effects driver failed");
+        hw_acc_ctxt->fd = -1;
+        return -EFAULT;
+    }
+    return 0;
+}
+
+int hw_accelerator_disable(effect_context_t *context)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, hw_acc_ctxt);
+    if (hw_acc_ctxt->fd > 0)
+        if (close(hw_acc_ctxt->fd) < 0)
+            ALOGE("releasing hardware accelerated effects driver failed");
+    hw_acc_ctxt->fd = -1;
+    return 0;
+}
+
+int hw_accelerator_release(effect_context_t *context)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, hw_acc_ctxt);
+    if (hw_acc_ctxt->fd > 0)
+        if (close(hw_acc_ctxt->fd) < 0)
+            ALOGE("releasing hardware accelerated effects driver failed");
+    hw_acc_ctxt->fd = -1;
+    return 0;
+}
+
+int hw_accelerator_process(effect_context_t *context, audio_buffer_t *in_buf,
+                           audio_buffer_t *out_buf)
+{
+    hw_accelerator_context_t *hw_acc_ctxt = (hw_accelerator_context_t *)context;
+    struct msm_hwacc_buf_cfg buf_cfg;
+    struct msm_hwacc_buf_avail buf_avail;
+    int ret = 0;
+
+    ALOGV("%s: ctxt %p", __func__, hw_acc_ctxt);
+    if (in_buf == NULL || in_buf->raw == NULL ||
+        out_buf == NULL || out_buf->raw == NULL)
+        return -EINVAL;
+
+    buf_cfg.output_len = in_buf->frameCount *
+                         audio_bytes_per_sample(context->config.inputCfg.format) *
+                         hw_acc_ctxt->cfg.output.num_channels;
+    buf_cfg.input_len = out_buf->frameCount *
+                         audio_bytes_per_sample(context->config.outputCfg.format) *
+                         hw_acc_ctxt->cfg.input.num_channels;
+
+    if (ioctl(hw_acc_ctxt->fd, AUDIO_EFFECTS_GET_BUF_AVAIL, &buf_avail) < 0) {
+        ALOGE("AUDIO_EFFECTS_GET_BUF_AVAIL failed");
+        return -ENOMEM;
+    }
+
+    if (!hw_acc_ctxt->intial_buffer_done) {
+        if (ioctl(hw_acc_ctxt->fd, AUDIO_EFFECTS_SET_BUF_LEN, &buf_cfg) < 0) {
+            ALOGE("AUDIO_EFFECTS_BUF_CFG failed");
+            return -EFAULT;
+        }
+        if (ioctl(hw_acc_ctxt->fd, AUDIO_EFFECTS_WRITE, (char *)in_buf->raw) < 0) {
+            ALOGE("AUDIO_EFFECTS_WRITE failed");
+            return -EFAULT;
+        }
+        ALOGV("Request for more data");
+        hw_acc_ctxt->intial_buffer_done = true;
+        return -ENODATA;
+    }
+    if (buf_avail.output_num_avail > 1) {
+        if (ioctl(hw_acc_ctxt->fd, AUDIO_EFFECTS_SET_BUF_LEN, &buf_cfg) < 0) {
+            ALOGE("AUDIO_EFFECTS_BUF_CFG failed");
+            return -EFAULT;
+        }
+        if (ioctl(hw_acc_ctxt->fd, AUDIO_EFFECTS_WRITE, (char *)in_buf->raw) < 0) {
+            ALOGE("AUDIO_EFFECTS_WRITE failed");
+            return -EFAULT;
+        }
+        ret = in_buf->frameCount;
+    }
+    if (ioctl(hw_acc_ctxt->fd, AUDIO_EFFECTS_READ, (char *)out_buf->raw) < 0) {
+        ALOGE("AUDIO_EFFECTS_READ failed");
+        return -EFAULT;
+    }
+
+    return ret;
+}
diff --git a/post_proc/hw_accelerator.h b/post_proc/hw_accelerator.h
new file mode 100644
index 0000000..6387da8
--- /dev/null
+++ b/post_proc/hw_accelerator.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef HW_ACCELERATOR_EFFECT_H_
+#define HW_ACCELERATOR_EFFECT_H_
+
+#include "bundle.h"
+
+#include <linux/msm_audio.h>
+
+#define HWACCELERATOR_OUTPUT_CHANNELS AUDIO_CHANNEL_OUT_STEREO
+
+extern const effect_descriptor_t hw_accelerator_descriptor;
+
+typedef struct hw_accelerator_context_s {
+    effect_context_t common;
+
+    int fd;
+    uint32_t device;
+    bool intial_buffer_done;
+    struct msm_hwacc_effects_config cfg;
+} hw_accelerator_context_t;
+
+int hw_accelerator_get_parameter(effect_context_t *context,
+                                 effect_param_t *p, uint32_t *size);
+
+int hw_accelerator_set_parameter(effect_context_t *context,
+                                 effect_param_t *p, uint32_t size);
+
+int hw_accelerator_set_device(effect_context_t *context,  uint32_t device);
+
+int hw_accelerator_reset(effect_context_t *context);
+
+int hw_accelerator_init(effect_context_t *context);
+
+int hw_accelerator_enable(effect_context_t *context);
+
+int hw_accelerator_disable(effect_context_t *context);
+
+int hw_accelerator_release(effect_context_t *context);
+
+int hw_accelerator_set_mode(effect_context_t *context,  int32_t frame_count);
+
+int hw_accelerator_process(effect_context_t *context, audio_buffer_t *in,
+                           audio_buffer_t *out);
+
+#endif /* HW_ACCELERATOR_EFFECT_H_ */
diff --git a/post_proc/reverb.c b/post_proc/reverb.c
index 77ae303..b256e53 100644
--- a/post_proc/reverb.c
+++ b/post_proc/reverb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013 - 2014, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -18,7 +18,7 @@
  */
 
 #define LOG_TAG "offload_effect_reverb"
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <cutils/list.h>
 #include <cutils/log.h>
@@ -102,6 +102,14 @@
     context->preset = false;
 }
 
+void reverb_insert_init(reverb_context_t *context)
+{
+    context->auxiliary = false;
+    context->preset = true;
+    context->cur_preset = REVERB_PRESET_LAST + 1;
+    context->next_preset = REVERB_DEFAULT_PRESET;
+}
+
 void reverb_preset_init(reverb_context_t *context)
 {
     context->auxiliary = false;
@@ -125,9 +133,13 @@
     context->reverb_settings.roomLevel = room_level;
     offload_reverb_set_room_level(&(context->offload_reverb), room_level);
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_ROOM_LEVEL);
+    if (context->hw_acc_fd > 0)
+        hw_acc_reverb_send_params(context->hw_acc_fd, &context->offload_reverb,
+                                  OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                  OFFLOAD_SEND_REVERB_ROOM_LEVEL);
 }
 
 int16_t reverb_get_room_hf_level(reverb_context_t *context)
@@ -143,9 +155,13 @@
     context->reverb_settings.roomHFLevel = room_hf_level;
     offload_reverb_set_room_hf_level(&(context->offload_reverb), room_hf_level);
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL);
+    if (context->hw_acc_fd > 0)
+        hw_acc_reverb_send_params(context->hw_acc_fd, &context->offload_reverb,
+                                  OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                  OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL);
 }
 
 uint32_t reverb_get_decay_time(reverb_context_t *context)
@@ -161,9 +177,13 @@
     context->reverb_settings.decayTime = decay_time;
     offload_reverb_set_decay_time(&(context->offload_reverb), decay_time);
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_DECAY_TIME);
+    if (context->hw_acc_fd > 0)
+        hw_acc_reverb_send_params(context->hw_acc_fd, &context->offload_reverb,
+                                  OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                  OFFLOAD_SEND_REVERB_DECAY_TIME);
 }
 
 int16_t reverb_get_decay_hf_ratio(reverb_context_t *context)
@@ -179,9 +199,13 @@
     context->reverb_settings.decayHFRatio = decay_hf_ratio;
     offload_reverb_set_decay_hf_ratio(&(context->offload_reverb), decay_hf_ratio);
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_DECAY_HF_RATIO);
+    if (context->hw_acc_fd > 0)
+        hw_acc_reverb_send_params(context->hw_acc_fd, &context->offload_reverb,
+                                  OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                  OFFLOAD_SEND_REVERB_DECAY_HF_RATIO);
 }
 
 int16_t reverb_get_reverb_level(reverb_context_t *context)
@@ -197,9 +221,13 @@
     context->reverb_settings.reverbLevel = reverb_level;
     offload_reverb_set_reverb_level(&(context->offload_reverb), reverb_level);
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_LEVEL);
+    if (context->hw_acc_fd > 0)
+        hw_acc_reverb_send_params(context->hw_acc_fd, &context->offload_reverb,
+                                  OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                  OFFLOAD_SEND_REVERB_LEVEL);
 }
 
 int16_t reverb_get_diffusion(reverb_context_t *context)
@@ -215,9 +243,13 @@
     context->reverb_settings.diffusion = diffusion;
     offload_reverb_set_diffusion(&(context->offload_reverb), diffusion);
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_DIFFUSION);
+    if (context->hw_acc_fd > 0)
+        hw_acc_reverb_send_params(context->hw_acc_fd, &context->offload_reverb,
+                                  OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                  OFFLOAD_SEND_REVERB_DIFFUSION);
 }
 
 int16_t reverb_get_density(reverb_context_t *context)
@@ -233,9 +265,13 @@
     context->reverb_settings.density = density;
     offload_reverb_set_density(&(context->offload_reverb), density);
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_DENSITY);
+    if (context->hw_acc_fd > 0)
+        hw_acc_reverb_send_params(context->hw_acc_fd, &context->offload_reverb,
+                                  OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                  OFFLOAD_SEND_REVERB_DENSITY);
 }
 
 void reverb_set_preset(reverb_context_t *context, int16_t preset)
@@ -249,9 +285,13 @@
     offload_reverb_set_enable_flag(&(context->offload_reverb), enable);
 
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_PRESET);
+    if (context->hw_acc_fd > 0)
+        hw_acc_reverb_send_params(context->hw_acc_fd, &context->offload_reverb,
+                                  OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                  OFFLOAD_SEND_REVERB_PRESET);
 }
 
 void reverb_set_all_properties(reverb_context_t *context,
@@ -266,7 +306,7 @@
     context->reverb_settings.diffusion = reverb_settings->diffusion;
     context->reverb_settings.density = reverb_settings->density;
     if (context->ctl)
-        offload_reverb_send_params(context->ctl, context->offload_reverb,
+        offload_reverb_send_params(context->ctl, &context->offload_reverb,
                                    OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                    OFFLOAD_SEND_REVERB_ROOM_LEVEL |
                                    OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL |
@@ -275,6 +315,16 @@
                                    OFFLOAD_SEND_REVERB_LEVEL |
                                    OFFLOAD_SEND_REVERB_DIFFUSION |
                                    OFFLOAD_SEND_REVERB_DENSITY);
+    if (context->hw_acc_fd > 0)
+        hw_acc_reverb_send_params(context->hw_acc_fd, &context->offload_reverb,
+                                  OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                  OFFLOAD_SEND_REVERB_ROOM_LEVEL |
+                                  OFFLOAD_SEND_REVERB_ROOM_HF_LEVEL |
+                                  OFFLOAD_SEND_REVERB_DECAY_TIME |
+                                  OFFLOAD_SEND_REVERB_DECAY_HF_RATIO |
+                                  OFFLOAD_SEND_REVERB_LEVEL |
+                                  OFFLOAD_SEND_REVERB_DIFFUSION |
+                                  OFFLOAD_SEND_REVERB_DENSITY);
 }
 
 void reverb_load_preset(reverb_context_t *context)
@@ -433,7 +483,7 @@
 }
 
 int reverb_set_parameter(effect_context_t *context, effect_param_t *p,
-                         uint32_t size)
+                         uint32_t size __unused)
 {
     reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
     int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
@@ -549,6 +599,7 @@
 
     set_config(context, &context->config);
 
+    reverb_ctxt->hw_acc_fd = -1;
     memset(&(reverb_ctxt->reverb_settings), 0, sizeof(reverb_settings_t));
     memset(&(reverb_ctxt->offload_reverb), 0, sizeof(struct reverb_params));
 
@@ -579,8 +630,12 @@
         offload_reverb_set_enable_flag(&(reverb_ctxt->offload_reverb), false);
         if (reverb_ctxt->ctl)
             offload_reverb_send_params(reverb_ctxt->ctl,
-                                       reverb_ctxt->offload_reverb,
+                                       &reverb_ctxt->offload_reverb,
                                        OFFLOAD_SEND_REVERB_ENABLE_FLAG);
+        if (reverb_ctxt->hw_acc_fd > 0)
+            hw_acc_reverb_send_params(reverb_ctxt->hw_acc_fd,
+                                      &reverb_ctxt->offload_reverb,
+                                      OFFLOAD_SEND_REVERB_ENABLE_FLAG);
     }
     return 0;
 }
@@ -593,21 +648,48 @@
     reverb_ctxt->ctl = output->ctl;
     if (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))) {
         if (reverb_ctxt->ctl && reverb_ctxt->preset) {
-            offload_reverb_send_params(reverb_ctxt->ctl, reverb_ctxt->offload_reverb,
+            offload_reverb_send_params(reverb_ctxt->ctl, &reverb_ctxt->offload_reverb,
                                        OFFLOAD_SEND_REVERB_ENABLE_FLAG |
                                        OFFLOAD_SEND_REVERB_PRESET);
         }
+        if ((reverb_ctxt->hw_acc_fd > 0) && reverb_ctxt->preset) {
+            hw_acc_reverb_send_params(reverb_ctxt->hw_acc_fd,
+                                      &reverb_ctxt->offload_reverb,
+                                      OFFLOAD_SEND_REVERB_ENABLE_FLAG |
+                                      OFFLOAD_SEND_REVERB_PRESET);
+        }
     }
 
     return 0;
 }
 
-int reverb_stop(effect_context_t *context, output_context_t *output)
+int reverb_stop(effect_context_t *context, output_context_t *output __unused)
 {
     reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
 
     ALOGV("%s: ctxt %p", __func__, reverb_ctxt);
+    if (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb)) &&
+        reverb_ctxt->ctl) {
+        struct reverb_params reverb;
+        reverb.enable_flag = false;
+        offload_reverb_send_params(reverb_ctxt->ctl, &reverb,
+                                   OFFLOAD_SEND_REVERB_ENABLE_FLAG);
+    }
     reverb_ctxt->ctl = NULL;
     return 0;
 }
 
+int reverb_set_mode(effect_context_t *context, int32_t hw_acc_fd)
+{
+    reverb_context_t *reverb_ctxt = (reverb_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, reverb_ctxt);
+    reverb_ctxt->hw_acc_fd = hw_acc_fd;
+    if ((reverb_ctxt->hw_acc_fd > 0) &&
+        (offload_reverb_get_enable_flag(&(reverb_ctxt->offload_reverb))))
+        hw_acc_reverb_send_params(reverb_ctxt->hw_acc_fd,
+                                  &reverb_ctxt->offload_reverb,
+                                  OFFLOAD_SEND_BASSBOOST_ENABLE_FLAG |
+                                  OFFLOAD_SEND_BASSBOOST_STRENGTH);
+    return 0;
+}
diff --git a/post_proc/reverb.h b/post_proc/reverb.h
index 63192eb..991151e 100644
--- a/post_proc/reverb.h
+++ b/post_proc/reverb.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -47,6 +47,7 @@
 
     // Offload vars
     struct mixer_ctl *ctl;
+    int hw_acc_fd;
     bool auxiliary;
     bool preset;
     uint16_t cur_preset;
@@ -61,6 +62,8 @@
 
 void reverb_preset_init(reverb_context_t *context);
 
+void reverb_insert_init(reverb_context_t *context);
+
 int reverb_get_parameter(effect_context_t *context, effect_param_t *p,
                             uint32_t *size);
 
@@ -69,6 +72,8 @@
 
 int reverb_set_device(effect_context_t *context,  uint32_t device);
 
+int reverb_set_mode(effect_context_t *context,  int32_t hw_acc_fd);
+
 int reverb_reset(effect_context_t *context);
 
 int reverb_init(effect_context_t *context);
diff --git a/post_proc/virtualizer.c b/post_proc/virtualizer.c
index 9ed1ac5..f6e2881 100644
--- a/post_proc/virtualizer.c
+++ b/post_proc/virtualizer.c
@@ -18,7 +18,7 @@
  */
 
 #define LOG_TAG "offload_effect_virtualizer"
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <cutils/list.h>
 #include <cutils/log.h>
@@ -58,9 +58,14 @@
 
     offload_virtualizer_set_strength(&(context->offload_virt), strength);
     if (context->ctl)
-        offload_virtualizer_send_params(context->ctl, context->offload_virt,
+        offload_virtualizer_send_params(context->ctl, &context->offload_virt,
                                         OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
                                         OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
+    if (context->hw_acc_fd > 0)
+        hw_acc_virtualizer_send_params(context->hw_acc_fd,
+                                       &context->offload_virt,
+                                       OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
+                                       OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
     return 0;
 }
 
@@ -162,8 +167,12 @@
                 offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
                 if (virt_ctxt->ctl)
                     offload_virtualizer_send_params(virt_ctxt->ctl,
-                                                    virt_ctxt->offload_virt,
+                                                    &virt_ctxt->offload_virt,
                                                     OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+                if (virt_ctxt->hw_acc_fd > 0)
+                    hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+                                                   &virt_ctxt->offload_virt,
+                                                   OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
             }
             virt_ctxt->temp_disabled = true;
             ALOGI("%s: ctxt %p, disabled based on device", __func__, virt_ctxt);
@@ -174,8 +183,12 @@
                 offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
                 if (virt_ctxt->ctl)
                     offload_virtualizer_send_params(virt_ctxt->ctl,
-                                                    virt_ctxt->offload_virt,
+                                                    &virt_ctxt->offload_virt,
                                                     OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+                if (virt_ctxt->hw_acc_fd > 0)
+                    hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+                                                   &virt_ctxt->offload_virt,
+                                                   OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
             }
             virt_ctxt->temp_disabled = false;
         }
@@ -216,6 +229,7 @@
     set_config(context, &context->config);
 
     virt_ctxt->temp_disabled = false;
+    virt_ctxt->hw_acc_fd = -1;
     memset(&(virt_ctxt->offload_virt), 0, sizeof(struct virtualizer_params));
 
     return 0;
@@ -232,9 +246,14 @@
         offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), true);
         if (virt_ctxt->ctl && virt_ctxt->strength)
             offload_virtualizer_send_params(virt_ctxt->ctl,
-                                          virt_ctxt->offload_virt,
+                                          &virt_ctxt->offload_virt,
                                           OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
-                                          OFFLOAD_SEND_BASSBOOST_STRENGTH);
+                                          OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
+        if ((virt_ctxt->hw_acc_fd > 0) && virt_ctxt->strength)
+            hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+                                           &virt_ctxt->offload_virt,
+                                           OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
+                                           OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
     }
     return 0;
 }
@@ -248,8 +267,12 @@
         offload_virtualizer_set_enable_flag(&(virt_ctxt->offload_virt), false);
         if (virt_ctxt->ctl)
             offload_virtualizer_send_params(virt_ctxt->ctl,
-                                          virt_ctxt->offload_virt,
+                                          &virt_ctxt->offload_virt,
                                           OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+        if (virt_ctxt->hw_acc_fd > 0)
+            hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+                                           &virt_ctxt->offload_virt,
+                                           OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
     }
     return 0;
 }
@@ -260,19 +283,47 @@
 
     ALOGV("%s: ctxt %p, ctl %p", __func__, virt_ctxt, output->ctl);
     virt_ctxt->ctl = output->ctl;
-    if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)))
+    if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))) {
         if (virt_ctxt->ctl)
-            offload_virtualizer_send_params(virt_ctxt->ctl, virt_ctxt->offload_virt,
+            offload_virtualizer_send_params(virt_ctxt->ctl, &virt_ctxt->offload_virt,
                                           OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
                                           OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
+        if (virt_ctxt->hw_acc_fd > 0)
+            hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+                                           &virt_ctxt->offload_virt,
+                                           OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
+                                           OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
+    }
     return 0;
 }
 
-int virtualizer_stop(effect_context_t *context, output_context_t *output)
+int virtualizer_stop(effect_context_t *context, output_context_t *output __unused)
 {
     virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
 
     ALOGV("%s: ctxt %p", __func__, virt_ctxt);
+    if (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt)) &&
+        virt_ctxt->ctl) {
+        struct virtualizer_params virt;
+        virt.enable_flag = false;
+        offload_virtualizer_send_params(virt_ctxt->ctl, &virt,
+                                        OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG);
+    }
     virt_ctxt->ctl = NULL;
     return 0;
 }
+
+int virtualizer_set_mode(effect_context_t *context, int32_t hw_acc_fd)
+{
+    virtualizer_context_t *virt_ctxt = (virtualizer_context_t *)context;
+
+    ALOGV("%s: ctxt %p", __func__, virt_ctxt);
+    virt_ctxt->hw_acc_fd = hw_acc_fd;
+    if ((virt_ctxt->hw_acc_fd > 0) &&
+        (offload_virtualizer_get_enable_flag(&(virt_ctxt->offload_virt))))
+        hw_acc_virtualizer_send_params(virt_ctxt->hw_acc_fd,
+                                       &virt_ctxt->offload_virt,
+                                       OFFLOAD_SEND_VIRTUALIZER_ENABLE_FLAG |
+                                       OFFLOAD_SEND_VIRTUALIZER_STRENGTH);
+    return 0;
+}
diff --git a/post_proc/virtualizer.h b/post_proc/virtualizer.h
index 4a5005f..440c8a2 100644
--- a/post_proc/virtualizer.h
+++ b/post_proc/virtualizer.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  * Not a Contribution.
  *
  * Copyright (C) 2013 The Android Open Source Project
@@ -31,6 +31,7 @@
 
     // Offload vars
     struct mixer_ctl *ctl;
+    int hw_acc_fd;
     bool temp_disabled;
     uint32_t device;
     struct virtualizer_params offload_virt;
@@ -44,6 +45,8 @@
 
 int virtualizer_set_device(effect_context_t *context,  uint32_t device);
 
+int virtualizer_set_mode(effect_context_t *context,  int32_t hw_acc_fd);
+
 int virtualizer_reset(effect_context_t *context);
 
 int virtualizer_init(effect_context_t *context);