Merge "audiohal: Re-implement effect process using FMQ and IMemory"
diff --git a/audio/effect/2.0/IEffect.hal b/audio/effect/2.0/IEffect.hal
index 615a460..9027c68 100644
--- a/audio/effect/2.0/IEffect.hal
+++ b/audio/effect/2.0/IEffect.hal
@@ -226,49 +226,47 @@
     getDescriptor() generates (Result retval, EffectDescriptor descriptor);
 
     /*
-     * Effect process function. Takes input samples as specified (count and
-     * location) in input buffer and returns processed samples as specified in
-     * output buffer. If the buffer descriptor is empty the function must use
-     * either the buffer or the buffer provider callback installed by the
-     * setConfig command.  The effect framework must call the 'process' function
-     * after the 'enable' command is received and until the 'disable' is
-     * received. When the engine receives the 'disable' command it should turn
-     * off the effect gracefully and when done indicate that it is OK to stop
-     * calling the 'process' function by returning the INVALID_STATE status.
+     * Set up required transports for passing audio buffers to the effect.
      *
-     * Output audio buffer must contain no more frames than the input audio
-     * buffer. Since the effect may transform input channels into a different
-     * amount of channels, the caller provides the output frame size.
+     * The transport consists of shared memory and a message queue for reporting
+     * effect processing operation status. The shared memory is set up
+     * separately using 'setProcessBuffers' method.
      *
-     * @param inBuffer input audio buffer.
-     * @param outFrameSize output frame size in bytes.
-     * @return retval operation completion status.
-     * @return outBuffer output audio buffer.
+     * Processing is requested by setting 'REQUEST_PROCESS' or
+     * 'REQUEST_PROCESS_REVERSE' EventFlags associated with the status message
+     * queue. The result of processing may be one of the following:
+     *   OK if there were no errors during processing;
+     *   INVALID_ARGUMENTS if audio buffers are invalid;
+     *   INVALID_STATE if the engine has finished the disable phase;
+     *   NOT_INITIALIZED if the audio buffers were not set;
+     *   NOT_SUPPORTED if the requested processing type is not supported by
+     *                 the effect.
+     *
+     * @return retval OK if both message queues were created successfully.
+     *                INVALID_STATE if the method was already called.
+     *                INVALID_ARGUMENTS if there was a problem setting up
+     *                                  the queue.
+     * @return statusMQ a message queue used for passing status from the effect.
      */
-    // TODO(mnaganov): replace with FMQ version.
-    @callflow(next={"*"})
-    process(AudioBuffer inBuffer, uint32_t outFrameSize)
-            generates (Result retval, AudioBuffer outBuffer);
+    prepareForProcessing() generates (Result retval, fmq_sync<Result> statusMQ);
 
     /*
-     * Process reverse stream function. This function is used to pass a
-     * reference stream to the effect engine. If the engine does not need a
-     * reference stream, this function MUST return NOT_SUPPORTED. For example,
-     * this function would typically implemented by an Echo Canceler.
+     * Set up input and output buffers for processing audio data. The effect
+     * may modify both the input and the output buffer during the operation.
+     * Buffers may be set multiple times during effect lifetime.
      *
-     * Output audio buffer must contain no more frames than the input audio
-     * buffer. Since the effect may transform input channels into a different
-     * amount of channels, the caller provides the output frame size.
+     * The input and the output buffer may be reused between different effects,
+     * and the input buffer may be used as an output buffer. Buffers are
+     * distinguished using 'AudioBuffer.id' field.
      *
      * @param inBuffer input audio buffer.
-     * @param outFrameSize output frame size in bytes.
-     * @return retval operation completion status.
-     * @return outBuffer output audio buffer.
+     * @param outBuffer output audio buffer.
+     * @return retval OK if both buffers were mapped successfully.
+     *                INVALID_ARGUMENTS if there was a problem with mapping
+     *                                  any of the buffers.
      */
-    // TODO(mnaganov): replace with FMQ version.
-    @callflow(next={"*"})
-    processReverse(AudioBuffer inBuffer, uint32_t outFrameSize)
-            generates (Result retval, AudioBuffer outBuffer);
+    setProcessBuffers(AudioBuffer inBuffer, AudioBuffer outBuffer) generates (
+            Result retval);
 
     /*
      * Execute a vendor specific command on the effect. The command code
@@ -406,4 +404,14 @@
      */
     setCurrentConfigForFeature(uint32_t featureId, vec<uint8_t> configData)
             generates (Result retval);
+
+    /*
+     * Called by the framework to deinitialize the effect and free up
+     * all the currently allocated resources. It is recommended to close
+     * the effect on the client side as soon as it is becomes unused.
+     *
+     * @return retval OK in case the success.
+     *                INVALID_STATE if the effect was already closed.
+     */
+    close() generates (Result retval);
 };
diff --git a/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp b/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp
index 341466f..f6e72bf 100644
--- a/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp
+++ b/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp
@@ -115,16 +115,14 @@
     return mEffect->getDescriptor(_hidl_cb);
 }
 
-Return<void> AcousticEchoCancelerEffect::process(
-        const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb) {
-    return mEffect->process(inBuffer, outFrameSize, _hidl_cb);
+Return<void> AcousticEchoCancelerEffect::prepareForProcessing(
+        prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
 }
 
-Return<void> AcousticEchoCancelerEffect::processReverse(
-        const AudioBuffer& inBuffer,
-        uint32_t outFrameSize,
-        processReverse_cb _hidl_cb) {
-    return mEffect->processReverse(inBuffer, outFrameSize, _hidl_cb);
+Return<Result> AcousticEchoCancelerEffect::setProcessBuffers(
+        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
 }
 
 Return<void> AcousticEchoCancelerEffect::command(
@@ -167,6 +165,10 @@
     return mEffect->setCurrentConfigForFeature(featureId, configData);
 }
 
+Return<Result> AcousticEchoCancelerEffect::close() {
+    return mEffect->close();
+}
+
 // Methods from ::android::hardware::audio::effect::V2_0::IAcousticEchoCancelerEffect follow.
 Return<Result> AcousticEchoCancelerEffect::setEchoDelay(uint32_t echoDelayMs)  {
     return mEffect->setParam(AEC_PARAM_ECHO_DELAY, echoDelayMs);
diff --git a/audio/effect/2.0/default/AcousticEchoCancelerEffect.h b/audio/effect/2.0/default/AcousticEchoCancelerEffect.h
index 71fcc97..c777b02 100644
--- a/audio/effect/2.0/default/AcousticEchoCancelerEffect.h
+++ b/audio/effect/2.0/default/AcousticEchoCancelerEffect.h
@@ -69,12 +69,9 @@
     Return<Result> setAudioSource(AudioSource source)  override;
     Return<Result> offload(const EffectOffloadParameter& param)  override;
     Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> process(
-            const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb)  override;
-    Return<void> processReverse(
-            const AudioBuffer& inBuffer,
-            uint32_t outFrameSize,
-            processReverse_cb _hidl_cb)  override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
+    Return<Result> setProcessBuffers(
+            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
     Return<void> command(
             uint32_t commandId,
             const hidl_vec<uint8_t>& data,
@@ -97,6 +94,7 @@
             getCurrentConfigForFeature_cb _hidl_cb)  override;
     Return<Result> setCurrentConfigForFeature(
             uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
+    Return<Result> close()  override;
 
     // Methods from ::android::hardware::audio::effect::V2_0::IAcousticEchoCancelerEffect follow.
     Return<Result> setEchoDelay(uint32_t echoDelayMs)  override;
diff --git a/audio/effect/2.0/default/Android.mk b/audio/effect/2.0/default/Android.mk
index 9b99737..18076ed 100644
--- a/audio/effect/2.0/default/Android.mk
+++ b/audio/effect/2.0/default/Android.mk
@@ -5,6 +5,7 @@
 LOCAL_MODULE_RELATIVE_PATH := hw
 LOCAL_SRC_FILES := \
     AcousticEchoCancelerEffect.cpp \
+    AudioBufferManager.cpp \
     AutomaticGainControlEffect.cpp \
     BassBoostEffect.cpp \
     Conversions.cpp \
@@ -20,14 +21,19 @@
     VisualizerEffect.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    libcutils \
+    libeffects \
+    libfmq \
     libhidlbase \
+    libhidlmemory \
     libhidltransport \
     libhwbinder \
-    libutils \
-    libeffects \
     liblog \
+    libutils \
     android.hardware.audio.common@2.0 \
     android.hardware.audio.common@2.0-util \
     android.hardware.audio.effect@2.0 \
+    android.hidl.memory@1.0 \
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/audio/effect/2.0/default/AudioBufferManager.cpp b/audio/effect/2.0/default/AudioBufferManager.cpp
new file mode 100644
index 0000000..603dbb8
--- /dev/null
+++ b/audio/effect/2.0/default/AudioBufferManager.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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>
+
+#include <hidlmemory/mapping.h>
+
+#include "AudioBufferManager.h"
+
+namespace android {
+
+ANDROID_SINGLETON_STATIC_INSTANCE(AudioBufferManager);
+
+bool AudioBufferManager::wrap(const AudioBuffer& buffer, sp<AudioBufferWrapper>* wrapper) {
+    // Check if we have this buffer already
+    std::lock_guard<std::mutex> lock(mLock);
+    ssize_t idx = mBuffers.indexOfKey(buffer.id);
+    if (idx >= 0) {
+        *wrapper = mBuffers[idx].promote();
+        if (*wrapper != nullptr) return true;
+        mBuffers.removeItemsAt(idx);
+    }
+    // Need to create and init a new AudioBufferWrapper.
+    sp<AudioBufferWrapper> tempBuffer(new AudioBufferWrapper(buffer));
+    if (!tempBuffer->init()) return false;
+    *wrapper = tempBuffer;
+    mBuffers.add(buffer.id, *wrapper);
+    return true;
+}
+
+void AudioBufferManager::removeEntry(uint64_t id) {
+    std::lock_guard<std::mutex> lock(mLock);
+    ssize_t idx = mBuffers.indexOfKey(id);
+    if (idx >= 0) mBuffers.removeItemsAt(idx);
+}
+
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+AudioBufferWrapper::AudioBufferWrapper(const AudioBuffer& buffer) :
+        mHidlBuffer(buffer), mHalBuffer{ 0, { nullptr } } {
+}
+
+AudioBufferWrapper::~AudioBufferWrapper() {
+    AudioBufferManager::getInstance().removeEntry(mHidlBuffer.id);
+}
+
+bool AudioBufferWrapper::init() {
+    if (mHalBuffer.raw != nullptr) {
+        ALOGE("An attempt to init AudioBufferWrapper twice");
+        return false;
+    }
+    mHidlMemory = mapMemory(mHidlBuffer.data);
+    if (mHidlMemory == nullptr) {
+        ALOGE("Could not map HIDL memory to IMemory");
+        return false;
+    }
+    mHalBuffer.raw = static_cast<void*>(mHidlMemory->getPointer());
+    if (mHalBuffer.raw == nullptr) {
+        ALOGE("IMemory buffer pointer is null");
+        return false;
+    }
+    mHalBuffer.frameCount = mHidlBuffer.frameCount;
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/2.0/default/AudioBufferManager.h b/audio/effect/2.0/default/AudioBufferManager.h
new file mode 100644
index 0000000..6d65995
--- /dev/null
+++ b/audio/effect/2.0/default/AudioBufferManager.h
@@ -0,0 +1,82 @@
+/*
+ * 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_audio_effect_V2_0_AudioBufferManager_H_
+#define android_hardware_audio_effect_V2_0_AudioBufferManager_H_
+
+#include <mutex>
+
+#include <android/hardware/audio/effect/2.0/types.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <system/audio_effect.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/Singleton.h>
+
+using ::android::hardware::audio::effect::V2_0::AudioBuffer;
+using ::android::hidl::memory::V1_0::IMemory;
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V2_0 {
+namespace implementation {
+
+class AudioBufferWrapper : public RefBase {
+  public:
+    explicit AudioBufferWrapper(const AudioBuffer& buffer);
+    virtual ~AudioBufferWrapper();
+    bool init();
+    audio_buffer_t* getHalBuffer() { return &mHalBuffer; }
+  private:
+    AudioBufferWrapper(const AudioBufferWrapper&) = delete;
+    void operator=(AudioBufferWrapper) = delete;
+
+    AudioBuffer mHidlBuffer;
+    sp<IMemory> mHidlMemory;
+    audio_buffer_t mHalBuffer;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
+
+using ::android::hardware::audio::effect::V2_0::implementation::AudioBufferWrapper;
+
+namespace android {
+
+// This class needs to be in 'android' ns because Singleton macros require that.
+class AudioBufferManager : public Singleton<AudioBufferManager> {
+  public:
+    bool wrap(const AudioBuffer& buffer, sp<AudioBufferWrapper>* wrapper);
+
+  private:
+    friend class hardware::audio::effect::V2_0::implementation::AudioBufferWrapper;
+
+    // Called by AudioBufferWrapper.
+    void removeEntry(uint64_t id);
+
+    std::mutex mLock;
+    KeyedVector<uint64_t, wp<AudioBufferWrapper>> mBuffers;
+};
+
+}  // namespace android
+
+#endif  // android_hardware_audio_effect_V2_0_AudioBufferManager_H_
diff --git a/audio/effect/2.0/default/AutomaticGainControlEffect.cpp b/audio/effect/2.0/default/AutomaticGainControlEffect.cpp
index 6ebfb3c..2c386d3 100644
--- a/audio/effect/2.0/default/AutomaticGainControlEffect.cpp
+++ b/audio/effect/2.0/default/AutomaticGainControlEffect.cpp
@@ -130,16 +130,14 @@
     return mEffect->getDescriptor(_hidl_cb);
 }
 
-Return<void> AutomaticGainControlEffect::process(
-        const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb) {
-    return mEffect->process(inBuffer, outFrameSize, _hidl_cb);
+Return<void> AutomaticGainControlEffect::prepareForProcessing(
+        prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
 }
 
-Return<void> AutomaticGainControlEffect::processReverse(
-        const AudioBuffer& inBuffer,
-        uint32_t outFrameSize,
-        processReverse_cb _hidl_cb) {
-    return mEffect->processReverse(inBuffer, outFrameSize, _hidl_cb);
+Return<Result> AutomaticGainControlEffect::setProcessBuffers(
+        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
 }
 
 Return<void> AutomaticGainControlEffect::command(
@@ -182,6 +180,10 @@
     return mEffect->setCurrentConfigForFeature(featureId, configData);
 }
 
+Return<Result> AutomaticGainControlEffect::close() {
+    return mEffect->close();
+}
+
 // Methods from ::android::hardware::audio::effect::V2_0::IAutomaticGainControlEffect follow.
 Return<Result> AutomaticGainControlEffect::setTargetLevel(int16_t targetLevelMb)  {
     return mEffect->setParam(AGC_PARAM_TARGET_LEVEL, targetLevelMb);
diff --git a/audio/effect/2.0/default/AutomaticGainControlEffect.h b/audio/effect/2.0/default/AutomaticGainControlEffect.h
index 1696d3c..73d94a5 100644
--- a/audio/effect/2.0/default/AutomaticGainControlEffect.h
+++ b/audio/effect/2.0/default/AutomaticGainControlEffect.h
@@ -71,12 +71,9 @@
     Return<Result> setAudioSource(AudioSource source)  override;
     Return<Result> offload(const EffectOffloadParameter& param)  override;
     Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> process(
-            const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb)  override;
-    Return<void> processReverse(
-            const AudioBuffer& inBuffer,
-            uint32_t outFrameSize,
-            processReverse_cb _hidl_cb)  override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
+    Return<Result> setProcessBuffers(
+            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
     Return<void> command(
             uint32_t commandId,
             const hidl_vec<uint8_t>& data,
@@ -99,6 +96,7 @@
             getCurrentConfigForFeature_cb _hidl_cb)  override;
     Return<Result> setCurrentConfigForFeature(
             uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
+    Return<Result> close()  override;
 
     // Methods from ::android::hardware::audio::effect::V2_0::IAutomaticGainControlEffect follow.
     Return<Result> setTargetLevel(int16_t targetLevelMb)  override;
diff --git a/audio/effect/2.0/default/BassBoostEffect.cpp b/audio/effect/2.0/default/BassBoostEffect.cpp
index 8a64806..4120e6e 100644
--- a/audio/effect/2.0/default/BassBoostEffect.cpp
+++ b/audio/effect/2.0/default/BassBoostEffect.cpp
@@ -115,16 +115,14 @@
     return mEffect->getDescriptor(_hidl_cb);
 }
 
-Return<void> BassBoostEffect::process(
-        const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb) {
-    return mEffect->process(inBuffer, outFrameSize, _hidl_cb);
+Return<void> BassBoostEffect::prepareForProcessing(
+        prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
 }
 
-Return<void> BassBoostEffect::processReverse(
-        const AudioBuffer& inBuffer,
-        uint32_t outFrameSize,
-        processReverse_cb _hidl_cb) {
-    return mEffect->processReverse(inBuffer, outFrameSize, _hidl_cb);
+Return<Result> BassBoostEffect::setProcessBuffers(
+        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
 }
 
 Return<void> BassBoostEffect::command(
@@ -167,6 +165,10 @@
     return mEffect->setCurrentConfigForFeature(featureId, configData);
 }
 
+Return<Result> BassBoostEffect::close() {
+    return mEffect->close();
+}
+
 // Methods from ::android::hardware::audio::effect::V2_0::IBassBoostEffect follow.
 Return<void> BassBoostEffect::isStrengthSupported(isStrengthSupported_cb _hidl_cb)  {
     return mEffect->getIntegerParam(BASSBOOST_PARAM_STRENGTH_SUPPORTED, _hidl_cb);
diff --git a/audio/effect/2.0/default/BassBoostEffect.h b/audio/effect/2.0/default/BassBoostEffect.h
index 6636717..1861937 100644
--- a/audio/effect/2.0/default/BassBoostEffect.h
+++ b/audio/effect/2.0/default/BassBoostEffect.h
@@ -69,12 +69,9 @@
     Return<Result> setAudioSource(AudioSource source)  override;
     Return<Result> offload(const EffectOffloadParameter& param)  override;
     Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> process(
-            const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb)  override;
-    Return<void> processReverse(
-            const AudioBuffer& inBuffer,
-            uint32_t outFrameSize,
-            processReverse_cb _hidl_cb)  override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
+    Return<Result> setProcessBuffers(
+            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
     Return<void> command(
             uint32_t commandId,
             const hidl_vec<uint8_t>& data,
@@ -97,6 +94,7 @@
             getCurrentConfigForFeature_cb _hidl_cb)  override;
     Return<Result> setCurrentConfigForFeature(
             uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
+    Return<Result> close()  override;
 
     // Methods from ::android::hardware::audio::effect::V2_0::IBassBoostEffect follow.
     Return<void> isStrengthSupported(isStrengthSupported_cb _hidl_cb)  override;
diff --git a/audio/effect/2.0/default/DownmixEffect.cpp b/audio/effect/2.0/default/DownmixEffect.cpp
index 40bb5ec..41497d0 100644
--- a/audio/effect/2.0/default/DownmixEffect.cpp
+++ b/audio/effect/2.0/default/DownmixEffect.cpp
@@ -115,16 +115,14 @@
     return mEffect->getDescriptor(_hidl_cb);
 }
 
-Return<void> DownmixEffect::process(
-        const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb) {
-    return mEffect->process(inBuffer, outFrameSize, _hidl_cb);
+Return<void> DownmixEffect::prepareForProcessing(
+        prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
 }
 
-Return<void> DownmixEffect::processReverse(
-        const AudioBuffer& inBuffer,
-        uint32_t outFrameSize,
-        processReverse_cb _hidl_cb) {
-    return mEffect->processReverse(inBuffer, outFrameSize, _hidl_cb);
+Return<Result> DownmixEffect::setProcessBuffers(
+        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
 }
 
 Return<void> DownmixEffect::command(
@@ -167,6 +165,10 @@
     return mEffect->setCurrentConfigForFeature(featureId, configData);
 }
 
+Return<Result> DownmixEffect::close() {
+    return mEffect->close();
+}
+
 // Methods from ::android::hardware::audio::effect::V2_0::IDownmixEffect follow.
 Return<Result> DownmixEffect::setType(IDownmixEffect::Type preset)  {
     return mEffect->setParam(DOWNMIX_PARAM_TYPE, static_cast<downmix_type_t>(preset));
diff --git a/audio/effect/2.0/default/DownmixEffect.h b/audio/effect/2.0/default/DownmixEffect.h
index c7e1b9b..1d4c3a9 100644
--- a/audio/effect/2.0/default/DownmixEffect.h
+++ b/audio/effect/2.0/default/DownmixEffect.h
@@ -69,12 +69,9 @@
     Return<Result> setAudioSource(AudioSource source)  override;
     Return<Result> offload(const EffectOffloadParameter& param)  override;
     Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> process(
-            const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb)  override;
-    Return<void> processReverse(
-            const AudioBuffer& inBuffer,
-            uint32_t outFrameSize,
-            processReverse_cb _hidl_cb)  override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
+    Return<Result> setProcessBuffers(
+            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
     Return<void> command(
             uint32_t commandId,
             const hidl_vec<uint8_t>& data,
@@ -97,6 +94,7 @@
             getCurrentConfigForFeature_cb _hidl_cb)  override;
     Return<Result> setCurrentConfigForFeature(
             uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
+    Return<Result> close()  override;
 
     // Methods from ::android::hardware::audio::effect::V2_0::IDownmixEffect follow.
     Return<Result> setType(IDownmixEffect::Type preset)  override;
diff --git a/audio/effect/2.0/default/Effect.cpp b/audio/effect/2.0/default/Effect.cpp
index 1a7ea9c..9ca5834 100644
--- a/audio/effect/2.0/default/Effect.cpp
+++ b/audio/effect/2.0/default/Effect.cpp
@@ -17,8 +17,8 @@
 #include <memory.h>
 
 #define LOG_TAG "EffectHAL"
-#include <media/EffectsFactoryApi.h>
 #include <android/log.h>
+#include <media/EffectsFactoryApi.h>
 
 #include "Conversions.h"
 #include "Effect.h"
@@ -33,20 +33,108 @@
 
 using ::android::hardware::audio::common::V2_0::AudioChannelMask;
 using ::android::hardware::audio::common::V2_0::AudioFormat;
+using ::android::hardware::audio::effect::V2_0::MessageQueueFlagBits;
+
+namespace {
+
+class ProcessThread : public Thread {
+  public:
+    // ProcessThread's lifespan never exceeds Effect's lifespan.
+    ProcessThread(std::atomic<bool>* stop,
+            effect_handle_t effect,
+            std::atomic<audio_buffer_t*>* inBuffer,
+            std::atomic<audio_buffer_t*>* outBuffer,
+            Effect::StatusMQ* statusMQ,
+            EventFlag* efGroup)
+            : Thread(false /*canCallJava*/),
+              mStop(stop),
+              mEffect(effect),
+              mHasProcessReverse((*mEffect)->process_reverse != NULL),
+              mInBuffer(inBuffer),
+              mOutBuffer(outBuffer),
+              mStatusMQ(statusMQ),
+              mEfGroup(efGroup) {
+    }
+    virtual ~ProcessThread() {}
+
+  private:
+    std::atomic<bool>* mStop;
+    effect_handle_t mEffect;
+    bool mHasProcessReverse;
+    std::atomic<audio_buffer_t*>* mInBuffer;
+    std::atomic<audio_buffer_t*>* mOutBuffer;
+    Effect::StatusMQ* mStatusMQ;
+    EventFlag* mEfGroup;
+
+    bool threadLoop() override;
+};
+
+bool ProcessThread::threadLoop() {
+    // This implementation doesn't return control back to the Thread until it decides to stop,
+    // as the Thread uses mutexes, and this can lead to priority inversion.
+    while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
+        uint32_t efState = 0;
+        mEfGroup->wait(
+                static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_ALL),
+                &efState,
+                NS_PER_SEC);
+        if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_ALL))) {
+            continue;  // Nothing to do.
+        }
+        Result retval = Result::OK;
+        if (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_REVERSE)
+                && !mHasProcessReverse) {
+            retval = Result::NOT_SUPPORTED;
+        }
+
+        if (retval == Result::OK) {
+            // affects both buffer pointers and their contents.
+            std::atomic_thread_fence(std::memory_order_acquire);
+            int32_t processResult;
+            audio_buffer_t* inBuffer =
+                    std::atomic_load_explicit(mInBuffer, std::memory_order_relaxed);
+            audio_buffer_t* outBuffer =
+                    std::atomic_load_explicit(mOutBuffer, std::memory_order_relaxed);
+            if (inBuffer != nullptr && outBuffer != nullptr) {
+                if (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS)) {
+                    processResult = (*mEffect)->process(mEffect, inBuffer, outBuffer);
+                } else {
+                    processResult = (*mEffect)->process_reverse(mEffect, inBuffer, outBuffer);
+                }
+                std::atomic_thread_fence(std::memory_order_release);
+            } else {
+                ALOGE("processing buffers were not set before calling 'process'");
+                processResult = -ENODEV;
+            }
+            switch(processResult) {
+                case 0: retval = Result::OK; break;
+                case -ENODATA: retval = Result::INVALID_STATE; break;
+                case -EINVAL: retval = Result::INVALID_ARGUMENTS; break;
+                default: retval = Result::NOT_INITIALIZED;
+            }
+        }
+        if (!mStatusMQ->write(&retval)) {
+            ALOGW("status message queue write failed");
+        }
+        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING));
+    }
+
+    return false;
+}
+
+}  // namespace
 
 // static
 const char *Effect::sContextResultOfCommand = "returned status";
 const char *Effect::sContextCallToCommand = "error";
 const char *Effect::sContextCallFunction = sContextCallToCommand;
 
-Effect::Effect(effect_handle_t handle) : mHandle(handle) {
+Effect::Effect(effect_handle_t handle)
+        : mIsClosed(false), mHandle(handle), mEfGroup(nullptr), mStopProcessThread(false) {
 }
 
 Effect::~Effect() {
-    int status = EffectRelease(mHandle);
-    ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status));
-    EffectMap::getInstance().remove(mHandle);
-    mHandle = 0;
+    close();
 }
 
 // static
@@ -83,9 +171,6 @@
 // static
 void Effect::effectBufferConfigFromHal(
         const buffer_config_t& halConfig, EffectBufferConfig* config) {
-    // TODO(mnaganov): Use FMQ instead of AudioBuffer.
-    (void)halConfig.buffer.frameCount;
-    (void)halConfig.buffer.raw;
     config->samplingRateHz = halConfig.samplingRate;
     config->channels = AudioChannelMask(halConfig.channels);
     config->format = AudioFormat(halConfig.format);
@@ -95,12 +180,13 @@
 
 // static
 void Effect::effectBufferConfigToHal(const EffectBufferConfig& config, buffer_config_t* halConfig) {
-    // TODO(mnaganov): Use FMQ instead of AudioBuffer.
+    // Note: setting the buffers directly is considered obsolete. They need to be set
+    // using 'setProcessBuffers'.
     halConfig->buffer.frameCount = 0;
     halConfig->buffer.raw = NULL;
     halConfig->samplingRate = config.samplingRateHz;
     halConfig->channels = static_cast<uint32_t>(config.channels);
-    // TODO(mnaganov): As the calling code does not use BP for now, implement later.
+    // TODO(mnaganov): The framework code currently does not use BP, implement later.
     halConfig->bufferProvider.cookie = NULL;
     halConfig->bufferProvider.getBuffer = NULL;
     halConfig->bufferProvider.releaseBuffer = NULL;
@@ -250,31 +336,66 @@
             });
 }
 
-void Effect::processImpl(
-        ProcessFunction process,
-        const char* funcName,
-        const AudioBuffer& inBuffer,
-        uint32_t outFrameSize,
-        ProcessCallback cb) {
-    audio_buffer_t halInBuffer;
-    halInBuffer.frameCount = inBuffer.frameCount;
-    halInBuffer.u8 = const_cast<uint8_t*>(&inBuffer.data[0]);
-    audio_buffer_t halOutBuffer;
-    halOutBuffer.frameCount = halInBuffer.frameCount;
-    // TODO(mnaganov): Consider stashing the buffer to avoid reallocating it every time.
-    std::unique_ptr<uint8_t[]> halOutBufferData(
-            new uint8_t[halOutBuffer.frameCount * outFrameSize]);
-    halOutBuffer.u8 = &halOutBufferData[0];
-    status_t status = process(mHandle, &halInBuffer, &halOutBuffer);
-    Result retval = analyzeStatus(funcName, "", sContextCallFunction, status);
-    AudioBuffer outBuffer;
-    if (status == OK) {
-        outBuffer.frameCount = halOutBuffer.frameCount;
-        outBuffer.data.setToExternal(halOutBuffer.u8, halOutBuffer.frameCount * outFrameSize);
-    } else {
-        outBuffer.frameCount = 0;
+Return<void> Effect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+    status_t status;
+    // Create message queue.
+    if (mStatusMQ) {
+        ALOGE("the client attempts to call prepareForProcessing_cb twice");
+        _hidl_cb(Result::INVALID_STATE, StatusMQ::Descriptor());
+        return Void();
     }
-    cb(retval, outBuffer);
+    std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1, true /*EventFlag*/));
+    if (!tempStatusMQ->isValid()) {
+        ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
+        _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor());
+        return Void();
+    }
+    status = EventFlag::createEventFlag(tempStatusMQ->getEventFlagWord(), &mEfGroup);
+    if (status != OK || !mEfGroup) {
+        ALOGE("failed creating event flag for status MQ: %s", strerror(-status));
+        _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor());
+        return Void();
+    }
+
+    // Create and launch the thread.
+    mProcessThread = new ProcessThread(
+            &mStopProcessThread,
+            mHandle,
+            &mHalInBufferPtr,
+            &mHalOutBufferPtr,
+            tempStatusMQ.get(),
+            mEfGroup);
+    status = mProcessThread->run("effect", PRIORITY_URGENT_AUDIO);
+    if (status != OK) {
+        ALOGW("failed to start effect processing thread: %s", strerror(-status));
+        _hidl_cb(Result::INVALID_ARGUMENTS, MQDescriptorSync<Result>());
+        return Void();
+    }
+
+    mStatusMQ = std::move(tempStatusMQ);
+    _hidl_cb(Result::OK, *mStatusMQ->getDesc());
+    return Void();
+}
+
+Return<Result> Effect::setProcessBuffers(
+        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+    AudioBufferManager& manager = AudioBufferManager::getInstance();
+    sp<AudioBufferWrapper> tempInBuffer, tempOutBuffer;
+    if (!manager.wrap(inBuffer, &tempInBuffer)) {
+        ALOGE("Could not map memory of the input buffer");
+        return Result::INVALID_ARGUMENTS;
+    }
+    if (!manager.wrap(outBuffer, &tempOutBuffer)) {
+        ALOGE("Could not map memory of the output buffer");
+        return Result::INVALID_ARGUMENTS;
+    }
+    mInBuffer = tempInBuffer;
+    mOutBuffer = tempOutBuffer;
+    // The processing thread only reads these pointers after waking up by an event flag,
+    // so it's OK to update the pair non-atomically.
+    mHalInBufferPtr.store(mInBuffer->getHalBuffer(), std::memory_order_release);
+    mHalOutBufferPtr.store(mOutBuffer->getHalBuffer(), std::memory_order_release);
+    return Result::OK;
 }
 
 Result Effect::sendCommand(int commandCode, const char* commandName) {
@@ -510,23 +631,6 @@
     return Void();
 }
 
-Return<void> Effect::process(
-        const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb)  {
-    processImpl((*mHandle)->process, "process", inBuffer, outFrameSize, _hidl_cb);
-    return Void();
-}
-
-Return<void> Effect::processReverse(
-        const AudioBuffer& inBuffer, uint32_t outFrameSize, processReverse_cb _hidl_cb)  {
-    if ((*mHandle)->process_reverse != NULL) {
-        processImpl(
-                (*mHandle)->process_reverse, "process_reverse", inBuffer, outFrameSize, _hidl_cb);
-    } else {
-        _hidl_cb(Result::NOT_SUPPORTED, AudioBuffer());
-    }
-    return Void();
-}
-
 Return<void> Effect::command(
         uint32_t commandId,
         const hidl_vec<uint8_t>& data,
@@ -611,6 +715,27 @@
             EFFECT_CMD_SET_FEATURE_CONFIG, "SET_FEATURE_CONFIG", sizeof(halCmd), halCmd);
 }
 
+Return<Result> Effect::close() {
+    if (mIsClosed) return Result::INVALID_STATE;
+    mIsClosed = true;
+    if (mProcessThread.get()) {
+        mStopProcessThread.store(true, std::memory_order_release);
+        status_t status = mProcessThread->requestExitAndWait();
+        ALOGE_IF(status, "processing thread exit error: %s", strerror(-status));
+    }
+    if (mEfGroup) {
+        status_t status = EventFlag::deleteEventFlag(&mEfGroup);
+        ALOGE_IF(status, "processing MQ event flag deletion error: %s", strerror(-status));
+    }
+    mInBuffer.clear();
+    mOutBuffer.clear();
+    int status = EffectRelease(mHandle);
+    ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status));
+    EffectMap::getInstance().remove(mHandle);
+    mHandle = 0;
+    return Result::OK;
+}
+
 } // namespace implementation
 }  // namespace V2_0
 }  // namespace effect
diff --git a/audio/effect/2.0/default/Effect.h b/audio/effect/2.0/default/Effect.h
index 61d0121..8daffb8 100644
--- a/audio/effect/2.0/default/Effect.h
+++ b/audio/effect/2.0/default/Effect.h
@@ -17,16 +17,21 @@
 #ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECT_H
 #define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECT_H
 
+#include <atomic>
 #include <memory>
 #include <vector>
 
 #include <android/hardware/audio/effect/2.0/IEffect.h>
-#include <hidl/Status.h>
-
+#include <fmq/EventFlag.h>
+#include <fmq/MessageQueue.h>
 #include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <utils/Thread.h>
 
 #include <hardware/audio_effect.h>
 
+#include "AudioBufferManager.h"
+
 namespace android {
 namespace hardware {
 namespace audio {
@@ -54,6 +59,8 @@
 using ::android::sp;
 
 struct Effect : public IEffect {
+    typedef MessageQueue<Result, kSynchronizedReadWrite> StatusMQ;
+
     explicit Effect(effect_handle_t handle);
 
     // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
@@ -83,12 +90,9 @@
     Return<Result> setAudioSource(AudioSource source)  override;
     Return<Result> offload(const EffectOffloadParameter& param)  override;
     Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> process(
-            const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb)  override;
-    Return<void> processReverse(
-            const AudioBuffer& inBuffer,
-            uint32_t outFrameSize,
-            processReverse_cb _hidl_cb)  override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
+    Return<Result> setProcessBuffers(
+            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
     Return<void> command(
             uint32_t commandId,
             const hidl_vec<uint8_t>& data,
@@ -111,6 +115,7 @@
             getCurrentConfigForFeature_cb _hidl_cb)  override;
     Return<Result> setCurrentConfigForFeature(
             uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
+    Return<Result> close()  override;
 
     // Utility methods for extending interfaces.
     template<typename T> Return<void> getIntegerParam(
@@ -161,8 +166,6 @@
     friend struct VirtualizerEffect;  // for getParameterImpl
     friend struct VisualizerEffect;   // to allow executing commands
 
-    typedef int32_t (*ProcessFunction)(
-            effect_handle_t self, audio_buffer_t* inBuffer, audio_buffer_t* outBuffer);
     using CommandSuccessCallback = std::function<void()>;
     using GetConfigCallback = std::function<void(Result retval, const EffectConfig& config)>;
     using GetCurrentConfigSuccessCallback = std::function<void(void* configData)>;
@@ -170,13 +173,21 @@
             std::function<void(uint32_t valueSize, const void* valueData)>;
     using GetSupportedConfigsSuccessCallback =
             std::function<void(uint32_t supportedConfigs, void* configsData)>;
-    using ProcessCallback = std::function<void(Result retval, const AudioBuffer& outBuffer)>;
 
     static const char *sContextResultOfCommand;
     static const char *sContextCallToCommand;
     static const char *sContextCallFunction;
 
+    bool mIsClosed;
     effect_handle_t mHandle;
+    sp<AudioBufferWrapper> mInBuffer;
+    sp<AudioBufferWrapper> mOutBuffer;
+    std::atomic<audio_buffer_t*> mHalInBufferPtr;
+    std::atomic<audio_buffer_t*> mHalOutBufferPtr;
+    std::unique_ptr<StatusMQ> mStatusMQ;
+    EventFlag* mEfGroup;
+    std::atomic<bool> mStopProcessThread;
+    sp<Thread> mProcessThread;
 
     virtual ~Effect();
 
@@ -218,12 +229,6 @@
             uint32_t maxConfigs,
             uint32_t configSize,
             GetSupportedConfigsSuccessCallback onSuccess);
-    void processImpl(
-            ProcessFunction process,
-            const char* funcName,
-            const AudioBuffer& inBuffer,
-            uint32_t outFrameSize,
-            ProcessCallback cb);
     Result sendCommand(int commandCode, const char* commandName);
     Result sendCommand(int commandCode, const char* commandName, uint32_t size, void* data);
     Result sendCommandReturningData(
diff --git a/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp b/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp
index db1ad51..2c1fd68 100644
--- a/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp
+++ b/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp
@@ -144,16 +144,14 @@
     return mEffect->getDescriptor(_hidl_cb);
 }
 
-Return<void> EnvironmentalReverbEffect::process(
-        const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb) {
-    return mEffect->process(inBuffer, outFrameSize, _hidl_cb);
+Return<void> EnvironmentalReverbEffect::prepareForProcessing(
+        prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
 }
 
-Return<void> EnvironmentalReverbEffect::processReverse(
-        const AudioBuffer& inBuffer,
-        uint32_t outFrameSize,
-        processReverse_cb _hidl_cb) {
-    return mEffect->processReverse(inBuffer, outFrameSize, _hidl_cb);
+Return<Result> EnvironmentalReverbEffect::setProcessBuffers(
+        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
 }
 
 Return<void> EnvironmentalReverbEffect::command(
@@ -196,6 +194,9 @@
     return mEffect->setCurrentConfigForFeature(featureId, configData);
 }
 
+Return<Result> EnvironmentalReverbEffect::close() {
+    return mEffect->close();
+}
 
 // Methods from ::android::hardware::audio::effect::V2_0::IEnvironmentalReverbEffect follow.
 Return<Result> EnvironmentalReverbEffect::setBypass(bool bypass)  {
diff --git a/audio/effect/2.0/default/EnvironmentalReverbEffect.h b/audio/effect/2.0/default/EnvironmentalReverbEffect.h
index edb5747..d0c8962 100644
--- a/audio/effect/2.0/default/EnvironmentalReverbEffect.h
+++ b/audio/effect/2.0/default/EnvironmentalReverbEffect.h
@@ -81,12 +81,9 @@
     Return<Result> setAudioSource(AudioSource source)  override;
     Return<Result> offload(const EffectOffloadParameter& param)  override;
     Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> process(
-            const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb)  override;
-    Return<void> processReverse(
-            const AudioBuffer& inBuffer,
-            uint32_t outFrameSize,
-            processReverse_cb _hidl_cb)  override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
+    Return<Result> setProcessBuffers(
+            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
     Return<void> command(
             uint32_t commandId,
             const hidl_vec<uint8_t>& data,
@@ -109,6 +106,7 @@
             getCurrentConfigForFeature_cb _hidl_cb)  override;
     Return<Result> setCurrentConfigForFeature(
             uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
+    Return<Result> close()  override;
 
     // Methods from ::android::hardware::audio::effect::V2_0::IEnvironmentalReverbEffect follow.
     Return<Result> setBypass(bool bypass)  override;
diff --git a/audio/effect/2.0/default/EqualizerEffect.cpp b/audio/effect/2.0/default/EqualizerEffect.cpp
index 490a300..833ea5b 100644
--- a/audio/effect/2.0/default/EqualizerEffect.cpp
+++ b/audio/effect/2.0/default/EqualizerEffect.cpp
@@ -135,16 +135,14 @@
     return mEffect->getDescriptor(_hidl_cb);
 }
 
-Return<void> EqualizerEffect::process(
-        const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb) {
-    return mEffect->process(inBuffer, outFrameSize, _hidl_cb);
+Return<void> EqualizerEffect::prepareForProcessing(
+        prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
 }
 
-Return<void> EqualizerEffect::processReverse(
-        const AudioBuffer& inBuffer,
-        uint32_t outFrameSize,
-        processReverse_cb _hidl_cb) {
-    return mEffect->processReverse(inBuffer, outFrameSize, _hidl_cb);
+Return<Result> EqualizerEffect::setProcessBuffers(
+        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
 }
 
 Return<void> EqualizerEffect::command(
@@ -187,6 +185,9 @@
     return mEffect->setCurrentConfigForFeature(featureId, configData);
 }
 
+Return<Result> EqualizerEffect::close() {
+    return mEffect->close();
+}
 
 // Methods from ::android::hardware::audio::effect::V2_0::IEqualizerEffect follow.
 Return<void> EqualizerEffect::getNumBands(getNumBands_cb _hidl_cb)  {
diff --git a/audio/effect/2.0/default/EqualizerEffect.h b/audio/effect/2.0/default/EqualizerEffect.h
index ba99e2b..200ca1a 100644
--- a/audio/effect/2.0/default/EqualizerEffect.h
+++ b/audio/effect/2.0/default/EqualizerEffect.h
@@ -83,12 +83,9 @@
     Return<Result> setAudioSource(AudioSource source)  override;
     Return<Result> offload(const EffectOffloadParameter& param)  override;
     Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> process(
-            const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb)  override;
-    Return<void> processReverse(
-            const AudioBuffer& inBuffer,
-            uint32_t outFrameSize,
-            processReverse_cb _hidl_cb)  override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
+    Return<Result> setProcessBuffers(
+            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
     Return<void> command(
             uint32_t commandId,
             const hidl_vec<uint8_t>& data,
@@ -111,6 +108,7 @@
             getCurrentConfigForFeature_cb _hidl_cb)  override;
     Return<Result> setCurrentConfigForFeature(
             uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
+    Return<Result> close()  override;
 
     // Methods from ::android::hardware::audio::effect::V2_0::IEqualizerEffect follow.
     Return<void> getNumBands(getNumBands_cb _hidl_cb)  override;
diff --git a/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp b/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp
index a49019c..1f7124b 100644
--- a/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp
+++ b/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp
@@ -117,16 +117,14 @@
     return mEffect->getDescriptor(_hidl_cb);
 }
 
-Return<void> LoudnessEnhancerEffect::process(
-        const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb) {
-    return mEffect->process(inBuffer, outFrameSize, _hidl_cb);
+Return<void> LoudnessEnhancerEffect::prepareForProcessing(
+        prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
 }
 
-Return<void> LoudnessEnhancerEffect::processReverse(
-        const AudioBuffer& inBuffer,
-        uint32_t outFrameSize,
-        processReverse_cb _hidl_cb) {
-    return mEffect->processReverse(inBuffer, outFrameSize, _hidl_cb);
+Return<Result> LoudnessEnhancerEffect::setProcessBuffers(
+        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
 }
 
 Return<void> LoudnessEnhancerEffect::command(
@@ -169,6 +167,9 @@
     return mEffect->setCurrentConfigForFeature(featureId, configData);
 }
 
+Return<Result> LoudnessEnhancerEffect::close() {
+    return mEffect->close();
+}
 
 // Methods from ::android::hardware::audio::effect::V2_0::ILoudnessEnhancerEffect follow.
 Return<Result> LoudnessEnhancerEffect::setTargetGain(int32_t targetGainMb)  {
diff --git a/audio/effect/2.0/default/LoudnessEnhancerEffect.h b/audio/effect/2.0/default/LoudnessEnhancerEffect.h
index 8ca6e94..308c47f 100644
--- a/audio/effect/2.0/default/LoudnessEnhancerEffect.h
+++ b/audio/effect/2.0/default/LoudnessEnhancerEffect.h
@@ -79,12 +79,9 @@
     Return<Result> setAudioSource(AudioSource source)  override;
     Return<Result> offload(const EffectOffloadParameter& param)  override;
     Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> process(
-            const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb)  override;
-    Return<void> processReverse(
-            const AudioBuffer& inBuffer,
-            uint32_t outFrameSize,
-            processReverse_cb _hidl_cb)  override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
+    Return<Result> setProcessBuffers(
+            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
     Return<void> command(
             uint32_t commandId,
             const hidl_vec<uint8_t>& data,
@@ -107,6 +104,7 @@
             getCurrentConfigForFeature_cb _hidl_cb)  override;
     Return<Result> setCurrentConfigForFeature(
             uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
+    Return<Result> close()  override;
 
     // Methods from ::android::hardware::audio::effect::V2_0::ILoudnessEnhancerEffect follow.
     Return<Result> setTargetGain(int32_t targetGainMb)  override;
diff --git a/audio/effect/2.0/default/NoiseSuppressionEffect.cpp b/audio/effect/2.0/default/NoiseSuppressionEffect.cpp
index 69a1226..b0b929f 100644
--- a/audio/effect/2.0/default/NoiseSuppressionEffect.cpp
+++ b/audio/effect/2.0/default/NoiseSuppressionEffect.cpp
@@ -128,16 +128,14 @@
     return mEffect->getDescriptor(_hidl_cb);
 }
 
-Return<void> NoiseSuppressionEffect::process(
-        const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb) {
-    return mEffect->process(inBuffer, outFrameSize, _hidl_cb);
+Return<void> NoiseSuppressionEffect::prepareForProcessing(
+        prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
 }
 
-Return<void> NoiseSuppressionEffect::processReverse(
-        const AudioBuffer& inBuffer,
-        uint32_t outFrameSize,
-        processReverse_cb _hidl_cb) {
-    return mEffect->processReverse(inBuffer, outFrameSize, _hidl_cb);
+Return<Result> NoiseSuppressionEffect::setProcessBuffers(
+        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
 }
 
 Return<void> NoiseSuppressionEffect::command(
@@ -180,6 +178,9 @@
     return mEffect->setCurrentConfigForFeature(featureId, configData);
 }
 
+Return<Result> NoiseSuppressionEffect::close() {
+    return mEffect->close();
+}
 
 // Methods from ::android::hardware::audio::effect::V2_0::INoiseSuppressionEffect follow.
 Return<Result> NoiseSuppressionEffect::setSuppressionLevel(INoiseSuppressionEffect::Level level)  {
diff --git a/audio/effect/2.0/default/NoiseSuppressionEffect.h b/audio/effect/2.0/default/NoiseSuppressionEffect.h
index b73727e..5e3a5c1 100644
--- a/audio/effect/2.0/default/NoiseSuppressionEffect.h
+++ b/audio/effect/2.0/default/NoiseSuppressionEffect.h
@@ -81,12 +81,9 @@
     Return<Result> setAudioSource(AudioSource source)  override;
     Return<Result> offload(const EffectOffloadParameter& param)  override;
     Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> process(
-            const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb)  override;
-    Return<void> processReverse(
-            const AudioBuffer& inBuffer,
-            uint32_t outFrameSize,
-            processReverse_cb _hidl_cb)  override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
+    Return<Result> setProcessBuffers(
+            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
     Return<void> command(
             uint32_t commandId,
             const hidl_vec<uint8_t>& data,
@@ -109,6 +106,7 @@
             getCurrentConfigForFeature_cb _hidl_cb)  override;
     Return<Result> setCurrentConfigForFeature(
             uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
+    Return<Result> close()  override;
 
     // Methods from ::android::hardware::audio::effect::V2_0::INoiseSuppressionEffect follow.
     Return<Result> setSuppressionLevel(INoiseSuppressionEffect::Level level)  override;
diff --git a/audio/effect/2.0/default/PresetReverbEffect.cpp b/audio/effect/2.0/default/PresetReverbEffect.cpp
index 0e6d1b8..803c9be 100644
--- a/audio/effect/2.0/default/PresetReverbEffect.cpp
+++ b/audio/effect/2.0/default/PresetReverbEffect.cpp
@@ -115,16 +115,14 @@
     return mEffect->getDescriptor(_hidl_cb);
 }
 
-Return<void> PresetReverbEffect::process(
-        const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb) {
-    return mEffect->process(inBuffer, outFrameSize, _hidl_cb);
+Return<void> PresetReverbEffect::prepareForProcessing(
+        prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
 }
 
-Return<void> PresetReverbEffect::processReverse(
-        const AudioBuffer& inBuffer,
-        uint32_t outFrameSize,
-        processReverse_cb _hidl_cb) {
-    return mEffect->processReverse(inBuffer, outFrameSize, _hidl_cb);
+Return<Result> PresetReverbEffect::setProcessBuffers(
+        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
 }
 
 Return<void> PresetReverbEffect::command(
@@ -167,6 +165,9 @@
     return mEffect->setCurrentConfigForFeature(featureId, configData);
 }
 
+Return<Result> PresetReverbEffect::close() {
+    return mEffect->close();
+}
 
 // Methods from ::android::hardware::audio::effect::V2_0::IPresetReverbEffect follow.
 Return<Result> PresetReverbEffect::setPreset(IPresetReverbEffect::Preset preset)  {
diff --git a/audio/effect/2.0/default/PresetReverbEffect.h b/audio/effect/2.0/default/PresetReverbEffect.h
index 4d39569..f6a900c 100644
--- a/audio/effect/2.0/default/PresetReverbEffect.h
+++ b/audio/effect/2.0/default/PresetReverbEffect.h
@@ -79,12 +79,9 @@
     Return<Result> setAudioSource(AudioSource source)  override;
     Return<Result> offload(const EffectOffloadParameter& param)  override;
     Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> process(
-            const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb)  override;
-    Return<void> processReverse(
-            const AudioBuffer& inBuffer,
-            uint32_t outFrameSize,
-            processReverse_cb _hidl_cb)  override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
+    Return<Result> setProcessBuffers(
+            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
     Return<void> command(
             uint32_t commandId,
             const hidl_vec<uint8_t>& data,
@@ -107,6 +104,7 @@
             getCurrentConfigForFeature_cb _hidl_cb)  override;
     Return<Result> setCurrentConfigForFeature(
             uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
+    Return<Result> close()  override;
 
     // Methods from ::android::hardware::audio::effect::V2_0::IPresetReverbEffect follow.
     Return<Result> setPreset(IPresetReverbEffect::Preset preset)  override;
diff --git a/audio/effect/2.0/default/VirtualizerEffect.cpp b/audio/effect/2.0/default/VirtualizerEffect.cpp
index 313674d..4f193e7 100644
--- a/audio/effect/2.0/default/VirtualizerEffect.cpp
+++ b/audio/effect/2.0/default/VirtualizerEffect.cpp
@@ -127,16 +127,14 @@
     return mEffect->getDescriptor(_hidl_cb);
 }
 
-Return<void> VirtualizerEffect::process(
-        const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb) {
-    return mEffect->process(inBuffer, outFrameSize, _hidl_cb);
+Return<void> VirtualizerEffect::prepareForProcessing(
+        prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
 }
 
-Return<void> VirtualizerEffect::processReverse(
-        const AudioBuffer& inBuffer,
-        uint32_t outFrameSize,
-        processReverse_cb _hidl_cb) {
-    return mEffect->processReverse(inBuffer, outFrameSize, _hidl_cb);
+Return<Result> VirtualizerEffect::setProcessBuffers(
+        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
 }
 
 Return<void> VirtualizerEffect::command(
@@ -179,6 +177,9 @@
     return mEffect->setCurrentConfigForFeature(featureId, configData);
 }
 
+Return<Result> VirtualizerEffect::close() {
+    return mEffect->close();
+}
 
 // Methods from ::android::hardware::audio::effect::V2_0::IVirtualizerEffect follow.
 Return<bool> VirtualizerEffect::isStrengthSupported()  {
diff --git a/audio/effect/2.0/default/VirtualizerEffect.h b/audio/effect/2.0/default/VirtualizerEffect.h
index ba89a61..5b0773d 100644
--- a/audio/effect/2.0/default/VirtualizerEffect.h
+++ b/audio/effect/2.0/default/VirtualizerEffect.h
@@ -80,12 +80,9 @@
     Return<Result> setAudioSource(AudioSource source)  override;
     Return<Result> offload(const EffectOffloadParameter& param)  override;
     Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> process(
-            const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb)  override;
-    Return<void> processReverse(
-            const AudioBuffer& inBuffer,
-            uint32_t outFrameSize,
-            processReverse_cb _hidl_cb)  override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
+    Return<Result> setProcessBuffers(
+            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
     Return<void> command(
             uint32_t commandId,
             const hidl_vec<uint8_t>& data,
@@ -108,6 +105,7 @@
             getCurrentConfigForFeature_cb _hidl_cb)  override;
     Return<Result> setCurrentConfigForFeature(
             uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
+    Return<Result> close()  override;
 
     // Methods from ::android::hardware::audio::effect::V2_0::IVirtualizerEffect follow.
     Return<bool> isStrengthSupported()  override;
diff --git a/audio/effect/2.0/default/VisualizerEffect.cpp b/audio/effect/2.0/default/VisualizerEffect.cpp
index a53eabc..141817b 100644
--- a/audio/effect/2.0/default/VisualizerEffect.cpp
+++ b/audio/effect/2.0/default/VisualizerEffect.cpp
@@ -115,16 +115,14 @@
     return mEffect->getDescriptor(_hidl_cb);
 }
 
-Return<void> VisualizerEffect::process(
-        const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb) {
-    return mEffect->process(inBuffer, outFrameSize, _hidl_cb);
+Return<void> VisualizerEffect::prepareForProcessing(
+        prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
 }
 
-Return<void> VisualizerEffect::processReverse(
-        const AudioBuffer& inBuffer,
-        uint32_t outFrameSize,
-        processReverse_cb _hidl_cb) {
-    return mEffect->processReverse(inBuffer, outFrameSize, _hidl_cb);
+Return<Result> VisualizerEffect::setProcessBuffers(
+        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
 }
 
 Return<void> VisualizerEffect::command(
@@ -167,6 +165,9 @@
     return mEffect->setCurrentConfigForFeature(featureId, configData);
 }
 
+Return<Result> VisualizerEffect::close() {
+    return mEffect->close();
+}
 
 // Methods from ::android::hardware::audio::effect::V2_0::IVisualizerEffect follow.
 Return<Result> VisualizerEffect::setCaptureSize(uint16_t captureSize)  {
diff --git a/audio/effect/2.0/default/VisualizerEffect.h b/audio/effect/2.0/default/VisualizerEffect.h
index ae0b05c..b6dc768 100644
--- a/audio/effect/2.0/default/VisualizerEffect.h
+++ b/audio/effect/2.0/default/VisualizerEffect.h
@@ -79,12 +79,9 @@
     Return<Result> setAudioSource(AudioSource source)  override;
     Return<Result> offload(const EffectOffloadParameter& param)  override;
     Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> process(
-            const AudioBuffer& inBuffer, uint32_t outFrameSize, process_cb _hidl_cb)  override;
-    Return<void> processReverse(
-            const AudioBuffer& inBuffer,
-            uint32_t outFrameSize,
-            processReverse_cb _hidl_cb)  override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
+    Return<Result> setProcessBuffers(
+            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
     Return<void> command(
             uint32_t commandId,
             const hidl_vec<uint8_t>& data,
@@ -107,6 +104,7 @@
             getCurrentConfigForFeature_cb _hidl_cb)  override;
     Return<Result> setCurrentConfigForFeature(
             uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
+    Return<Result> close()  override;
 
     // Methods from ::android::hardware::audio::effect::V2_0::IVisualizerEffect follow.
     Return<Result> setCaptureSize(uint16_t captureSize)  override;
diff --git a/audio/effect/2.0/types.hal b/audio/effect/2.0/types.hal
index ad7f4ce..0cac59a 100644
--- a/audio/effect/2.0/types.hal
+++ b/audio/effect/2.0/types.hal
@@ -222,10 +222,10 @@
  * samples for all channels at a given time. Frame size for unspecified format
  * (AUDIO_FORMAT_OTHER) is 8 bit by definition.
  */
-// TODO(mnaganov): replace with FMQ version.
 struct AudioBuffer {
+    uint64_t id;
     uint32_t frameCount;
-    vec<uint8_t> data;
+    memory data;
 };
 
 @export(name="effect_buffer_access_e", value_prefix="EFFECT_BUFFER_")
@@ -284,3 +284,14 @@
     AudioIoHandle ioHandle;  // io handle of the playback thread
                              // the effect is attached to
 };
+
+/*
+ * The message queue flags used to synchronize reads and writes from
+ * the status message queue used by effects.
+ */
+enum MessageQueueFlagBits : uint32_t {
+    DONE_PROCESSING = 1 << 0,
+    REQUEST_PROCESS = 1 << 1,
+    REQUEST_PROCESS_REVERSE = 1 << 2,
+    REQUEST_PROCESS_ALL = REQUEST_PROCESS | REQUEST_PROCESS_REVERSE
+};