Merge "Fix plugin loading"
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index f656008..ba2100c 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -335,7 +335,7 @@
         return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
     }
     out->numCameras = numCameras;
-    out->cameraIds = new const char*[numCameras] {nullptr};
+    out->cameraIds = new const char*[numCameras];
     if (!out->cameraIds) {
         ALOGE("Allocate memory for ACameraIdList failed!");
         deleteCameraIdList(out);
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index b28d509..9a236fc 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -124,29 +124,6 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:=         \
-	sf2.cpp    \
-
-LOCAL_SHARED_LIBRARIES := \
-	libstagefright liblog libutils libbinder libstagefright_foundation \
-	libmedia libgui libcutils
-
-LOCAL_C_INCLUDES:= \
-	frameworks/av/media/libstagefright \
-	$(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE:= sf2
-
-include $(BUILD_EXECUTABLE)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
 LOCAL_SRC_FILES:=               \
 	codec.cpp               \
 	SimplePlayer.cpp        \
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
deleted file mode 100644
index 12bbfd1..0000000
--- a/cmds/stagefright/sf2.cpp
+++ /dev/null
@@ -1,788 +0,0 @@
-/*
- * Copyright (C) 2010 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_NDEBUG 0
-#define LOG_TAG "sf2"
-#include <inttypes.h>
-#include <utils/Log.h>
-
-#include <signal.h>
-
-#include <binder/ProcessState.h>
-
-#include <media/IMediaHTTPService.h>
-
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-#include <media/stagefright/ACodec.h>
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaExtractor.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
-#include <gui/SurfaceComposerClient.h>
-#include <gui/Surface.h>
-
-#include "include/ESDS.h"
-
-using namespace android;
-
-volatile static bool ctrlc = false;
-
-static sighandler_t oldhandler = NULL;
-
-static void mysighandler(int signum) {
-    if (signum == SIGINT) {
-        ctrlc = true;
-        return;
-    }
-    oldhandler(signum);
-}
-
-namespace {
-
-enum {
-    kWhatFillThisBuffer      = 'fill',
-    kWhatDrainThisBuffer     = 'drai',
-    kWhatEOS                 = 'eos ',
-    kWhatStopCompleted       = 'scom',
-    kWhatReleaseCompleted    = 'rcom',
-    kWhatFlushCompleted      = 'fcom',
-    kWhatError               = 'erro',
-};
-
-class Sf2Callback : public CodecBase::Callback {
-public:
-    explicit Sf2Callback(const sp<AMessage> &notify);
-    ~Sf2Callback();
-
-    virtual void fillThisBuffer(IOMX::buffer_id bufferId, const sp<MediaCodecBuffer> &buffer,
-            const sp<AMessage> &reply) override;
-    virtual void drainThisBuffer(IOMX::buffer_id bufferId, const sp<MediaCodecBuffer> &buffer,
-            int32_t flags, const sp<AMessage> &reply) override;
-    virtual void onEos(status_t err) override;
-    virtual void onStopCompleted() override;
-    virtual void onReleaseCompleted() override;
-    virtual void onFlushCompleted() override;
-    virtual void onError(status_t err, enum ActionCode actionCode) override;
-    // Events below are not handled; thus ignore.
-    virtual void onComponentAllocated(const char *) override {}
-    virtual void onComponentConfigured(const sp<AMessage> &, const sp<AMessage> &) override {}
-    virtual void onInputSurfaceCreated(
-            const sp<AMessage> &,
-            const sp<AMessage> &,
-            const sp<BufferProducerWrapper> &) override {}
-    virtual void onInputSurfaceCreationFailed(status_t) override {}
-    virtual void onInputSurfaceAccepted(const sp<AMessage> &, const sp<AMessage> &) override {}
-    virtual void onInputSurfaceDeclined(status_t) override {}
-    virtual void onSignaledInputEOS(status_t) override {}
-    virtual void onBuffersAllocated(int32_t, const sp<CodecBase::PortDescription> &) override {}
-    virtual void onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &) override {}
-private:
-    const sp<AMessage> mNotify;
-};
-
-Sf2Callback::Sf2Callback(const sp<AMessage> &notify) : mNotify(notify) {}
-
-Sf2Callback::~Sf2Callback() {}
-
-void Sf2Callback::fillThisBuffer(
-        IOMX::buffer_id bufferId,
-        const sp<MediaCodecBuffer> &buffer,
-        const sp<AMessage> &reply) {
-    sp<AMessage> notify(mNotify->dup());
-    notify->setInt32("what", kWhatFillThisBuffer);
-    notify->setInt32("buffer-id", bufferId);
-    notify->setObject("buffer", buffer);
-    notify->setMessage("reply", reply);
-    notify->post();
-}
-
-void Sf2Callback::drainThisBuffer(
-        IOMX::buffer_id bufferId,
-        const sp<MediaCodecBuffer> &buffer,
-        int32_t flags,
-        const sp<AMessage> &reply) {
-    sp<AMessage> notify(mNotify->dup());
-    notify->setInt32("what", kWhatDrainThisBuffer);
-    notify->setInt32("buffer-id", bufferId);
-    notify->setObject("buffer", buffer);
-    notify->setInt32("flags", flags);
-    notify->setMessage("reply", reply);
-    notify->post();
-}
-
-void Sf2Callback::onEos(status_t err) {
-    sp<AMessage> notify(mNotify->dup());
-    notify->setInt32("what", kWhatEOS);
-    notify->setInt32("err", err);
-    notify->post();
-}
-
-void Sf2Callback::onStopCompleted() {
-    sp<AMessage> notify(mNotify->dup());
-    notify->setInt32("what", kWhatStopCompleted);
-    notify->post();
-}
-
-void Sf2Callback::onReleaseCompleted() {
-    sp<AMessage> notify(mNotify->dup());
-    notify->setInt32("what", kWhatReleaseCompleted);
-    notify->post();
-}
-
-void Sf2Callback::onFlushCompleted() {
-    sp<AMessage> notify(mNotify->dup());
-    notify->setInt32("what", kWhatFlushCompleted);
-    notify->post();
-}
-
-void Sf2Callback::onError(status_t err, enum ActionCode actionCode) {
-    sp<AMessage> notify(mNotify->dup());
-    notify->setInt32("what", kWhatError);
-    notify->setInt32("err", err);
-    notify->setInt32("actionCode", actionCode);
-    notify->post();
-}
-
-}  // namespace
-
-struct Controller : public AHandler {
-    Controller(const char *uri, bool decodeAudio,
-               const sp<Surface> &surface, bool renderToSurface)
-        : mURI(uri),
-          mDecodeAudio(decodeAudio),
-          mSurface(surface),
-          mRenderToSurface(renderToSurface),
-          mCodec(new ACodec),
-          mIsVorbis(false) {
-        CHECK(!mDecodeAudio || mSurface == NULL);
-    }
-
-    void startAsync() {
-        (new AMessage(kWhatStart, this))->post();
-    }
-
-protected:
-    virtual ~Controller() {
-    }
-
-    virtual void printStatistics() {
-        int64_t delayUs = ALooper::GetNowUs() - mStartTimeUs;
-
-        if (mDecodeAudio) {
-            printf("%" PRId64 " bytes received. %.2f KB/sec\n",
-            mTotalBytesReceived,
-            mTotalBytesReceived * 1E6 / 1024 / delayUs);
-        } else {
-            printf("%d frames decoded, %.2f fps. %" PRId64 " bytes "
-                    "received. %.2f KB/sec\n",
-            mNumOutputBuffersReceived,
-            mNumOutputBuffersReceived * 1E6 / delayUs,
-            mTotalBytesReceived,
-            mTotalBytesReceived * 1E6 / 1024 / delayUs);
-        }
-    }
-
-    virtual void onMessageReceived(const sp<AMessage> &msg) {
-        if (ctrlc) {
-            printf("\n");
-            printStatistics();
-            (new AMessage(kWhatStop, this))->post();
-            ctrlc = false;
-        }
-        switch (msg->what()) {
-            case kWhatStart:
-            {
-#if 1
-                mDecodeLooper = looper();
-#else
-                mDecodeLooper = new ALooper;
-                mDecodeLooper->setName("sf2 decode looper");
-                mDecodeLooper->start();
-#endif
-
-                sp<DataSource> dataSource =
-                    DataSource::CreateFromURI(
-                            NULL /* httpService */, mURI.c_str());
-
-                sp<IMediaExtractor> extractor =
-                    MediaExtractor::Create(dataSource);
-
-                for (size_t i = 0; i < extractor->countTracks(); ++i) {
-                    sp<MetaData> meta = extractor->getTrackMetaData(i);
-
-                    const char *mime;
-                    CHECK(meta->findCString(kKeyMIMEType, &mime));
-
-                    if (!strncasecmp(mDecodeAudio ? "audio/" : "video/",
-                                     mime, 6)) {
-                        mSource = extractor->getTrack(i);
-
-                        if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
-                            mIsVorbis = true;
-                        } else {
-                            mIsVorbis = false;
-                        }
-                        break;
-                    }
-                }
-                if (mSource == NULL) {
-                    printf("no %s track found\n", mDecodeAudio ? "audio" : "video");
-                    exit (1);
-                }
-
-                CHECK_EQ(mSource->start(), (status_t)OK);
-
-                mDecodeLooper->registerHandler(mCodec);
-
-                mCodec->setCallback(
-                        std::make_shared<Sf2Callback>(new AMessage(kWhatCodecNotify, this)));
-
-                sp<AMessage> format = makeFormat(mSource->getFormat());
-
-                if (mSurface != NULL) {
-                    format->setObject("surface", mSurface);
-                }
-
-                mCodec->initiateSetup(format);
-
-                mCSDIndex = 0;
-                mStartTimeUs = ALooper::GetNowUs();
-                mNumOutputBuffersReceived = 0;
-                mTotalBytesReceived = 0;
-                mLeftOverBuffer = NULL;
-                mFinalResult = OK;
-                mSeekState = SEEK_NONE;
-
-                // (new AMessage(kWhatSeek, this))->post(5000000ll);
-                break;
-            }
-
-            case kWhatSeek:
-            {
-                printf("+");
-                fflush(stdout);
-
-                CHECK(mSeekState == SEEK_NONE
-                        || mSeekState == SEEK_FLUSH_COMPLETED);
-
-                if (mLeftOverBuffer != NULL) {
-                    mLeftOverBuffer->release();
-                    mLeftOverBuffer = NULL;
-                }
-
-                mSeekState = SEEK_FLUSHING;
-                mSeekTimeUs = 30000000ll;
-
-                mCodec->signalFlush();
-                break;
-            }
-
-            case kWhatStop:
-            {
-                if (mLeftOverBuffer != NULL) {
-                    mLeftOverBuffer->release();
-                    mLeftOverBuffer = NULL;
-                }
-
-                CHECK_EQ(mSource->stop(), (status_t)OK);
-                mSource.clear();
-
-                mCodec->initiateShutdown();
-                break;
-            }
-
-            case kWhatCodecNotify:
-            {
-                int32_t what;
-                CHECK(msg->findInt32("what", &what));
-
-                if (what == kWhatFillThisBuffer) {
-                    onFillThisBuffer(msg);
-                } else if (what == kWhatDrainThisBuffer) {
-                    if ((mNumOutputBuffersReceived++ % 16) == 0) {
-                        printf(".");
-                        fflush(stdout);
-                    }
-
-                    onDrainThisBuffer(msg);
-                } else if (what == kWhatEOS
-                        || what == kWhatError) {
-                    printf((what == kWhatEOS) ? "$\n" : "E\n");
-
-                    printStatistics();
-                    (new AMessage(kWhatStop, this))->post();
-                } else if (what == kWhatFlushCompleted) {
-                    mSeekState = SEEK_FLUSH_COMPLETED;
-                    mCodec->signalResume();
-
-                    (new AMessage(kWhatSeek, this))->post(5000000ll);
-                } else if (what == kWhatStopCompleted ||
-                        what == kWhatReleaseCompleted) {
-                    mDecodeLooper->unregisterHandler(mCodec->id());
-
-                    if (mDecodeLooper != looper()) {
-                        mDecodeLooper->stop();
-                    }
-
-                    looper()->stop();
-                }
-                break;
-            }
-
-            default:
-                TRESPASS();
-                break;
-        }
-    }
-
-private:
-    enum {
-        kWhatStart             = 'strt',
-        kWhatStop              = 'stop',
-        kWhatCodecNotify       = 'noti',
-        kWhatSeek              = 'seek',
-    };
-
-    sp<ALooper> mDecodeLooper;
-
-    AString mURI;
-    bool mDecodeAudio;
-    sp<Surface> mSurface;
-    bool mRenderToSurface;
-    sp<ACodec> mCodec;
-    sp<IMediaSource> mSource;
-    bool mIsVorbis;
-
-    Vector<sp<ABuffer> > mCSD;
-    size_t mCSDIndex;
-
-    MediaBuffer *mLeftOverBuffer;
-    status_t mFinalResult;
-
-    int64_t mStartTimeUs;
-    int32_t mNumOutputBuffersReceived;
-    int64_t mTotalBytesReceived;
-
-    enum SeekState {
-        SEEK_NONE,
-        SEEK_FLUSHING,
-        SEEK_FLUSH_COMPLETED,
-    };
-    SeekState mSeekState;
-    int64_t mSeekTimeUs;
-
-    sp<AMessage> makeFormat(const sp<MetaData> &meta) {
-        CHECK(mCSD.isEmpty());
-
-        const char *mime;
-        CHECK(meta->findCString(kKeyMIMEType, &mime));
-
-        sp<AMessage> msg = new AMessage;
-        msg->setString("mime", mime);
-
-        if (!strncasecmp("video/", mime, 6)) {
-            int32_t width, height;
-            CHECK(meta->findInt32(kKeyWidth, &width));
-            CHECK(meta->findInt32(kKeyHeight, &height));
-
-            msg->setInt32("width", width);
-            msg->setInt32("height", height);
-        } else {
-            CHECK(!strncasecmp("audio/", mime, 6));
-
-            int32_t numChannels, sampleRate;
-            CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
-            CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
-
-            msg->setInt32("channel-count", numChannels);
-            msg->setInt32("sample-rate", sampleRate);
-
-            int32_t isADTS;
-            if (meta->findInt32(kKeyIsADTS, &isADTS) && isADTS != 0) {
-                msg->setInt32("is-adts", true);
-            }
-        }
-
-        uint32_t type;
-        const void *data;
-        size_t size;
-        if (meta->findData(kKeyAVCC, &type, &data, &size)) {
-            // Parse the AVCDecoderConfigurationRecord
-
-            const uint8_t *ptr = (const uint8_t *)data;
-
-            CHECK(size >= 7);
-            CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
-            uint8_t profile __unused = ptr[1];
-            uint8_t level __unused = ptr[3];
-
-            // There is decodable content out there that fails the following
-            // assertion, let's be lenient for now...
-            // CHECK((ptr[4] >> 2) == 0x3f);  // reserved
-
-            size_t lengthSize __unused = 1 + (ptr[4] & 3);
-
-            // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
-            // violates it...
-            // CHECK((ptr[5] >> 5) == 7);  // reserved
-
-            size_t numSeqParameterSets = ptr[5] & 31;
-
-            ptr += 6;
-            size -= 6;
-
-            sp<ABuffer> buffer = new ABuffer(1024);
-            buffer->setRange(0, 0);
-
-            for (size_t i = 0; i < numSeqParameterSets; ++i) {
-                CHECK(size >= 2);
-                size_t length = U16_AT(ptr);
-
-                ptr += 2;
-                size -= 2;
-
-                CHECK(size >= length);
-
-                memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4);
-                memcpy(buffer->data() + buffer->size() + 4, ptr, length);
-                buffer->setRange(0, buffer->size() + 4 + length);
-
-                ptr += length;
-                size -= length;
-            }
-
-            buffer->meta()->setInt32("csd", true);
-            mCSD.push(buffer);
-
-            buffer = new ABuffer(1024);
-            buffer->setRange(0, 0);
-
-            CHECK(size >= 1);
-            size_t numPictureParameterSets = *ptr;
-            ++ptr;
-            --size;
-
-            for (size_t i = 0; i < numPictureParameterSets; ++i) {
-                CHECK(size >= 2);
-                size_t length = U16_AT(ptr);
-
-                ptr += 2;
-                size -= 2;
-
-                CHECK(size >= length);
-
-                memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4);
-                memcpy(buffer->data() + buffer->size() + 4, ptr, length);
-                buffer->setRange(0, buffer->size() + 4 + length);
-
-                ptr += length;
-                size -= length;
-            }
-
-            buffer->meta()->setInt32("csd", true);
-            mCSD.push(buffer);
-
-            msg->setBuffer("csd", buffer);
-        } else if (meta->findData(kKeyESDS, &type, &data, &size)) {
-            ESDS esds((const char *)data, size);
-            CHECK_EQ(esds.InitCheck(), (status_t)OK);
-
-            const void *codec_specific_data;
-            size_t codec_specific_data_size;
-            esds.getCodecSpecificInfo(
-                    &codec_specific_data, &codec_specific_data_size);
-
-            sp<ABuffer> buffer = new ABuffer(codec_specific_data_size);
-
-            memcpy(buffer->data(), codec_specific_data,
-                   codec_specific_data_size);
-
-            buffer->meta()->setInt32("csd", true);
-            mCSD.push(buffer);
-        } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) {
-            sp<ABuffer> buffer = new ABuffer(size);
-            memcpy(buffer->data(), data, size);
-
-            buffer->meta()->setInt32("csd", true);
-            mCSD.push(buffer);
-
-            CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size));
-
-            buffer = new ABuffer(size);
-            memcpy(buffer->data(), data, size);
-
-            buffer->meta()->setInt32("csd", true);
-            mCSD.push(buffer);
-        }
-
-        int32_t maxInputSize;
-        if (meta->findInt32(kKeyMaxInputSize, &maxInputSize)) {
-            msg->setInt32("max-input-size", maxInputSize);
-        }
-
-        return msg;
-    }
-
-    void onFillThisBuffer(const sp<AMessage> &msg) {
-        sp<AMessage> reply;
-        CHECK(msg->findMessage("reply", &reply));
-
-        if (mSource == NULL || mSeekState == SEEK_FLUSHING) {
-            reply->setInt32("err", ERROR_END_OF_STREAM);
-            reply->post();
-            return;
-        }
-
-        sp<ABuffer> outBuffer;
-        CHECK(msg->findBuffer("buffer", &outBuffer));
-
-        if (mCSDIndex < mCSD.size()) {
-            outBuffer = mCSD.editItemAt(mCSDIndex++);
-            outBuffer->meta()->setInt64("timeUs", 0);
-        } else {
-            size_t sizeLeft = outBuffer->capacity();
-            outBuffer->setRange(0, 0);
-
-            int32_t n = 0;
-
-            for (;;) {
-                MediaBuffer *inBuffer;
-
-                if (mLeftOverBuffer != NULL) {
-                    inBuffer = mLeftOverBuffer;
-                    mLeftOverBuffer = NULL;
-                } else if (mFinalResult != OK) {
-                    break;
-                } else {
-                    MediaSource::ReadOptions options;
-                    if (mSeekState == SEEK_FLUSH_COMPLETED) {
-                        options.setSeekTo(mSeekTimeUs);
-                        mSeekState = SEEK_NONE;
-                    }
-                    status_t err = mSource->read(&inBuffer, &options);
-
-                    if (err != OK) {
-                        mFinalResult = err;
-                        break;
-                    }
-                }
-
-                size_t sizeNeeded = inBuffer->range_length();
-                if (mIsVorbis) {
-                    // Vorbis data is suffixed with the number of
-                    // valid samples on the page.
-                    sizeNeeded += sizeof(int32_t);
-                }
-
-                if (sizeNeeded > sizeLeft) {
-                    if (outBuffer->size() == 0) {
-                        ALOGE("Unable to fit even a single input buffer of size %zu.",
-                             sizeNeeded);
-                    }
-                    CHECK_GT(outBuffer->size(), 0u);
-
-                    mLeftOverBuffer = inBuffer;
-                    break;
-                }
-
-                ++n;
-
-                if (outBuffer->size() == 0) {
-                    int64_t timeUs;
-                    CHECK(inBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
-
-                    outBuffer->meta()->setInt64("timeUs", timeUs);
-                }
-
-                memcpy(outBuffer->data() + outBuffer->size(),
-                       (const uint8_t *)inBuffer->data()
-                        + inBuffer->range_offset(),
-                       inBuffer->range_length());
-
-                if (mIsVorbis) {
-                    int32_t numPageSamples;
-                    if (!inBuffer->meta_data()->findInt32(
-                                kKeyValidSamples, &numPageSamples)) {
-                        numPageSamples = -1;
-                    }
-
-                    memcpy(outBuffer->data()
-                            + outBuffer->size() + inBuffer->range_length(),
-                           &numPageSamples, sizeof(numPageSamples));
-                }
-
-                outBuffer->setRange(
-                        0, outBuffer->size() + sizeNeeded);
-
-                sizeLeft -= sizeNeeded;
-
-                inBuffer->release();
-                inBuffer = NULL;
-
-                break;  // Don't coalesce
-            }
-
-            ALOGV("coalesced %d input buffers", n);
-
-            if (outBuffer->size() == 0) {
-                CHECK_NE(mFinalResult, (status_t)OK);
-
-                reply->setInt32("err", mFinalResult);
-                reply->post();
-                return;
-            }
-        }
-
-        reply->setBuffer("buffer", outBuffer);
-        reply->post();
-    }
-
-    void onDrainThisBuffer(const sp<AMessage> &msg) {
-        sp<ABuffer> buffer;
-        CHECK(msg->findBuffer("buffer", &buffer));
-
-        mTotalBytesReceived += buffer->size();
-
-        sp<AMessage> reply;
-        CHECK(msg->findMessage("reply", &reply));
-
-        if (mRenderToSurface) {
-            reply->setInt32("render", 1);
-        }
-
-        reply->post();
-    }
-
-    DISALLOW_EVIL_CONSTRUCTORS(Controller);
-};
-
-static void usage(const char *me) {
-    fprintf(stderr, "usage: %s\n", me);
-    fprintf(stderr, "       -h(elp)\n");
-    fprintf(stderr, "       -a(udio)\n");
-
-    fprintf(stderr,
-            "       -S(urface) Allocate output buffers on a surface.\n"
-            "       -R(ender)  Render surface-allocated buffers.\n");
-}
-
-int main(int argc, char **argv) {
-    android::ProcessState::self()->startThreadPool();
-
-    bool decodeAudio = false;
-    bool useSurface = false;
-    bool renderToSurface = false;
-
-    int res;
-    while ((res = getopt(argc, argv, "haSR")) >= 0) {
-        switch (res) {
-            case 'a':
-                decodeAudio = true;
-                break;
-
-            case 'S':
-                useSurface = true;
-                break;
-
-            case 'R':
-                renderToSurface = true;
-                break;
-
-            case '?':
-            case 'h':
-            default:
-            {
-                usage(argv[0]);
-                return 1;
-            }
-        }
-    }
-
-    argc -= optind;
-    argv += optind;
-
-    if (argc != 1) {
-        usage(argv[-optind]);
-        return 1;
-    }
-
-    sp<ALooper> looper = new ALooper;
-    looper->setName("sf2");
-
-    sp<SurfaceComposerClient> composerClient;
-    sp<SurfaceControl> control;
-    sp<Surface> surface;
-
-    if (!decodeAudio && useSurface) {
-        composerClient = new SurfaceComposerClient;
-        CHECK_EQ(composerClient->initCheck(), (status_t)OK);
-
-        control = composerClient->createSurface(
-                String8("A Surface"),
-                1280,
-                800,
-                PIXEL_FORMAT_RGB_565,
-                0);
-
-        CHECK(control != NULL);
-        CHECK(control->isValid());
-
-        SurfaceComposerClient::openGlobalTransaction();
-        CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
-        CHECK_EQ(control->show(), (status_t)OK);
-        SurfaceComposerClient::closeGlobalTransaction();
-
-        surface = control->getSurface();
-        CHECK(surface != NULL);
-
-        CHECK_EQ((status_t)OK,
-                 native_window_api_connect(
-                     surface.get(), NATIVE_WINDOW_API_MEDIA));
-    }
-
-    sp<Controller> controller =
-        new Controller(argv[0], decodeAudio, surface, renderToSurface);
-
-    looper->registerHandler(controller);
-
-    signal(SIGINT, mysighandler);
-
-    controller->startAsync();
-
-    CHECK_EQ(looper->start(true /* runOnCallingThread */), (status_t)OK);
-
-    looper->unregisterHandler(controller->id());
-
-    if (!decodeAudio && useSurface) {
-        CHECK_EQ((status_t)OK,
-                 native_window_api_disconnect(
-                     surface.get(), NATIVE_WINDOW_API_MEDIA));
-
-        composerClient->dispose();
-    }
-
-    return 0;
-}
-
diff --git a/services/audioflinger/AudioMixer.h b/include/media/AudioMixer.h
similarity index 99%
rename from services/audioflinger/AudioMixer.h
rename to include/media/AudioMixer.h
index 540caac..87ada76 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/include/media/AudioMixer.h
@@ -22,15 +22,14 @@
 #include <sys/types.h>
 
 #include <media/AudioBufferProvider.h>
+#include <media/AudioResampler.h>
 #include <media/AudioResamplerPublic.h>
+#include <media/BufferProviders.h>
 #include <media/nbaio/NBLog.h>
 #include <system/audio.h>
 #include <utils/Compat.h>
 #include <utils/threads.h>
 
-#include "AudioResampler.h"
-#include "BufferProviders.h"
-
 // FIXME This is actually unity gain, which might not be max in future, expressed in U.12
 #define MAX_GAIN_INT AudioMixer::UNITY_GAIN_INT
 
diff --git a/services/audioflinger/AudioResampler.h b/include/media/AudioResampler.h
similarity index 100%
rename from services/audioflinger/AudioResampler.h
rename to include/media/AudioResampler.h
diff --git a/services/audioflinger/BufferProviders.h b/include/media/BufferProviders.h
similarity index 96%
rename from services/audioflinger/BufferProviders.h
rename to include/media/BufferProviders.h
index 2a857fe..68b3f23 100644
--- a/services/audioflinger/BufferProviders.h
+++ b/include/media/BufferProviders.h
@@ -23,11 +23,15 @@
 #include <media/AudioBufferProvider.h>
 #include <system/audio.h>
 #include <system/audio_effect.h>
-#include <sonic.h>
 #include <utils/StrongPointer.h>
 
+// external forward declaration from external/sonic/sonic.h
+struct sonicStreamStruct;
+typedef struct sonicStreamStruct *sonicStream;
+
 namespace android {
 
+class EffectBufferHalInterface;
 class EffectHalInterface;
 class EffectsFactoryHalInterface;
 
@@ -108,6 +112,8 @@
 protected:
     sp<EffectsFactoryHalInterface> mEffectsFactory;
     sp<EffectHalInterface> mDownmixInterface;
+    sp<EffectBufferHalInterface> mInBuffer;
+    sp<EffectBufferHalInterface> mOutBuffer;
     effect_config_t    mDownmixConfig;
 
     // effect descriptor for the downmixer used by the mixer
diff --git a/services/audioflinger/LinearMap.h b/include/media/LinearMap.h
similarity index 100%
rename from services/audioflinger/LinearMap.h
rename to include/media/LinearMap.h
diff --git a/include/media/audiohal/EffectBufferHalInterface.h b/include/media/audiohal/EffectBufferHalInterface.h
new file mode 100644
index 0000000..102ec56
--- /dev/null
+++ b/include/media/audiohal/EffectBufferHalInterface.h
@@ -0,0 +1,58 @@
+/*
+ * 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_INTERFACE_H
+#define ANDROID_HARDWARE_EFFECT_BUFFER_HAL_INTERFACE_H
+
+#include <system/audio_effect.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+// Abstraction for an audio buffer. It may be a "mirror" for
+// a buffer that the effect chain doesn't own, or a buffer owned by
+// the effect chain.
+class EffectBufferHalInterface : public RefBase
+{
+  public:
+    virtual audio_buffer_t* audioBuffer() = 0;
+    virtual void* externalData() const = 0;
+    // To be used when interacting with the code that doesn't know about
+    // "mirrored" buffers.
+    virtual void* ptr() {
+        return externalData() != nullptr ? externalData() : audioBuffer()->raw;
+    }
+
+    virtual void setExternalData(void* external) = 0;
+    virtual void setFrameCount(size_t frameCount) = 0;
+
+    virtual void update() = 0;  // copies data from the external buffer, noop for allocated buffers
+    virtual void commit() = 0;  // copies data to the external buffer, noop for allocated buffers
+
+    static status_t allocate(size_t size, sp<EffectBufferHalInterface>* buffer);
+    static status_t mirror(void* external, size_t size, sp<EffectBufferHalInterface>* buffer);
+
+  protected:
+    // Subclasses can not be constructed directly by clients.
+    EffectBufferHalInterface() {}
+
+    virtual ~EffectBufferHalInterface() {}
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_EFFECT_BUFFER_HAL_INTERFACE_H
diff --git a/include/media/audiohal/EffectHalInterface.h b/include/media/audiohal/EffectHalInterface.h
index 7bbd3b5..7f9a6fd 100644
--- a/include/media/audiohal/EffectHalInterface.h
+++ b/include/media/audiohal/EffectHalInterface.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_HARDWARE_EFFECT_HAL_INTERFACE_H
 #define ANDROID_HARDWARE_EFFECT_HAL_INTERFACE_H
 
+#include <media/audiohal/EffectBufferHalInterface.h>
 #include <system/audio_effect.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
@@ -26,14 +27,20 @@
 class EffectHalInterface : public RefBase
 {
   public:
+    // Set the input buffer.
+    virtual status_t setInBuffer(const sp<EffectBufferHalInterface>& buffer) = 0;
+
+    // Set the output buffer.
+    virtual status_t setOutBuffer(const sp<EffectBufferHalInterface>& buffer) = 0;
+
     // 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) = 0;
+    virtual status_t process() = 0;
 
     // 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) = 0;
+    virtual status_t processReverse() = 0;
 
     // Send a command and receive a response to/from effect engine.
     virtual status_t command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
@@ -42,6 +49,9 @@
     // Returns the effect descriptor.
     virtual status_t getDescriptor(effect_descriptor_t *pDescriptor) = 0;
 
+    // Free resources on the remote side.
+    virtual status_t close() = 0;
+
   protected:
     // Subclasses can not be constructed directly by clients.
     EffectHalInterface() {}
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index d42012b..3420617 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -35,6 +35,7 @@
 namespace android {
 
 struct ABuffer;
+class ACodecBufferChannel;
 class MediaCodecBuffer;
 class MemoryDealer;
 struct DescribeColorFormat2Params;
@@ -43,10 +44,9 @@
 struct ACodec : public AHierarchicalStateMachine, public CodecBase {
     ACodec();
 
-    virtual void setNotificationMessage(const sp<AMessage> &msg);
-
     void initiateSetup(const sp<AMessage> &msg);
 
+    virtual std::shared_ptr<BufferChannelBase> getBufferChannel() override;
     virtual void initiateAllocateComponent(const sp<AMessage> &msg);
     virtual void initiateConfigureComponent(const sp<AMessage> &msg);
     virtual void initiateCreateInputSurface();
@@ -72,23 +72,6 @@
         handleMessage(msg);
     }
 
-    struct PortDescription : public CodecBase::PortDescription {
-        size_t countBuffers();
-        IOMX::buffer_id bufferIDAt(size_t index) const;
-        sp<MediaCodecBuffer> bufferAt(size_t index) const;
-
-    private:
-        friend struct ACodec;
-
-        Vector<IOMX::buffer_id> mBufferIDs;
-        Vector<sp<MediaCodecBuffer> > mBuffers;
-
-        PortDescription();
-        void addBuffer(IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer);
-
-        DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
-    };
-
     // Returns 0 if configuration is not supported.  NOTE: this is treated by
     // some OMX components as auto level, and by others as invalid level.
     static int /* OMX_VIDEO_AVCLEVELTYPE */ getAVCLevelFor(
@@ -218,8 +201,6 @@
     KeyedVector<int64_t, BufferStats> mBufferStats;
 #endif
 
-    sp<AMessage> mNotify;
-
     sp<UninitializedState> mUninitializedState;
     sp<LoadedState> mLoadedState;
     sp<LoadedToIdleState> mLoadedToIdleState;
@@ -296,6 +277,8 @@
     OMX_INDEXTYPE mDescribeColorAspectsIndex;
     OMX_INDEXTYPE mDescribeHDRStaticInfoIndex;
 
+    std::shared_ptr<ACodecBufferChannel> mBufferChannel;
+
     status_t setCyclicIntraMacroblockRefresh(const sp<AMessage> &msg, int32_t mode);
     status_t allocateBuffersOnPort(OMX_U32 portIndex);
     status_t freeBuffersOnPort(OMX_U32 portIndex);
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
index 516f698..cfbaea4 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -24,6 +24,7 @@
 
 #define STRINGIFY_ENUMS
 
+#include <media/ICrypto.h>
 #include <media/IOMX.h>
 #include <media/MediaCodecInfo.h>
 #include <media/stagefright/MediaErrors.h>
@@ -37,6 +38,7 @@
 
 namespace android {
 
+class BufferChannelBase;
 class BufferProducerWrapper;
 class MediaCodecBuffer;
 struct PersistentSurface;
@@ -44,43 +46,15 @@
 class Surface;
 
 struct CodecBase : public AHandler, /* static */ ColorUtils {
-    struct PortDescription;
-
     /**
      * This interface defines events firing from CodecBase back to MediaCodec.
      * All methods must not block.
      */
-    class Callback {
+    class CodecCallback {
     public:
-        virtual ~Callback() = default;
+        virtual ~CodecCallback() = default;
 
         /**
-         * Request MediaCodec to fill the specified input buffer.
-         *
-         * @param bufferId  ID of the buffer, assigned by underlying component.
-         * @param buffer    a buffer to be filled.
-         * @param reply     a message to post once MediaCodec has filled the
-         *                  buffer.
-         */
-        virtual void fillThisBuffer(
-                IOMX::buffer_id bufferId,
-                const sp<MediaCodecBuffer> &buffer,
-                const sp<AMessage> &reply) = 0;
-        /**
-         * Request MediaCodec to drain the specified output buffer.
-         *
-         * @param bufferId  ID of the buffer, assigned by underlying component.
-         * @param buffer    a buffer to be filled.
-         * @param flags     flags associated with this buffer (e.g. EOS).
-         * @param reply     a message to post once MediaCodec has filled the
-         *                  buffer.
-         */
-        virtual void drainThisBuffer(
-                IOMX::buffer_id bufferId,
-                const sp<MediaCodecBuffer> &buffer,
-                int32_t flags,
-                const sp<AMessage> &reply) = 0;
-        /**
          * Notify MediaCodec for seeing an output EOS.
          *
          * @param err the underlying cause of the EOS. If the value is neither
@@ -89,6 +63,10 @@
          */
         virtual void onEos(status_t err) = 0;
         /**
+         * Notify MediaCodec that start operation is complete.
+         */
+        virtual void onStartCompleted() = 0;
+        /**
          * Notify MediaCodec that stop operation is complete.
          */
         virtual void onStopCompleted() = 0;
@@ -169,27 +147,55 @@
          */
         virtual void onSignaledInputEOS(status_t err) = 0;
         /**
-         * Notify MediaCodec with the allocated buffers.
-         *
-         * @param portIndex zero for input port, one for output port.
-         * @param portDesc  a PortDescription object containing allocated
-         *                  buffers.
-         */
-        virtual void onBuffersAllocated(int32_t portIndex, const sp<PortDescription> &portDesc) = 0;
-        /**
          * Notify MediaCodec that output frames are rendered with information on
          * those frames.
          *
          * @param done  a list of rendered frames.
          */
         virtual void onOutputFramesRendered(const std::list<RenderedFrameInfo> &done) = 0;
+        /**
+         * Notify MediaCodec that output buffers are changed.
+         */
+        virtual void onOutputBuffersChanged() = 0;
     };
 
+    /**
+     * This interface defines events firing from BufferChannelBase back to MediaCodec.
+     * All methods must not block.
+     */
+    class BufferCallback {
+    public:
+        virtual ~BufferCallback() = default;
+
+        /**
+         * Notify MediaCodec that an input buffer is available with given index.
+         * When BufferChannelBase::getInputBufferArray() is not called,
+         * BufferChannelBase may report different buffers with the same index if
+         * MediaCodec already queued/discarded the buffer. After calling
+         * BufferChannelBase::getInputBufferArray(), the buffer and index match the
+         * returned array.
+         */
+        virtual void onInputBufferAvailable(
+                size_t index, const sp<MediaCodecBuffer> &buffer) = 0;
+        /**
+         * Notify MediaCodec that an output buffer is available with given index.
+         * When BufferChannelBase::getOutputBufferArray() is not called,
+         * BufferChannelBase may report different buffers with the same index if
+         * MediaCodec already queued/discarded the buffer. After calling
+         * BufferChannelBase::getOutputBufferArray(), the buffer and index match the
+         * returned array.
+         */
+        virtual void onOutputBufferAvailable(
+                size_t index, const sp<MediaCodecBuffer> &buffer) = 0;
+    };
     enum {
         kMaxCodecBufferSize = 8192 * 4096 * 4, // 8K RGBA
     };
 
-    void setCallback(std::shared_ptr<Callback> &&callback);
+    inline void setCallback(std::unique_ptr<CodecCallback> &&callback) {
+        mCallback = std::move(callback);
+    }
+    virtual std::shared_ptr<BufferChannelBase> getBufferChannel() = 0;
 
     virtual void initiateAllocateComponent(const sp<AMessage> &msg) = 0;
     virtual void initiateConfigureComponent(const sp<AMessage> &msg) = 0;
@@ -215,33 +221,104 @@
     virtual void signalSetParameters(const sp<AMessage> &msg) = 0;
     virtual void signalEndOfInputStream() = 0;
 
-    struct PortDescription : public RefBase {
-        virtual size_t countBuffers() = 0;
-        virtual IOMX::buffer_id bufferIDAt(size_t index) const = 0;
-        virtual sp<MediaCodecBuffer> bufferAt(size_t index) const = 0;
-
-    protected:
-        PortDescription();
-        virtual ~PortDescription();
-
-    private:
-        DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
-    };
-
     /*
      * Codec-related defines
      */
 
 protected:
-    CodecBase();
-    virtual ~CodecBase();
+    CodecBase() = default;
+    virtual ~CodecBase() = default;
 
-    std::shared_ptr<Callback> mCallback;
+    std::unique_ptr<CodecCallback> mCallback;
 
 private:
     DISALLOW_EVIL_CONSTRUCTORS(CodecBase);
 };
 
+/**
+ * A channel between MediaCodec and CodecBase object which manages buffer
+ * passing. Only MediaCodec is expected to call these methods, and
+ * underlying CodecBase implementation should define its own interface
+ * separately for itself.
+ *
+ * Concurrency assumptions:
+ *
+ * 1) Clients may access the object at multiple threads concurrently.
+ * 2) All methods do not call underlying CodecBase object while holding a lock.
+ * 3) Code inside critical section executes within 1ms.
+ */
+class BufferChannelBase {
+public:
+    virtual ~BufferChannelBase() = default;
+
+    inline void setCallback(std::unique_ptr<CodecBase::BufferCallback> &&callback) {
+        mCallback = std::move(callback);
+    }
+
+    inline void setCrypto(const sp<ICrypto> &crypto) {
+        mCrypto = crypto;
+    }
+
+    /**
+     * Queue an input buffer into the buffer channel.
+     *
+     * @return    OK if successful;
+     *            -ENOENT if the buffer is not known (TODO: this should be
+     *            handled gracefully in the future, here and below).
+     */
+    virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) = 0;
+    /**
+     * Queue a secure input buffer into the buffer channel.
+     *
+     * @return    OK if successful;
+     *            -ENOENT if the buffer is not known;
+     *            -ENOSYS if mCrypto is not set so that decryption is not
+     *            possible;
+     *            other errors if decryption failed.
+     */
+    virtual status_t queueSecureInputBuffer(
+            const sp<MediaCodecBuffer> &buffer,
+            bool secure,
+            const uint8_t *key,
+            const uint8_t *iv,
+            CryptoPlugin::Mode mode,
+            CryptoPlugin::Pattern pattern,
+            const CryptoPlugin::SubSample *subSamples,
+            size_t numSubSamples,
+            AString *errorDetailMsg) = 0;
+    /**
+     * Request buffer rendering at specified time.
+     *
+     * @param     timestampNs   nanosecond timestamp for rendering time.
+     * @return    OK if successful;
+     *            -ENOENT if the buffer is not known.
+     */
+    virtual status_t renderOutputBuffer(
+            const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) = 0;
+    /**
+     * Discard a buffer to the underlying CodecBase object.
+     *
+     * TODO: remove once this operation can be handled by just clearing the
+     * reference.
+     *
+     * @return    OK if successful;
+     *            -ENOENT if the buffer is not known.
+     */
+    virtual status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) = 0;
+    /**
+     * Clear and fill array with input buffers.
+     */
+    virtual void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) = 0;
+    /**
+     * Clear and fill array with output buffers.
+     */
+    virtual void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) = 0;
+
+protected:
+    std::unique_ptr<CodecBase::BufferCallback> mCallback;
+    sp<ICrypto> mCrypto;
+};
+
 }  // namespace android
 
 #endif  // CODEC_BASE_H_
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 1031de0..2e367bf 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -18,6 +18,9 @@
 
 #define MEDIA_CODEC_H_
 
+#include <memory>
+#include <vector>
+
 #include <gui/IGraphicBufferProducer.h>
 #include <media/hardware/CryptoAPI.h>
 #include <media/MediaCodecInfo.h>
@@ -32,12 +35,12 @@
 struct AMessage;
 struct AReplyToken;
 struct AString;
+class BufferChannelBase;
 struct CodecBase;
 class IBatteryStats;
 struct ICrypto;
 class MediaCodecBuffer;
 class IMemory;
-struct MemoryDealer;
 class IResourceManagerClient;
 class IResourceManagerService;
 struct PersistentSurface;
@@ -252,11 +255,9 @@
     };
 
     struct BufferInfo {
-        uint32_t mBufferID;
+        BufferInfo();
+
         sp<MediaCodecBuffer> mData;
-        sp<MediaCodecBuffer> mSecureData;
-        sp<IMemory> mSharedEncryptedBuffer;
-        sp<AMessage> mNotify;
         bool mOwnedByClient;
     };
 
@@ -301,7 +302,6 @@
     sp<AMessage> mInputFormat;
     sp<AMessage> mCallback;
     sp<AMessage> mOnFrameRenderedNotification;
-    sp<MemoryDealer> mDealer;
 
     sp<IResourceManagerClient> mResourceManagerClient;
     sp<ResourceManagerServiceProxy> mResourceManagerService;
@@ -327,8 +327,7 @@
     Mutex mBufferLock;
 
     List<size_t> mAvailPortBuffers[2];
-    Vector<BufferInfo> mPortBuffers[2];
-    Vector<sp<MediaCodecBuffer>> mPortBufferArrays[2];
+    std::vector<BufferInfo> mPortBuffers[2];
 
     int32_t mDequeueInputTimeoutGeneration;
     sp<AReplyToken> mDequeueInputReplyID;
@@ -345,6 +344,8 @@
     bool mHaveInputSurface;
     bool mHavePendingInputBuffers;
 
+    std::shared_ptr<BufferChannelBase> mBufferChannel;
+
     MediaCodec(const sp<ALooper> &looper, pid_t pid, uid_t uid);
 
     static sp<CodecBase> GetCodecBase(const AString &name, bool nameIsType = false);
diff --git a/include/media/stagefright/MediaFilter.h b/include/media/stagefright/MediaFilter.h
index c8b681c..0c10d11 100644
--- a/include/media/stagefright/MediaFilter.h
+++ b/include/media/stagefright/MediaFilter.h
@@ -21,6 +21,7 @@
 
 namespace android {
 
+class ACodecBufferChannel;
 struct GraphicBufferListener;
 class MemoryDealer;
 struct SimpleFilter;
@@ -28,6 +29,7 @@
 struct MediaFilter : public CodecBase {
     MediaFilter();
 
+    virtual std::shared_ptr<BufferChannelBase> getBufferChannel() override;
     virtual void initiateAllocateComponent(const sp<AMessage> &msg);
     virtual void initiateConfigureComponent(const sp<AMessage> &msg);
     virtual void initiateCreateInputSurface();
@@ -45,25 +47,6 @@
 
     virtual void onMessageReceived(const sp<AMessage> &msg);
 
-    struct PortDescription : public CodecBase::PortDescription {
-        virtual size_t countBuffers();
-        virtual IOMX::buffer_id bufferIDAt(size_t index) const;
-        virtual sp<MediaCodecBuffer> bufferAt(size_t index) const;
-
-    protected:
-        PortDescription();
-
-    private:
-        friend struct MediaFilter;
-
-        Vector<IOMX::buffer_id> mBufferIDs;
-        Vector<sp<MediaCodecBuffer> > mBuffers;
-
-        void addBuffer(IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer);
-
-        DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
-    };
-
 protected:
     virtual ~MediaFilter();
 
@@ -130,6 +113,8 @@
     sp<SimpleFilter> mFilter;
     sp<GraphicBufferListener> mGraphicBufferListener;
 
+    std::shared_ptr<ACodecBufferChannel> mBufferChannel;
+
     // helper functions
     void signalProcessBuffers();
     void signalError(status_t error);
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
new file mode 100644
index 0000000..03dce0c
--- /dev/null
+++ b/media/libaudioclient/Android.bp
@@ -0,0 +1,45 @@
+cc_library_shared {
+    name: "libaudioclient",
+    srcs: [
+        "AudioEffect.cpp",
+        "AudioPolicy.cpp",
+        "AudioRecord.cpp",
+        "AudioSystem.cpp",
+        "AudioTrack.cpp",
+        "AudioTrackShared.cpp",
+        "IAudioFlinger.cpp",
+        "IAudioFlingerClient.cpp",
+        "IAudioPolicyService.cpp",
+        "IAudioPolicyServiceClient.cpp",
+        "IAudioRecord.cpp",
+        "IAudioTrack.cpp",
+        "IEffect.cpp",
+        "IEffectClient.cpp",
+        "ToneGenerator.cpp",
+    ],
+    shared_libs: [
+        "liblog",
+        "libcutils",
+        "libutils",
+        "libbinder",
+        "libdl",
+        "libaudioutils",
+    ],
+    export_shared_lib_headers: ["libbinder"],
+    // for memory heap analysis
+    static_libs: [
+        "libc_malloc_debug_backtrace",
+        "libc_logging",
+    ],
+    cflags: [
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wall",
+    ],
+    sanitize: {
+        misc_undefined : [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/libaudioclient/Android.mk b/media/libaudioclient/Android.mk
deleted file mode 100644
index 348ab50..0000000
--- a/media/libaudioclient/Android.mk
+++ /dev/null
@@ -1,50 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES += \
-    AudioEffect.cpp \
-    AudioPolicy.cpp \
-    AudioRecord.cpp \
-    AudioSystem.cpp \
-    AudioTrack.cpp \
-    AudioTrackShared.cpp \
-    IAudioFlinger.cpp \
-    IAudioFlingerClient.cpp \
-    IAudioPolicyService.cpp \
-    IAudioPolicyServiceClient.cpp \
-    IAudioRecord.cpp \
-    IAudioTrack.cpp \
-    IEffect.cpp \
-    IEffectClient.cpp \
-    ToneGenerator.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog libcutils libutils libbinder \
-        libdl libaudioutils \
-
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder
-
-# for memory heap analysis
-LOCAL_STATIC_LIBRARIES := libc_malloc_debug_backtrace libc_logging
-
-LOCAL_MODULE:= libaudioclient
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_C_INCLUDES := \
-    $(TOP)/frameworks/native/include/media/openmax \
-    $(TOP)/frameworks/av/include/media/ \
-    $(TOP)/frameworks/av/media/libstagefright \
-    $(TOP)/frameworks/av/media/libmedia/aidl \
-    $(call include-path-for, audio-utils)
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := \
-    frameworks/av/include/media \
-    frameworks/av/media/libmedia/aidl
-
-LOCAL_CFLAGS += -Werror -Wno-error=deprecated-declarations -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
-
-include $(BUILD_SHARED_LIBRARY)
-
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 776e509..f0f413d 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -834,10 +834,15 @@
                     static_cast <audio_policy_dev_state_t>(data.readInt32());
             const char *device_address = data.readCString();
             const char *device_name = data.readCString();
-            reply->writeInt32(static_cast<uint32_t> (setDeviceConnectionState(device,
-                                                                              state,
-                                                                              device_address,
-                                                                              device_name)));
+            if (device_address == nullptr || device_name == nullptr) {
+                ALOGE("Bad Binder transaction: SET_DEVICE_CONNECTION_STATE for device %u", device);
+                reply->writeInt32(static_cast<int32_t> (BAD_VALUE));
+            } else {
+                reply->writeInt32(static_cast<uint32_t> (setDeviceConnectionState(device,
+                                                                                  state,
+                                                                                  device_address,
+                                                                                  device_name)));
+            }
             return NO_ERROR;
         } break;
 
@@ -846,8 +851,13 @@
             audio_devices_t device =
                     static_cast<audio_devices_t> (data.readInt32());
             const char *device_address = data.readCString();
-            reply->writeInt32(static_cast<uint32_t> (getDeviceConnectionState(device,
-                                                                              device_address)));
+            if (device_address == nullptr) {
+                ALOGE("Bad Binder transaction: GET_DEVICE_CONNECTION_STATE for device %u", device);
+                reply->writeInt32(static_cast<int32_t> (AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
+            } else {
+                reply->writeInt32(static_cast<uint32_t> (getDeviceConnectionState(device,
+                                                                                  device_address)));
+            }
             return NO_ERROR;
         } break;
 
@@ -857,9 +867,14 @@
                     static_cast <audio_devices_t>(data.readInt32());
             const char *device_address = data.readCString();
             const char *device_name = data.readCString();
-            reply->writeInt32(static_cast<uint32_t> (handleDeviceConfigChange(device,
-                                                                              device_address,
-                                                                              device_name)));
+            if (device_address == nullptr || device_name == nullptr) {
+                ALOGE("Bad Binder transaction: HANDLE_DEVICE_CONFIG_CHANGE for device %u", device);
+                reply->writeInt32(static_cast<int32_t> (BAD_VALUE));
+            } else {
+                reply->writeInt32(static_cast<uint32_t> (handleDeviceConfigChange(device,
+                                                                                  device_address,
+                                                                                  device_name)));
+            }
             return NO_ERROR;
         } break;
 
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.cpp b/media/libaudiohal/ConversionHelperHidl.cpp
index 1fabfbe..9f9eb75 100644
--- a/media/libaudiohal/ConversionHelperHidl.cpp
+++ b/media/libaudiohal/ConversionHelperHidl.cpp
@@ -82,26 +82,8 @@
     }
 }
 
-// static
-void ConversionHelperHidl::crashIfHalIsDead(const Status& status) {
-    LOG_ALWAYS_FATAL_IF(
-            status.transactionError() == DEAD_OBJECT, "HAL server crashed, need to restart");
-}
-
-status_t ConversionHelperHidl::processReturn(const char* funcName, const Status& status) {
-    const status_t st = status.transactionError();
-    ALOGE_IF(st, "%s %p %s: %s (from rpc)", mClassName, this, funcName, strerror(-st));
-    crashIfHalIsDead(status);
-    return st;
-}
-
-status_t ConversionHelperHidl::processReturn(
-        const char* funcName, const Status& status, hardware::audio::V2_0::Result retval) {
-    const status_t st = status.isOk() ? analyzeResult(retval) : status.transactionError();
-    ALOGE_IF(!status.isOk() && st, "%s %p %s: %s (from rpc)",
-            mClassName, this, funcName, strerror(-st));
-    crashIfHalIsDead(status);
-    return st;
+void ConversionHelperHidl::emitError(const char* funcName, const char* description) {
+    ALOGE("%s %p %s: %s (from rpc)", mClassName, this, funcName, description);
 }
 
 }  // namespace android
diff --git a/media/libaudiohal/ConversionHelperHidl.h b/media/libaudiohal/ConversionHelperHidl.h
index 428daf2..00d5b2c 100644
--- a/media/libaudiohal/ConversionHelperHidl.h
+++ b/media/libaudiohal/ConversionHelperHidl.h
@@ -30,9 +30,6 @@
 namespace android {
 
 class ConversionHelperHidl {
-  public:
-    static void crashIfHalIsDead(const Status& status);
-
   protected:
     static status_t keysFromHal(const String8& keys, hidl_vec<hidl_string> *hidlKeys);
     static status_t parametersFromHal(const String8& kvPairs, hidl_vec<ParameterValue> *hidlParams);
@@ -40,18 +37,22 @@
 
     ConversionHelperHidl(const char* className);
 
-    status_t processReturn(const char* funcName, const Return<void>& ret) {
-        return processReturn(funcName, ret.getStatus());
-    }
-
     template<typename R, typename T>
     status_t processReturn(const char* funcName, const Return<R>& ret, T *retval) {
-        if (ret.getStatus().isOk()) {
+        if (ret.isOk()) {
             // This way it also works for enum class to unscoped enum conversion.
             *retval = static_cast<T>(static_cast<R>(ret));
             return OK;
         }
-        return processReturn(funcName, ret.getStatus());
+        return processReturn(funcName, ret);
+    }
+
+    template<typename T>
+    status_t processReturn(const char* funcName, const Return<T>& ret) {
+        if (!ret.isOk()) {
+            emitError(funcName, ret.description().c_str());
+        }
+        return ret.isOk() ? OK : UNKNOWN_ERROR;
     }
 
     status_t processReturn(const char* funcName, const Return<hardware::audio::V2_0::Result>& ret) {
@@ -61,16 +62,19 @@
     template<typename T>
     status_t processReturn(
             const char* funcName, const Return<T>& ret, hardware::audio::V2_0::Result retval) {
-        return processReturn(funcName, ret.getStatus(), retval);
+        const status_t st = ret.isOk() ? analyzeResult(retval) : UNKNOWN_ERROR;
+        if (!ret.isOk()) {
+            emitError(funcName, ret.description().c_str());
+        }
+        return st;
     }
 
   private:
     const char* mClassName;
 
     static status_t analyzeResult(const hardware::audio::V2_0::Result& result);
-    status_t processReturn(const char* funcName, const Status& status);
-    status_t processReturn(
-            const char* funcName, const Status& status, hardware::audio::V2_0::Result retval);
+
+    void emitError(const char* funcName, const char* description);
 };
 
 }  // namespace android
diff --git a/media/libaudiohal/DevicesFactoryHalHidl.cpp b/media/libaudiohal/DevicesFactoryHalHidl.cpp
index efcc089..6444079 100644
--- a/media/libaudiohal/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/DevicesFactoryHalHidl.cpp
@@ -78,13 +78,12 @@
                     *device = new DeviceHalHidl(result);
                 }
             });
-    if (ret.getStatus().isOk()) {
+    if (ret.isOk()) {
         if (retval == Result::OK) return OK;
         else if (retval == Result::INVALID_ARGUMENTS) return BAD_VALUE;
         else return NO_INIT;
     }
-    ConversionHelperHidl::crashIfHalIsDead(ret.getStatus());
-    return ret.getStatus().transactionError();
+    return UNKNOWN_ERROR;
 }
 
 } // namespace android
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 1cd1997..f1f3f2a 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.isOk() || retval != Result::OK) {
+        return ret.isOk() ? analyzeResult(retval) : FAILED_TRANSACTION;
+    }
+    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.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;
@@ -103,8 +192,13 @@
                     effectDescriptorToHal(result, pDescriptor);
                 }
             });
-    ConversionHelperHidl::crashIfHalIsDead(ret.getStatus());
-    return ret.getStatus().isOk() ? analyzeResult(retval) : ret.getStatus().transactionError();
+    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..dd465c3 100644
--- a/media/libaudiohal/EffectHalLocal.cpp
+++ b/media/libaudiohal/EffectHalLocal.cpp
@@ -34,12 +34,37 @@
     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() {
+    if (mInBuffer == nullptr || mOutBuffer == nullptr) {
+        ALOGE_IF(mInBuffer == nullptr, "Input buffer not set");
+        ALOGE_IF(mOutBuffer == nullptr, "Output buffer not set");
+        return NO_INIT;
+    }
+    return (*mHandle)->process(mHandle, mInBuffer->audioBuffer(), mOutBuffer->audioBuffer());
+}
+
+status_t EffectHalLocal::processReverse() {
+    if ((*mHandle)->process_reverse != NULL) {
+        if (mInBuffer == nullptr || mOutBuffer == nullptr) {
+            ALOGE_IF(mInBuffer == nullptr, "Input buffer not set");
+            ALOGE_IF(mOutBuffer == nullptr, "Output buffer not set");
+            return NO_INIT;
+        }
+        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 +76,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;
 
diff --git a/media/libaudiohal/EffectsFactoryHalHidl.cpp b/media/libaudiohal/EffectsFactoryHalHidl.cpp
index bacbe4e..1ab5dad 100644
--- a/media/libaudiohal/EffectsFactoryHalHidl.cpp
+++ b/media/libaudiohal/EffectsFactoryHalHidl.cpp
@@ -43,7 +43,7 @@
     return EffectIsNullUuid(pEffectUuid);
 }
 
-EffectsFactoryHalHidl::EffectsFactoryHalHidl() {
+EffectsFactoryHalHidl::EffectsFactoryHalHidl() : ConversionHelperHidl("EffectsFactory"){
     mEffectsFactory = IEffectsFactory::getService("audio_effects_factory");
 }
 
@@ -60,12 +60,11 @@
                     mLastDescriptors = result;
                 }
             });
-    if (ret.getStatus().isOk()) {
+    if (ret.isOk()) {
         return retval == Result::OK ? OK : NO_INIT;
     }
     mLastDescriptors.resize(0);
-    ConversionHelperHidl::crashIfHalIsDead(ret.getStatus());
-    return ret.getStatus().transactionError();
+    return processReturn(__FUNCTION__, ret);
 }
 
 status_t EffectsFactoryHalHidl::queryNumberEffects(uint32_t *pNumEffects) {
@@ -104,13 +103,12 @@
                     EffectHalHidl::effectDescriptorToHal(result, pDescriptor);
                 }
             });
-    if (ret.getStatus().isOk()) {
+    if (ret.isOk()) {
         if (retval == Result::OK) return OK;
         else if (retval == Result::INVALID_ARGUMENTS) return NAME_NOT_FOUND;
         else return NO_INIT;
     }
-    ConversionHelperHidl::crashIfHalIsDead(ret.getStatus());
-    return ret.getStatus().transactionError();
+    return processReturn(__FUNCTION__, ret);
 }
 
 status_t EffectsFactoryHalHidl::createEffect(
@@ -128,13 +126,12 @@
                     *effect = new EffectHalHidl(result, effectId);
                 }
             });
-    if (ret.getStatus().isOk()) {
+    if (ret.isOk()) {
         if (retval == Result::OK) return OK;
         else if (retval == Result::INVALID_ARGUMENTS) return NAME_NOT_FOUND;
         else return NO_INIT;
     }
-    ConversionHelperHidl::crashIfHalIsDead(ret.getStatus());
-    return ret.getStatus().transactionError();
+    return processReturn(__FUNCTION__, ret);
 }
 
 status_t EffectsFactoryHalHidl::dumpEffects(int fd) {
@@ -143,8 +140,7 @@
     hidlHandle->data[0] = fd;
     Return<void> ret = mEffectsFactory->debugDump(hidlHandle);
     native_handle_delete(hidlHandle);
-    ConversionHelperHidl::crashIfHalIsDead(ret.getStatus());
-    return ret.getStatus().transactionError();
+    return processReturn(__FUNCTION__, ret);
 }
 
 } // namespace android
diff --git a/media/libaudiohal/EffectsFactoryHalHidl.h b/media/libaudiohal/EffectsFactoryHalHidl.h
index f16db17..e89f042 100644
--- a/media/libaudiohal/EffectsFactoryHalHidl.h
+++ b/media/libaudiohal/EffectsFactoryHalHidl.h
@@ -27,7 +27,7 @@
 using ::android::hardware::audio::effect::V2_0::IEffectsFactory;
 using ::android::hardware::hidl_vec;
 
-class EffectsFactoryHalHidl : public EffectsFactoryHalInterface
+class EffectsFactoryHalHidl : public EffectsFactoryHalInterface, public ConversionHelperHidl
 {
   public:
     // Returns the number of different effects in all loaded libraries.
diff --git a/media/libaudiohal/StreamHalHidl.cpp b/media/libaudiohal/StreamHalHidl.cpp
index 7f8d663..5943e22 100644
--- a/media/libaudiohal/StreamHalHidl.cpp
+++ b/media/libaudiohal/StreamHalHidl.cpp
@@ -342,7 +342,7 @@
                     }
                 }
             });
-    if (!ret.getStatus().isOk() || retval != Result::OK) {
+    if (!ret.isOk() || retval != Result::OK) {
         return processReturn("prepareForWriting", ret, retval);
     }
     if (!tempDataMQ || !tempDataMQ->isValid() || !tempStatusMQ || !tempStatusMQ->isValid()
@@ -456,7 +456,7 @@
                     timestamp->tv_nsec = hidlTimeStamp.tvNSec;
                 }
             });
-    if (ret.getStatus().isOk() && retval == Result::NOT_SUPPORTED) {
+    if (ret.isOk() && retval == Result::NOT_SUPPORTED) {
         mGetPresentationPositionNotSupported = true;
     }
     return processReturn("getPresentationPosition", ret, retval);
@@ -570,7 +570,7 @@
                     }
                 }
             });
-    if (!ret.getStatus().isOk() || retval != Result::OK) {
+    if (!ret.isOk() || retval != Result::OK) {
         return processReturn("prepareForReading", ret, retval);
     }
     if (!tempDataMQ || !tempDataMQ->isValid() || !tempStatusMQ || !tempStatusMQ->isValid()
diff --git a/media/libaudioprocessing/Android.mk b/media/libaudioprocessing/Android.mk
new file mode 100644
index 0000000..d47d158
--- /dev/null
+++ b/media/libaudioprocessing/Android.mk
@@ -0,0 +1,35 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    AudioMixer.cpp.arm \
+    AudioResampler.cpp.arm \
+    AudioResamplerCubic.cpp.arm \
+    AudioResamplerSinc.cpp.arm \
+    AudioResamplerDyn.cpp.arm \
+    BufferProviders.cpp \
+
+LOCAL_C_INCLUDES := \
+    $(TOP) \
+    $(call include-path-for, audio-utils) \
+
+LOCAL_SHARED_LIBRARIES := \
+    libaudiohal \
+    libaudioutils \
+    libcutils \
+    liblog \
+    libnbaio \
+    libsonic \
+    libutils \
+
+LOCAL_MODULE := libaudioprocessing
+
+LOCAL_CFLAGS := -Werror -Wall
+
+# uncomment to disable NEON on architectures that actually do support NEON, for benchmarking
+#LOCAL_CFLAGS += -DUSE_NEON=false
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/audioflinger/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
similarity index 99%
rename from services/audioflinger/AudioMixer.cpp
rename to media/libaudioprocessing/AudioMixer.cpp
index 945f4b3..a7d9f0f 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -18,7 +18,6 @@
 #define LOG_TAG "AudioMixer"
 //#define LOG_NDEBUG 0
 
-#include "Configuration.h"
 #include <stdint.h>
 #include <string.h>
 #include <stdlib.h>
@@ -36,9 +35,9 @@
 
 #include <audio_utils/primitives.h>
 #include <audio_utils/format.h>
+#include <media/AudioMixer.h>
 
 #include "AudioMixerOps.h"
-#include "AudioMixer.h"
 
 // The FCC_2 macro refers to the Fixed Channel Count of 2 for the legacy integer mixer.
 #ifndef FCC_2
diff --git a/services/audioflinger/AudioMixerOps.h b/media/libaudioprocessing/AudioMixerOps.h
similarity index 100%
rename from services/audioflinger/AudioMixerOps.h
rename to media/libaudioprocessing/AudioMixerOps.h
diff --git a/services/audioflinger/AudioResampler.cpp b/media/libaudioprocessing/AudioResampler.cpp
similarity index 99%
rename from services/audioflinger/AudioResampler.cpp
rename to media/libaudioprocessing/AudioResampler.cpp
index 43624a0..c761b38 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/media/libaudioprocessing/AudioResampler.cpp
@@ -22,11 +22,11 @@
 #include <stdlib.h>
 #include <sys/types.h>
 
-#include <android/log.h>
 #include <cutils/properties.h>
+#include <log/log.h>
 
 #include <audio_utils/primitives.h>
-#include "AudioResampler.h"
+#include <media/AudioResampler.h>
 #include "AudioResamplerSinc.h"
 #include "AudioResamplerCubic.h"
 #include "AudioResamplerDyn.h"
diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/media/libaudioprocessing/AudioResamplerCubic.cpp
similarity index 98%
rename from services/audioflinger/AudioResamplerCubic.cpp
rename to media/libaudioprocessing/AudioResamplerCubic.cpp
index d27dce7..9bcd8e1 100644
--- a/services/audioflinger/AudioResamplerCubic.cpp
+++ b/media/libaudioprocessing/AudioResamplerCubic.cpp
@@ -19,9 +19,9 @@
 #include <stdint.h>
 #include <string.h>
 #include <sys/types.h>
-#include <android/log.h>
 
-#include "AudioResampler.h"
+#include <log/log.h>
+
 #include "AudioResamplerCubic.h"
 
 namespace android {
diff --git a/services/audioflinger/AudioResamplerCubic.h b/media/libaudioprocessing/AudioResamplerCubic.h
similarity index 98%
rename from services/audioflinger/AudioResamplerCubic.h
rename to media/libaudioprocessing/AudioResamplerCubic.h
index f218fd9..defaf33 100644
--- a/services/audioflinger/AudioResamplerCubic.h
+++ b/media/libaudioprocessing/AudioResamplerCubic.h
@@ -21,7 +21,7 @@
 #include <sys/types.h>
 #include <android/log.h>
 
-#include "AudioResampler.h"
+#include <media/AudioResampler.h>
 
 namespace android {
 // ----------------------------------------------------------------------------
diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/media/libaudioprocessing/AudioResamplerDyn.cpp
similarity index 100%
rename from services/audioflinger/AudioResamplerDyn.cpp
rename to media/libaudioprocessing/AudioResamplerDyn.cpp
diff --git a/services/audioflinger/AudioResamplerDyn.h b/media/libaudioprocessing/AudioResamplerDyn.h
similarity index 98%
rename from services/audioflinger/AudioResamplerDyn.h
rename to media/libaudioprocessing/AudioResamplerDyn.h
index 6af9017..1840fc7 100644
--- a/services/audioflinger/AudioResamplerDyn.h
+++ b/media/libaudioprocessing/AudioResamplerDyn.h
@@ -21,7 +21,7 @@
 #include <sys/types.h>
 #include <android/log.h>
 
-#include "AudioResampler.h"
+#include <media/AudioResampler.h>
 
 namespace android {
 
diff --git a/services/audioflinger/AudioResamplerFirGen.h b/media/libaudioprocessing/AudioResamplerFirGen.h
similarity index 100%
rename from services/audioflinger/AudioResamplerFirGen.h
rename to media/libaudioprocessing/AudioResamplerFirGen.h
diff --git a/services/audioflinger/AudioResamplerFirOps.h b/media/libaudioprocessing/AudioResamplerFirOps.h
similarity index 100%
rename from services/audioflinger/AudioResamplerFirOps.h
rename to media/libaudioprocessing/AudioResamplerFirOps.h
diff --git a/services/audioflinger/AudioResamplerFirProcess.h b/media/libaudioprocessing/AudioResamplerFirProcess.h
similarity index 100%
rename from services/audioflinger/AudioResamplerFirProcess.h
rename to media/libaudioprocessing/AudioResamplerFirProcess.h
diff --git a/services/audioflinger/AudioResamplerFirProcessNeon.h b/media/libaudioprocessing/AudioResamplerFirProcessNeon.h
similarity index 100%
rename from services/audioflinger/AudioResamplerFirProcessNeon.h
rename to media/libaudioprocessing/AudioResamplerFirProcessNeon.h
diff --git a/services/audioflinger/AudioResamplerFirProcessSSE.h b/media/libaudioprocessing/AudioResamplerFirProcessSSE.h
similarity index 100%
rename from services/audioflinger/AudioResamplerFirProcessSSE.h
rename to media/libaudioprocessing/AudioResamplerFirProcessSSE.h
diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/media/libaudioprocessing/AudioResamplerSinc.cpp
similarity index 100%
rename from services/audioflinger/AudioResamplerSinc.cpp
rename to media/libaudioprocessing/AudioResamplerSinc.cpp
diff --git a/services/audioflinger/AudioResamplerSinc.h b/media/libaudioprocessing/AudioResamplerSinc.h
similarity index 98%
rename from services/audioflinger/AudioResamplerSinc.h
rename to media/libaudioprocessing/AudioResamplerSinc.h
index df8b45a..f6dcf91 100644
--- a/services/audioflinger/AudioResamplerSinc.h
+++ b/media/libaudioprocessing/AudioResamplerSinc.h
@@ -21,7 +21,7 @@
 #include <sys/types.h>
 #include <android/log.h>
 
-#include "AudioResampler.h"
+#include <media/AudioResampler.h>
 
 namespace android {
 
diff --git a/services/audioflinger/AudioResamplerSincDown.h b/media/libaudioprocessing/AudioResamplerSincDown.h
similarity index 100%
rename from services/audioflinger/AudioResamplerSincDown.h
rename to media/libaudioprocessing/AudioResamplerSincDown.h
diff --git a/services/audioflinger/AudioResamplerSincUp.h b/media/libaudioprocessing/AudioResamplerSincUp.h
similarity index 100%
rename from services/audioflinger/AudioResamplerSincUp.h
rename to media/libaudioprocessing/AudioResamplerSincUp.h
diff --git a/services/audioflinger/BufferProviders.cpp b/media/libaudioprocessing/BufferProviders.cpp
similarity index 92%
rename from services/audioflinger/BufferProviders.cpp
rename to media/libaudioprocessing/BufferProviders.cpp
index ba5f7b6..8341a1e 100644
--- a/services/audioflinger/BufferProviders.cpp
+++ b/media/libaudioprocessing/BufferProviders.cpp
@@ -19,16 +19,15 @@
 
 #include <audio_utils/primitives.h>
 #include <audio_utils/format.h>
+#include <external/sonic/sonic.h>
+#include <media/audiohal/EffectBufferHalInterface.h>
 #include <media/audiohal/EffectHalInterface.h>
 #include <media/audiohal/EffectsFactoryHalInterface.h>
 #include <media/AudioResamplerPublic.h>
+#include <media/BufferProviders.h>
 #include <system/audio_effects/effect_downmix.h>
-
 #include <utils/Log.h>
 
-#include "Configuration.h"
-#include "BufferProviders.h"
-
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
 #endif
@@ -179,17 +178,44 @@
              EFFECT_CONFIG_FORMAT | EFFECT_CONFIG_ACC_MODE;
      mDownmixConfig.outputCfg.mask = mDownmixConfig.inputCfg.mask;
 
+     status_t status;
+     status = EffectBufferHalInterface::mirror(
+             nullptr,
+             audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(inputChannelMask),
+             &mInBuffer);
+     if (status != 0) {
+         ALOGE("DownmixerBufferProvider() error %d while creating input buffer", status);
+         mDownmixInterface.clear();
+         mEffectsFactory.clear();
+         return;
+     }
+     status = EffectBufferHalInterface::mirror(
+             nullptr,
+             audio_bytes_per_sample(format) * audio_channel_count_from_out_mask(outputChannelMask),
+             &mOutBuffer);
+     if (status != 0) {
+         ALOGE("DownmixerBufferProvider() error %d while creating output buffer", status);
+         mInBuffer.clear();
+         mDownmixInterface.clear();
+         mEffectsFactory.clear();
+         return;
+     }
+     mDownmixInterface->setInBuffer(mInBuffer);
+     mDownmixInterface->setOutBuffer(mOutBuffer);
+
      int cmdStatus;
      uint32_t replySize = sizeof(int);
 
      // Configure downmixer
-     status_t status = mDownmixInterface->command(
+     status = mDownmixInterface->command(
              EFFECT_CMD_SET_CONFIG /*cmdCode*/, sizeof(effect_config_t) /*cmdSize*/,
              &mDownmixConfig /*pCmdData*/,
              &replySize, &cmdStatus /*pReplyData*/);
      if (status != 0 || cmdStatus != 0) {
          ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while configuring downmixer",
                  status, cmdStatus);
+         mOutBuffer.clear();
+         mInBuffer.clear();
          mDownmixInterface.clear();
          mEffectsFactory.clear();
          return;
@@ -203,6 +229,8 @@
      if (status != 0 || cmdStatus != 0) {
          ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while enabling downmixer",
                  status, cmdStatus);
+         mOutBuffer.clear();
+         mInBuffer.clear();
          mDownmixInterface.clear();
          mEffectsFactory.clear();
          return;
@@ -228,6 +256,8 @@
      if (status != 0 || cmdStatus != 0) {
          ALOGE("DownmixerBufferProvider() error %d cmdStatus %d while setting downmix type",
                  status, cmdStatus);
+         mOutBuffer.clear();
+         mInBuffer.clear();
          mDownmixInterface.clear();
          mEffectsFactory.clear();
          return;
@@ -238,18 +268,26 @@
 DownmixerBufferProvider::~DownmixerBufferProvider()
 {
     ALOGV("~DownmixerBufferProvider (%p)", this);
+    if (mDownmixInterface != 0) {
+        mDownmixInterface->close();
+    }
 }
 
 void DownmixerBufferProvider::copyFrames(void *dst, const void *src, size_t frames)
 {
-    mDownmixConfig.inputCfg.buffer.frameCount = frames;
-    mDownmixConfig.inputCfg.buffer.raw = const_cast<void *>(src);
-    mDownmixConfig.outputCfg.buffer.frameCount = frames;
-    mDownmixConfig.outputCfg.buffer.raw = dst;
+    mInBuffer->setExternalData(const_cast<void*>(src));
+    mInBuffer->setFrameCount(frames);
+    mInBuffer->update();
+    mOutBuffer->setExternalData(dst);
+    mOutBuffer->setFrameCount(frames);
+    mOutBuffer->update();
     // may be in-place if src == dst.
-    status_t res = mDownmixInterface->process(
-            &mDownmixConfig.inputCfg.buffer, &mDownmixConfig.outputCfg.buffer);
-    ALOGE_IF(res != OK, "DownmixBufferProvider error %d", res);
+    status_t res = mDownmixInterface->process();
+    if (res == OK) {
+        mOutBuffer->commit();
+    } else {
+        ALOGE("DownmixBufferProvider error %d", res);
+    }
 }
 
 /* call once in a pthread_once handler. */
diff --git a/services/audioflinger/audio-resampler/Android.mk b/media/libaudioprocessing/audio-resampler/Android.mk
similarity index 100%
rename from services/audioflinger/audio-resampler/Android.mk
rename to media/libaudioprocessing/audio-resampler/Android.mk
diff --git a/services/audioflinger/audio-resampler/AudioResamplerCoefficients.cpp b/media/libaudioprocessing/audio-resampler/AudioResamplerCoefficients.cpp
similarity index 100%
rename from services/audioflinger/audio-resampler/AudioResamplerCoefficients.cpp
rename to media/libaudioprocessing/audio-resampler/AudioResamplerCoefficients.cpp
diff --git a/services/audioflinger/audio-resampler/filter_coefficients.h b/media/libaudioprocessing/audio-resampler/filter_coefficients.h
similarity index 100%
rename from services/audioflinger/audio-resampler/filter_coefficients.h
rename to media/libaudioprocessing/audio-resampler/filter_coefficients.h
diff --git a/media/libaudioprocessing/tests/Android.mk b/media/libaudioprocessing/tests/Android.mk
new file mode 100644
index 0000000..23e1c3a
--- /dev/null
+++ b/media/libaudioprocessing/tests/Android.mk
@@ -0,0 +1,87 @@
+# Build the unit tests for libaudioprocessing
+
+LOCAL_PATH := $(call my-dir)
+
+#
+# resampler unit test
+#
+include $(CLEAR_VARS)
+
+LOCAL_SHARED_LIBRARIES := \
+    libaudioutils \
+    libaudioprocessing \
+    libcutils \
+    liblog \
+    libutils \
+
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+
+LOCAL_SRC_FILES := \
+    resampler_tests.cpp
+
+LOCAL_MODULE := resampler_tests
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CFLAGS := -Werror -Wall
+
+include $(BUILD_NATIVE_TEST)
+
+#
+# audio mixer test tool
+#
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    test-mixer.cpp \
+
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+
+LOCAL_STATIC_LIBRARIES := \
+    libsndfile \
+
+LOCAL_SHARED_LIBRARIES := \
+    libaudioprocessing \
+    libaudioutils \
+    libcutils \
+    liblog \
+    libutils \
+
+LOCAL_MODULE := test-mixer
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -Werror -Wall
+
+include $(BUILD_EXECUTABLE)
+
+#
+# build audio resampler test tool
+#
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    test-resampler.cpp \
+
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+
+LOCAL_STATIC_LIBRARIES := \
+    libsndfile \
+
+LOCAL_SHARED_LIBRARIES := \
+    libaudioprocessing \
+    libaudioutils \
+    libcutils \
+    liblog \
+    libutils \
+
+LOCAL_MODULE := test-resampler
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS := -Werror -Wall
+
+include $(BUILD_EXECUTABLE)
diff --git a/services/audioflinger/tests/README b/media/libaudioprocessing/tests/README
similarity index 61%
rename from services/audioflinger/tests/README
rename to media/libaudioprocessing/tests/README
index 508e960..ed7e2ed 100644
--- a/services/audioflinger/tests/README
+++ b/media/libaudioprocessing/tests/README
@@ -1,9 +1,9 @@
 For libsonic dependency:
-pushd external/sonic
+pushd $ANDROID_BUILD_TOP/external/sonic
 mm
 popd
 
-To build resampler library:
+To build audio processing library:
 pushd ..
 Optionally uncomment USE_NEON=false in Android.mk
 mm
diff --git a/services/audioflinger/tests/build_and_run_all_unit_tests.sh b/media/libaudioprocessing/tests/build_and_run_all_unit_tests.sh
similarity index 79%
rename from services/audioflinger/tests/build_and_run_all_unit_tests.sh
rename to media/libaudioprocessing/tests/build_and_run_all_unit_tests.sh
index 9a71096..704d095 100755
--- a/services/audioflinger/tests/build_and_run_all_unit_tests.sh
+++ b/media/libaudioprocessing/tests/build_and_run_all_unit_tests.sh
@@ -8,7 +8,7 @@
 # ensure we have mm
 . $ANDROID_BUILD_TOP/build/envsetup.sh
 
-pushd $ANDROID_BUILD_TOP/frameworks/av/services/audioflinger/
+pushd $ANDROID_BUILD_TOP/frameworks/av/media/libaudioprocessing
 pwd
 mm
 
@@ -19,6 +19,6 @@
 adb push $OUT/data/nativetest/resampler_tests/resampler_tests /data/nativetest/resampler_tests/resampler_tests
 adb push $OUT/data/nativetest64/resampler_tests/resampler_tests /data/nativetest64/resampler_tests/resampler_tests
 
-sh $ANDROID_BUILD_TOP/frameworks/av/services/audioflinger/tests/run_all_unit_tests.sh
+sh $ANDROID_BUILD_TOP/frameworks/av/media/libaudioprocessing/tests/run_all_unit_tests.sh
 
 popd
diff --git a/services/audioflinger/tests/mixer_to_wav_tests.sh b/media/libaudioprocessing/tests/mixer_to_wav_tests.sh
similarity index 95%
rename from services/audioflinger/tests/mixer_to_wav_tests.sh
rename to media/libaudioprocessing/tests/mixer_to_wav_tests.sh
index d0482a1..72b02fc 100755
--- a/services/audioflinger/tests/mixer_to_wav_tests.sh
+++ b/media/libaudioprocessing/tests/mixer_to_wav_tests.sh
@@ -37,7 +37,7 @@
 # ensure we have mm
 . $ANDROID_BUILD_TOP/build/envsetup.sh
 
-pushd $ANDROID_BUILD_TOP/frameworks/av/services/audioflinger/
+pushd $ANDROID_BUILD_TOP/frameworks/av/media/libaudioprocessing
 
 # build
 pwd
@@ -46,7 +46,8 @@
 # send to device
 echo "waiting for device"
 adb root && adb wait-for-device remount
-adb push $OUT/system/lib/libaudioresampler.so /system/lib
+adb push $OUT/system/lib/libaudioprocessing.so /system/lib
+adb push $OUT/system/lib64/libaudioprocessing.so /system/lib64
 adb push $OUT/system/bin/test-mixer /system/bin
 
 # createwav creates a series of WAV files testing various
diff --git a/services/audioflinger/tests/resampler_tests.cpp b/media/libaudioprocessing/tests/resampler_tests.cpp
similarity index 99%
rename from services/audioflinger/tests/resampler_tests.cpp
rename to media/libaudioprocessing/tests/resampler_tests.cpp
index 77a265f..8d5e016 100644
--- a/services/audioflinger/tests/resampler_tests.cpp
+++ b/media/libaudioprocessing/tests/resampler_tests.cpp
@@ -36,7 +36,7 @@
 #include <gtest/gtest.h>
 #include <media/AudioBufferProvider.h>
 
-#include "AudioResampler.h"
+#include <media/AudioResampler.h>
 #include "test_utils.h"
 
 template <typename T>
diff --git a/services/audioflinger/tests/run_all_unit_tests.sh b/media/libaudioprocessing/tests/run_all_unit_tests.sh
similarity index 100%
rename from services/audioflinger/tests/run_all_unit_tests.sh
rename to media/libaudioprocessing/tests/run_all_unit_tests.sh
diff --git a/services/audioflinger/tests/test-mixer.cpp b/media/libaudioprocessing/tests/test-mixer.cpp
similarity index 99%
rename from services/audioflinger/tests/test-mixer.cpp
rename to media/libaudioprocessing/tests/test-mixer.cpp
index 65e22da..75dbf91 100644
--- a/services/audioflinger/tests/test-mixer.cpp
+++ b/media/libaudioprocessing/tests/test-mixer.cpp
@@ -21,7 +21,7 @@
 #include <audio_utils/primitives.h>
 #include <audio_utils/sndfile.h>
 #include <media/AudioBufferProvider.h>
-#include "AudioMixer.h"
+#include <media/AudioMixer.h>
 #include "test_utils.h"
 
 /* Testing is typically through creation of an output WAV file from several
diff --git a/services/audioflinger/test-resample.cpp b/media/libaudioprocessing/tests/test-resampler.cpp
similarity index 98%
rename from services/audioflinger/test-resample.cpp
rename to media/libaudioprocessing/tests/test-resampler.cpp
index bae3c5b..fbc9326 100644
--- a/services/audioflinger/test-resample.cpp
+++ b/media/libaudioprocessing/tests/test-resampler.cpp
@@ -29,7 +29,7 @@
 #include <audio_utils/sndfile.h>
 #include <utils/Vector.h>
 #include <media/AudioBufferProvider.h>
-#include "AudioResampler.h"
+#include <media/AudioResampler.h>
 
 using namespace android;
 
diff --git a/services/audioflinger/tests/test_utils.h b/media/libaudioprocessing/tests/test_utils.h
similarity index 98%
rename from services/audioflinger/tests/test_utils.h
rename to media/libaudioprocessing/tests/test_utils.h
index 283c768..b61a929 100644
--- a/services/audioflinger/tests/test_utils.h
+++ b/media/libaudioprocessing/tests/test_utils.h
@@ -17,6 +17,12 @@
 #ifndef ANDROID_AUDIO_TEST_UTILS_H
 #define ANDROID_AUDIO_TEST_UTILS_H
 
+#ifndef LOG_TAG
+#define LOG_TAG "test_utils"
+#endif
+
+#include <log/log.h>
+
 #include <audio_utils/sndfile.h>
 
 #ifndef ARRAY_SIZE
diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c
index 323930a..f27d5ca 100644
--- a/media/libeffects/downmix/EffectDownmix.c
+++ b/media/libeffects/downmix/EffectDownmix.c
@@ -22,7 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "EffectDownmix.h"
 
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index 74d489b..554c14d 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -24,10 +24,10 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <android/log.h>
 #include <cutils/config_utils.h>
 #include <cutils/misc.h>
 #include <cutils/properties.h>
+#include <log/log.h>
 
 #include <system/audio_effects/audio_effects_conf.h>
 
diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h b/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
index 4f9f438..7ea0593 100644
--- a/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
+++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
@@ -21,7 +21,7 @@
 #endif
 //#define LOG_NDEBUG 0
 
-#include <android/log.h>
+#include <log/log.h>
 
 namespace le_fx {
 
diff --git a/media/libeffects/loudness/dsp/core/interpolator_base-inl.h b/media/libeffects/loudness/dsp/core/interpolator_base-inl.h
index bdb6818..fb87c79 100644
--- a/media/libeffects/loudness/dsp/core/interpolator_base-inl.h
+++ b/media/libeffects/loudness/dsp/core/interpolator_base-inl.h
@@ -21,7 +21,7 @@
 #endif
 //#define LOG_NDEBUG 0
 
-#include <android/log.h>
+#include <log/log.h>
 
 #include "dsp/core/basic.h"
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index f8a6a4e..d1ade1d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -16,6 +16,9 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "NuPlayer"
+
+#include <inttypes.h>
+
 #include <utils/Log.h>
 
 #include "NuPlayer.h"
@@ -1287,6 +1290,8 @@
     } else {
         ALOGW("resume called when renderer is gone or not set");
     }
+
+    mLastStartedPlayingTimeNs = systemTime();
 }
 
 status_t NuPlayer::onInstantiateSecureDecoders() {
@@ -1342,26 +1347,26 @@
         flags |= Renderer::FLAG_REAL_TIME;
     }
 
-    sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
-    sp<MetaData> videoMeta = mSource->getFormatMeta(false /* audio */);
-    if (audioMeta == NULL && videoMeta == NULL) {
+    bool hasAudio = (mSource->getFormat(true /* audio */) != NULL);
+    bool hasVideo = (mSource->getFormat(false /* audio */) != NULL);
+    if (!hasAudio && !hasVideo) {
         ALOGE("no metadata for either audio or video source");
         mSource->stop();
         mSourceStarted = false;
         notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_MALFORMED);
         return;
     }
-    ALOGV_IF(audioMeta == NULL, "no metadata for audio source");  // video only stream
+    ALOGV_IF(!hasAudio, "no metadata for audio source");  // video only stream
+
+    sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
 
     audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
     if (mAudioSink != NULL) {
         streamType = mAudioSink->getAudioStreamType();
     }
 
-    sp<AMessage> videoFormat = mSource->getFormat(false /* audio */);
-
     mOffloadAudio =
-        canOffloadStream(audioMeta, (videoFormat != NULL), mSource->isStreaming(), streamType)
+        canOffloadStream(audioMeta, hasVideo, mSource->isStreaming(), streamType)
                 && (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
     if (mOffloadAudio) {
         flags |= Renderer::FLAG_OFFLOAD_AUDIO;
@@ -1396,6 +1401,8 @@
         mAudioDecoder->setRenderer(mRenderer);
     }
 
+    mLastStartedPlayingTimeNs = systemTime();
+
     postScanSources();
 }
 
@@ -1414,6 +1421,16 @@
     } else {
         ALOGW("pause called when renderer is gone or not set");
     }
+
+    sp<NuPlayerDriver> driver = mDriver.promote();
+    if (driver != NULL) {
+        int64_t now = systemTime();
+        int64_t played = now - mLastStartedPlayingTimeNs;
+        ALOGD("played from %" PRId64 " to %" PRId64 " = %" PRId64 ,
+              mLastStartedPlayingTimeNs, now, played);
+
+        driver->notifyMorePlayingTimeUs((played+500)/1000);
+    }
 }
 
 bool NuPlayer::audioDecoderStillNeeded() {
@@ -1697,6 +1714,16 @@
         notifyListener(MEDIA_SET_VIDEO_SIZE, 0, 0);
         return;
     }
+    int32_t err = OK;
+    inputFormat->findInt32("err", &err);
+    if (err == -EWOULDBLOCK) {
+        ALOGW("Video meta is not available yet!");
+        return;
+    }
+    if (err != OK) {
+        ALOGW("Something is wrong with video meta!");
+        return;
+    }
 
     int32_t displayWidth, displayHeight;
     if (outputFormat != NULL) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index c8b0102..6f737bb 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -158,6 +158,8 @@
     int32_t mVideoDecoderGeneration;
     int32_t mRendererGeneration;
 
+    int64_t mLastStartedPlayingTimeNs;
+
     int64_t mPreviousSeekTimeUs;
 
     List<sp<Action> > mDeferredActions;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 6ec79e6..f7e56e4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -31,8 +31,14 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
+#include <media/IMediaAnalyticsService.h>
+
+static const int kDumpLockRetries = 50;
+static const int kDumpLockSleepUs = 20000;
+
 namespace android {
 
+
 NuPlayerDriver::NuPlayerDriver(pid_t pid)
     : mState(STATE_IDLE),
       mIsAsyncPrepare(false),
@@ -41,14 +47,20 @@
       mDurationUs(-1),
       mPositionUs(-1),
       mSeekInProgress(false),
+      mPlayingTimeUs(0),
       mLooper(new ALooper),
       mPlayerFlags(0),
+      mAnalyticsItem(NULL),
       mAtEOS(false),
       mLooping(false),
       mAutoLoop(false) {
-    ALOGV("NuPlayerDriver(%p)", this);
+    ALOGD("NuPlayerDriver(%p) created, clientPid(%d)", this, pid);
     mLooper->setName("NuPlayerDriver Looper");
 
+    // set up an analytics record
+    mAnalyticsItem = new MediaAnalyticsItem("nuplayer");
+    mAnalyticsItem->generateSessionID();
+
     mLooper->start(
             false, /* runOnCallingThread */
             true,  /* canCallJava */
@@ -63,6 +75,15 @@
 NuPlayerDriver::~NuPlayerDriver() {
     ALOGV("~NuPlayerDriver(%p)", this);
     mLooper->stop();
+
+    // finalize any pending metrics, usually a no-op.
+    finalizeMetrics("destructor");
+    logMetrics("destructor");
+
+    if (mAnalyticsItem != NULL) {
+        delete mAnalyticsItem;
+        mAnalyticsItem = NULL;
+    }
 }
 
 status_t NuPlayerDriver::initCheck() {
@@ -450,8 +471,103 @@
     return OK;
 }
 
+void NuPlayerDriver::finalizeMetrics(const char *where) {
+    if (where == NULL) {
+        where = "unknown";
+    }
+    ALOGD("finalizeMetrics(%p) from %s at state %d", this, where, mState);
+
+    // gather the final stats for this record
+    Vector<sp<AMessage>> trackStats;
+    mPlayer->getStats(&trackStats);
+
+    if (trackStats.size() > 0) {
+        for (size_t i = 0; i < trackStats.size(); ++i) {
+            const sp<AMessage> &stats = trackStats.itemAt(i);
+
+            AString mime;
+            stats->findString("mime", &mime);
+
+            AString name;
+            stats->findString("component-name", &name);
+
+            if (mime.startsWith("video/")) {
+                int32_t width, height;
+                mAnalyticsItem->setCString("video/mime", mime.c_str());
+                if (!name.empty()) {
+                    mAnalyticsItem->setCString("video/codec", name.c_str());
+                }
+
+                if (stats->findInt32("width", &width)
+                        && stats->findInt32("height", &height)) {
+                    mAnalyticsItem->setInt32("wid", width);
+                    mAnalyticsItem->setInt32("ht", height);
+                }
+
+                int64_t numFramesTotal = 0;
+                int64_t numFramesDropped = 0;
+                stats->findInt64("frames-total", &numFramesTotal);
+                stats->findInt64("frames-dropped-output", &numFramesDropped);
+
+                mAnalyticsItem->setInt64("frames", numFramesTotal);
+                mAnalyticsItem->setInt64("dropped", numFramesDropped);
+
+
+            } else if (mime.startsWith("audio/")) {
+                mAnalyticsItem->setCString("audio/mime", mime.c_str());
+                if (!name.empty()) {
+                    mAnalyticsItem->setCString("audio/codec", name.c_str());
+                }
+            }
+        }
+
+        // getDuration() uses mLock for mutex -- careful where we use it.
+        int duration_ms = -1;
+        getDuration(&duration_ms);
+        if (duration_ms != -1) {
+            mAnalyticsItem->setInt64("duration", duration_ms);
+        }
+
+        if (mPlayingTimeUs > 0) {
+            mAnalyticsItem->setInt64("playing", (mPlayingTimeUs+500)/1000 );
+        }
+    }
+}
+
+
+void NuPlayerDriver::logMetrics(const char *where) {
+    if (where == NULL) {
+        where = "unknown";
+    }
+    ALOGD("logMetrics(%p) from %s at state %d", this, where, mState);
+
+    if (mAnalyticsItem == NULL || mAnalyticsItem->isEnabled() == false) {
+        return;
+    }
+
+    // only bother to log non-empty records
+    if (mAnalyticsItem->count() > 0) {
+
+        mAnalyticsItem->setFinalized(true);
+        mAnalyticsItem->selfrecord();
+
+        // re-init in case we prepare() and start() again.
+        delete mAnalyticsItem ;
+        mAnalyticsItem = new MediaAnalyticsItem("nuplayer");
+        if (mAnalyticsItem) {
+            mAnalyticsItem->generateSessionID();
+        }
+    } else {
+        ALOGV("did not have anything to record");
+    }
+}
+
 status_t NuPlayerDriver::reset() {
     ALOGD("reset(%p) at state %d", this, mState);
+
+    finalizeMetrics("reset");
+    logMetrics("reset");
+
     Mutex::Autolock autoLock(mLock);
 
     switch (mState) {
@@ -493,6 +609,7 @@
     mDurationUs = -1;
     mPositionUs = -1;
     mLooping = false;
+    mPlayingTimeUs = 0;
 
     return OK;
 }
@@ -624,6 +741,11 @@
     mDurationUs = durationUs;
 }
 
+void NuPlayerDriver::notifyMorePlayingTimeUs(int64_t playingUs) {
+    Mutex::Autolock autoLock(mLock);
+    mPlayingTimeUs += playingUs;
+}
+
 void NuPlayerDriver::notifySeekComplete() {
     ALOGV("notifySeekComplete(%p)", this);
     Mutex::Autolock autoLock(mLock);
@@ -657,6 +779,24 @@
     AString logString(" NuPlayer\n");
     char buf[256] = {0};
 
+    bool locked = false;
+    for (int i = 0; i < kDumpLockRetries; ++i) {
+        if (mLock.tryLock() == NO_ERROR) {
+            locked = true;
+            break;
+        }
+        usleep(kDumpLockSleepUs);
+    }
+
+    if (locked) {
+        snprintf(buf, sizeof(buf), "  state(%d), atEOS(%d), looping(%d), autoLoop(%d)\n",
+                mState, mAtEOS, mLooping, mAutoLoop);
+        mLock.unlock();
+    } else {
+        snprintf(buf, sizeof(buf), "  NPD(%p) lock is taken\n", this);
+    }
+    logString.append(buf);
+
     for (size_t i = 0; i < trackStats.size(); ++i) {
         const sp<AMessage> &stats = trackStats.itemAt(i);
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 317b34c..9b784ae 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -16,6 +16,7 @@
 
 #include <media/MediaPlayerInterface.h>
 
+#include <media/MediaAnalyticsItem.h>
 #include <media/stagefright/foundation/ABase.h>
 
 namespace android {
@@ -75,6 +76,7 @@
     void notifyResetComplete();
     void notifySetSurfaceComplete();
     void notifyDuration(int64_t durationUs);
+    void notifyMorePlayingTimeUs(int64_t timeUs);
     void notifySeekComplete();
     void notifySeekComplete_l();
     void notifyListener(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL);
@@ -112,6 +114,7 @@
     int64_t mDurationUs;
     int64_t mPositionUs;
     bool mSeekInProgress;
+    int64_t mPlayingTimeUs;
     // <<<
 
     sp<ALooper> mLooper;
@@ -119,10 +122,15 @@
     sp<AudioSink> mAudioSink;
     uint32_t mPlayerFlags;
 
+    MediaAnalyticsItem *mAnalyticsItem;
+
     bool mAtEOS;
     bool mLooping;
     bool mAutoLoop;
 
+    void finalizeMetrics(const char *where);
+    void logMetrics(const char *where);
+
     status_t prepare_l();
     status_t start_l();
     void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 5197167..6006730 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -77,7 +77,11 @@
     // an error or ERROR_END_OF_STREAM if not.
     virtual status_t feedMoreTSData() = 0;
 
+    // Returns non-NULL format when the specified track exists.
+    // When the format has "err" set to -EWOULDBLOCK, source needs more time to get valid meta data.
+    // Returns NULL if the specified track doesn't exist or is invalid;
     virtual sp<AMessage> getFormat(bool audio);
+
     virtual sp<MetaData> getFormatMeta(bool /* audio */) { return NULL; }
     virtual sp<MetaData> getFileFormatMeta() const { return NULL; }
 
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index 7f9f913..d6b1e8c 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -234,8 +234,7 @@
     }
     status_t err = convertMetaDataToMessage(meta, &format);
     if (err != OK) { // format may have been cleared on error
-        format = new AMessage;
-        format->setInt32("err", err);
+        return NULL;
     }
     return format;
 }
diff --git a/media/liboboe/include/oboe/OboeAudio.h b/media/liboboe/include/oboe/OboeAudio.h
index 788cf5f..2181b8c 100644
--- a/media/liboboe/include/oboe/OboeAudio.h
+++ b/media/liboboe/include/oboe/OboeAudio.h
@@ -372,7 +372,7 @@
  *
  * @param stream A stream created using OboeStreamBuilder_openStream().
  * @param periodNanoseconds the estimated period at which the audio thread will need to wake up
- * @param start_routine your thread entry point
+ * @param startRoutine your thread entry point
  * @param arg an argument that will be passed to your thread entry point
  * @return OBOE_OK or a negative error.
  */
@@ -408,7 +408,7 @@
  *
  * @param stream handle provided by OboeStreamBuilder_openStream()
  * @param requestedFrames requested number of frames that can be filled without blocking
- * @return actualFrames receives final number of frames
+ * @param actualFrames receives final number of frames
  * @return OBOE_OK or a negative error
  */
 OBOE_API oboe_result_t OboeStream_setBufferSize(OboeStream stream,
diff --git a/media/liboboe/src/utility/HandleTracker.h b/media/liboboe/src/utility/HandleTracker.h
index da5b654..37dbac8 100644
--- a/media/liboboe/src/utility/HandleTracker.h
+++ b/media/liboboe/src/utility/HandleTracker.h
@@ -53,7 +53,7 @@
     /**
      * Store a pointer and return a handle that can be used to retrieve the pointer.
      *
-     * @param type the type of the object to be tracked
+     * @param expectedType the type of the object to be tracked
      * @param address pointer to be converted to a handle
      * @return a valid handle or a negative error
      */
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 13401fc..f247475 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -53,6 +53,7 @@
 #include <OMX_AsString.h>
 
 #include "include/avc_utils.h"
+#include "include/ACodecBufferChannel.h"
 #include "include/DataConverter.h"
 #include "include/SecureBuffer.h"
 #include "include/SharedMemoryBuffer.h"
@@ -564,16 +565,21 @@
 ACodec::~ACodec() {
 }
 
-void ACodec::setNotificationMessage(const sp<AMessage> &msg) {
-    mNotify = msg;
-}
-
 void ACodec::initiateSetup(const sp<AMessage> &msg) {
     msg->setWhat(kWhatSetup);
     msg->setTarget(this);
     msg->post();
 }
 
+std::shared_ptr<BufferChannelBase> ACodec::getBufferChannel() {
+    if (!mBufferChannel) {
+        mBufferChannel = std::make_shared<ACodecBufferChannel>(
+                new AMessage(kWhatInputBufferFilled, this),
+                new AMessage(kWhatOutputBufferDrained, this));
+    }
+    return mBufferChannel;
+}
+
 void ACodec::signalSetParameters(const sp<AMessage> &params) {
     sp<AMessage> msg = new AMessage(kWhatSetParameters, this);
     msg->setMessage("params", params);
@@ -936,12 +942,17 @@
         return err;
     }
 
-    sp<PortDescription> desc = new PortDescription;
+    std::vector<ACodecBufferChannel::BufferAndId> array(mBuffers[portIndex].size());
     for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
-        const BufferInfo &info = mBuffers[portIndex][i];
-        desc->addBuffer(info.mBufferID, info.mData);
+        array[i] = {mBuffers[portIndex][i].mData, mBuffers[portIndex][i].mBufferID};
     }
-    mCallback->onBuffersAllocated(portIndex, desc);
+    if (portIndex == kPortIndexInput) {
+        mBufferChannel->setInputBufferArray(array);
+    } else if (portIndex == kPortIndexOutput) {
+        mBufferChannel->setOutputBufferArray(array);
+    } else {
+        TRESPASS();
+    }
 
     return OK;
 }
@@ -1432,6 +1443,12 @@
 }
 
 status_t ACodec::freeBuffersOnPort(OMX_U32 portIndex) {
+    if (portIndex == kPortIndexInput) {
+        mBufferChannel->setInputBufferArray({});
+    } else {
+        mBufferChannel->setOutputBufferArray({});
+    }
+
     status_t err = OK;
     for (size_t i = mBuffers[portIndex].size(); i > 0;) {
         i--;
@@ -5076,25 +5093,6 @@
     }
 }
 
-void ACodec::addKeyFormatChangesToRenderBufferNotification(sp<AMessage> &notify) {
-    AString mime;
-    CHECK(mOutputFormat->findString("mime", &mime));
-
-    if (mime == MEDIA_MIMETYPE_VIDEO_RAW && mNativeWindow != NULL) {
-        // notify renderer of the crop change and dataspace change
-        // NOTE: native window uses extended right-bottom coordinate
-        int32_t left, top, right, bottom;
-        if (mOutputFormat->findRect("crop", &left, &top, &right, &bottom)) {
-            notify->setRect("crop", left, top, right + 1, bottom + 1);
-        }
-
-        int32_t dataSpace;
-        if (mOutputFormat->findInt32("android._dataspace", &dataSpace)) {
-            notify->setInt32("dataspace", dataSpace);
-        }
-    }
-}
-
 void ACodec::sendFormatChange() {
     AString mime;
     CHECK(mOutputFormat->findString("mime", &mime));
@@ -5156,29 +5154,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-ACodec::PortDescription::PortDescription() {
-}
-
-void ACodec::PortDescription::addBuffer(
-        IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer) {
-    mBufferIDs.push_back(id);
-    mBuffers.push_back(buffer);
-}
-
-size_t ACodec::PortDescription::countBuffers() {
-    return mBufferIDs.size();
-}
-
-IOMX::buffer_id ACodec::PortDescription::bufferIDAt(size_t index) const {
-    return mBufferIDs.itemAt(index);
-}
-
-sp<MediaCodecBuffer> ACodec::PortDescription::bufferAt(size_t index) const {
-    return mBuffers.itemAt(index);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
 ACodec::BaseState::BaseState(ACodec *codec, const sp<AState> &parentState)
     : AState(parentState),
       mCodec(codec) {
@@ -5486,9 +5461,7 @@
     CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
 
     info->mData->setFormat(mCodec->mInputFormat);
-    sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, mCodec);
-    reply->setInt32("buffer-id", info->mBufferID);
-    mCodec->mCallback->fillThisBuffer(info->mBufferID, info->mData, reply);
+    mCodec->mBufferChannel->fillThisBuffer(info->mBufferID);
     info->mData.clear();
     info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
 }
@@ -5502,17 +5475,9 @@
     PortMode mode = getPortMode(kPortIndexInput);
     int32_t discarded = 0;
     if (msg->findInt32("discarded", &discarded) && discarded) {
-        /* these are unfilled buffers returned by client */
-        CHECK(msg->findInt32("err", &err));
-
-        if (err == OK) {
-            /* buffers with no errors are returned on MediaCodec.flush */
-            mode = KEEP_BUFFERS;
-        } else {
-            ALOGV("[%s] saw error %d instead of an input buffer",
-                 mCodec->mComponentName.c_str(), err);
-            eos = true;
-        }
+        // these are unfilled buffers returned by client
+        // buffers are returned on MediaCodec.flush
+        mode = KEEP_BUFFERS;
     }
     sp<RefBase> obj;
     CHECK(msg->findObject("buffer", &obj));
@@ -5839,7 +5804,6 @@
                 break;
             }
 
-            sp<AMessage> reply = new AMessage(kWhatOutputBufferDrained, mCodec);
             sp<MediaCodecBuffer> buffer = info->mData;
 
             if (mCodec->mOutputFormat != mCodec->mLastOutputFormat && rangeLength > 0) {
@@ -5847,12 +5811,7 @@
                 if (mCodec->mBaseOutputFormat == mCodec->mOutputFormat) {
                     mCodec->onOutputFormatChanged(mCodec->mOutputFormat);
                 }
-                mCodec->addKeyFormatChangesToRenderBufferNotification(reply);
                 mCodec->sendFormatChange();
-            } else if (rangeLength > 0 && mCodec->mNativeWindow != NULL) {
-                // If potentially rendering onto a surface, always save key format data (crop &
-                // data space) so that we can set it if and once the buffer is rendered.
-                mCodec->addKeyFormatChangesToRenderBufferNotification(reply);
             }
             buffer->setFormat(mCodec->mOutputFormat);
 
@@ -5897,9 +5856,7 @@
 
             info->mData.clear();
 
-            reply->setInt32("buffer-id", info->mBufferID);
-
-            mCodec->mCallback->drainThisBuffer(info->mBufferID, buffer, flags, reply);
+            mCodec->mBufferChannel->drainThisBuffer(info->mBufferID, flags);
 
             info->mStatus = BufferInfo::OWNED_BY_DOWNSTREAM;
 
@@ -5947,24 +5904,6 @@
         return;
     }
     info->mData = buffer;
-
-    android_native_rect_t crop;
-    if (msg->findRect("crop", &crop.left, &crop.top, &crop.right, &crop.bottom)
-            && memcmp(&crop, &mCodec->mLastNativeWindowCrop, sizeof(crop)) != 0) {
-        mCodec->mLastNativeWindowCrop = crop;
-        status_t err = native_window_set_crop(mCodec->mNativeWindow.get(), &crop);
-        ALOGW_IF(err != NO_ERROR, "failed to set crop: %d", err);
-    }
-
-    int32_t dataSpace;
-    if (msg->findInt32("dataspace", &dataSpace)
-            && dataSpace != mCodec->mLastNativeWindowDataSpace) {
-        status_t err = native_window_set_buffers_data_space(
-                mCodec->mNativeWindow.get(), (android_dataspace)dataSpace);
-        mCodec->mLastNativeWindowDataSpace = dataSpace;
-        ALOGW_IF(err != NO_ERROR, "failed to set dataspace: %d", err);
-    }
-
     int32_t render;
     if (mCodec->mNativeWindow != NULL
             && msg->findInt32("render", &render) && render != 0
@@ -5972,6 +5911,27 @@
         ATRACE_NAME("render");
         // The client wants this buffer to be rendered.
 
+        android_native_rect_t crop;
+        if (buffer->format()->findRect("crop", &crop.left, &crop.top, &crop.right, &crop.bottom)) {
+            // NOTE: native window uses extended right-bottom coordinate
+            ++crop.right;
+            ++crop.bottom;
+            if (memcmp(&crop, &mCodec->mLastNativeWindowCrop, sizeof(crop)) != 0) {
+                mCodec->mLastNativeWindowCrop = crop;
+                status_t err = native_window_set_crop(mCodec->mNativeWindow.get(), &crop);
+                ALOGW_IF(err != NO_ERROR, "failed to set crop: %d", err);
+            }
+        }
+
+        int32_t dataSpace;
+        if (buffer->format()->findInt32("android._dataspace", &dataSpace)
+                && dataSpace != mCodec->mLastNativeWindowDataSpace) {
+            status_t err = native_window_set_buffers_data_space(
+                    mCodec->mNativeWindow.get(), (android_dataspace)dataSpace);
+            mCodec->mLastNativeWindowDataSpace = dataSpace;
+            ALOGW_IF(err != NO_ERROR, "failed to set dataspace: %d", err);
+        }
+
         // save buffers sent to the surface so we can get render time when they return
         int64_t mediaTimeUs = -1;
         buffer->meta()->findInt64("timeUs", &mediaTimeUs);
@@ -6613,12 +6573,18 @@
 
 status_t ACodec::LoadedToIdleState::allocateBuffers() {
     status_t err = mCodec->allocateBuffersOnPort(kPortIndexInput);
-
     if (err != OK) {
         return err;
     }
 
-    return mCodec->allocateBuffersOnPort(kPortIndexOutput);
+    err = mCodec->allocateBuffersOnPort(kPortIndexOutput);
+    if (err != OK) {
+        return err;
+    }
+
+    mCodec->mCallback->onStartCompleted();
+
+    return OK;
 }
 
 bool ACodec::LoadedToIdleState::onMessageReceived(const sp<AMessage> &msg) {
@@ -7226,6 +7192,7 @@
                     err = mCodec->allocateBuffersOnPort(kPortIndexOutput);
                     ALOGE_IF(err != OK, "Failed to allocate output port buffers after port "
                             "reconfiguration: (%d)", err);
+                    mCodec->mCallback->onOutputBuffersChanged();
                 }
 
                 if (err != OK) {
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
new file mode 100644
index 0000000..1db7ab0
--- /dev/null
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2016, 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_NDEBUG 0
+#define LOG_TAG "ACodecBufferChannel"
+#include <utils/Log.h>
+
+#include <numeric>
+
+#include <binder/MemoryDealer.h>
+#include <media/openmax/OMX_Core.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/MediaCodecBuffer.h>
+#include <system/window.h>
+
+#include "include/ACodecBufferChannel.h"
+#include "include/SecureBuffer.h"
+#include "include/SharedMemoryBuffer.h"
+
+namespace android {
+
+using BufferInfo = ACodecBufferChannel::BufferInfo;
+using BufferInfoIterator = std::vector<const BufferInfo>::const_iterator;
+
+static BufferInfoIterator findClientBuffer(
+        const std::shared_ptr<const std::vector<const BufferInfo>> &array,
+        const sp<MediaCodecBuffer> &buffer) {
+    return std::find_if(
+            array->begin(), array->end(),
+            [buffer](const BufferInfo &info) { return info.mClientBuffer == buffer; });
+}
+
+static BufferInfoIterator findBufferId(
+        const std::shared_ptr<const std::vector<const BufferInfo>> &array,
+        IOMX::buffer_id bufferId) {
+    return std::find_if(
+            array->begin(), array->end(),
+            [bufferId](const BufferInfo &info) { return bufferId == info.mBufferId; });
+}
+
+ACodecBufferChannel::BufferInfo::BufferInfo(
+        const sp<MediaCodecBuffer> &buffer,
+        IOMX::buffer_id bufferId,
+        const sp<IMemory> &sharedEncryptedBuffer)
+    : mClientBuffer(
+          (sharedEncryptedBuffer == nullptr)
+          ? buffer
+          : new SharedMemoryBuffer(buffer->format(), sharedEncryptedBuffer)),
+      mCodecBuffer(buffer),
+      mBufferId(bufferId),
+      mSharedEncryptedBuffer(sharedEncryptedBuffer) {
+}
+
+ACodecBufferChannel::ACodecBufferChannel(
+        const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained)
+    : mInputBufferFilled(inputBufferFilled),
+      mOutputBufferDrained(outputBufferDrained) {
+}
+
+status_t ACodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mInputBuffers));
+    BufferInfoIterator it = findClientBuffer(array, buffer);
+    if (it == array->end()) {
+        return -ENOENT;
+    }
+    ALOGV("queueInputBuffer #%d", it->mBufferId);
+    sp<AMessage> msg = mInputBufferFilled->dup();
+    msg->setObject("buffer", it->mCodecBuffer);
+    msg->setInt32("buffer-id", it->mBufferId);
+    msg->post();
+    return OK;
+}
+
+status_t ACodecBufferChannel::queueSecureInputBuffer(
+        const sp<MediaCodecBuffer> &buffer,
+        bool secure,
+        const uint8_t *key,
+        const uint8_t *iv,
+        CryptoPlugin::Mode mode,
+        CryptoPlugin::Pattern pattern,
+        const CryptoPlugin::SubSample *subSamples,
+        size_t numSubSamples,
+        AString *errorDetailMsg) {
+    if (mCrypto == nullptr) {
+        return -ENOSYS;
+    }
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mInputBuffers));
+    BufferInfoIterator it = findClientBuffer(array, buffer);
+    if (it == array->end()) {
+        return -ENOENT;
+    }
+
+    void *dst_pointer = nullptr;
+    ICrypto::DestinationType dst_type = ICrypto::kDestinationTypeOpaqueHandle;
+
+    if (secure) {
+        sp<SecureBuffer> secureData = static_cast<SecureBuffer *>(it->mCodecBuffer.get());
+        dst_pointer = secureData->getDestinationPointer();
+        dst_type = secureData->getDestinationType();
+    } else {
+        dst_pointer = it->mCodecBuffer->base();
+        dst_type = ICrypto::kDestinationTypeVmPointer;
+    }
+
+    ssize_t result = mCrypto->decrypt(
+            dst_type,
+            key,
+            iv,
+            mode,
+            pattern,
+            it->mSharedEncryptedBuffer,
+            it->mClientBuffer->offset(),
+            subSamples,
+            numSubSamples,
+            dst_pointer,
+            errorDetailMsg);
+
+    if (result < 0) {
+        return result;
+    }
+
+    it->mCodecBuffer->setRange(0, result);
+
+    // Copy metadata from client to codec buffer.
+    it->mCodecBuffer->meta()->clear();
+    int64_t timeUs;
+    CHECK(it->mClientBuffer->meta()->findInt64("timeUs", &timeUs));
+    it->mCodecBuffer->meta()->setInt64("timeUs", timeUs);
+    int32_t eos;
+    if (it->mClientBuffer->meta()->findInt32("eos", &eos)) {
+        it->mCodecBuffer->meta()->setInt32("eos", eos);
+    }
+    int32_t csd;
+    if (it->mClientBuffer->meta()->findInt32("csd", &csd)) {
+        it->mCodecBuffer->meta()->setInt32("csd", csd);
+    }
+
+    ALOGV("queueSecureInputBuffer #%d", it->mBufferId);
+    sp<AMessage> msg = mInputBufferFilled->dup();
+    msg->setObject("buffer", it->mCodecBuffer);
+    msg->setInt32("buffer-id", it->mBufferId);
+    msg->post();
+    return OK;
+}
+
+status_t ACodecBufferChannel::renderOutputBuffer(
+        const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) {
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mOutputBuffers));
+    BufferInfoIterator it = findClientBuffer(array, buffer);
+    if (it == array->end()) {
+        return -ENOENT;
+    }
+
+    ALOGV("renderOutputBuffer #%d", it->mBufferId);
+    sp<AMessage> msg = mOutputBufferDrained->dup();
+    msg->setObject("buffer", buffer);
+    msg->setInt32("buffer-id", it->mBufferId);
+    msg->setInt32("render", true);
+    msg->setInt64("timestampNs", timestampNs);
+    msg->post();
+    return OK;
+}
+
+status_t ACodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mInputBuffers));
+    bool input = true;
+    BufferInfoIterator it = findClientBuffer(array, buffer);
+    if (it == array->end()) {
+        array = std::atomic_load(&mOutputBuffers);
+        input = false;
+        it = findClientBuffer(array, buffer);
+        if (it == array->end()) {
+            return -ENOENT;
+        }
+    }
+    ALOGV("discardBuffer #%d", it->mBufferId);
+    sp<AMessage> msg = input ? mInputBufferFilled->dup() : mOutputBufferDrained->dup();
+    msg->setObject("buffer", it->mCodecBuffer);
+    msg->setInt32("buffer-id", it->mBufferId);
+    msg->setInt32("discarded", true);
+    msg->post();
+    return OK;
+}
+
+void ACodecBufferChannel::getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
+    std::shared_ptr<const std::vector<const BufferInfo>> inputBuffers(
+            std::atomic_load(&mInputBuffers));
+    array->clear();
+    for (const BufferInfo &elem : *inputBuffers) {
+        array->push_back(elem.mClientBuffer);
+    }
+}
+
+void ACodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
+    std::shared_ptr<const std::vector<const BufferInfo>> outputBuffers(
+            std::atomic_load(&mOutputBuffers));
+    array->clear();
+    for (const BufferInfo &elem : *outputBuffers) {
+        array->push_back(elem.mClientBuffer);
+    }
+}
+
+void ACodecBufferChannel::setInputBufferArray(const std::vector<BufferAndId> &array) {
+    bool secure = (mCrypto != nullptr);
+    if (secure) {
+        size_t totalSize = std::accumulate(
+                array.begin(), array.end(), 0u,
+                [alignment = MemoryDealer::getAllocationAlignment()]
+                (size_t sum, const BufferAndId& elem) {
+                    return sum + align(elem.mBuffer->capacity(), alignment);
+                });
+        mDealer = new MemoryDealer(totalSize, "ACodecBufferChannel");
+    }
+    std::vector<const BufferInfo> inputBuffers;
+    for (const BufferAndId &elem : array) {
+        sp<IMemory> sharedEncryptedBuffer;
+        if (secure) {
+            sharedEncryptedBuffer = mDealer->allocate(elem.mBuffer->capacity());
+        }
+        inputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, sharedEncryptedBuffer);
+    }
+    std::atomic_store(
+            &mInputBuffers,
+            std::make_shared<const std::vector<const BufferInfo>>(inputBuffers));
+}
+
+void ACodecBufferChannel::setOutputBufferArray(const std::vector<BufferAndId> &array) {
+    std::vector<const BufferInfo> outputBuffers;
+    for (const BufferAndId &elem : array) {
+        outputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, nullptr);
+    }
+    std::atomic_store(
+            &mOutputBuffers,
+            std::make_shared<const std::vector<const BufferInfo>>(outputBuffers));
+}
+
+void ACodecBufferChannel::fillThisBuffer(IOMX::buffer_id bufferId) {
+    ALOGV("fillThisBuffer #%d", bufferId);
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mInputBuffers));
+    BufferInfoIterator it = findBufferId(array, bufferId);
+
+    if (it == array->end()) {
+        ALOGE("fillThisBuffer: unrecognized buffer #%d", bufferId);
+        return;
+    }
+    if (it->mClientBuffer != it->mCodecBuffer) {
+        it->mClientBuffer->setFormat(it->mCodecBuffer->format());
+    }
+
+    mCallback->onInputBufferAvailable(
+            std::distance(array->begin(), it),
+            it->mClientBuffer);
+}
+
+void ACodecBufferChannel::drainThisBuffer(
+        IOMX::buffer_id bufferId,
+        OMX_U32 omxFlags) {
+    ALOGV("drainThisBuffer #%d", bufferId);
+    std::shared_ptr<const std::vector<const BufferInfo>> array(
+            std::atomic_load(&mOutputBuffers));
+    BufferInfoIterator it = findBufferId(array, bufferId);
+
+    if (it == array->end()) {
+        ALOGE("drainThisBuffer: unrecognized buffer #%d", bufferId);
+        return;
+    }
+    if (it->mClientBuffer != it->mCodecBuffer) {
+        it->mClientBuffer->setFormat(it->mCodecBuffer->format());
+    }
+
+    uint32_t flags = 0;
+    if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
+        flags |= MediaCodec::BUFFER_FLAG_SYNCFRAME;
+    }
+    if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+        flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
+    }
+    if (omxFlags & OMX_BUFFERFLAG_EOS) {
+        flags |= MediaCodec::BUFFER_FLAG_EOS;
+    }
+    it->mClientBuffer->meta()->setInt32("flags", flags);
+
+    mCallback->onOutputBufferAvailable(
+            std::distance(array->begin(), it),
+            it->mClientBuffer);
+}
+
+}  // namespace android
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 8c42cfd..f3d622b 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -4,6 +4,7 @@
 
 LOCAL_SRC_FILES:=                         \
         ACodec.cpp                        \
+        ACodecBufferChannel.cpp           \
         AACExtractor.cpp                  \
         AACWriter.cpp                     \
         AMRExtractor.cpp                  \
@@ -14,7 +15,6 @@
         CallbackDataSource.cpp            \
         CameraSource.cpp                  \
         CameraSourceTimeLapse.cpp         \
-        CodecBase.cpp                     \
         DataConverter.cpp                 \
         DataSource.cpp                    \
         DataURISource.cpp                 \
diff --git a/media/libstagefright/CodecBase.cpp b/media/libstagefright/CodecBase.cpp
deleted file mode 100644
index 3eca52a..0000000
--- a/media/libstagefright/CodecBase.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2014 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_NDEBUG 0
-#define LOG_TAG "CodecBase"
-
-#include <inttypes.h>
-
-#include <media/stagefright/CodecBase.h>
-
-namespace android {
-
-CodecBase::CodecBase() {
-}
-
-CodecBase::~CodecBase() {
-}
-
-CodecBase::PortDescription::PortDescription() {
-}
-
-CodecBase::PortDescription::~PortDescription() {
-}
-
-void CodecBase::setCallback(std::shared_ptr<Callback> &&callback) {
-    mCallback = callback;
-}
-
-}  // namespace android
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
old mode 100644
new mode 100755
index 0d61bf5..716f5d8
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -3309,13 +3309,22 @@
 
 void MPEG4Writer::Track::writeMdhdBox(uint32_t now) {
     int64_t trakDurationUs = getDurationUs();
+    int64_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
     mOwner->beginBox("mdhd");
-    mOwner->writeInt32(0);             // version=0, flags=0
-    mOwner->writeInt32(now);           // creation time
-    mOwner->writeInt32(now);           // modification time
-    mOwner->writeInt32(mTimeScale);    // media timescale
-    int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
-    mOwner->writeInt32(mdhdDuration);  // use media timescale
+
+    if (mdhdDuration > UINT32_MAX) {
+        mOwner->writeInt32((1 << 24));            // version=1, flags=0
+        mOwner->writeInt64((int64_t)now);         // creation time
+        mOwner->writeInt64((int64_t)now);         // modification time
+        mOwner->writeInt32(mTimeScale);           // media timescale
+        mOwner->writeInt64(mdhdDuration);         // media timescale
+    } else {
+        mOwner->writeInt32(0);                      // version=0, flags=0
+        mOwner->writeInt32(now);                    // creation time
+        mOwner->writeInt32(now);                    // modification time
+        mOwner->writeInt32(mTimeScale);             // media timescale
+        mOwner->writeInt32((int32_t)mdhdDuration);  // use media timescale
+    }
     // Language follows the three letter standard ISO-639-2/T
     // 'e', 'n', 'g' for "English", for instance.
     // Each character is packed as the difference between its ASCII value and 0x60.
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index f29f786..9eca982 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -37,6 +37,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/ACodec.h>
 #include <media/stagefright/BufferProducerWrapper.h>
@@ -66,6 +67,7 @@
 
 static const int kMaxRetry = 2;
 static const int kMaxReclaimWaitTimeInUs = 500000;  // 0.5s
+static const int kNumBuffersAlign = 16;
 
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -175,12 +177,17 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+MediaCodec::BufferInfo::BufferInfo() : mOwnedByClient(false) {}
+
+////////////////////////////////////////////////////////////////////////////////
+
 namespace {
 
 enum {
     kWhatFillThisBuffer      = 'fill',
     kWhatDrainThisBuffer     = 'drai',
     kWhatEOS                 = 'eos ',
+    kWhatStartCompleted      = 'Scom',
     kWhatStopCompleted       = 'scom',
     kWhatReleaseCompleted    = 'rcom',
     kWhatFlushCompleted      = 'fcom',
@@ -190,20 +197,51 @@
     kWhatInputSurfaceCreated = 'isfc',
     kWhatInputSurfaceAccepted = 'isfa',
     kWhatSignaledInputEOS    = 'seos',
-    kWhatBuffersAllocated    = 'allc',
     kWhatOutputFramesRendered = 'outR',
+    kWhatOutputBuffersChanged = 'outC',
 };
 
-class MediaCodecCallback : public CodecBase::Callback {
+class BufferCallback : public CodecBase::BufferCallback {
 public:
-    explicit MediaCodecCallback(const sp<AMessage> &notify);
-    virtual ~MediaCodecCallback();
+    explicit BufferCallback(const sp<AMessage> &notify);
+    virtual ~BufferCallback() = default;
 
-    virtual void fillThisBuffer(IOMX::buffer_id bufferId, const sp<MediaCodecBuffer> &buffer,
-            const sp<AMessage> &reply) override;
-    virtual void drainThisBuffer(IOMX::buffer_id bufferId, const sp<MediaCodecBuffer> &buffer,
-            int32_t flags, const sp<AMessage> &reply) override;
+    virtual void onInputBufferAvailable(
+            size_t index, const sp<MediaCodecBuffer> &buffer) override;
+    virtual void onOutputBufferAvailable(
+            size_t index, const sp<MediaCodecBuffer> &buffer) override;
+private:
+    const sp<AMessage> mNotify;
+};
+
+BufferCallback::BufferCallback(const sp<AMessage> &notify)
+    : mNotify(notify) {}
+
+void BufferCallback::onInputBufferAvailable(
+        size_t index, const sp<MediaCodecBuffer> &buffer) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatFillThisBuffer);
+    notify->setSize("index", index);
+    notify->setObject("buffer", buffer);
+    notify->post();
+}
+
+void BufferCallback::onOutputBufferAvailable(
+        size_t index, const sp<MediaCodecBuffer> &buffer) {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatDrainThisBuffer);
+    notify->setSize("index", index);
+    notify->setObject("buffer", buffer);
+    notify->post();
+}
+
+class CodecCallback : public CodecBase::CodecCallback {
+public:
+    explicit CodecCallback(const sp<AMessage> &notify);
+    virtual ~CodecCallback() = default;
+
     virtual void onEos(status_t err) override;
+    virtual void onStartCompleted() override;
     virtual void onStopCompleted() override;
     virtual void onReleaseCompleted() override;
     virtual void onFlushCompleted() override;
@@ -221,69 +259,46 @@
             const sp<AMessage> &outputFormat) override;
     virtual void onInputSurfaceDeclined(status_t err) override;
     virtual void onSignaledInputEOS(status_t err) override;
-    virtual void onBuffersAllocated(
-            int32_t portIndex, const sp<CodecBase::PortDescription> &portDesc) override;
     virtual void onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) override;
+    virtual void onOutputBuffersChanged() override;
 private:
     const sp<AMessage> mNotify;
 };
 
-MediaCodecCallback::MediaCodecCallback(const sp<AMessage> &notify) : mNotify(notify) {}
+CodecCallback::CodecCallback(const sp<AMessage> &notify) : mNotify(notify) {}
 
-MediaCodecCallback::~MediaCodecCallback() {}
-
-void MediaCodecCallback::fillThisBuffer(
-        IOMX::buffer_id bufferId,
-        const sp<MediaCodecBuffer> &buffer,
-        const sp<AMessage> &reply) {
-    sp<AMessage> notify(mNotify->dup());
-    notify->setInt32("what", kWhatFillThisBuffer);
-    notify->setInt32("buffer-id", bufferId);
-    notify->setObject("buffer", buffer);
-    notify->setMessage("reply", reply);
-    notify->post();
-}
-
-void MediaCodecCallback::drainThisBuffer(
-        IOMX::buffer_id bufferId,
-        const sp<MediaCodecBuffer> &buffer,
-        int32_t flags,
-        const sp<AMessage> &reply) {
-    sp<AMessage> notify(mNotify->dup());
-    notify->setInt32("what", kWhatDrainThisBuffer);
-    notify->setInt32("buffer-id", bufferId);
-    notify->setObject("buffer", buffer);
-    notify->setInt32("flags", flags);
-    notify->setMessage("reply", reply);
-    notify->post();
-}
-
-void MediaCodecCallback::onEos(status_t err) {
+void CodecCallback::onEos(status_t err) {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatEOS);
     notify->setInt32("err", err);
     notify->post();
 }
 
-void MediaCodecCallback::onStopCompleted() {
+void CodecCallback::onStartCompleted() {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatStartCompleted);
+    notify->post();
+}
+
+void CodecCallback::onStopCompleted() {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatStopCompleted);
     notify->post();
 }
 
-void MediaCodecCallback::onReleaseCompleted() {
+void CodecCallback::onReleaseCompleted() {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatReleaseCompleted);
     notify->post();
 }
 
-void MediaCodecCallback::onFlushCompleted() {
+void CodecCallback::onFlushCompleted() {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatFlushCompleted);
     notify->post();
 }
 
-void MediaCodecCallback::onError(status_t err, enum ActionCode actionCode) {
+void CodecCallback::onError(status_t err, enum ActionCode actionCode) {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatError);
     notify->setInt32("err", err);
@@ -291,14 +306,14 @@
     notify->post();
 }
 
-void MediaCodecCallback::onComponentAllocated(const char *componentName) {
+void CodecCallback::onComponentAllocated(const char *componentName) {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatComponentAllocated);
     notify->setString("componentName", componentName);
     notify->post();
 }
 
-void MediaCodecCallback::onComponentConfigured(
+void CodecCallback::onComponentConfigured(
         const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatComponentConfigured);
@@ -307,7 +322,7 @@
     notify->post();
 }
 
-void MediaCodecCallback::onInputSurfaceCreated(
+void CodecCallback::onInputSurfaceCreated(
         const sp<AMessage> &inputFormat,
         const sp<AMessage> &outputFormat,
         const sp<BufferProducerWrapper> &inputSurface) {
@@ -319,14 +334,14 @@
     notify->post();
 }
 
-void MediaCodecCallback::onInputSurfaceCreationFailed(status_t err) {
+void CodecCallback::onInputSurfaceCreationFailed(status_t err) {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatInputSurfaceCreated);
     notify->setInt32("err", err);
     notify->post();
 }
 
-void MediaCodecCallback::onInputSurfaceAccepted(
+void CodecCallback::onInputSurfaceAccepted(
         const sp<AMessage> &inputFormat,
         const sp<AMessage> &outputFormat) {
     sp<AMessage> notify(mNotify->dup());
@@ -336,14 +351,14 @@
     notify->post();
 }
 
-void MediaCodecCallback::onInputSurfaceDeclined(status_t err) {
+void CodecCallback::onInputSurfaceDeclined(status_t err) {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatInputSurfaceAccepted);
     notify->setInt32("err", err);
     notify->post();
 }
 
-void MediaCodecCallback::onSignaledInputEOS(status_t err) {
+void CodecCallback::onSignaledInputEOS(status_t err) {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatSignaledInputEOS);
     if (err != OK) {
@@ -352,16 +367,7 @@
     notify->post();
 }
 
-void MediaCodecCallback::onBuffersAllocated(
-        int32_t portIndex, const sp<CodecBase::PortDescription> &portDesc) {
-    sp<AMessage> notify(mNotify->dup());
-    notify->setInt32("what", kWhatBuffersAllocated);
-    notify->setInt32("portIndex", portIndex);
-    notify->setObject("portDesc", portDesc);
-    notify->post();
-}
-
-void MediaCodecCallback::onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) {
+void CodecCallback::onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) {
     sp<AMessage> notify(mNotify->dup());
     notify->setInt32("what", kWhatOutputFramesRendered);
     if (MediaCodec::CreateFramesRenderedMessage(done, notify)) {
@@ -369,6 +375,12 @@
     }
 }
 
+void CodecCallback::onOutputBuffersChanged() {
+    sp<AMessage> notify(mNotify->dup());
+    notify->setInt32("what", kWhatOutputBuffersChanged);
+    notify->post();
+}
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -573,7 +585,12 @@
     mLooper->registerHandler(this);
 
     mCodec->setCallback(
-            std::make_shared<MediaCodecCallback>(new AMessage(kWhatCodecNotify, this)));
+            std::unique_ptr<CodecBase::CodecCallback>(
+                    new CodecCallback(new AMessage(kWhatCodecNotify, this))));
+    mBufferChannel = mCodec->getBufferChannel();
+    mBufferChannel->setCallback(
+            std::unique_ptr<CodecBase::BufferCallback>(
+                    new BufferCallback(new AMessage(kWhatCodecNotify, this))));
 
     sp<AMessage> msg = new AMessage(kWhatInit, this);
     msg->setString("name", name);
@@ -800,14 +817,9 @@
 }
 
 bool MediaCodec::hasPendingBuffer(int portIndex) {
-    const Vector<BufferInfo> &buffers = mPortBuffers[portIndex];
-    for (size_t i = 0; i < buffers.size(); ++i) {
-        const BufferInfo &info = buffers.itemAt(i);
-        if (info.mOwnedByClient) {
-            return true;
-        }
-    }
-    return false;
+    return std::any_of(
+            mPortBuffers[portIndex].begin(), mPortBuffers[portIndex].end(),
+            [](const BufferInfo &info) { return info.mOwnedByClient; });
 }
 
 bool MediaCodec::hasPendingBuffer() {
@@ -1114,14 +1126,14 @@
     // we also don't want mOwnedByClient to change during this
     Mutex::Autolock al(mBufferLock);
 
-    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
-    if (index >= buffers->size()) {
+    std::vector<BufferInfo> &buffers = mPortBuffers[portIndex];
+    if (index >= buffers.size()) {
         ALOGE("getBufferAndFormat - trying to get buffer with "
-              "bad index (index=%zu buffer_size=%zu)", index, buffers->size());
+              "bad index (index=%zu buffer_size=%zu)", index, buffers.size());
         return INVALID_OPERATION;
     }
 
-    const BufferInfo &info = buffers->itemAt(index);
+    const BufferInfo &info = buffers[index];
     if (!info.mOwnedByClient) {
         ALOGE("getBufferAndFormat - invalid operation "
               "(the index %zu is not owned by client)", index);
@@ -1219,7 +1231,7 @@
         }
 
         const sp<MediaCodecBuffer> &buffer =
-            mPortBuffers[kPortIndexOutput].itemAt(index).mData;
+            mPortBuffers[kPortIndexOutput][index].mData;
 
         response->setSize("index", index);
         response->setSize("offset", buffer->offset());
@@ -1230,19 +1242,8 @@
 
         response->setInt64("timeUs", timeUs);
 
-        int32_t omxFlags;
-        CHECK(buffer->meta()->findInt32("omxFlags", &omxFlags));
-
-        uint32_t flags = 0;
-        if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
-            flags |= BUFFER_FLAG_SYNCFRAME;
-        }
-        if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
-            flags |= BUFFER_FLAG_CODECCONFIG;
-        }
-        if (omxFlags & OMX_BUFFERFLAG_EOS) {
-            flags |= BUFFER_FLAG_EOS;
-        }
+        int32_t flags;
+        CHECK(buffer->meta()->findInt32("flags", &flags));
 
         response->setInt32("flags", flags);
         response->postReply(replyID);
@@ -1507,75 +1508,24 @@
                     break;
                 }
 
-
-                case kWhatBuffersAllocated:
+                case kWhatStartCompleted:
                 {
-                    Mutex::Autolock al(mBufferLock);
-                    int32_t portIndex;
-                    CHECK(msg->findInt32("portIndex", &portIndex));
-
-                    ALOGV("%s buffers allocated",
-                          portIndex == kPortIndexInput ? "input" : "output");
-
-                    CHECK(portIndex == kPortIndexInput
-                            || portIndex == kPortIndexOutput);
-
-                    mPortBuffers[portIndex].clear();
-                    mPortBufferArrays[portIndex].clear();
-
-                    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
-
-                    sp<RefBase> obj;
-                    CHECK(msg->findObject("portDesc", &obj));
-
-                    sp<CodecBase::PortDescription> portDesc =
-                        static_cast<CodecBase::PortDescription *>(obj.get());
-
-                    size_t numBuffers = portDesc->countBuffers();
-
-                    size_t totalSize = 0;
-                    for (size_t i = 0; i < numBuffers; ++i) {
-                        if (portIndex == kPortIndexInput && mCrypto != NULL) {
-                            totalSize += portDesc->bufferAt(i)->capacity();
-                        }
+                    CHECK_EQ(mState, STARTING);
+                    if (mIsVideo) {
+                        addResource(
+                                MediaResource::kGraphicMemory,
+                                MediaResource::kUnspecifiedSubType,
+                                getGraphicBufferSize());
                     }
+                    setState(STARTED);
+                    (new AMessage)->postReply(mReplyID);
+                    break;
+                }
 
-                    if (totalSize) {
-                        mDealer = new MemoryDealer(totalSize, "MediaCodec");
-                    }
-
-                    for (size_t i = 0; i < numBuffers; ++i) {
-                        BufferInfo info;
-                        info.mBufferID = portDesc->bufferIDAt(i);
-                        info.mOwnedByClient = false;
-                        sp<MediaCodecBuffer> buffer = portDesc->bufferAt(i);
-                        if (portIndex == kPortIndexInput && mCrypto != NULL) {
-                            info.mSharedEncryptedBuffer = mDealer->allocate(buffer->capacity());
-                            buffer = new SharedMemoryBuffer(
-                                    mInputFormat, info.mSharedEncryptedBuffer);
-                        }
-                        buffers->push_back(info);
-                        mPortBufferArrays[portIndex].push_back(buffer);
-                    }
-
-                    if (portIndex == kPortIndexOutput) {
-                        if (mState == STARTING) {
-                            // We're always allocating output buffers after
-                            // allocating input buffers, so this is a good
-                            // indication that now all buffers are allocated.
-                            if (mIsVideo) {
-                                addResource(
-                                        MediaResource::kGraphicMemory,
-                                        MediaResource::kUnspecifiedSubType,
-                                        getGraphicBufferSize());
-                            }
-                            setState(STARTED);
-                            (new AMessage)->postReply(mReplyID);
-                        } else {
-                            mFlags |= kFlagOutputBuffersChanged;
-                            postActivityNotificationIfPossible();
-                        }
-                    }
+                case kWhatOutputBuffersChanged:
+                {
+                    mFlags |= kFlagOutputBuffersChanged;
+                    postActivityNotificationIfPossible();
                     break;
                 }
 
@@ -1602,9 +1552,6 @@
                         break;
                     }
 
-                    // TODO: hold reference of buffer from downstream when
-                    // mPortBuffers is removed.
-
                     if (!mCSD.empty()) {
                         ssize_t index = dequeuePortBuffer(kPortIndexInput);
                         CHECK_GE(index, 0);
@@ -1663,12 +1610,7 @@
                     sp<RefBase> obj;
                     CHECK(msg->findObject("buffer", &obj));
                     sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
-                    // TODO: hold buffer's reference when we remove mPortBuffers
 
-                    int32_t omxFlags;
-                    CHECK(msg->findInt32("flags", &omxFlags));
-
-                    buffer->meta()->setInt32("omxFlags", omxFlags);
                     if (mOutputFormat != buffer->format()) {
                         mOutputFormat = buffer->format();
                         ALOGV("[%s] output format changed to: %s",
@@ -1701,7 +1643,9 @@
                             // Before we announce the format change we should
                             // collect codec specific data and amend the output
                             // format as necessary.
-                            if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+                            int32_t flags = 0;
+                            (void) buffer->meta()->findInt32("flags", &flags);
+                            if (flags & BUFFER_FLAG_CODECCONFIG) {
                                 status_t err =
                                     amendOutputFormatWithCodecSpecificData(buffer);
 
@@ -1924,6 +1868,7 @@
             }
 
             mCrypto = static_cast<ICrypto *>(crypto);
+            mBufferChannel->setCrypto(mCrypto);
 
             uint32_t flags;
             CHECK(msg->findInt32("flags", (int32_t *)&flags));
@@ -2351,10 +2296,10 @@
             // createInputSurface(), or persistent set by setInputSurface()),
             // give the client an empty input buffers array.
             if (portIndex != kPortIndexInput || !mHaveInputSurface) {
-                const Vector<sp<MediaCodecBuffer>> &srcBuffers = mPortBufferArrays[portIndex];
-
-                for (size_t i = 0; i < srcBuffers.size(); ++i) {
-                    dstBuffers->push_back(srcBuffers[i]);
+                if (portIndex == kPortIndexInput) {
+                    mBufferChannel->getInputBufferArray(dstBuffers);
+                } else {
+                    mBufferChannel->getOutputBufferArray(dstBuffers);
                 }
             }
 
@@ -2483,13 +2428,12 @@
 status_t MediaCodec::queueCSDInputBuffer(size_t bufferIndex) {
     CHECK(!mCSD.empty());
 
-    const BufferInfo *info =
-        &mPortBuffers[kPortIndexInput].itemAt(bufferIndex);
+    const BufferInfo &info = mPortBuffers[kPortIndexInput][bufferIndex];
 
     sp<ABuffer> csd = *mCSD.begin();
     mCSD.erase(mCSD.begin());
 
-    const sp<MediaCodecBuffer> &codecInputData = info->mData;
+    const sp<MediaCodecBuffer> &codecInputData = info.mData;
 
     if (csd->size() > codecInputData->capacity()) {
         return -EINVAL;
@@ -2557,31 +2501,19 @@
     CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
     Mutex::Autolock al(mBufferLock);
 
-    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
+    for (size_t i = 0; i < mPortBuffers[portIndex].size(); ++i) {
+        BufferInfo *info = &mPortBuffers[portIndex][i];
 
-    for (size_t i = 0; i < buffers->size(); ++i) {
-        BufferInfo *info = &buffers->editItemAt(i);
-
-        if (info->mNotify != NULL) {
-            sp<AMessage> msg = info->mNotify;
-            msg->setObject("buffer", (info->mSecureData != nullptr)
-                    ? info->mSecureData : info->mData);
-            msg->setInt32("discarded", true);
-            info->mNotify = NULL;
+        if (info->mData != nullptr) {
+            sp<MediaCodecBuffer> buffer = info->mData;
             if (isReclaim && info->mOwnedByClient) {
                 ALOGD("port %d buffer %zu still owned by client when codec is reclaimed",
                         portIndex, i);
             } else {
                 info->mOwnedByClient = false;
                 info->mData.clear();
-                info->mSecureData.clear();
             }
-
-            if (portIndex == kPortIndexInput) {
-                /* no error, just returning buffers */
-                msg->setInt32("err", OK);
-            }
-            msg->post();
+            mBufferChannel->discardBuffer(buffer);
         }
     }
 
@@ -2591,37 +2523,22 @@
 size_t MediaCodec::updateBuffers(
         int32_t portIndex, const sp<AMessage> &msg) {
     CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
-
-    uint32_t bufferID;
-    CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
+    size_t index;
+    CHECK(msg->findSize("index", &index));
     sp<RefBase> obj;
     CHECK(msg->findObject("buffer", &obj));
     sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
 
-    Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
-
-    for (size_t i = 0; i < buffers->size(); ++i) {
-        BufferInfo *info = &buffers->editItemAt(i);
-
-        if (info->mBufferID == bufferID) {
-            CHECK(info->mNotify == NULL);
-            CHECK(msg->findMessage("reply", &info->mNotify));
-
-            if (portIndex == kPortIndexInput && mCrypto != NULL) {
-                info->mSecureData = buffer;
-                info->mData = mPortBufferArrays[portIndex][i];
-            } else {
-                info->mData = buffer;
-            }
-            mAvailPortBuffers[portIndex].push_back(i);
-
-            return i;
+    {
+        Mutex::Autolock al(mBufferLock);
+        if (mPortBuffers[portIndex].size() <= index) {
+            mPortBuffers[portIndex].resize(align(index + 1, kNumBuffersAlign));
         }
+        mPortBuffers[portIndex][index].mData = buffer;
     }
+    mAvailPortBuffers[portIndex].push_back(index);
 
-    TRESPASS();
-
-    return 0;
+    return index;
 }
 
 status_t MediaCodec::onQueueInputBuffer(const sp<AMessage> &msg) {
@@ -2686,9 +2603,9 @@
         return -ERANGE;
     }
 
-    BufferInfo *info = &mPortBuffers[kPortIndexInput].editItemAt(index);
+    BufferInfo *info = &mPortBuffers[kPortIndexInput][index];
 
-    if (info->mNotify == NULL || !info->mOwnedByClient) {
+    if (info->mData == nullptr || !info->mOwnedByClient) {
         return -EACCES;
     }
 
@@ -2696,69 +2613,44 @@
         return -EINVAL;
     }
 
-    sp<AMessage> reply = info->mNotify;
     info->mData->setRange(offset, size);
+    info->mData->meta()->setInt64("timeUs", timeUs);
+    if (flags & BUFFER_FLAG_EOS) {
+        info->mData->meta()->setInt32("eos", true);
+    }
+
+    if (flags & BUFFER_FLAG_CODECCONFIG) {
+        info->mData->meta()->setInt32("csd", true);
+    }
 
     sp<MediaCodecBuffer> buffer = info->mData;
+    status_t err = OK;
     if (mCrypto != NULL) {
         AString *errorDetailMsg;
         CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg));
 
-        void *dst_pointer = nullptr;
-        ICrypto::DestinationType dst_type = ICrypto::kDestinationTypeOpaqueHandle;
-
-        if ((mFlags & kFlagIsSecure) == 0) {
-            dst_pointer = info->mSecureData->base();
-            dst_type = ICrypto::kDestinationTypeVmPointer;
-        } else {
-            sp<SecureBuffer> secureData = static_cast<SecureBuffer *>(info->mSecureData.get());
-            dst_pointer = secureData->getDestinationPointer();
-            dst_type = secureData->getDestinationType();
-        }
-
-        ssize_t result = mCrypto->decrypt(
-                dst_type,
+        err = mBufferChannel->queueSecureInputBuffer(
+                buffer,
+                (mFlags & kFlagIsSecure),
                 key,
                 iv,
                 mode,
                 pattern,
-                info->mSharedEncryptedBuffer,
-                offset,
                 subSamples,
                 numSubSamples,
-                dst_pointer,
                 errorDetailMsg);
-
-        if (result < 0) {
-            return result;
-        }
-
-        info->mSecureData->setRange(0, result);
-        buffer = info->mSecureData;
-    }
-    buffer->meta()->setInt64("timeUs", timeUs);
-
-    if (flags & BUFFER_FLAG_EOS) {
-        buffer->meta()->setInt32("eos", true);
+    } else {
+        err = mBufferChannel->queueInputBuffer(buffer);
     }
 
-    if (flags & BUFFER_FLAG_CODECCONFIG) {
-        buffer->meta()->setInt32("csd", true);
-    }
-
-    // synchronization boundary for getBufferAndFormat
-    {
+    if (err == OK) {
+        // synchronization boundary for getBufferAndFormat
         Mutex::Autolock al(mBufferLock);
         info->mOwnedByClient = false;
+        info->mData.clear();
     }
-    info->mData.clear();
-    info->mSecureData.clear();
-    reply->setObject("buffer", buffer);
-    reply->post();
 
-    info->mNotify = NULL;
-
-    return OK;
+    return err;
 }
 
 //static
@@ -2795,23 +2687,24 @@
         return -ERANGE;
     }
 
-    BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index);
+    BufferInfo *info = &mPortBuffers[kPortIndexOutput][index];
 
-    if (info->mNotify == NULL || !info->mOwnedByClient) {
+    if (info->mData == nullptr || !info->mOwnedByClient) {
         return -EACCES;
     }
 
     // synchronization boundary for getBufferAndFormat
+    sp<MediaCodecBuffer> buffer;
     {
         Mutex::Autolock al(mBufferLock);
         info->mOwnedByClient = false;
+        buffer = info->mData;
+        info->mData.clear();
     }
 
-    if (render && info->mData != NULL && info->mData->size() != 0) {
-        info->mNotify->setInt32("render", true);
-
+    if (render && buffer->size() != 0) {
         int64_t mediaTimeUs = -1;
-        info->mData->meta()->findInt64("timeUs", &mediaTimeUs);
+        buffer->meta()->findInt64("timeUs", &mediaTimeUs);
 
         int64_t renderTimeNs = 0;
         if (!msg->findInt64("timestampNs", &renderTimeNs)) {
@@ -2819,12 +2712,11 @@
             ALOGV("using buffer PTS of %lld", (long long)mediaTimeUs);
             renderTimeNs = mediaTimeUs * 1000;
         }
-        info->mNotify->setInt64("timestampNs", renderTimeNs);
 
         if (mSoftRenderer != NULL) {
             std::list<FrameRenderTracker::Info> doneFrames = mSoftRenderer->render(
-                    info->mData->data(), info->mData->size(),
-                    mediaTimeUs, renderTimeNs, NULL, info->mData->format());
+                    buffer->data(), buffer->size(),
+                    mediaTimeUs, renderTimeNs, NULL, buffer->format());
 
             // if we are running, notify rendered frames
             if (!doneFrames.empty() && mState == STARTED && mOnFrameRenderedNotification != NULL) {
@@ -2836,13 +2728,11 @@
                 }
             }
         }
+        mBufferChannel->renderOutputBuffer(buffer, renderTimeNs);
+    } else {
+        mBufferChannel->discardBuffer(buffer);
     }
 
-    info->mNotify->setObject("buffer", info->mData);
-    info->mData.clear();
-    info->mNotify->post();
-    info->mNotify.clear();
-
     return OK;
 }
 
@@ -2858,7 +2748,7 @@
     size_t index = *availBuffers->begin();
     availBuffers->erase(availBuffers->begin());
 
-    BufferInfo *info = &mPortBuffers[portIndex].editItemAt(index);
+    BufferInfo *info = &mPortBuffers[portIndex][index];
     CHECK(!info->mOwnedByClient);
     {
         Mutex::Autolock al(mBufferLock);
@@ -2962,7 +2852,7 @@
     int32_t index;
     while ((index = dequeuePortBuffer(kPortIndexOutput)) >= 0) {
         const sp<MediaCodecBuffer> &buffer =
-            mPortBuffers[kPortIndexOutput].itemAt(index).mData;
+            mPortBuffers[kPortIndexOutput][index].mData;
         sp<AMessage> msg = mCallback->dup();
         msg->setInt32("callbackID", CB_OUTPUT_AVAILABLE);
         msg->setInt32("index", index);
@@ -2974,19 +2864,8 @@
 
         msg->setInt64("timeUs", timeUs);
 
-        int32_t omxFlags;
-        CHECK(buffer->meta()->findInt32("omxFlags", &omxFlags));
-
-        uint32_t flags = 0;
-        if (omxFlags & OMX_BUFFERFLAG_SYNCFRAME) {
-            flags |= BUFFER_FLAG_SYNCFRAME;
-        }
-        if (omxFlags & OMX_BUFFERFLAG_CODECCONFIG) {
-            flags |= BUFFER_FLAG_CODECCONFIG;
-        }
-        if (omxFlags & OMX_BUFFERFLAG_EOS) {
-            flags |= BUFFER_FLAG_EOS;
-        }
+        int32_t flags;
+        CHECK(buffer->meta()->findInt32("flags", &flags));
 
         msg->setInt32("flags", flags);
 
@@ -3018,7 +2897,6 @@
     }
 }
 
-
 void MediaCodec::postActivityNotificationIfPossible() {
     if (mActivityNotify == NULL) {
         return;
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index de4d06f..5981b35 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -689,7 +689,9 @@
 
             sp<MediaCodecBuffer> inbuf;
             status_t err = mEncoder->getInputBuffer(bufferIndex, &inbuf);
-            if (err != OK || inbuf == NULL) {
+
+            if (err != OK || inbuf == NULL || inbuf->data() == NULL
+                    || mbuf->data() == NULL || mbuf->size() == 0) {
                 mbuf->release();
                 signalEOS();
                 break;
@@ -851,7 +853,8 @@
 
             sp<MediaCodecBuffer> outbuf;
             status_t err = mEncoder->getOutputBuffer(index, &outbuf);
-            if (err != OK || outbuf == NULL) {
+            if (err != OK || outbuf == NULL || outbuf->data() == NULL
+                || outbuf->size() == 0) {
                 signalEOS();
                 break;
             }
diff --git a/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp b/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp
index 9d9cd3b..5a47510 100644
--- a/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/src/a_refl.cpp
@@ -60,7 +60,7 @@
 ; INCLUDES
 ----------------------------------------------------------------------------*/
 #define LOG_TAG "a_refl"
-#include <android/log.h>
+#include <log/log.h>
 
 #include "a_refl.h"
 #include "typedef.h"
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp
index 5baa2a2..8393d79 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp
@@ -18,7 +18,7 @@
 
 #define LOG_TAG "conceal"
 
-#include "android/log.h"
+#include "log/log.h"
 
 #include "mp4dec_lib.h" /* video decoder function prototypes */
 #include "vlc_decode.h"
diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp
index 7290193..777ab5b 100644
--- a/media/libstagefright/filters/MediaFilter.cpp
+++ b/media/libstagefright/filters/MediaFilter.cpp
@@ -42,6 +42,7 @@
 #include "SaturationFilter.h"
 #include "ZeroFilter.h"
 
+#include "../include/ACodecBufferChannel.h"
 #include "../include/SharedMemoryBuffer.h"
 
 namespace android {
@@ -53,6 +54,9 @@
     : mState(UNINITIALIZED),
       mGeneration(0),
       mGraphicBufferListener(NULL) {
+    mBufferChannel = std::make_shared<ACodecBufferChannel>(
+            new AMessage(kWhatInputBufferFilled, this),
+            new AMessage(kWhatOutputBufferDrained, this));
 }
 
 MediaFilter::~MediaFilter() {
@@ -60,6 +64,10 @@
 
 //////////////////// PUBLIC FUNCTIONS //////////////////////////////////////////
 
+std::shared_ptr<BufferChannelBase> MediaFilter::getBufferChannel() {
+    return mBufferChannel;
+}
+
 void MediaFilter::initiateAllocateComponent(const sp<AMessage> &msg) {
     msg->setWhat(kWhatAllocateComponent);
     msg->setTarget(this);
@@ -189,29 +197,6 @@
     }
 }
 
-//////////////////// PORT DESCRIPTION //////////////////////////////////////////
-
-MediaFilter::PortDescription::PortDescription() {
-}
-
-void MediaFilter::PortDescription::addBuffer(
-        IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer) {
-    mBufferIDs.push_back(id);
-    mBuffers.push_back(buffer);
-}
-
-size_t MediaFilter::PortDescription::countBuffers() {
-    return mBufferIDs.size();
-}
-
-IOMX::buffer_id MediaFilter::PortDescription::bufferIDAt(size_t index) const {
-    return mBufferIDs.itemAt(index);
-}
-
-sp<MediaCodecBuffer> MediaFilter::PortDescription::bufferAt(size_t index) const {
-    return mBuffers.itemAt(index);
-}
-
 //////////////////// HELPER FUNCTIONS //////////////////////////////////////////
 
 void MediaFilter::signalProcessBuffers() {
@@ -259,14 +244,15 @@
         }
     }
 
-    sp<PortDescription> desc = new PortDescription;
-
+    std::vector<ACodecBufferChannel::BufferAndId> array(mBuffers[portIndex].size());
     for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
-        const BufferInfo &info = mBuffers[portIndex][i];
-
-        desc->addBuffer(info.mBufferID, info.mData);
+        array[i] = {mBuffers[portIndex][i].mData, mBuffers[portIndex][i].mBufferID};
     }
-    mCallback->onBuffersAllocated(portIndex, desc);
+    if (portIndex == kPortIndexInput) {
+        mBufferChannel->setInputBufferArray(array);
+    } else {
+        mBufferChannel->setOutputBufferArray(array);
+    }
 
     return OK;
 }
@@ -307,7 +293,7 @@
 
     info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
 
-    mCallback->fillThisBuffer(info->mBufferID, info->mData, reply);
+    mBufferChannel->fillThisBuffer(info->mBufferID);
 }
 
 void MediaFilter::postDrainThisBuffer(BufferInfo *info) {
@@ -318,8 +304,7 @@
     sp<AMessage> reply = new AMessage(kWhatOutputBufferDrained, this);
     reply->setInt32("buffer-id", info->mBufferID);
 
-    mCallback->drainThisBuffer(
-            info->mBufferID, info->mData, info->mOutputFlags, reply);
+    mBufferChannel->drainThisBuffer(info->mBufferID, info->mOutputFlags);
 
     info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
 }
@@ -505,6 +490,8 @@
 
     allocateBuffersOnPort(kPortIndexOutput);
 
+    mCallback->onStartCompleted();
+
     status_t err = mFilter->start();
     if (err != (status_t)OK) {
         ALOGE("Failed to start filter component, err %d", err);
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
new file mode 100644
index 0000000..d52ce53
--- /dev/null
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2016, 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 A_BUFFER_CHANNEL_H_
+
+#define A_BUFFER_CHANNEL_H_
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include <media/openmax/OMX_Types.h>
+#include <media/stagefright/CodecBase.h>
+#include <media/ICrypto.h>
+#include <media/IOMX.h>
+
+namespace android {
+
+/**
+ * BufferChannelBase implementation for ACodec.
+ */
+class ACodecBufferChannel : public BufferChannelBase {
+public:
+    struct BufferAndId {
+        sp<MediaCodecBuffer> mBuffer;
+        IOMX::buffer_id mBufferId;
+    };
+
+    struct BufferInfo {
+        BufferInfo(
+                const sp<MediaCodecBuffer> &buffer,
+                IOMX::buffer_id bufferId,
+                const sp<IMemory> &sharedEncryptedBuffer);
+
+        BufferInfo() = delete;
+
+        // Buffer facing MediaCodec and its clients.
+        const sp<MediaCodecBuffer> mClientBuffer;
+        // Buffer facing CodecBase.
+        const sp<MediaCodecBuffer> mCodecBuffer;
+        // OMX buffer ID.
+        const IOMX::buffer_id mBufferId;
+        // Encrypted buffer in case of secure input.
+        const sp<IMemory> mSharedEncryptedBuffer;
+    };
+
+    ACodecBufferChannel(
+            const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained);
+    virtual ~ACodecBufferChannel() = default;
+
+    // BufferChannelBase interface
+    virtual status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override;
+    virtual status_t queueSecureInputBuffer(
+            const sp<MediaCodecBuffer> &buffer,
+            bool secure,
+            const uint8_t *key,
+            const uint8_t *iv,
+            CryptoPlugin::Mode mode,
+            CryptoPlugin::Pattern pattern,
+            const CryptoPlugin::SubSample *subSamples,
+            size_t numSubSamples,
+            AString *errorDetailMsg) override;
+    virtual status_t renderOutputBuffer(
+            const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override;
+    virtual status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override;
+    virtual void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
+    virtual void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) override;
+
+    // Methods below are interface for ACodec to use.
+
+    /**
+     * Set input buffer array.
+     *
+     * @param array     Newly allocated buffers. Empty if buffers are
+     *                  deallocated.
+     */
+    void setInputBufferArray(const std::vector<BufferAndId> &array);
+    /**
+     * Set output buffer array.
+     *
+     * @param array     Newly allocated buffers. Empty if buffers are
+     *                  deallocated.
+     */
+    void setOutputBufferArray(const std::vector<BufferAndId> &array);
+    /**
+     * Request MediaCodec to fill the specified input buffer.
+     *
+     * @param bufferId  ID of the buffer, assigned by underlying component.
+     */
+    void fillThisBuffer(IOMX::buffer_id bufferID);
+    /**
+     * Request MediaCodec to drain the specified output buffer.
+     *
+     * @param bufferId  ID of the buffer, assigned by underlying component.
+     * @param omxFlags  flags associated with this buffer (e.g. EOS).
+     */
+    void drainThisBuffer(IOMX::buffer_id bufferID, OMX_U32 omxFlags);
+
+private:
+    const sp<AMessage> mInputBufferFilled;
+    const sp<AMessage> mOutputBufferDrained;
+
+    sp<MemoryDealer> mDealer;
+
+    // These should only be accessed via std::atomic_* functions.
+    //
+    // Note on thread safety: since the vector and BufferInfo are const, it's
+    // safe to read them at any thread once the shared_ptr object is atomically
+    // obtained. Inside BufferInfo, mBufferId and mSharedEncryptedBuffer are
+    // immutable objects. We write internal states of mClient/CodecBuffer when
+    // the caller has given up the reference, so that access is also safe.
+    std::shared_ptr<const std::vector<const BufferInfo>> mInputBuffers;
+    std::shared_ptr<const std::vector<const BufferInfo>> mOutputBuffers;
+};
+
+}  // namespace android
+
+#endif  // A_BUFFER_CHANNEL_H_
diff --git a/media/libstagefright/omx/hal/1.0/Conversion.h b/media/libstagefright/omx/hal/1.0/Conversion.h
index 44d2c84..d42e5bf 100644
--- a/media/libstagefright/omx/hal/1.0/Conversion.h
+++ b/media/libstagefright/omx/hal/1.0/Conversion.h
@@ -2,7 +2,6 @@
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0__CONVERSION_H
 
 #include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
 
 #include <unistd.h>
 #include <vector>
@@ -147,13 +146,13 @@
  */
 
 /**
- * \brief Convert `binder::Status` to `hardware::Status`.
+ * \brief Convert `binder::Status` to `Return<void>`.
  *
  * \param[in] l The source `binder::Status`.
- * \return The corresponding `hardware::Status`.
+ * \return The corresponding `Return<void>`.
  */
-// convert: ::android::binder::Status -> ::android::hardware::Status
-inline ::android::hardware::Status toHardwareStatus(
+// convert: ::android::binder::Status -> Return<void>
+inline Return<void> toHardwareStatus(
         ::android::binder::Status const& l) {
     if (l.exceptionCode() == ::android::binder::Status::EX_SERVICE_SPECIFIC) {
         return ::android::hardware::Status::fromServiceSpecificError(
@@ -166,36 +165,17 @@
 }
 
 /**
- * \brief Convert `hardware::Status` to `binder::Status`.
+ * \brief Convert `Return<void>` to `binder::Status`.
  *
- * \param[in] t The source `hardware::Status`.
+ * \param[in] t The source `Return<void>`.
  * \return The corresponding `binder::Status`.
  */
-// convert: ::android::hardware::Status -> ::android::binder::Status
+// convert: Return<void> -> ::android::binder::Status
 inline ::android::binder::Status toBinderStatus(
-        ::android::hardware::Status const& t) {
-    if (t.exceptionCode() == ::android::hardware::Status::EX_SERVICE_SPECIFIC) {
-        return ::android::binder::Status::fromServiceSpecificError(
-                t.serviceSpecificErrorCode(),
-                t.exceptionMessage());
-    }
+        Return<void> const& t) {
     return ::android::binder::Status::fromExceptionCode(
-            t.exceptionCode(),
-            t.exceptionMessage());
-}
-
-/**
- * \brief Convert `hardware::Return<void>` to `binder::Status`.
- *
- * \param[in] t The source `hardware::Return<void>`.
- * \return The corresponding `binder::Status`.
- *
- * This function simply calls `toBinderStatus(::android::hardware::Status
- * const&)`.
- */
-// convert: ::android::hardware::Return<void> -> ::android::binder::Status
-inline ::android::binder::Status toBinderStatus(Return<void> const& t) {
-    return toBinderStatus(t.getStatus());
+            t.isOk() ? OK : UNKNOWN_ERROR,
+            t.description().c_str());
 }
 
 /**
@@ -215,8 +195,7 @@
  */
 // convert: Status -> status_t
 inline status_t toStatusT(Return<Status> const& t) {
-    return t.isOk() ? static_cast<status_t>(static_cast<Status>(t)) :
-            t.getStatus().transactionError();
+    return t.isOk() ? static_cast<status_t>(static_cast<Status>(t)) : UNKNOWN_ERROR;
 }
 
 /**
@@ -227,7 +206,7 @@
  */
 // convert: Return<void> -> status_t
 inline status_t toStatusT(Return<void> const& t) {
-    return t.getStatus().transactionError();
+    return t.isOk() ? OK : UNKNOWN_ERROR;
 }
 
 /**
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 10314e9..d11a10d 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -38,6 +38,8 @@
 #define cpu_to_le16(x)  htole16(x)
 #define cpu_to_le32(x)  htole32(x)
 
+#define FUNCTIONFS_ENDPOINT_ALLOC       _IOR('g', 131, __u32)
+
 namespace {
 
 constexpr char FFS_MTP_EP_IN[] = "/dev/usb-ffs/mtp/ep1";
@@ -467,6 +469,24 @@
     mLock.unlock();
 }
 
+class ScopedEndpointBufferAlloc {
+private:
+    const int mFd;
+    const unsigned int mAllocSize;
+public:
+    ScopedEndpointBufferAlloc(int fd, unsigned alloc_size) :
+        mFd(fd),
+        mAllocSize(alloc_size) {
+        if (ioctl(mFd, FUNCTIONFS_ENDPOINT_ALLOC, static_cast<__u32>(mAllocSize)))
+            PLOG(DEBUG) << "FFS endpoint alloc failed!";
+    }
+
+    ~ScopedEndpointBufferAlloc() {
+        if (ioctl(mFd, FUNCTIONFS_ENDPOINT_ALLOC, static_cast<__u32>(0)))
+            PLOG(DEBUG) << "FFS endpoint alloc reset failed!";
+    }
+};
+
 /* Read from USB and write to a local file. */
 int MtpFfsHandle::receiveFile(mtp_file_range mfr) {
     // When receiving files, the incoming length is given in 32 bits.
@@ -494,6 +514,7 @@
     bool write = false;
 
     posix_fadvise(mfr.fd, 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE);
+    ScopedEndpointBufferAlloc(mBulkOut, mMaxRead);
 
     // Break down the file into pieces that fit in buffers
     while (file_length > 0 || write) {
@@ -609,6 +630,8 @@
     if (writeHandle(mBulkIn, data, packet_size) == -1) return -1;
     if (file_length == 0) return 0;
 
+    ScopedEndpointBufferAlloc(mBulkIn, mMaxWrite);
+
     // Break down the file into pieces that fit in buffers
     while(file_length > 0) {
         if (read) {
diff --git a/radio/IRadio.cpp b/radio/IRadio.cpp
index ebf3859..5bbe7cb 100644
--- a/radio/IRadio.cpp
+++ b/radio/IRadio.cpp
@@ -172,16 +172,11 @@
     virtual status_t getProgramInformation(struct radio_program_info *info)
     {
         Parcel data, reply;
-        if (info == NULL) {
+        if (info == nullptr || info->metadata == nullptr) {
             return BAD_VALUE;
         }
         radio_metadata_t *metadata = info->metadata;
         data.writeInterfaceToken(IRadio::getInterfaceDescriptor());
-        if (metadata != NULL) {
-            data.writeUint32(1);
-        } else {
-            data.writeUint32(0);
-        }
         status_t status = remote()->transact(GET_PROGRAM_INFORMATION, data, &reply);
         if (status == NO_ERROR) {
             status = (status_t)reply.readInt32();
@@ -190,13 +185,13 @@
                 // restore local metadata pointer
                 info->metadata = metadata;
 
-                uint32_t metatataSize = reply.readUint32();
-                if ((metadata != NULL) && (metatataSize != 0)) {
-                    radio_metadata_t *newMetadata = (radio_metadata_t *)malloc(metatataSize);
+                uint32_t metadataSize = reply.readUint32();
+                if (metadataSize != 0) {
+                    radio_metadata_t *newMetadata = (radio_metadata_t *)malloc(metadataSize);
                     if (newMetadata == NULL) {
                         return NO_MEMORY;
                     }
-                    reply.read(newMetadata, metatataSize);
+                    reply.read(newMetadata, metadataSize);
                     status = radio_metadata_add_metadata(&info->metadata, newMetadata);
                     free(newMetadata);
                 }
@@ -306,21 +301,17 @@
             CHECK_INTERFACE(IRadio, data, reply);
             struct radio_program_info info;
             status_t status;
-            // query metadata only if requested by remote side
-            if (data.readUint32() == 1) {
-                status = radio_metadata_allocate(&info.metadata, 0, 0);
-                if (status != NO_ERROR) {
-                    return status;
-                }
-            } else {
-                info.metadata = NULL;
+
+            status = radio_metadata_allocate(&info.metadata, 0, 0);
+            if (status != NO_ERROR) {
+                return status;
             }
             status = getProgramInformation(&info);
 
             reply->writeInt32(status);
             if (status == NO_ERROR) {
                 reply->write(&info, sizeof(struct radio_program_info));
-                if ((info.metadata != NULL) && (radio_metadata_get_count(info.metadata) > 0)) {
+                if (radio_metadata_get_count(info.metadata) > 0) {
                     size_t size = radio_metadata_get_size(info.metadata);
                     reply->writeUint32((uint32_t)size);
                     reply->write(info.metadata, size);
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 51d785a..aa2cd95 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -28,8 +28,6 @@
     AudioStreamOut.cpp          \
     SpdifStreamOut.cpp          \
     Effects.cpp                 \
-    AudioMixer.cpp.arm          \
-    BufferProviders.cpp         \
     PatchPanel.cpp              \
     StateQueue.cpp              \
     BufLog.cpp
@@ -37,12 +35,11 @@
 LOCAL_C_INCLUDES := \
     $(TOPDIR)frameworks/av/services/audiopolicy \
     $(TOPDIR)frameworks/av/services/medialog \
-    $(TOPDIR)external/sonic \
     $(call include-path-for, audio-utils)
 
 LOCAL_SHARED_LIBRARIES := \
     libaudiohal \
-    libaudioresampler \
+    libaudioprocessing \
     libaudiospdif \
     libaudioutils \
     libcutils \
@@ -55,7 +52,6 @@
     libnbaio \
     libpowermanager \
     libserviceutility \
-    libsonic \
     libmediautils \
     libmemunreachable \
     libmedia_helper
@@ -87,59 +83,4 @@
 
 include $(BUILD_SHARED_LIBRARY)
 
-#
-# build audio resampler test tool
-#
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=               \
-    test-resample.cpp           \
-
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils)
-
-LOCAL_STATIC_LIBRARIES := \
-    libsndfile
-
-LOCAL_SHARED_LIBRARIES := \
-    libaudioresampler \
-    libaudioutils \
-    libdl \
-    libcutils \
-    libutils \
-    liblog
-
-LOCAL_MODULE:= test-resample
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -Werror -Wall
-
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    AudioResampler.cpp.arm \
-    AudioResamplerCubic.cpp.arm \
-    AudioResamplerSinc.cpp.arm \
-    AudioResamplerDyn.cpp.arm
-
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils)
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libdl \
-    liblog
-
-LOCAL_MODULE := libaudioresampler
-
-LOCAL_CFLAGS := -Werror -Wall
-
-# uncomment to disable NEON on architectures that actually do support NEON, for benchmarking
-#LOCAL_CFLAGS += -DUSE_NEON=false
-
-include $(BUILD_SHARED_LIBRARY)
-
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index e4b73c6..a248912 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -46,7 +46,6 @@
 
 #include <system/audio.h>
 
-#include "AudioMixer.h"
 #include "AudioFlinger.h"
 #include "ServiceUtilities.h"
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index d18ca47..35eceb2 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -48,19 +48,20 @@
 #include <system/audio.h>
 #include <system/audio_policy.h>
 
+#include <media/audiohal/EffectBufferHalInterface.h>
 #include <media/audiohal/StreamHalInterface.h>
 #include <media/AudioBufferProvider.h>
+#include <media/AudioMixer.h>
 #include <media/ExtendedAudioBufferProvider.h>
+#include <media/LinearMap.h>
 
 #include "FastCapture.h"
 #include "FastMixer.h"
 #include <media/nbaio/NBAIO.h>
 #include "AudioWatchdog.h"
-#include "AudioMixer.h"
 #include "AudioStreamOut.h"
 #include "SpdifStreamOut.h"
 #include "AudioHwDevice.h"
-#include "LinearMap.h"
 
 #include <powermanager/IPowerManager.h>
 
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 6c937a5..343ad25 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -188,6 +188,7 @@
     // this object is released which can happen after next process is called.
     if (mHandles.size() == 0 && !mPinned) {
         mState = DESTROYED;
+        mEffectInterface->close();
     }
 
     return mHandles.size();
@@ -275,9 +276,7 @@
 {
     Mutex::Autolock _l(mLock);
 
-    if (mState == DESTROYED || mEffectInterface == 0 ||
-            mConfig.inputCfg.buffer.raw == NULL ||
-            mConfig.outputCfg.buffer.raw == NULL) {
+    if (mState == DESTROYED || mEffectInterface == 0 || mInBuffer == 0 || mOutBuffer == 0) {
         return;
     }
 
@@ -291,7 +290,7 @@
         int ret;
         if (isProcessImplemented()) {
             // do the actual processing in the effect engine
-            ret = mEffectInterface->process(&mConfig.inputCfg.buffer, &mConfig.outputCfg.buffer);
+            ret = mEffectInterface->process();
         } else {
             if (mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) {
                 size_t frameCnt = mConfig.inputCfg.buffer.frameCount * FCC_2;  //always stereo here
@@ -409,6 +408,12 @@
     mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
     mConfig.inputCfg.buffer.frameCount = thread->frameCount();
     mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount;
+    if (mInBuffer != 0) {
+        mInBuffer->setFrameCount(mConfig.inputCfg.buffer.frameCount);
+    }
+    if (mOutBuffer != 0) {
+        mOutBuffer->setFrameCount(mConfig.outputCfg.buffer.frameCount);
+    }
 
     ALOGV("configure() %p thread %p buffer %p framecount %zu",
             this, thread.get(), mConfig.inputCfg.buffer.raw, mConfig.inputCfg.buffer.frameCount);
@@ -568,6 +573,7 @@
     if (mEffectInterface != 0) {
         remove_effect_from_hal_l();
         // release effect engine
+        mEffectInterface->close();
         mEffectInterface.clear();
     }
 }
@@ -762,6 +768,28 @@
     }
 }
 
+void AudioFlinger::EffectModule::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
+    if (buffer != 0) {
+        mConfig.inputCfg.buffer.raw = buffer->audioBuffer()->raw;
+        buffer->setFrameCount(mConfig.inputCfg.buffer.frameCount);
+    } else {
+        mConfig.inputCfg.buffer.raw = NULL;
+    }
+    mInBuffer = buffer;
+    mEffectInterface->setInBuffer(buffer);
+}
+
+void AudioFlinger::EffectModule::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
+    if (buffer != 0) {
+        mConfig.outputCfg.buffer.raw = buffer->audioBuffer()->raw;
+        buffer->setFrameCount(mConfig.outputCfg.buffer.frameCount);
+    } else {
+        mConfig.outputCfg.buffer.raw = NULL;
+    }
+    mOutBuffer = buffer;
+    mEffectInterface->setOutBuffer(buffer);
+}
+
 status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller)
 {
     Mutex::Autolock _l(mLock);
@@ -1482,7 +1510,7 @@
 AudioFlinger::EffectChain::EffectChain(ThreadBase *thread,
                                         audio_session_t sessionId)
     : mThread(thread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
-      mOwnInBuffer(false), mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
+      mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
       mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
 {
     mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
@@ -1495,9 +1523,6 @@
 
 AudioFlinger::EffectChain::~EffectChain()
 {
-    if (mOwnInBuffer) {
-        delete[] mInBuffer;
-    }
 }
 
 // getEffectFromDesc_l() must be called with ThreadBase::mLock held
@@ -1562,7 +1587,8 @@
     // (4 bytes frame size)
     const size_t frameSize =
             audio_bytes_per_sample(AUDIO_FORMAT_PCM_16_BIT) * min(FCC_2, thread->channelCount());
-    memset(mInBuffer, 0, thread->frameCount() * frameSize);
+    memset(mInBuffer->audioBuffer()->raw, 0, thread->frameCount() * frameSize);
+    mInBuffer->commit();
 }
 
 // Must be called with EffectChain::mLock locked
@@ -1600,9 +1626,15 @@
 
     size_t size = mEffects.size();
     if (doProcess) {
+        // Only the input and output buffers of the chain can be external,
+        // and 'update' / 'commit' do nothing for allocated buffers, thus
+        // it's not needed to consider any other buffers here.
+        mInBuffer->update();
+        mOutBuffer->update();
         for (size_t i = 0; i < size; i++) {
             mEffects[i]->process();
         }
+        mOutBuffer->commit();
     }
     bool doResetVolume = false;
     for (size_t i = 0; i < size; i++) {
@@ -1662,9 +1694,11 @@
         // accumulation stage. Saturation is done in EffectModule::process() before
         // calling the process in effect engine
         size_t numSamples = thread->frameCount();
-        int32_t *buffer = new int32_t[numSamples];
-        memset(buffer, 0, numSamples * sizeof(int32_t));
-        effect->setInBuffer((int16_t *)buffer);
+        sp<EffectBufferHalInterface> halBuffer;
+        status_t result = EffectBufferHalInterface::allocate(
+                numSamples * sizeof(int32_t), &halBuffer);
+        if (result != OK) return result;
+        effect->setInBuffer(halBuffer);
         // auxiliary effects output samples to chain input buffer for further processing
         // by insert effects
         effect->setOutBuffer(mInBuffer);
@@ -1775,9 +1809,7 @@
                 mEffects[i]->release_l();
             }
 
-            if (type == EFFECT_FLAG_TYPE_AUXILIARY) {
-                delete[] effect->inBuffer();
-            } else {
+            if (type != EFFECT_FLAG_TYPE_AUXILIARY) {
                 if (i == size - 1 && i != 0) {
                     mEffects[i - 1]->setOutBuffer(mOutBuffer);
                     mEffects[i - 1]->configure();
@@ -1922,8 +1954,8 @@
 
         result.append("\tIn buffer   Out buffer   Active tracks:\n");
         snprintf(buffer, SIZE, "\t%p  %p   %d\n",
-                mInBuffer,
-                mOutBuffer,
+                mInBuffer->audioBuffer(),
+                mOutBuffer->audioBuffer(),
                 mActiveTrackCnt);
         result.append(buffer);
         write(fd, result.string(), result.size());
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index dc29ce0..0755c52 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -86,10 +86,14 @@
     bool isEnabled() const;
     bool isProcessEnabled() const;
 
-    void        setInBuffer(int16_t *buffer) { mConfig.inputCfg.buffer.s16 = buffer; }
-    int16_t     *inBuffer() { return mConfig.inputCfg.buffer.s16; }
-    void        setOutBuffer(int16_t *buffer) { mConfig.outputCfg.buffer.s16 = buffer; }
-    int16_t     *outBuffer() { return mConfig.outputCfg.buffer.s16; }
+    void        setInBuffer(const sp<EffectBufferHalInterface>& buffer);
+    int16_t     *inBuffer() const {
+        return mInBuffer != 0 ? reinterpret_cast<int16_t*>(mInBuffer->ptr()) : NULL;
+    }
+    void        setOutBuffer(const sp<EffectBufferHalInterface>& buffer);
+    int16_t     *outBuffer() const {
+        return mOutBuffer != 0 ? reinterpret_cast<int16_t*>(mOutBuffer->ptr()) : NULL;
+    }
     void        setChain(const wp<EffectChain>& chain) { mChain = chain; }
     void        setThread(const wp<ThreadBase>& thread) { mThread = thread; }
     const wp<ThreadBase>& thread() { return mThread; }
@@ -153,6 +157,8 @@
     const effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
     effect_config_t     mConfig;    // input and output audio configuration
     sp<EffectHalInterface> mEffectInterface; // Effect module HAL
+    sp<EffectBufferHalInterface> mInBuffer;  // Buffers for interacting with HAL
+    sp<EffectBufferHalInterface> mOutBuffer;
     status_t            mStatus;    // initialization status
     effect_state        mState;     // current activation state
     Vector<EffectHandle *> mHandles;    // list of client handles
@@ -301,18 +307,17 @@
     void setMode_l(audio_mode_t mode);
     void setAudioSource_l(audio_source_t source);
 
-    void setInBuffer(int16_t *buffer, bool ownsBuffer = false) {
+    void setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
         mInBuffer = buffer;
-        mOwnInBuffer = ownsBuffer;
     }
     int16_t *inBuffer() const {
-        return mInBuffer;
+        return mInBuffer != 0 ? reinterpret_cast<int16_t*>(mInBuffer->ptr()) : NULL;
     }
-    void setOutBuffer(int16_t *buffer) {
+    void setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
         mOutBuffer = buffer;
     }
     int16_t *outBuffer() const {
-        return mOutBuffer;
+        return mOutBuffer != 0 ? reinterpret_cast<int16_t*>(mOutBuffer->ptr()) : NULL;
     }
 
     void incTrackCnt() { android_atomic_inc(&mTrackCnt); }
@@ -394,8 +399,8 @@
     mutable  Mutex mLock;        // mutex protecting effect list
              Vector< sp<EffectModule> > mEffects; // list of effect modules
              audio_session_t mSessionId; // audio session ID
-             int16_t *mInBuffer;         // chain input buffer
-             int16_t *mOutBuffer;        // chain output buffer
+             sp<EffectBufferHalInterface> mInBuffer;  // chain input buffer
+             sp<EffectBufferHalInterface> mOutBuffer; // chain output buffer
 
     // 'volatile' here means these are accessed with atomic operations instead of mutex
     volatile int32_t mActiveTrackCnt;    // number of active tracks connected
@@ -403,7 +408,6 @@
 
              int32_t mTailBufferCount;   // current effect tail buffer count
              int32_t mMaxTailBuffers;    // maximum effect tail buffers
-             bool mOwnInBuffer;          // true if the chain owns its input buffer
              int mVolumeCtrlIdx;         // index of insert effect having control over volume
              uint32_t mLeftVolume;       // previous volume on left channel
              uint32_t mRightVolume;      // previous volume on right channel
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 93f7ce5..7182f32 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -39,7 +39,7 @@
 #endif
 #include <audio_utils/conversion.h>
 #include <audio_utils/format.h>
-#include "AudioMixer.h"
+#include <media/AudioMixer.h>
 #include "FastMixer.h"
 
 namespace android {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index abfbf0f..e025316 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -56,8 +56,6 @@
 #include <powermanager/PowerManager.h>
 
 #include "AudioFlinger.h"
-#include "AudioMixer.h"
-#include "BufferProviders.h"
 #include "FastMixer.h"
 #include "FastCapture.h"
 #include "ServiceUtilities.h"
@@ -2759,9 +2757,14 @@
 status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain)
 {
     audio_session_t session = chain->sessionId();
-    int16_t* buffer = reinterpret_cast<int16_t*>(mEffectBufferEnabled
-            ? mEffectBuffer : mSinkBuffer);
-    bool ownsBuffer = false;
+    sp<EffectBufferHalInterface> halInBuffer, halOutBuffer;
+    status_t result = EffectBufferHalInterface::mirror(
+            mEffectBufferEnabled ? mEffectBuffer : mSinkBuffer,
+            mEffectBufferEnabled ? mEffectBufferSize : mSinkBufferSize,
+            &halInBuffer);
+    if (result != OK) return result;
+    halOutBuffer = halInBuffer;
+    int16_t *buffer = reinterpret_cast<int16_t*>(halInBuffer->externalData());
 
     ALOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
     if (session > AUDIO_SESSION_OUTPUT_MIX) {
@@ -2769,10 +2772,13 @@
         // the sink buffer as input
         if (mType != DIRECT) {
             size_t numSamples = mNormalFrameCount * mChannelCount;
-            buffer = new int16_t[numSamples];
-            memset(buffer, 0, numSamples * sizeof(int16_t));
-            ALOGV("addEffectChain_l() creating new input buffer %p session %d", buffer, session);
-            ownsBuffer = true;
+            status_t result = EffectBufferHalInterface::allocate(
+                    numSamples * sizeof(int16_t),
+                    &halInBuffer);
+            if (result != OK) return result;
+            buffer = halInBuffer->audioBuffer()->s16;
+            ALOGV("addEffectChain_l() creating new input buffer %p session %d",
+                    buffer, session);
         }
 
         // Attach all tracks with same session ID to this chain.
@@ -2795,9 +2801,8 @@
         }
     }
     chain->setThread(this);
-    chain->setInBuffer(buffer, ownsBuffer);
-    chain->setOutBuffer(reinterpret_cast<int16_t*>(mEffectBufferEnabled
-            ? mEffectBuffer : mSinkBuffer));
+    chain->setInBuffer(halInBuffer);
+    chain->setOutBuffer(halOutBuffer);
     // Effect chain for session AUDIO_SESSION_OUTPUT_STAGE is inserted at end of effect
     // chains list in order to be processed last as it contains output stage effects.
     // Effect chain for session AUDIO_SESSION_OUTPUT_MIX is inserted before
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 9746075..48e09c7 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -27,7 +27,6 @@
 
 #include <private/media/AudioTrackShared.h>
 
-#include "AudioMixer.h"
 #include "AudioFlinger.h"
 #include "ServiceUtilities.h"
 
diff --git a/services/audioflinger/tests/Android.mk b/services/audioflinger/tests/Android.mk
deleted file mode 100644
index a741079..0000000
--- a/services/audioflinger/tests/Android.mk
+++ /dev/null
@@ -1,68 +0,0 @@
-# Build the unit tests for audioflinger
-
-#
-# resampler unit test
-#
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libutils \
-	libcutils \
-	libaudioutils \
-	libaudioresampler
-
-LOCAL_C_INCLUDES := \
-	$(call include-path-for, audio-utils) \
-	frameworks/av/services/audioflinger
-
-LOCAL_SRC_FILES := \
-	resampler_tests.cpp
-
-LOCAL_MODULE := resampler_tests
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := -Werror -Wall
-
-include $(BUILD_NATIVE_TEST)
-
-#
-# audio mixer test tool
-#
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	test-mixer.cpp \
-	../AudioMixer.cpp.arm  \
-	../BufferProviders.cpp
-
-LOCAL_C_INCLUDES := \
-	$(call include-path-for, audio-utils) \
-	frameworks/av/services/audioflinger \
-	external/sonic
-
-LOCAL_STATIC_LIBRARIES := \
-	libsndfile
-
-LOCAL_SHARED_LIBRARIES := \
-	libaudiohal \
-	libeffects \
-	libnbaio \
-	libaudioresampler \
-	libaudioutils \
-	libdl \
-	libcutils \
-	libutils \
-	liblog \
-	libsonic
-
-LOCAL_MODULE:= test-mixer
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CXX_STL := libc++
-
-LOCAL_CFLAGS := -Werror -Wall
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 43c1b0a..923d4f6 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -342,6 +342,9 @@
     ALOGV("handleDeviceConfigChange(() device: 0x%X, address %s name %s",
           device, device_address, device_name);
 
+    // connect/disconnect only 1 device at a time
+    if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
+
     // Check if the device is currently connected
     sp<DeviceDescriptor> devDesc =
             mHwModules.getDeviceDescriptor(device, device_address, device_name);
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 52aa143..1e63a05 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -37,9 +37,6 @@
     if (!settingsAllowed()) {
         return PERMISSION_DENIED;
     }
-    if (!audio_is_output_device(device) && !audio_is_input_device(device)) {
-        return BAD_VALUE;
-    }
     if (state != AUDIO_POLICY_DEVICE_STATE_AVAILABLE &&
             state != AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
         return BAD_VALUE;
@@ -72,9 +69,6 @@
     if (!settingsAllowed()) {
         return PERMISSION_DENIED;
     }
-    if (!audio_is_output_device(device) && !audio_is_input_device(device)) {
-        return BAD_VALUE;
-    }
 
     ALOGV("handleDeviceConfigChange()");
     Mutex::Autolock _l(mLock);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 4a5250a..3aec562 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -68,13 +68,22 @@
     mLegacyMode = legacyMode;
 }
 
-status_t Camera2Client::initialize(CameraModule *module)
+status_t Camera2Client::initialize(CameraModule *module) {
+    return initializeImpl(module);
+}
+
+status_t Camera2Client::initialize(sp<CameraProviderManager> manager) {
+    return initializeImpl(manager);
+}
+
+template<typename TProviderPtr>
+status_t Camera2Client::initializeImpl(TProviderPtr providerPtr)
 {
     ATRACE_CALL();
     ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId);
     status_t res;
 
-    res = Camera2ClientBase::initialize(module);
+    res = Camera2ClientBase::initialize(providerPtr);
     if (res != OK) {
         return res;
     }
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index e2129f5..87c91a0 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -98,7 +98,8 @@
 
     virtual ~Camera2Client();
 
-    status_t initialize(CameraModule *module);
+    virtual status_t initialize(CameraModule *module) override;
+    virtual status_t initialize(sp<CameraProviderManager> manager) override;
 
     virtual status_t dump(int fd, const Vector<String16>& args);
 
@@ -219,6 +220,9 @@
 
     // Video snapshot jpeg size overriding helper function
     status_t overrideVideoSnapshotSize(Parameters &params);
+
+    template<typename TProviderPtr>
+    status_t initializeImpl(TProviderPtr providerPtr);
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 32b99ca..6efe4e3 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -917,6 +917,8 @@
     } else {
         allowZslMode = true;
     }
+    // TODO (b/34131351): turn ZSL back on after fixing the issue
+    allowZslMode = false;
 
     ALOGI("%s: allowZslMode: %d slowJpegMode %d", __FUNCTION__, allowZslMode, slowJpegMode);
 
diff --git a/services/radio/HidlUtils.cpp b/services/radio/HidlUtils.cpp
index bfced7a..3b33386 100644
--- a/services/radio/HidlUtils.cpp
+++ b/services/radio/HidlUtils.cpp
@@ -122,8 +122,7 @@
 
 //static
 void HidlUtils::convertProgramInfoFromHal(radio_program_info_t *info,
-                                          const ProgramInfo *halInfo,
-                                          bool withMetadata)
+                                          const ProgramInfo *halInfo)
 {
     info->channel = halInfo->channel;
     info->sub_channel = halInfo->subChannel;
@@ -131,10 +130,8 @@
     info->stereo = halInfo->stereo;
     info->digital = halInfo->digital;
     info->signal_strength = halInfo->signalStrength;
-    if (withMetadata && halInfo->metadata.size() != 0) {
-        convertMetaDataFromHal(&info->metadata, halInfo->metadata,
-                               halInfo->channel, halInfo->subChannel);
-    }
+    convertMetaDataFromHal(&info->metadata, halInfo->metadata,
+                           halInfo->channel, halInfo->subChannel);
 }
 
 //static
diff --git a/services/radio/HidlUtils.h b/services/radio/HidlUtils.h
index 091abb7..c771060 100644
--- a/services/radio/HidlUtils.h
+++ b/services/radio/HidlUtils.h
@@ -38,8 +38,7 @@
     static void convertBandConfigToHal(BandConfig *halConfig,
                                        const radio_hal_band_config_t *config);
     static void convertProgramInfoFromHal(radio_program_info_t *info,
-                                          const ProgramInfo *halInfo,
-                                          bool withMetadata);
+                                          const ProgramInfo *halInfo);
     static void convertMetaDataFromHal(radio_metadata_t **metadata,
                                        const hidl_vec<MetaData>& halMetadata,
                                        uint32_t channel,
diff --git a/services/radio/RadioHalHidl.cpp b/services/radio/RadioHalHidl.cpp
index c7a899a..34a6db7 100644
--- a/services/radio/RadioHalHidl.cpp
+++ b/services/radio/RadioHalHidl.cpp
@@ -39,11 +39,6 @@
     return new RadioHalHidl(classId);
 }
 
-void RadioHalHidl::crashIfHalIsDead(const Status& status) {
-    LOG_ALWAYS_FATAL_IF(
-            status.transactionError() == DEAD_OBJECT, "HAL server crashed, need to restart");
-}
-
 int RadioHalHidl::getProperties(radio_hal_properties_t *properties)
 {
     ALOGV("%s IN", __FUNCTION__);
@@ -52,7 +47,7 @@
         return -ENODEV;
     }
     Properties halProperties;
-    Result halResult;
+    Result halResult = Result::NOT_INITIALIZED;
     Return<void> hidlReturn =
             module->getProperties([&](Result result, const Properties& properties) {
                     halResult = result;
@@ -61,7 +56,6 @@
                     }
                 });
 
-    crashIfHalIsDead(hidlReturn.getStatus());
     if (halResult == Result::OK) {
         HidlUtils::convertPropertiesFromHal(properties, &halProperties);
     }
@@ -80,7 +74,7 @@
     sp<Tuner> tunerImpl = new Tuner(callback, this);
 
     BandConfig halConfig;
-    Result halResult;
+    Result halResult = Result::NOT_INITIALIZED;
     sp<ITuner> halTuner;
 
     HidlUtils::convertBandConfigToHal(&halConfig, config);
@@ -93,7 +87,6 @@
                     }
                 });
 
-    crashIfHalIsDead(hidlReturn.getStatus());
     if (halResult == Result::OK) {
         tunerImpl->setHalTuner(halTuner);
         tuner = tunerImpl;
@@ -154,7 +147,6 @@
     HidlUtils::convertBandConfigToHal(&halConfig, config);
 
     Return<Result> hidlResult = mHalTuner->setConfiguration(halConfig);
-    checkHidlStatus(hidlResult.getStatus());
     return HidlUtils::convertHalResult(hidlResult);
 }
 
@@ -173,8 +165,7 @@
                         halConfig = config;
                     }
                 });
-    status_t status = checkHidlStatus(hidlReturn.getStatus());
-    if (status == NO_ERROR && halResult == Result::OK) {
+    if (hidlReturn.isOk() && halResult == Result::OK) {
         HidlUtils::convertBandConfigFromHal(config, &halConfig);
     }
     return HidlUtils::convertHalResult(halResult);
@@ -188,7 +179,6 @@
     }
     Return<Result> hidlResult =
             mHalTuner->scan(static_cast<Direction>(direction), skip_sub_channel);
-    checkHidlStatus(hidlResult.getStatus());
     return HidlUtils::convertHalResult(hidlResult);
 }
 
@@ -200,7 +190,6 @@
     }
     Return<Result> hidlResult =
             mHalTuner->step(static_cast<Direction>(direction), skip_sub_channel);
-    checkHidlStatus(hidlResult.getStatus());
     return HidlUtils::convertHalResult(hidlResult);
 }
 
@@ -212,7 +201,6 @@
     }
     Return<Result> hidlResult =
             mHalTuner->tune(channel, sub_channel);
-    checkHidlStatus(hidlResult.getStatus());
     return HidlUtils::convertHalResult(hidlResult);
 }
 
@@ -223,7 +211,6 @@
         return -ENODEV;
     }
     Return<Result> hidlResult = mHalTuner->cancel();
-    checkHidlStatus(hidlResult.getStatus());
     return HidlUtils::convertHalResult(hidlResult);
 }
 
@@ -233,19 +220,20 @@
     if (mHalTuner == 0) {
         return -ENODEV;
     }
+    if (info == nullptr || info->metadata == nullptr) {
+        return BAD_VALUE;
+    }
     ProgramInfo halInfo;
     Result halResult;
-    bool withMetaData = (info->metadata != NULL);
     Return<void> hidlReturn = mHalTuner->getProgramInformation(
-                    withMetaData, [&](Result result, const ProgramInfo& info) {
-                        halResult = result;
-                        if (result == Result::OK) {
-                            halInfo = info;
-                        }
-    });
-    status_t status = checkHidlStatus(hidlReturn.getStatus());
-    if (status == NO_ERROR && halResult == Result::OK) {
-        HidlUtils::convertProgramInfoFromHal(info, &halInfo, withMetaData);
+        [&](Result result, const ProgramInfo& info) {
+            halResult = result;
+            if (result == Result::OK) {
+                halInfo = info;
+            }
+        });
+    if (hidlReturn.isOk() && halResult == Result::OK) {
+        HidlUtils::convertProgramInfoFromHal(info, &halInfo);
     }
     return HidlUtils::convertHalResult(halResult);
 }
@@ -276,11 +264,9 @@
     memset(&event, 0, sizeof(radio_hal_event_t));
     event.type = RADIO_EVENT_TUNED;
     event.status = HidlUtils::convertHalResult(result);
-    HidlUtils::convertProgramInfoFromHal(&event.info, &info, true);
+    HidlUtils::convertProgramInfoFromHal(&event.info, &info);
     onCallback(&event);
-    if (event.info.metadata != NULL) {
-        radio_metadata_deallocate(event.info.metadata);
-    }
+    radio_metadata_deallocate(event.info.metadata);
     return Return<void>();
 }
 
@@ -290,7 +276,7 @@
     radio_hal_event_t event;
     memset(&event, 0, sizeof(radio_hal_event_t));
     event.type = RADIO_EVENT_AF_SWITCH;
-    HidlUtils::convertProgramInfoFromHal(&event.info, &info, true);
+    HidlUtils::convertProgramInfoFromHal(&event.info, &info);
     onCallback(&event);
     if (event.info.metadata != NULL) {
         radio_metadata_deallocate(event.info.metadata);
@@ -368,16 +354,6 @@
     mHalTuner.clear();
 }
 
-status_t RadioHalHidl::Tuner::checkHidlStatus(Status hidlStatus)
-{
-    status_t status = hidlStatus.transactionError();
-    if (status == DEAD_OBJECT) {
-        handleHwFailure();
-    }
-    RadioHalHidl::crashIfHalIsDead(hidlStatus);
-    return status;
-}
-
 void RadioHalHidl::Tuner::onCallback(radio_hal_event_t *halEvent)
 {
     if (mCallback != 0) {
diff --git a/services/radio/RadioHalHidl.h b/services/radio/RadioHalHidl.h
index 1657a40..b60a95e 100644
--- a/services/radio/RadioHalHidl.h
+++ b/services/radio/RadioHalHidl.h
@@ -45,8 +45,6 @@
 public:
                     RadioHalHidl(radio_class_t classId);
 
-        static void crashIfHalIsDead(const Status& status);
-
                     // RadioInterface
         virtual int getProperties(radio_hal_properties_t *properties);
         virtual int openTuner(const radio_hal_band_config_t *config,
@@ -88,7 +86,6 @@
 
                     void     onCallback(radio_hal_event_t *halEvent);
                     void     handleHwFailure();
-                    status_t checkHidlStatus(Status hidlStatus);
 
             sp<ITuner> mHalTuner;
             sp<TunerCallbackInterface>  mCallback;
diff --git a/services/soundtrigger/SoundTriggerHalHidl.cpp b/services/soundtrigger/SoundTriggerHalHidl.cpp
index c027799..eb9d38d 100644
--- a/services/soundtrigger/SoundTriggerHalHidl.cpp
+++ b/services/soundtrigger/SoundTriggerHalHidl.cpp
@@ -53,13 +53,13 @@
         });
     }
 
-    if (hidlReturn.getStatus().isOk()) {
+    if (hidlReturn.isOk()) {
         if (ret == 0) {
             convertPropertiesFromHal(properties, &halProperties);
         }
     } else {
-        ret = (int)hidlReturn.getStatus().transactionError();
-        crashIfHalIsDead(ret);
+        ALOGE("getProperties error %s", hidlReturn.description().c_str());
+        return UNKNOWN_ERROR;
     }
     ALOGI("getProperties ret %d", ret);
     return ret;
@@ -123,7 +123,7 @@
 
     delete halSoundModel;
 
-    if (hidlReturn.getStatus().isOk()) {
+    if (hidlReturn.isOk()) {
         if (ret == 0) {
             AutoMutex lock(mLock);
             *handle = (sound_model_handle_t)modelId;
@@ -131,12 +131,10 @@
             mSoundModels.add(*handle, model);
         }
     } else {
-        ret = (int)hidlReturn.getStatus().transactionError();
-        ALOGE("loadSoundModel error %d", ret);
-        crashIfHalIsDead(ret);
+        ALOGE("loadSoundModel error %s", hidlReturn.description().c_str());
+        return UNKNOWN_ERROR;
     }
 
-
     return ret;
 }
 
@@ -158,13 +156,13 @@
         AutoMutex lock(mHalLock);
         hidlReturn = soundtrigger->unloadSoundModel(model->mHalHandle);
     }
-    int ret = (int)hidlReturn.getStatus().transactionError();
-    ALOGE_IF(ret != 0, "unloadSoundModel error %d", ret);
-    crashIfHalIsDead(ret);
-    if (ret == 0) {
-        ret = hidlReturn;
+
+    if (!hidlReturn.isOk()) {
+        ALOGE("unloadSoundModel error %s", hidlReturn.description().c_str());
+        return UNKNOWN_ERROR;
     }
-    return ret;
+
+    return hidlReturn;
 }
 
 int SoundTriggerHalHidl::startRecognition(sound_model_handle_t handle,
@@ -197,13 +195,11 @@
 
     delete halConfig;
 
-    int ret = (int)hidlReturn.getStatus().transactionError();
-    ALOGE_IF(ret != 0, "startRecognition error %d", ret);
-    crashIfHalIsDead(ret);
-    if (ret == 0) {
-        ret = hidlReturn;
+    if (!hidlReturn.isOk()) {
+        ALOGE("startRecognition error %s", hidlReturn.description().c_str());
+        return UNKNOWN_ERROR;
     }
-    return ret;
+    return hidlReturn;
 }
 
 int SoundTriggerHalHidl::stopRecognition(sound_model_handle_t handle)
@@ -225,13 +221,11 @@
         hidlReturn = soundtrigger->stopRecognition(model->mHalHandle);
     }
 
-    int ret = (int)hidlReturn.getStatus().transactionError();
-    ALOGE_IF(ret != 0, "stopRecognition error %d", ret);
-    crashIfHalIsDead(ret);
-    if (ret == 0) {
-        ret = hidlReturn;
+    if (!hidlReturn.isOk()) {
+        ALOGE("stopRecognition error %s", hidlReturn.description().c_str());
+        return UNKNOWN_ERROR;
     }
-    return ret;
+    return hidlReturn;
 }
 
 int SoundTriggerHalHidl::stopAllRecognitions()
@@ -247,13 +241,11 @@
         hidlReturn = soundtrigger->stopAllRecognitions();
     }
 
-    int ret = (int)hidlReturn.getStatus().transactionError();
-    ALOGE_IF(ret != 0, "stopAllRecognitions error %d", ret);
-    crashIfHalIsDead(ret);
-    if (ret == 0) {
-        ret = hidlReturn;
+    if (!hidlReturn.isOk()) {
+        ALOGE("stopAllRecognitions error %s", hidlReturn.description().c_str());
+        return UNKNOWN_ERROR;
     }
-    return ret;
+    return hidlReturn;
 }
 
 SoundTriggerHalHidl::SoundTriggerHalHidl(const char *moduleName)
@@ -279,11 +271,6 @@
     return mISoundTrigger;
 }
 
-void SoundTriggerHalHidl::crashIfHalIsDead(int ret)
-{
-    LOG_ALWAYS_FATAL_IF(ret == -EPIPE, "HAL server crashed, need to restart");
-}
-
 sp<SoundTriggerHalHidl::SoundModel> SoundTriggerHalHidl::getModel(sound_model_handle_t handle)
 {
     AutoMutex lock(mLock);
diff --git a/services/soundtrigger/SoundTriggerHalHidl.h b/services/soundtrigger/SoundTriggerHalHidl.h
index b235e1c..916fcc4 100644
--- a/services/soundtrigger/SoundTriggerHalHidl.h
+++ b/services/soundtrigger/SoundTriggerHalHidl.h
@@ -25,7 +25,6 @@
 #include <android/hardware/soundtrigger/2.0/types.h>
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
-#include <android/hardware/soundtrigger/2.0/BnSoundTriggerHwCallback.h>
 
 namespace android {
 
@@ -143,7 +142,6 @@
 
         uint32_t nextUniqueId();
         sp<ISoundTriggerHw> getService();
-        void crashIfHalIsDead(int ret);
         sp<SoundModel> getModel(sound_model_handle_t handle);
         sp<SoundModel> removeModel(sound_model_handle_t handle);