Re-implement HIDL effect processing using FMQ and IMemory

Result: no hwbinder calls due music processing.

Test: make, use Play Music with effects, check traces
Bug: 30222631
Change-Id: I06d0e94e603688874b31824427f3b0878b5f7c8e
diff --git a/media/libaudiohal/Android.mk b/media/libaudiohal/Android.mk
index 893c626..deb26b5 100644
--- a/media/libaudiohal/Android.mk
+++ b/media/libaudiohal/Android.mk
@@ -3,12 +3,10 @@
 include $(CLEAR_VARS)
 
 LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libcutils \
-    libeffects \
-    libfmq \
+    libcutils   \
+    libeffects  \
     libhardware \
-    liblog \
+    liblog      \
     libutils
 
 ifeq ($(ENABLE_TREBLE), true)
@@ -19,19 +17,23 @@
     ConversionHelperHidl.cpp   \
     DeviceHalHidl.cpp          \
     DevicesFactoryHalHidl.cpp  \
+    EffectBufferHalHidl.cpp    \
     EffectHalHidl.cpp          \
     EffectsFactoryHalHidl.cpp  \
     StreamHalHidl.cpp
 
 LOCAL_SHARED_LIBRARIES += \
+    libbase          \
+    libfmq           \
     libhwbinder      \
     libhidlbase      \
+    libhidlmemory    \
     libhidltransport \
-    libbase          \
     android.hardware.audio@2.0             \
     android.hardware.audio.common@2.0      \
     android.hardware.audio.common@2.0-util \
-    android.hardware.audio.effect@2.0 \
+    android.hardware.audio.effect@2.0      \
+    android.hidl.memory@1.0                \
     libmedia_helper
 
 else  # if !ENABLE_TREBLE
@@ -39,6 +41,7 @@
 LOCAL_SRC_FILES := \
     DeviceHalLocal.cpp          \
     DevicesFactoryHalLocal.cpp  \
+    EffectBufferHalLocal.cpp    \
     EffectHalLocal.cpp          \
     EffectsFactoryHalLocal.cpp  \
     StreamHalLocal.cpp
diff --git a/media/libaudiohal/ConversionHelperHidl.h b/media/libaudiohal/ConversionHelperHidl.h
index 89e6e88..00d5b2c 100644
--- a/media/libaudiohal/ConversionHelperHidl.h
+++ b/media/libaudiohal/ConversionHelperHidl.h
@@ -65,8 +65,6 @@
         const status_t st = ret.isOk() ? analyzeResult(retval) : UNKNOWN_ERROR;
         if (!ret.isOk()) {
             emitError(funcName, ret.description().c_str());
-        } else if (st) {
-            emitError(funcName, strerror(st));
         }
         return st;
     }
diff --git a/media/libaudiohal/EffectBufferHalHidl.cpp b/media/libaudiohal/EffectBufferHalHidl.cpp
new file mode 100644
index 0000000..446d2ef
--- /dev/null
+++ b/media/libaudiohal/EffectBufferHalHidl.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <atomic>
+
+#define LOG_TAG "EffectBufferHalHidl"
+//#define LOG_NDEBUG 0
+
+#include <android/hidl/memory/1.0/IAllocator.h>
+#include <hidlmemory/mapping.h>
+#include <utils/Log.h>
+
+#include "ConversionHelperHidl.h"
+#include "EffectBufferHalHidl.h"
+
+using ::android::hardware::Return;
+using ::android::hardware::Status;
+using ::android::hidl::memory::V1_0::IAllocator;
+
+namespace android {
+
+// static
+uint64_t EffectBufferHalHidl::makeUniqueId() {
+    static std::atomic<uint64_t> counter{1};
+    return counter++;
+}
+
+// static
+status_t EffectBufferHalInterface::allocate(
+        size_t size, sp<EffectBufferHalInterface>* buffer) {
+    return mirror(nullptr, size, buffer);
+}
+
+// static
+status_t EffectBufferHalInterface::mirror(
+        void* external, size_t size, sp<EffectBufferHalInterface>* buffer) {
+    sp<EffectBufferHalInterface> tempBuffer = new EffectBufferHalHidl(size);
+    status_t result = reinterpret_cast<EffectBufferHalHidl*>(tempBuffer.get())->init();
+    if (result == OK) {
+        tempBuffer->setExternalData(external);
+        *buffer = tempBuffer;
+    }
+    return result;
+}
+
+EffectBufferHalHidl::EffectBufferHalHidl(size_t size)
+        : mBufferSize(size), mExternalData(nullptr), mAudioBuffer{0, {nullptr}} {
+    mHidlBuffer.id = makeUniqueId();
+    mHidlBuffer.frameCount = 0;
+}
+
+EffectBufferHalHidl::~EffectBufferHalHidl() {
+}
+
+status_t EffectBufferHalHidl::init() {
+    sp<IAllocator> ashmem = IAllocator::getService("ashmem");
+    if (ashmem == 0) {
+        ALOGE("Failed to retrieve ashmem allocator service");
+        return NO_INIT;
+    }
+    status_t retval = NO_MEMORY;
+    Return<void> result = ashmem->allocate(
+            mBufferSize,
+            [&](bool success, const hidl_memory& memory) {
+                if (success) {
+                    mHidlBuffer.data = memory;
+                    retval = OK;
+                }
+            });
+    if (retval == OK) {
+        mMemory = hardware::mapMemory(mHidlBuffer.data);
+        if (mMemory != 0) {
+            mMemory->update();
+            mAudioBuffer.raw = static_cast<void*>(mMemory->getPointer());
+            memset(mAudioBuffer.raw, 0, mMemory->getSize());
+            mMemory->commit();
+        } else {
+            ALOGE("Failed to map allocated ashmem");
+            retval = NO_MEMORY;
+        }
+    }
+    return retval;
+}
+
+audio_buffer_t* EffectBufferHalHidl::audioBuffer() {
+    return &mAudioBuffer;
+}
+
+void* EffectBufferHalHidl::externalData() const {
+    return mExternalData;
+}
+
+void EffectBufferHalHidl::setFrameCount(size_t frameCount) {
+    mHidlBuffer.frameCount = frameCount;
+    mAudioBuffer.frameCount = frameCount;
+}
+
+void EffectBufferHalHidl::setExternalData(void* external) {
+    mExternalData = external;
+}
+
+void EffectBufferHalHidl::update() {
+    if (mExternalData == nullptr) return;
+    mMemory->update();
+    memcpy(mAudioBuffer.raw, mExternalData, mBufferSize);
+    mMemory->commit();
+}
+
+void EffectBufferHalHidl::commit() {
+    if (mExternalData == nullptr) return;
+    memcpy(mExternalData, mAudioBuffer.raw, mBufferSize);
+}
+
+} // namespace android
diff --git a/media/libaudiohal/EffectBufferHalHidl.h b/media/libaudiohal/EffectBufferHalHidl.h
new file mode 100644
index 0000000..4c4ec87
--- /dev/null
+++ b/media/libaudiohal/EffectBufferHalHidl.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_EFFECT_BUFFER_HAL_HIDL_H
+#define ANDROID_HARDWARE_EFFECT_BUFFER_HAL_HIDL_H
+
+#include <android/hardware/audio/effect/2.0/types.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidl/HidlSupport.h>
+#include <media/audiohal/EffectBufferHalInterface.h>
+#include <system/audio_effect.h>
+
+using android::hardware::audio::effect::V2_0::AudioBuffer;
+using android::hardware::hidl_memory;
+using android::hidl::memory::V1_0::IMemory;
+
+namespace android {
+
+class EffectBufferHalHidl : public EffectBufferHalInterface
+{
+  public:
+    virtual audio_buffer_t* audioBuffer();
+    virtual void* externalData() const;
+
+    virtual void setExternalData(void* external);
+    virtual void setFrameCount(size_t frameCount);
+
+    virtual void update();
+    virtual void commit();
+
+    const AudioBuffer& hidlBuffer() const { return mHidlBuffer; }
+
+  private:
+    friend class EffectBufferHalInterface;
+
+    static uint64_t makeUniqueId();
+
+    const size_t mBufferSize;
+    void* mExternalData;
+    AudioBuffer mHidlBuffer;
+    sp<IMemory> mMemory;
+    audio_buffer_t mAudioBuffer;
+
+    // Can not be constructed directly by clients.
+    explicit EffectBufferHalHidl(size_t size);
+
+    virtual ~EffectBufferHalHidl();
+
+    status_t init();
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_EFFECT_BUFFER_HAL_HIDL_H
diff --git a/media/libaudiohal/EffectBufferHalLocal.cpp b/media/libaudiohal/EffectBufferHalLocal.cpp
new file mode 100644
index 0000000..20b1339
--- /dev/null
+++ b/media/libaudiohal/EffectBufferHalLocal.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "EffectBufferHalLocal"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include "EffectBufferHalLocal.h"
+
+namespace android {
+
+// static
+status_t EffectBufferHalInterface::allocate(
+        size_t size, sp<EffectBufferHalInterface>* buffer) {
+    *buffer = new EffectBufferHalLocal(size);
+    return OK;
+}
+
+// static
+status_t EffectBufferHalInterface::mirror(
+        void* external, size_t size, sp<EffectBufferHalInterface>* buffer) {
+    *buffer = new EffectBufferHalLocal(external, size);
+    return OK;
+}
+
+EffectBufferHalLocal::EffectBufferHalLocal(size_t size)
+        : mOwnBuffer(new uint8_t[size]),
+          mBufferSize(size),
+          mAudioBuffer{0, {mOwnBuffer.get()}} {
+}
+
+EffectBufferHalLocal::EffectBufferHalLocal(void* external, size_t size)
+        : mOwnBuffer(nullptr),
+          mBufferSize(size),
+          mAudioBuffer{0, {external}} {
+}
+
+EffectBufferHalLocal::~EffectBufferHalLocal() {
+}
+
+audio_buffer_t* EffectBufferHalLocal::audioBuffer() {
+    return &mAudioBuffer;
+}
+
+void* EffectBufferHalLocal::externalData() const {
+    return mAudioBuffer.raw;
+}
+
+void EffectBufferHalLocal::setFrameCount(size_t frameCount) {
+    mAudioBuffer.frameCount = frameCount;
+}
+
+void EffectBufferHalLocal::setExternalData(void* external) {
+    ALOGE_IF(mOwnBuffer != nullptr, "Attempt to set external data for allocated buffer");
+    mAudioBuffer.raw = external;
+}
+
+void EffectBufferHalLocal::update() {
+}
+
+void EffectBufferHalLocal::commit() {
+}
+
+} // namespace android
diff --git a/media/libaudiohal/EffectBufferHalLocal.h b/media/libaudiohal/EffectBufferHalLocal.h
new file mode 100644
index 0000000..df7bd43
--- /dev/null
+++ b/media/libaudiohal/EffectBufferHalLocal.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_EFFECT_BUFFER_HAL_LOCAL_H
+#define ANDROID_HARDWARE_EFFECT_BUFFER_HAL_LOCAL_H
+
+#include <memory>
+
+#include <media/audiohal/EffectBufferHalInterface.h>
+#include <system/audio_effect.h>
+
+namespace android {
+
+class EffectBufferHalLocal : public EffectBufferHalInterface
+{
+  public:
+    virtual audio_buffer_t* audioBuffer();
+    virtual void* externalData() const;
+
+    virtual void setExternalData(void* external);
+    virtual void setFrameCount(size_t frameCount);
+
+    virtual void update();
+    virtual void commit();
+
+  private:
+    friend class EffectBufferHalInterface;
+
+    std::unique_ptr<uint8_t[]> mOwnBuffer;
+    const size_t mBufferSize;
+    audio_buffer_t mAudioBuffer;
+
+    // Can not be constructed directly by clients.
+    explicit EffectBufferHalLocal(size_t size);
+    EffectBufferHalLocal(void* external, size_t size);
+
+    virtual ~EffectBufferHalLocal();
+
+    status_t init();
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_EFFECT_BUFFER_HAL_LOCAL_H
diff --git a/media/libaudiohal/EffectHalHidl.cpp b/media/libaudiohal/EffectHalHidl.cpp
index 0a58fa0..272bf5c 100644
--- a/media/libaudiohal/EffectHalHidl.cpp
+++ b/media/libaudiohal/EffectHalHidl.cpp
@@ -21,21 +21,26 @@
 #include <utils/Log.h>
 
 #include "ConversionHelperHidl.h"
+#include "EffectBufferHalHidl.h"
 #include "EffectHalHidl.h"
 #include "HidlUtils.h"
 
+using ::android::hardware::audio::effect::V2_0::AudioBuffer;
+using ::android::hardware::audio::effect::V2_0::MessageQueueFlagBits;
 using ::android::hardware::audio::effect::V2_0::Result;
 using ::android::hardware::hidl_vec;
+using ::android::hardware::MQDescriptorSync;
 using ::android::hardware::Return;
 using ::android::hardware::Status;
 
 namespace android {
 
 EffectHalHidl::EffectHalHidl(const sp<IEffect>& effect, uint64_t effectId)
-        : mEffect(effect), mEffectId(effectId) {
+        : mEffect(effect), mEffectId(effectId), mBuffersChanged(true) {
 }
 
 EffectHalHidl::~EffectHalHidl() {
+    close();
 }
 
 // static
@@ -64,16 +69,100 @@
     }
 }
 
-status_t EffectHalHidl::process(audio_buffer_t */*inBuffer*/, audio_buffer_t */*outBuffer*/) {
-    // Idea -- intercept set buffer config command, capture audio format, use it
-    // for determining frame size in bytes on input and output.
+status_t EffectHalHidl::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
+    if (mInBuffer == 0 || buffer->audioBuffer() != mInBuffer->audioBuffer()) {
+        mBuffersChanged = true;
+    }
+    mInBuffer = buffer;
     return OK;
 }
 
-status_t EffectHalHidl::processReverse(audio_buffer_t */*inBuffer*/, audio_buffer_t */*outBuffer*/) {
+status_t EffectHalHidl::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
+    if (mOutBuffer == 0 || buffer->audioBuffer() != mOutBuffer->audioBuffer()) {
+        mBuffersChanged = true;
+    }
+    mOutBuffer = buffer;
     return OK;
 }
 
+status_t EffectHalHidl::process() {
+    return processImpl(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS));
+}
+
+status_t EffectHalHidl::processReverse() {
+    return processImpl(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_REVERSE));
+}
+
+status_t EffectHalHidl::prepareForProcessing() {
+    std::unique_ptr<StatusMQ> tempStatusMQ;
+    Result retval;
+    Return<void> ret = mEffect->prepareForProcessing(
+            [&](Result r, const MQDescriptorSync<Result>& statusMQ) {
+                retval = r;
+                if (retval == Result::OK) {
+                    tempStatusMQ.reset(new StatusMQ(statusMQ));
+                    if (tempStatusMQ->isValid() && tempStatusMQ->getEventFlagWord()) {
+                        EventFlag::createEventFlag(tempStatusMQ->getEventFlagWord(), &mEfGroup);
+                    }
+                }
+            });
+    if (!ret.getStatus().isOk() || retval != Result::OK) {
+        return ret.getStatus().isOk() ? analyzeResult(retval) : ret.getStatus().transactionError();
+    }
+    if (!tempStatusMQ || !tempStatusMQ->isValid() || !mEfGroup) {
+        ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for effects");
+        ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
+                "Status message queue for effects is invalid");
+        ALOGE_IF(!mEfGroup, "Event flag creation for effects failed");
+        return NO_INIT;
+    }
+    mStatusMQ = std::move(tempStatusMQ);
+    return OK;
+}
+
+status_t EffectHalHidl::processImpl(uint32_t mqFlag) {
+    if (mEffect == 0 || mInBuffer == 0 || mOutBuffer == 0) return NO_INIT;
+    status_t status;
+    if (!mStatusMQ && (status = prepareForProcessing()) != OK) {
+        return status;
+    }
+    if (mBuffersChanged && (status = setProcessBuffers()) != OK) {
+        return status;
+    }
+    // The data is already in the buffers, just need to flush it and wake up the server side.
+    std::atomic_thread_fence(std::memory_order_release);
+    mEfGroup->wake(mqFlag);
+    uint32_t efState = 0;
+retry:
+    status_t ret = mEfGroup->wait(
+            static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING), &efState, NS_PER_SEC);
+    if (efState & static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING)) {
+        Result retval = Result::NOT_INITIALIZED;
+        mStatusMQ->read(&retval);
+        if (retval == Result::OK || retval == Result::INVALID_STATE) {
+            // Sync back the changed contents of the buffer.
+            std::atomic_thread_fence(std::memory_order_acquire);
+        }
+        return analyzeResult(retval);
+    }
+    if (ret == -EAGAIN) {
+        // This normally retries no more than once.
+        goto retry;
+    }
+    return ret;
+}
+
+status_t EffectHalHidl::setProcessBuffers() {
+    Return<Result> ret = mEffect->setProcessBuffers(
+            reinterpret_cast<EffectBufferHalHidl*>(mInBuffer.get())->hidlBuffer(),
+            reinterpret_cast<EffectBufferHalHidl*>(mOutBuffer.get())->hidlBuffer());
+    if (ret.getStatus().isOk() && ret == Result::OK) {
+        mBuffersChanged = false;
+        return OK;
+    }
+    return ret.isOk() ? analyzeResult(ret) : UNKNOWN_ERROR;
+}
+
 status_t EffectHalHidl::command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
         uint32_t *replySize, void *pReplyData) {
     if (mEffect == 0) return NO_INIT;
@@ -106,4 +195,10 @@
     return ret.isOk() ? analyzeResult(retval) : UNKNOWN_ERROR;
 }
 
+status_t EffectHalHidl::close() {
+    if (mEffect == 0) return NO_INIT;
+    Return<Result> ret = mEffect->close();
+    return ret.isOk() ? analyzeResult(ret) : UNKNOWN_ERROR;
+}
+
 } // namespace android
diff --git a/media/libaudiohal/EffectHalHidl.h b/media/libaudiohal/EffectHalHidl.h
index b79bee0..1ed1153 100644
--- a/media/libaudiohal/EffectHalHidl.h
+++ b/media/libaudiohal/EffectHalHidl.h
@@ -19,24 +19,32 @@
 
 #include <android/hardware/audio/effect/2.0/IEffect.h>
 #include <media/audiohal/EffectHalInterface.h>
+#include <fmq/EventFlag.h>
+#include <fmq/MessageQueue.h>
 #include <system/audio_effect.h>
 
 using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
 using ::android::hardware::audio::effect::V2_0::IEffect;
+using ::android::hardware::EventFlag;
+using ::android::hardware::MessageQueue;
 
 namespace android {
 
 class EffectHalHidl : public EffectHalInterface
 {
   public:
-    // Effect process function. Takes input samples as specified
-    // in input buffer descriptor and output processed samples as specified
-    // in output buffer descriptor.
-    virtual status_t process(audio_buffer_t *inBuffer, audio_buffer_t *outBuffer);
+    // Set the input buffer.
+    virtual status_t setInBuffer(const sp<EffectBufferHalInterface>& buffer);
+
+    // Set the output buffer.
+    virtual status_t setOutBuffer(const sp<EffectBufferHalInterface>& buffer);
+
+    // Effect process function.
+    virtual status_t process();
 
     // Process reverse stream function. This function is used to pass
     // a reference stream to the effect engine.
-    virtual status_t processReverse(audio_buffer_t *inBuffer, audio_buffer_t *outBuffer);
+    virtual status_t processReverse();
 
     // Send a command and receive a response to/from effect engine.
     virtual status_t command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
@@ -45,6 +53,9 @@
     // Returns the effect descriptor.
     virtual status_t getDescriptor(effect_descriptor_t *pDescriptor);
 
+    // Free resources on the remote side.
+    virtual status_t close();
+
     uint64_t effectId() const { return mEffectId; }
 
     static void effectDescriptorToHal(
@@ -52,8 +63,16 @@
 
   private:
     friend class EffectsFactoryHalHidl;
+    typedef MessageQueue<
+        hardware::audio::effect::V2_0::Result, hardware::kSynchronizedReadWrite> StatusMQ;
+
     sp<IEffect> mEffect;
     const uint64_t mEffectId;
+    sp<EffectBufferHalInterface> mInBuffer;
+    sp<EffectBufferHalInterface> mOutBuffer;
+    bool mBuffersChanged;
+    std::unique_ptr<StatusMQ> mStatusMQ;
+    EventFlag* mEfGroup;
 
     static status_t analyzeResult(const hardware::audio::effect::V2_0::Result& result);
 
@@ -62,6 +81,10 @@
 
     // The destructor automatically releases the effect.
     virtual ~EffectHalHidl();
+
+    status_t prepareForProcessing();
+    status_t processImpl(uint32_t mqFlag);
+    status_t setProcessBuffers();
 };
 
 } // namespace android
diff --git a/media/libaudiohal/EffectHalLocal.cpp b/media/libaudiohal/EffectHalLocal.cpp
index 56a365c..b4f1934 100644
--- a/media/libaudiohal/EffectHalLocal.cpp
+++ b/media/libaudiohal/EffectHalLocal.cpp
@@ -34,12 +34,27 @@
     mHandle = 0;
 }
 
-status_t EffectHalLocal::process(audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) {
-    return (*mHandle)->process(mHandle, inBuffer, outBuffer);
+status_t EffectHalLocal::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
+    mInBuffer = buffer;
+    return OK;
 }
 
-status_t EffectHalLocal::processReverse(audio_buffer_t *inBuffer, audio_buffer_t *outBuffer) {
-    return (*mHandle)->process_reverse(mHandle, inBuffer, outBuffer);
+status_t EffectHalLocal::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
+    mOutBuffer = buffer;
+    return OK;
+}
+
+status_t EffectHalLocal::process() {
+    return (*mHandle)->process(mHandle, mInBuffer->audioBuffer(), mOutBuffer->audioBuffer());
+}
+
+status_t EffectHalLocal::processReverse() {
+    if ((*mHandle)->process_reverse != NULL) {
+        return (*mHandle)->process_reverse(
+                mHandle, mInBuffer->audioBuffer(), mOutBuffer->audioBuffer());
+    } else {
+        return INVALID_OPERATION;
+    }
 }
 
 status_t EffectHalLocal::command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
@@ -51,4 +66,8 @@
     return (*mHandle)->get_descriptor(mHandle, pDescriptor);
 }
 
+status_t EffectHalLocal::close() {
+    return OK;
+}
+
 } // namespace android
diff --git a/media/libaudiohal/EffectHalLocal.h b/media/libaudiohal/EffectHalLocal.h
index 77f774f..b499462 100644
--- a/media/libaudiohal/EffectHalLocal.h
+++ b/media/libaudiohal/EffectHalLocal.h
@@ -25,14 +25,18 @@
 class EffectHalLocal : public EffectHalInterface
 {
   public:
-    // Effect process function. Takes input samples as specified
-    // in input buffer descriptor and output processed samples as specified
-    // in output buffer descriptor.
-    virtual status_t process(audio_buffer_t *inBuffer, audio_buffer_t *outBuffer);
+    // Set the input buffer.
+    virtual status_t setInBuffer(const sp<EffectBufferHalInterface>& buffer);
+
+    // Set the output buffer.
+    virtual status_t setOutBuffer(const sp<EffectBufferHalInterface>& buffer);
+
+    // Effect process function.
+    virtual status_t process();
 
     // Process reverse stream function. This function is used to pass
     // a reference stream to the effect engine.
-    virtual status_t processReverse(audio_buffer_t *inBuffer, audio_buffer_t *outBuffer);
+    virtual status_t processReverse();
 
     // Send a command and receive a response to/from effect engine.
     virtual status_t command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
@@ -41,10 +45,15 @@
     // Returns the effect descriptor.
     virtual status_t getDescriptor(effect_descriptor_t *pDescriptor);
 
+    // Free resources on the remote side.
+    virtual status_t close();
+
     effect_handle_t handle() const { return mHandle; }
 
   private:
     effect_handle_t mHandle;
+    sp<EffectBufferHalInterface> mInBuffer;
+    sp<EffectBufferHalInterface> mOutBuffer;
 
     friend class EffectsFactoryHalLocal;