Merge "MPEG4Extractor: ensure returned status is checked."
diff --git a/CleanSpec.mk b/CleanSpec.mk
index d0890fe..34d040e 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -59,6 +59,12 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libaudiopolicymanager.so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libaudiopolicyservice_intermediates)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libaudiopolicymanager_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/liboboe.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/liboboe.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/liboboe*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/liboboe*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj_arm/STATIC_LIBRARIES/liboboe*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj_arm/SHARED_LIBRARIES/liboboe*)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/camera/Android.mk b/camera/Android.mk
index c9c98e9..91d87ed 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -65,11 +65,11 @@
 	system/media/camera/include \
 	system/media/private/camera/include \
 	frameworks/native/include/media/openmax \
-	frameworks/av/include/camera
+	$(LOCAL_PATH)/include/camera
 
 LOCAL_EXPORT_C_INCLUDE_DIRS := \
 	system/media/camera/include \
-	frameworks/av/include/camera
+	$(LOCAL_PATH)/include/camera
 
 LOCAL_CFLAGS += -Werror -Wall -Wextra
 
diff --git a/camera/camera2/CaptureRequest.cpp b/camera/camera2/CaptureRequest.cpp
index 4daf35b..0597950 100644
--- a/camera/camera2/CaptureRequest.cpp
+++ b/camera/camera2/CaptureRequest.cpp
@@ -23,11 +23,19 @@
 
 #include <binder/Parcel.h>
 #include <gui/Surface.h>
+#include <gui/view/Surface.h>
 
 namespace android {
 namespace hardware {
 namespace camera2 {
 
+// These must be in the .cpp (to avoid inlining)
+CaptureRequest::CaptureRequest() = default;
+CaptureRequest::~CaptureRequest() = default;
+CaptureRequest::CaptureRequest(const CaptureRequest& rhs) = default;
+CaptureRequest::CaptureRequest(CaptureRequest&& rhs) noexcept = default;
+
+
 status_t CaptureRequest::readFromParcel(const android::Parcel* parcel) {
     if (parcel == NULL) {
         ALOGE("%s: Null parcel", __FUNCTION__);
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index f570b7f..468a1eb 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -22,7 +22,7 @@
 
 #include <camera/camera2/OutputConfiguration.h>
 #include <binder/Parcel.h>
-#include <gui/Surface.h>
+#include <gui/view/Surface.h>
 #include <utils/String8.h>
 
 namespace android {
diff --git a/camera/cameraserver/Android.mk b/camera/cameraserver/Android.mk
index bdafff1..f0a0db0 100644
--- a/camera/cameraserver/Android.mk
+++ b/camera/cameraserver/Android.mk
@@ -23,7 +23,9 @@
 	libcameraservice \
 	liblog \
 	libutils \
+	libui \
 	libbinder \
+	libhidltransport \
 	android.hardware.camera.common@1.0 \
 	android.hardware.camera.provider@2.4 \
 	android.hardware.camera.device@1.0 \
diff --git a/camera/cameraserver/main_cameraserver.cpp b/camera/cameraserver/main_cameraserver.cpp
index f4be468..3972436 100644
--- a/camera/cameraserver/main_cameraserver.cpp
+++ b/camera/cameraserver/main_cameraserver.cpp
@@ -17,8 +17,8 @@
 #define LOG_TAG "cameraserver"
 //#define LOG_NDEBUG 0
 
-// from LOCAL_C_INCLUDES
 #include "CameraService.h"
+#include <hidl/HidlTransportSupport.h>
 
 using namespace android;
 
@@ -26,6 +26,9 @@
 {
     signal(SIGPIPE, SIG_IGN);
 
+    // Set 3 threads for HIDL calls
+    hardware::configureRpcThreadpool(3, /*willjoin*/ false);
+
     sp<ProcessState> proc(ProcessState::self());
     sp<IServiceManager> sm = defaultServiceManager();
     ALOGI("ServiceManager: %p", sm.get());
diff --git a/include/camera/Camera.h b/camera/include/camera/Camera.h
similarity index 100%
rename from include/camera/Camera.h
rename to camera/include/camera/Camera.h
diff --git a/include/camera/CameraBase.h b/camera/include/camera/CameraBase.h
similarity index 100%
rename from include/camera/CameraBase.h
rename to camera/include/camera/CameraBase.h
diff --git a/include/camera/CameraMetadata.h b/camera/include/camera/CameraMetadata.h
similarity index 100%
rename from include/camera/CameraMetadata.h
rename to camera/include/camera/CameraMetadata.h
diff --git a/include/camera/CameraParameters.h b/camera/include/camera/CameraParameters.h
similarity index 100%
rename from include/camera/CameraParameters.h
rename to camera/include/camera/CameraParameters.h
diff --git a/include/camera/CameraParameters2.h b/camera/include/camera/CameraParameters2.h
similarity index 100%
rename from include/camera/CameraParameters2.h
rename to camera/include/camera/CameraParameters2.h
diff --git a/include/camera/CameraUtils.h b/camera/include/camera/CameraUtils.h
similarity index 100%
rename from include/camera/CameraUtils.h
rename to camera/include/camera/CameraUtils.h
diff --git a/include/camera/CaptureResult.h b/camera/include/camera/CaptureResult.h
similarity index 100%
rename from include/camera/CaptureResult.h
rename to camera/include/camera/CaptureResult.h
diff --git a/include/camera/ICameraRecordingProxy.h b/camera/include/camera/ICameraRecordingProxy.h
similarity index 100%
rename from include/camera/ICameraRecordingProxy.h
rename to camera/include/camera/ICameraRecordingProxy.h
diff --git a/include/camera/ICameraRecordingProxyListener.h b/camera/include/camera/ICameraRecordingProxyListener.h
similarity index 100%
rename from include/camera/ICameraRecordingProxyListener.h
rename to camera/include/camera/ICameraRecordingProxyListener.h
diff --git a/include/camera/ICameraServiceProxy.h b/camera/include/camera/ICameraServiceProxy.h
similarity index 100%
rename from include/camera/ICameraServiceProxy.h
rename to camera/include/camera/ICameraServiceProxy.h
diff --git a/include/camera/VendorTagDescriptor.h b/camera/include/camera/VendorTagDescriptor.h
similarity index 100%
rename from include/camera/VendorTagDescriptor.h
rename to camera/include/camera/VendorTagDescriptor.h
diff --git a/include/camera/android/hardware/ICamera.h b/camera/include/camera/android/hardware/ICamera.h
similarity index 100%
rename from include/camera/android/hardware/ICamera.h
rename to camera/include/camera/android/hardware/ICamera.h
diff --git a/include/camera/android/hardware/ICameraClient.h b/camera/include/camera/android/hardware/ICameraClient.h
similarity index 100%
rename from include/camera/android/hardware/ICameraClient.h
rename to camera/include/camera/android/hardware/ICameraClient.h
diff --git a/include/camera/camera2/CaptureRequest.h b/camera/include/camera/camera2/CaptureRequest.h
similarity index 78%
rename from include/camera/camera2/CaptureRequest.h
rename to camera/include/camera/camera2/CaptureRequest.h
index 978f48d..0180183 100644
--- a/include/camera/camera2/CaptureRequest.h
+++ b/camera/include/camera/camera2/CaptureRequest.h
@@ -30,6 +30,16 @@
 namespace camera2 {
 
 struct CaptureRequest : public Parcelable {
+
+    // those are needed so we can use a forward declaration of Surface, otherwise
+    // the type is incomplete when the ctor/dtors are generated. This has the added
+    // benefit that ctor/dtors are not inlined, which is good because they're not trivial
+    // (because of the vtable and Vector<>)
+    CaptureRequest();
+    CaptureRequest(const CaptureRequest& rhs);
+    CaptureRequest(CaptureRequest&& rhs) noexcept;
+    virtual ~CaptureRequest();
+
     CameraMetadata          mMetadata;
     Vector<sp<Surface> >    mSurfaceList;
     bool                    mIsReprocess;
diff --git a/include/camera/camera2/OutputConfiguration.h b/camera/include/camera/camera2/OutputConfiguration.h
similarity index 100%
rename from include/camera/camera2/OutputConfiguration.h
rename to camera/include/camera/camera2/OutputConfiguration.h
diff --git a/include/camera/camera2/SubmitInfo.h b/camera/include/camera/camera2/SubmitInfo.h
similarity index 100%
rename from include/camera/camera2/SubmitInfo.h
rename to camera/include/camera/camera2/SubmitInfo.h
diff --git a/include/camera/ndk/NdkCameraCaptureSession.h b/camera/include/camera/ndk/NdkCameraCaptureSession.h
similarity index 100%
rename from include/camera/ndk/NdkCameraCaptureSession.h
rename to camera/include/camera/ndk/NdkCameraCaptureSession.h
diff --git a/include/camera/ndk/NdkCameraDevice.h b/camera/include/camera/ndk/NdkCameraDevice.h
similarity index 100%
rename from include/camera/ndk/NdkCameraDevice.h
rename to camera/include/camera/ndk/NdkCameraDevice.h
diff --git a/include/camera/ndk/NdkCameraError.h b/camera/include/camera/ndk/NdkCameraError.h
similarity index 100%
rename from include/camera/ndk/NdkCameraError.h
rename to camera/include/camera/ndk/NdkCameraError.h
diff --git a/include/camera/ndk/NdkCameraManager.h b/camera/include/camera/ndk/NdkCameraManager.h
similarity index 100%
rename from include/camera/ndk/NdkCameraManager.h
rename to camera/include/camera/ndk/NdkCameraManager.h
diff --git a/include/camera/ndk/NdkCameraMetadata.h b/camera/include/camera/ndk/NdkCameraMetadata.h
similarity index 100%
rename from include/camera/ndk/NdkCameraMetadata.h
rename to camera/include/camera/ndk/NdkCameraMetadata.h
diff --git a/include/camera/ndk/NdkCameraMetadataTags.h b/camera/include/camera/ndk/NdkCameraMetadataTags.h
similarity index 100%
rename from include/camera/ndk/NdkCameraMetadataTags.h
rename to camera/include/camera/ndk/NdkCameraMetadataTags.h
diff --git a/include/camera/ndk/NdkCaptureRequest.h b/camera/include/camera/ndk/NdkCaptureRequest.h
similarity index 100%
rename from include/camera/ndk/NdkCaptureRequest.h
rename to camera/include/camera/ndk/NdkCaptureRequest.h
diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk
index 0978a81..659484f 100644
--- a/camera/tests/Android.mk
+++ b/camera/tests/Android.mk
@@ -18,7 +18,8 @@
 
 LOCAL_SRC_FILES:= \
 	VendorTagDescriptorTests.cpp \
-	CameraBinderTests.cpp
+	CameraBinderTests.cpp \
+	CameraZSLTests.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
diff --git a/camera/tests/CameraZSLTests.cpp b/camera/tests/CameraZSLTests.cpp
new file mode 100644
index 0000000..6c91fdc
--- /dev/null
+++ b/camera/tests/CameraZSLTests.cpp
@@ -0,0 +1,292 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "CameraZSLTests"
+
+#include <gtest/gtest.h>
+
+#include <binder/ProcessState.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <camera/CameraParameters.h>
+#include <camera/CameraMetadata.h>
+#include <camera/Camera.h>
+#include <android/hardware/ICameraService.h>
+
+using namespace android;
+using namespace android::hardware;
+
+class CameraZSLTests : public ::testing::Test,
+    public ::android::hardware::BnCameraClient {
+protected:
+
+    CameraZSLTests() : numCameras(0), mPreviewBufferCount(0),
+    mAutoFocusMessage(false), mSnapshotNotification(false) {}
+
+    //Gtest interface
+    void SetUp() override;
+    void TearDown() override;
+
+    //CameraClient interface
+    void notifyCallback(int32_t msgType, int32_t, int32_t) override;
+    void dataCallback(int32_t msgType, const sp<IMemory>&,
+            camera_frame_metadata_t *) override;
+    void dataCallbackTimestamp(nsecs_t, int32_t,
+            const sp<IMemory>&) override {};
+    void recordingFrameHandleCallbackTimestamp(nsecs_t,
+            native_handle_t*) override {};
+
+    status_t waitForPreviewStart();
+    status_t waitForEvent(Mutex &mutex, Condition &condition, bool &flag);
+
+    mutable Mutex mPreviewLock;
+    mutable Condition mPreviewCondition;
+    mutable Mutex mAutoFocusLock;
+    mutable Condition mAutoFocusCondition;
+    mutable Mutex mSnapshotLock;
+    mutable Condition mSnapshotCondition;
+
+    int32_t numCameras;
+    size_t mPreviewBufferCount;
+    sp<ICameraService> mCameraService;
+    sp<SurfaceComposerClient> mComposerClient;
+    bool mAutoFocusMessage;
+    bool mSnapshotNotification;
+    static const int32_t kPreviewThreshold  = 8;
+    static const nsecs_t kPreviewTimeout    = 5000000000;  // 5 [s.]
+    static const nsecs_t kEventTimeout      = 10000000000; // 10 [s.]
+};
+
+void CameraZSLTests::SetUp() {
+    ::android::binder::Status rc;
+    ProcessState::self()->startThreadPool();
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16("media.camera"));
+    mCameraService = interface_cast<ICameraService>(binder);
+    rc = mCameraService->getNumberOfCameras(
+            hardware::ICameraService::CAMERA_TYPE_ALL, &numCameras);
+    EXPECT_TRUE(rc.isOk());
+
+    mComposerClient = new SurfaceComposerClient;
+    ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+}
+
+void CameraZSLTests::TearDown() {
+    mCameraService.clear();
+    mComposerClient->dispose();
+}
+
+void CameraZSLTests::notifyCallback(int32_t msgType, int32_t,
+        int32_t) {
+    if (CAMERA_MSG_FOCUS == msgType) {
+        Mutex::Autolock l(mAutoFocusLock);
+        mAutoFocusMessage = true;
+        mAutoFocusCondition.broadcast();
+    } else {
+        ALOGV("%s: msgType: %d", __FUNCTION__, msgType);
+    }
+};
+
+void CameraZSLTests::dataCallback(int32_t msgType, const sp<IMemory>& /*data*/,
+        camera_frame_metadata_t *) {
+
+    switch (msgType) {
+    case CAMERA_MSG_PREVIEW_FRAME: {
+        Mutex::Autolock l(mPreviewLock);
+        mPreviewBufferCount++;
+        mPreviewCondition.broadcast();
+        break;
+    }
+    case CAMERA_MSG_COMPRESSED_IMAGE: {
+        Mutex::Autolock l(mSnapshotLock);
+        mSnapshotNotification = true;
+        //TODO: Add checks on incoming Jpeg
+        mSnapshotCondition.broadcast();
+        break;
+    }
+    default:
+        ALOGV("%s: msgType: %d", __FUNCTION__, msgType);
+    }
+};
+
+status_t CameraZSLTests::waitForPreviewStart() {
+    status_t rc = NO_ERROR;
+    Mutex::Autolock l(mPreviewLock);
+    mPreviewBufferCount = 0;
+
+    while (mPreviewBufferCount < kPreviewThreshold) {
+        rc = mPreviewCondition.waitRelative(mPreviewLock,
+                kPreviewTimeout);
+        if (NO_ERROR != rc) {
+            break;
+        }
+    }
+
+    return rc;
+}
+
+status_t CameraZSLTests::waitForEvent(Mutex &mutex,
+        Condition &condition, bool &flag) {
+    status_t rc = NO_ERROR;
+    Mutex::Autolock l(mutex);
+    flag = false;
+
+    while (!flag) {
+        rc = condition.waitRelative(mutex,
+                kEventTimeout);
+        if (NO_ERROR != rc) {
+            break;
+        }
+    }
+
+    return rc;
+}
+
+TEST_F(CameraZSLTests, TestAllPictureSizes) {
+    ::android::binder::Status rc;
+
+    for (int32_t cameraId = 0; cameraId < numCameras; cameraId++) {
+        sp<Surface> previewSurface;
+        sp<SurfaceControl> surfaceControl;
+        sp<ICamera> cameraDevice;
+
+        String16 cameraIdStr = String16(String8::format("%d", cameraId));
+        bool isSupported = false;
+        rc = mCameraService->supportsCameraApi(cameraIdStr,
+                hardware::ICameraService::API_VERSION_1, &isSupported);
+        EXPECT_TRUE(rc.isOk());
+
+        // We only care about camera Camera1 ZSL support.
+        if (!isSupported) {
+            continue;
+        }
+
+        CameraMetadata metadata;
+        rc = mCameraService->getCameraCharacteristics(cameraIdStr, &metadata);
+        if (!rc.isOk()) {
+            // The test is relevant only for cameras with Hal 3.x
+            // support.
+            continue;
+        }
+        EXPECT_FALSE(metadata.isEmpty());
+        camera_metadata_entry_t availableCapabilities =
+                metadata.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+        EXPECT_TRUE(0 < availableCapabilities.count);
+        bool isReprocessSupported = false;
+        const uint8_t *caps = availableCapabilities.data.u8;
+        for (size_t i = 0; i < availableCapabilities.count; i++) {
+            if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING ==
+                caps[i]) {
+                isReprocessSupported = true;
+                break;
+            }
+        }
+        if (!isReprocessSupported) {
+            // ZSL relies on this feature
+            continue;
+        }
+
+        rc = mCameraService->connect(this, cameraId,
+                String16("ZSLTest"), hardware::ICameraService::USE_CALLING_UID,
+                hardware::ICameraService::USE_CALLING_PID, &cameraDevice);
+        EXPECT_TRUE(rc.isOk());
+
+        CameraParameters params(cameraDevice->getParameters());
+
+        String8 focusModes(params.get(
+                CameraParameters::KEY_SUPPORTED_FOCUS_MODES));
+        bool isAFSupported = false;
+        const char *focusMode = nullptr;
+        if (focusModes.contains(CameraParameters::FOCUS_MODE_AUTO)) {
+            // If supported 'auto' should be set by default
+            isAFSupported = true;
+        } else if (focusModes.contains(
+                CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE)) {
+            isAFSupported = true;
+            focusMode = CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE;
+        } else if (focusModes.contains(
+                CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO)) {
+            isAFSupported = true;
+            focusMode = CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO;
+        } else if (focusModes.contains(CameraParameters::FOCUS_MODE_MACRO)) {
+            isAFSupported = true;
+            focusMode = CameraParameters::FOCUS_MODE_MACRO;
+        }
+
+        if (!isAFSupported) {
+            // AF state is needed
+            continue;
+        }
+
+        if (nullptr != focusMode) {
+            params.set(CameraParameters::KEY_FOCUS_MODE, focusMode);
+            ASSERT_EQ(NO_ERROR, cameraDevice->setParameters(params.flatten()));
+        }
+
+        int previewWidth, previewHeight;
+        params.getPreviewSize(&previewWidth, &previewHeight);
+        ASSERT_TRUE((0 < previewWidth) && (0 < previewHeight));
+
+        surfaceControl = mComposerClient->createSurface(
+                String8("Test Surface"),
+                previewWidth, previewHeight,
+                CameraParameters::previewFormatToEnum(
+                        params.getPreviewFormat()),
+                GRALLOC_USAGE_HW_RENDER);
+
+        ASSERT_TRUE(nullptr != surfaceControl.get());
+        ASSERT_TRUE(surfaceControl->isValid());
+
+        SurfaceComposerClient::openGlobalTransaction();
+        ASSERT_EQ(NO_ERROR, surfaceControl->setLayer(0x7fffffff));
+        ASSERT_EQ(NO_ERROR, surfaceControl->show());
+        SurfaceComposerClient::closeGlobalTransaction();
+
+        previewSurface = surfaceControl->getSurface();
+        ASSERT_TRUE(previewSurface != NULL);
+        ASSERT_EQ(NO_ERROR, cameraDevice->setPreviewTarget(
+                previewSurface->getIGraphicBufferProducer()));
+
+        cameraDevice->setPreviewCallbackFlag(
+                CAMERA_FRAME_CALLBACK_FLAG_CAMCORDER);
+
+        Vector<Size> pictureSizes;
+        params.getSupportedPictureSizes(pictureSizes);
+        for (size_t i = 0; i < pictureSizes.size(); i++) {
+            params.setPictureSize(pictureSizes[i].width,
+                    pictureSizes[i].height);
+            ASSERT_EQ(NO_ERROR, cameraDevice->setParameters(params.flatten()));
+            ASSERT_EQ(NO_ERROR, cameraDevice->startPreview());
+            ASSERT_EQ(NO_ERROR, waitForPreviewStart());
+
+            ASSERT_EQ(NO_ERROR, cameraDevice->autoFocus());
+            ASSERT_EQ(NO_ERROR, waitForEvent(mAutoFocusLock,
+                    mAutoFocusCondition, mAutoFocusMessage));
+
+            ASSERT_EQ(NO_ERROR,
+                    cameraDevice->takePicture(CAMERA_MSG_COMPRESSED_IMAGE));
+            ASSERT_EQ(NO_ERROR, waitForEvent(mSnapshotLock, mSnapshotCondition,
+                    mSnapshotNotification));
+        }
+
+        cameraDevice->stopPreview();
+        rc = cameraDevice->disconnect();
+        EXPECT_TRUE(rc.isOk());
+    }
+}
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 9a236fc..ad70470 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -3,19 +3,22 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=       \
-	stagefright.cpp \
-	jpeg.cpp	\
-	SineSource.cpp
+        stagefright.cpp \
+        jpeg.cpp        \
+        SineSource.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright libmedia libutils libbinder libstagefright_foundation \
-	libjpeg libgui libcutils liblog
+        libstagefright libmedia libutils libbinder libstagefright_foundation \
+        libjpeg libgui libcutils liblog \
+        libhidlmemory \
+        android.hardware.media.omx@1.0 \
+        android.hardware.media.omx@1.0-utils \
 
 LOCAL_C_INCLUDES:= \
-	frameworks/av/media/libstagefright \
-	frameworks/av/media/libstagefright/include \
-	$(TOP)/frameworks/native/include/media/openmax \
-	external/jpeg \
+        frameworks/av/media/libstagefright \
+        frameworks/av/media/libstagefright/include \
+        $(TOP)/frameworks/native/include/media/openmax \
+        external/jpeg \
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -30,16 +33,16 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=         \
-	SineSource.cpp    \
-	record.cpp
+        SineSource.cpp    \
+        record.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright libmedia liblog libutils libbinder libstagefright_foundation
+        libstagefright libmedia liblog libutils libbinder libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
-	frameworks/av/media/libstagefright \
-	$(TOP)/frameworks/native/include/media/openmax \
-	$(TOP)/frameworks/native/include/media/hardware
+        frameworks/av/media/libstagefright \
+        $(TOP)/frameworks/native/include/media/openmax \
+        $(TOP)/frameworks/native/include/media/hardware
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -54,16 +57,16 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=         \
-	SineSource.cpp    \
-	recordvideo.cpp
+        SineSource.cpp    \
+        recordvideo.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright libmedia liblog libutils libbinder libstagefright_foundation
+        libstagefright libmedia liblog libutils libbinder libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
-	frameworks/av/media/libstagefright \
-	$(TOP)/frameworks/native/include/media/openmax \
-	$(TOP)/frameworks/native/include/media/hardware
+        frameworks/av/media/libstagefright \
+        $(TOP)/frameworks/native/include/media/openmax \
+        $(TOP)/frameworks/native/include/media/hardware
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -79,15 +82,15 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=         \
-	SineSource.cpp    \
-	audioloop.cpp
+        SineSource.cpp    \
+        audioloop.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright libmedia liblog libutils libbinder libstagefright_foundation
+        libstagefright libmedia liblog libutils libbinder libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
-	frameworks/av/media/libstagefright \
-	$(TOP)/frameworks/native/include/media/openmax
+        frameworks/av/media/libstagefright \
+        $(TOP)/frameworks/native/include/media/openmax
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -105,12 +108,12 @@
         stream.cpp    \
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright liblog libutils libbinder libgui \
-	libstagefright_foundation libmedia libcutils
+        libstagefright liblog libutils libbinder libgui \
+        libstagefright_foundation libmedia libcutils
 
 LOCAL_C_INCLUDES:= \
-	frameworks/av/media/libstagefright \
-	$(TOP)/frameworks/native/include/media/openmax
+        frameworks/av/media/libstagefright \
+        $(TOP)/frameworks/native/include/media/openmax
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -125,16 +128,16 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=               \
-	codec.cpp               \
-	SimplePlayer.cpp        \
+        codec.cpp               \
+        SimplePlayer.cpp        \
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright liblog libutils libbinder libstagefright_foundation \
-	libmedia libaudioclient libgui libcutils
+        libstagefright liblog libutils libbinder libstagefright_foundation \
+        libmedia libaudioclient libgui libcutils
 
 LOCAL_C_INCLUDES:= \
-	frameworks/av/media/libstagefright \
-	$(TOP)/frameworks/native/include/media/openmax
+        frameworks/av/media/libstagefright \
+        $(TOP)/frameworks/native/include/media/openmax
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -149,33 +152,33 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	filters/argbtorgba.rs \
-	filters/nightvision.rs \
-	filters/saturation.rs \
-	mediafilter.cpp \
+        filters/argbtorgba.rs \
+        filters/nightvision.rs \
+        filters/saturation.rs \
+        mediafilter.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright \
-	liblog \
-	libutils \
-	libbinder \
-	libstagefright_foundation \
-	libmedia \
-	libgui \
-	libcutils \
-	libRScpp \
+        libstagefright \
+        liblog \
+        libutils \
+        libbinder \
+        libstagefright_foundation \
+        libmedia \
+        libgui \
+        libcutils \
+        libRScpp \
 
 LOCAL_C_INCLUDES:= \
-	$(TOP)/frameworks/av/media/libstagefright \
-	$(TOP)/frameworks/native/include/media/openmax \
-	$(TOP)/frameworks/rs/cpp \
-	$(TOP)/frameworks/rs \
+        $(TOP)/frameworks/av/media/libstagefright \
+        $(TOP)/frameworks/native/include/media/openmax \
+        $(TOP)/frameworks/rs/cpp \
+        $(TOP)/frameworks/rs \
 
 intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,)
 LOCAL_C_INCLUDES += $(intermediates)
 
 LOCAL_STATIC_LIBRARIES:= \
-	libstagefright_mediafilter
+        libstagefright_mediafilter
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
@@ -190,15 +193,15 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=               \
-	muxer.cpp            \
+        muxer.cpp            \
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright liblog libutils libbinder libstagefright_foundation \
-	libcutils libc
+        libstagefright liblog libutils libbinder libstagefright_foundation \
+        libcutils libc
 
 LOCAL_C_INCLUDES:= \
-	frameworks/av/media/libstagefright \
-	$(TOP)/frameworks/native/include/media/openmax
+        frameworks/av/media/libstagefright \
+        $(TOP)/frameworks/native/include/media/openmax
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 5e3a859..ffa09eb 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -64,6 +64,9 @@
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <omx/hal/1.0/utils/WOmx.h>
+
 using namespace android;
 
 static long gNumRepetitions;
@@ -904,13 +907,25 @@
     }
 
     if (listComponents) {
-        sp<IServiceManager> sm = defaultServiceManager();
-        sp<IBinder> binder = sm->getService(String16("media.codec"));
-        sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
+        sp<IOMX> omx;
+        int32_t trebleOmx = property_get_int32("persist.media.treble_omx", -1);
+        if ((trebleOmx == 1) || ((trebleOmx == -1) &&
+                property_get_bool("persist.hal.binderization", 0))) {
+            using namespace ::android::hardware::media::omx::V1_0;
+            sp<IOmx> tOmx = IOmx::getService();
 
-        CHECK(service.get() != NULL);
+            CHECK(tOmx.get() != NULL);
 
-        sp<IOMX> omx = service->getOMX();
+            omx = new utils::LWOmx(tOmx);
+        } else {
+            sp<IServiceManager> sm = defaultServiceManager();
+            sp<IBinder> binder = sm->getService(String16("media.codec"));
+            sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
+
+            CHECK(service.get() != NULL);
+
+            omx = service->getOMX();
+        }
         CHECK(omx.get() != NULL);
 
         List<IOMX::ComponentInfo> list;
diff --git a/drm/libmediadrm/Android.mk b/drm/libmediadrm/Android.mk
index 14740e6..a57fafa 100644
--- a/drm/libmediadrm/Android.mk
+++ b/drm/libmediadrm/Android.mk
@@ -6,14 +6,26 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= \
+LOCAL_AIDL_INCLUDES := \
+    frameworks/av/drm/libmediadrm/aidl
+
+LOCAL_SRC_FILES := \
+    aidl/android/media/ICas.aidl \
+    aidl/android/media/ICasListener.aidl \
+    aidl/android/media/IDescrambler.aidl \
+    aidl/android/media/IMediaCasService.aidl \
+
+LOCAL_SRC_FILES += \
+    CasImpl.cpp \
+    DescramblerImpl.cpp \
     DrmSessionManager.cpp \
     ICrypto.cpp \
     IDrm.cpp \
     IDrmClient.cpp \
     IMediaDrmService.cpp \
+    MediaCasDefs.cpp \
     SharedLibrary.cpp
-ifeq ($(ENABLE_TREBLE), true)
+ifneq ($(DISABLE_TREBLE_DRM), true)
 LOCAL_SRC_FILES += \
     DrmHal.cpp \
     CryptoHal.cpp
@@ -31,7 +43,7 @@
     libmediautils \
     libstagefright_foundation \
     libutils
-ifeq ($(ENABLE_TREBLE), true)
+ifneq ($(DISABLE_TREBLE_DRM), true)
 LOCAL_SHARED_LIBRARIES += \
     android.hidl.base@1.0 \
     android.hardware.drm@1.0 \
diff --git a/drm/libmediadrm/CasImpl.cpp b/drm/libmediadrm/CasImpl.cpp
new file mode 100644
index 0000000..de15244
--- /dev/null
+++ b/drm/libmediadrm/CasImpl.cpp
@@ -0,0 +1,201 @@
+
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "CasImpl"
+
+#include <android/media/ICasListener.h>
+#include <media/cas/CasAPI.h>
+#include <media/CasImpl.h>
+#include <media/SharedLibrary.h>
+#include <utils/Log.h>
+
+namespace android {
+
+static Status getBinderStatus(status_t err) {
+    if (err == OK) {
+        return Status::ok();
+    }
+    if (err == BAD_VALUE) {
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+    }
+    if (err == INVALID_OPERATION) {
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+    }
+    return Status::fromServiceSpecificError(err);
+}
+
+static String8 sessionIdToString(const CasSessionId &sessionId) {
+    String8 result;
+    for (size_t i = 0; i < sessionId.size(); i++) {
+        result.appendFormat("%02x ", sessionId[i]);
+    }
+    if (result.isEmpty()) {
+        result.append("(null)");
+    }
+    return result;
+}
+
+CasImpl::CasImpl(const sp<ICasListener> &listener)
+    : mPlugin(NULL), mListener(listener) {
+    ALOGV("CTOR: mPlugin=%p", mPlugin);
+}
+
+CasImpl::~CasImpl() {
+    ALOGV("DTOR: mPlugin=%p", mPlugin);
+    release();
+}
+
+//static
+void CasImpl::OnEvent(
+        void *appData,
+        int32_t event,
+        int32_t arg,
+        uint8_t *data,
+        size_t size) {
+    if (appData == NULL) {
+        ALOGE("Invalid appData!");
+        return;
+    }
+    CasImpl *casImpl = static_cast<CasImpl *>(appData);
+    casImpl->onEvent(event, arg, data, size);
+}
+
+void CasImpl::init(const sp<SharedLibrary>& library, CasPlugin *plugin) {
+    mLibrary = library;
+    mPlugin = plugin;
+}
+
+void CasImpl::onEvent(
+        int32_t event, int32_t arg, uint8_t *data, size_t size) {
+    if (mListener == NULL) {
+        return;
+    }
+
+    std::unique_ptr<CasData> eventData;
+    if (data != NULL && size > 0) {
+        eventData.reset(new CasData(data, data + size));
+    }
+
+    mListener->onEvent(event, arg, eventData);
+}
+
+Status CasImpl::setPrivateData(const CasData& pvtData) {
+    ALOGV("setPrivateData");
+    return getBinderStatus(mPlugin->setPrivateData(pvtData));
+}
+
+Status CasImpl::openSession(int32_t program_number, CasSessionId* sessionId) {
+    ALOGV("openSession: program_number=%d", program_number);
+
+    status_t err = mPlugin->openSession(program_number, sessionId);
+
+    ALOGV("openSession: session opened for program_number=%d, sessionId=%s",
+            program_number, sessionIdToString(*sessionId).string());
+
+    return getBinderStatus(err);
+}
+
+Status CasImpl::openSessionForStream(
+        int32_t program_number,
+        int32_t elementary_PID,
+        CasSessionId* sessionId) {
+    ALOGV("openSession: program_number=%d, elementary_PID=%d",
+            program_number, elementary_PID);
+
+    status_t err = mPlugin->openSession(
+            program_number, elementary_PID, sessionId);
+
+    ALOGV("openSession: session opened for "
+            "program_number=%d, elementary_PID=%d, sessionId=%s",
+            program_number, elementary_PID,
+            sessionIdToString(*sessionId).string());
+
+    return getBinderStatus(err);
+}
+
+Status CasImpl::setSessionPrivateData(
+        const CasSessionId &sessionId, const CasData& pvtData) {
+    ALOGV("setSessionPrivateData: sessionId=%s",
+            sessionIdToString(sessionId).string());
+
+    return getBinderStatus(mPlugin->setSessionPrivateData(sessionId, pvtData));
+}
+
+Status CasImpl::closeSession(const CasSessionId &sessionId) {
+    ALOGV("closeSession: sessionId=%s",
+            sessionIdToString(sessionId).string());
+
+    return getBinderStatus(mPlugin->closeSession(sessionId));
+}
+
+Status CasImpl::processEcm(const CasSessionId &sessionId, const ParcelableCasData& ecm) {
+    ALOGV("processEcm: sessionId=%s",
+            sessionIdToString(sessionId).string());
+
+    return getBinderStatus(mPlugin->processEcm(sessionId, ecm));
+}
+
+Status CasImpl::processEmm(const ParcelableCasData& emm) {
+    ALOGV("processEmm");
+
+    return getBinderStatus(mPlugin->processEmm(emm));
+}
+
+Status CasImpl::sendEvent(
+        int32_t event, int32_t arg, const ::std::unique_ptr<CasData> &eventData) {
+    ALOGV("sendEvent");
+
+    status_t err;
+    if (eventData == nullptr) {
+        err = mPlugin->sendEvent(event, arg, CasData());
+    } else {
+        err = mPlugin->sendEvent(event, arg, *eventData);
+    }
+    return getBinderStatus(err);
+}
+
+Status CasImpl::provision(const String16& provisionString) {
+    ALOGV("provision: provisionString=%s", String8(provisionString).string());
+
+    return getBinderStatus(mPlugin->provision(String8(provisionString)));
+}
+
+Status CasImpl::refreshEntitlements(
+        int32_t refreshType, const ::std::unique_ptr<CasData> &refreshData) {
+    ALOGV("refreshEntitlements");
+
+    status_t err;
+    if (refreshData == nullptr) {
+        err = mPlugin->refreshEntitlements(refreshType, CasData());
+    } else {
+        err = mPlugin->refreshEntitlements(refreshType, *refreshData);
+    }
+    return getBinderStatus(err);
+}
+
+Status CasImpl::release() {
+    ALOGV("release: mPlugin=%p", mPlugin);
+
+    if (mPlugin != NULL) {
+        delete mPlugin;
+        mPlugin = NULL;
+    }
+    return Status::ok();
+}
+
+} // namespace android
+
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index f1f3b01..5732613 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -95,17 +95,6 @@
 }
 
 
-static ::SharedBuffer toSharedBuffer(const sp<IMemory>& sharedBuffer) {
-    ssize_t offset;
-    size_t size;
-    sharedBuffer->getMemory(&offset, &size);
-
-    ::SharedBuffer buffer;
-    buffer.offset = offset >= 0 ? offset : 0;
-    buffer.size = size;
-    return buffer;
-}
-
 static String8 toString8(hidl_string hString) {
     return String8(hString.c_str());
 }
@@ -114,7 +103,7 @@
 CryptoHal::CryptoHal()
     : mFactory(makeCryptoFactory()),
       mInitCheck((mFactory == NULL) ? ERROR_UNSUPPORTED : NO_INIT),
-      mHeapBase(NULL) {
+      mNextBufferId(0) {
 }
 
 CryptoHal::~CryptoHal() {
@@ -206,20 +195,45 @@
  * size.  Once the heap base is established, shared memory buffers
  * are sent by providing an offset into the heap and a buffer size.
  */
-status_t CryptoHal::setHeapBase(const sp<IMemory>& sharedBuffer) {
-    sp<IMemoryHeap> heap = sharedBuffer->getMemory(NULL, NULL);
-    if (mHeapBase != heap->getBase()) {
-        int fd = heap->getHeapID();
-        native_handle_t* nativeHandle = native_handle_create(1, 0);
-        nativeHandle->data[0] = fd;
-        auto hidlHandle = hidl_handle(nativeHandle);
-        auto hidlMemory = hidl_memory("ashmem", hidlHandle, heap->getSize());
-        mHeapBase = heap->getBase();
-        Return<void> hResult = mPlugin->setSharedBufferBase(hidlMemory);
-        if (!hResult.isOk()) {
-            return DEAD_OBJECT;
-        }
+void CryptoHal::setHeapBase(const sp<IMemoryHeap>& heap) {
+    native_handle_t* nativeHandle = native_handle_create(1, 0);
+    if (!nativeHandle) {
+        ALOGE("setSharedBufferBase(), failed to create native handle");
+        return;
     }
+    if (heap == NULL) {
+        ALOGE("setSharedBufferBase(): heap is NULL");
+        return;
+    }
+    int fd = heap->getHeapID();
+    nativeHandle->data[0] = fd;
+    auto hidlHandle = hidl_handle(nativeHandle);
+    auto hidlMemory = hidl_memory("ashmem", hidlHandle, heap->getSize());
+    mHeapBases.add(heap->getBase(), mNextBufferId);
+    Return<void> hResult = mPlugin->setSharedBufferBase(hidlMemory, mNextBufferId++);
+    ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
+}
+
+status_t CryptoHal::toSharedBuffer(const sp<IMemory>& memory, ::SharedBuffer* buffer) {
+    ssize_t offset;
+    size_t size;
+
+    if (memory == NULL && buffer == NULL) {
+        return UNEXPECTED_NULL;
+    }
+
+    sp<IMemoryHeap> heap = memory->getMemory(&offset, &size);
+    if (heap == NULL) {
+        return UNEXPECTED_NULL;
+    }
+
+    if (mHeapBases.indexOfKey(heap->getBase()) < 0) {
+        setHeapBase(heap);
+    }
+
+    buffer->bufferId = mHeapBases.valueFor(heap->getBase());
+    buffer->offset = offset >= 0 ? offset : 0;
+    buffer->size = size;
     return OK;
 }
 
@@ -234,9 +248,6 @@
         return mInitCheck;
     }
 
-    // Establish the base of the shared memory heap
-    setHeapBase(source);
-
     Mode hMode;
     switch(mode) {
     case CryptoPlugin::kMode_Unencrypted:
@@ -272,7 +283,11 @@
     ::DestinationBuffer hDestination;
     if (destination.mType == kDestinationTypeSharedMemory) {
         hDestination.type = BufferType::SHARED_MEMORY;
-        hDestination.nonsecureMemory = toSharedBuffer(destination.mSharedMemory);
+        status_t status = toSharedBuffer(destination.mSharedMemory,
+                &hDestination.nonsecureMemory);
+        if (status != OK) {
+            return status;
+        }
         secure = false;
     } else {
         hDestination.type = BufferType::NATIVE_HANDLE;
@@ -280,12 +295,17 @@
         secure = true;
     }
 
+    ::SharedBuffer hSource;
+    status_t status = toSharedBuffer(source, &hSource);
+    if (status != OK) {
+        return status;
+    }
 
     status_t err = UNKNOWN_ERROR;
     uint32_t bytesWritten = 0;
 
     Return<void> hResult = mPlugin->decrypt(secure, toHidlArray16(keyId), toHidlArray16(iv), hMode,
-            hPattern, hSubSamples, toSharedBuffer(source), offset, hDestination,
+            hPattern, hSubSamples, hSource, offset, hDestination,
             [&](Status status, uint32_t hBytesWritten, hidl_string hDetailedError) {
                 if (status == Status::OK) {
                     bytesWritten = hBytesWritten;
diff --git a/drm/libmediadrm/DescramblerImpl.cpp b/drm/libmediadrm/DescramblerImpl.cpp
new file mode 100644
index 0000000..94e09e2
--- /dev/null
+++ b/drm/libmediadrm/DescramblerImpl.cpp
@@ -0,0 +1,107 @@
+
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "DescramblerImpl"
+
+#include <media/cas/DescramblerAPI.h>
+#include <media/DescramblerImpl.h>
+#include <media/SharedLibrary.h>
+#include <utils/Log.h>
+#include <binder/IMemory.h>
+
+namespace android {
+
+static Status getBinderStatus(status_t err) {
+    if (err == OK) {
+        return Status::ok();
+    }
+    if (err == BAD_VALUE) {
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
+    }
+    if (err == INVALID_OPERATION) {
+        return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
+    }
+    return Status::fromServiceSpecificError(err);
+}
+
+static String8 sessionIdToString(const CasSessionId &sessionId) {
+    String8 result;
+    for (size_t i = 0; i < sessionId.size(); i++) {
+        result.appendFormat("%02x ", sessionId[i]);
+    }
+    if (result.isEmpty()) {
+        result.append("(null)");
+    }
+    return result;
+}
+
+DescramblerImpl::DescramblerImpl(
+        const sp<SharedLibrary>& library, DescramblerPlugin *plugin) :
+        mLibrary(library), mPlugin(plugin) {
+    ALOGV("CTOR: mPlugin=%p", mPlugin);
+}
+
+DescramblerImpl::~DescramblerImpl() {
+    ALOGV("DTOR: mPlugin=%p", mPlugin);
+    release();
+}
+
+Status DescramblerImpl::setMediaCasSession(const CasSessionId& sessionId) {
+    ALOGV("setMediaCasSession: sessionId=%s",
+            sessionIdToString(sessionId).string());
+
+    return getBinderStatus(mPlugin->setMediaCasSession(sessionId));
+}
+
+Status DescramblerImpl::requiresSecureDecoderComponent(
+        const String16& mime, bool *result) {
+    *result = mPlugin->requiresSecureDecoderComponent(String8(mime));
+
+    return getBinderStatus(OK);
+}
+
+Status DescramblerImpl::descramble(
+        const DescrambleInfo& info, int32_t *result) {
+    ALOGV("descramble");
+
+    *result = mPlugin->descramble(
+            info.dstType != DescrambleInfo::kDestinationTypeVmPointer,
+            info.scramblingControl,
+            info.numSubSamples,
+            info.subSamples,
+            info.srcMem->pointer(),
+            info.srcOffset,
+            info.dstType == DescrambleInfo::kDestinationTypeVmPointer ?
+                    info.srcMem->pointer() : info.dstPtr,
+            info.dstOffset,
+            NULL);
+
+    return getBinderStatus(*result >= 0 ? OK : *result);
+}
+
+Status DescramblerImpl::release() {
+    ALOGV("release: mPlugin=%p", mPlugin);
+
+    if (mPlugin != NULL) {
+        delete mPlugin;
+        mPlugin = NULL;
+    }
+    return Status::ok();
+}
+
+} // namespace android
+
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 42dce35..8200d55 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -201,7 +201,12 @@
     sp<IDrmFactory> factory = IDrmFactory::getService("drm");
     if (factory == NULL) {
         ALOGE("Failed to make drm factory");
+        return NULL;
     }
+
+    ALOGD("makeDrmFactory: service is %s",
+            factory->isRemote() ? "Remote" : "Not Remote");
+
     return factory;
 }
 
@@ -344,6 +349,7 @@
     bool result = false;
 
     if (mFactory != NULL && mFactory->isCryptoSchemeSupported(uuid)) {
+        result = true;
         if (mimeType != "") {
             result = mFactory->isContentTypeSupported(mimeType.string());
         }
diff --git a/drm/libmediadrm/MediaCasDefs.cpp b/drm/libmediadrm/MediaCasDefs.cpp
new file mode 100644
index 0000000..9c2ba38
--- /dev/null
+++ b/drm/libmediadrm/MediaCasDefs.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "MediaCas"
+
+#include <media/MediaCasDefs.h>
+#include <utils/Log.h>
+#include <binder/IMemory.h>
+
+namespace android {
+namespace media {
+
+///////////////////////////////////////////////////////////////////////////////
+namespace MediaCas {
+
+status_t ParcelableCasData::readFromParcel(const Parcel* parcel) {
+    return parcel->readByteVector(this);
+}
+
+status_t ParcelableCasData::writeToParcel(Parcel* parcel) const  {
+    return parcel->writeByteVector(*this);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+status_t ParcelableCasPluginDescriptor::readFromParcel(const Parcel* /*parcel*/) {
+    ALOGE("CAPluginDescriptor::readFromParcel() shouldn't be called");
+    return INVALID_OPERATION;
+}
+
+status_t ParcelableCasPluginDescriptor::writeToParcel(Parcel* parcel) const {
+    status_t err = parcel->writeInt32(mCASystemId);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    return parcel->writeString16(mName);
+}
+
+} // namespace MediaCas
+///////////////////////////////////////////////////////////////////////////////
+
+namespace MediaDescrambler {
+
+DescrambleInfo::DescrambleInfo() {}
+
+DescrambleInfo::~DescrambleInfo() {}
+
+status_t DescrambleInfo::readFromParcel(const Parcel* parcel) {
+    status_t err = parcel->readInt32((int32_t*)&dstType);
+    if (err != OK) {
+        return err;
+    }
+    if (dstType != kDestinationTypeNativeHandle
+            && dstType != kDestinationTypeVmPointer) {
+        return BAD_VALUE;
+    }
+
+    err = parcel->readInt32((int32_t*)&scramblingControl);
+    if (err != OK) {
+        return err;
+    }
+
+    err = parcel->readUint32((uint32_t*)&numSubSamples);
+    if (err != OK) {
+        return err;
+    }
+    if (numSubSamples > 0xffff) {
+        return BAD_VALUE;
+    }
+
+    subSamples = new DescramblerPlugin::SubSample[numSubSamples];
+    if (subSamples == NULL) {
+        return NO_MEMORY;
+    }
+
+    for (size_t i = 0; i < numSubSamples; i++) {
+        err = parcel->readUint32(&subSamples[i].mNumBytesOfClearData);
+        if (err != OK) {
+            return err;
+        }
+        err = parcel->readUint32(&subSamples[i].mNumBytesOfEncryptedData);
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    srcMem = interface_cast<IMemory>(parcel->readStrongBinder());
+    if (srcMem == NULL) {
+        return BAD_VALUE;
+    }
+
+    err = parcel->readInt32(&srcOffset);
+    if (err != OK) {
+        return err;
+    }
+
+    native_handle_t *nativeHandle = NULL;
+    if (dstType == kDestinationTypeNativeHandle) {
+        nativeHandle = parcel->readNativeHandle();
+        dstPtr = static_cast<void *>(nativeHandle);
+    } else {
+        dstPtr = NULL;
+    }
+
+    err = parcel->readInt32(&dstOffset);
+    if (err != OK) {
+        return err;
+    }
+
+    return OK;
+}
+
+status_t DescrambleInfo::writeToParcel(Parcel* parcel) const {
+    if (dstType != kDestinationTypeNativeHandle
+            && dstType != kDestinationTypeVmPointer) {
+        return BAD_VALUE;
+    }
+
+    status_t err = parcel->writeInt32((int32_t)dstType);
+    if (err != OK) {
+        return err;
+    }
+
+    err = parcel->writeInt32(scramblingControl);
+    if (err != OK) {
+        return err;
+    }
+
+    err = parcel->writeUint32(numSubSamples);
+    if (err != OK) {
+        return err;
+    }
+
+    for (size_t i = 0; i < numSubSamples; i++) {
+        err = parcel->writeUint32(subSamples[i].mNumBytesOfClearData);
+        if (err != OK) {
+            return err;
+        }
+        err = parcel->writeUint32(subSamples[i].mNumBytesOfEncryptedData);
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    err = parcel->writeStrongBinder(IInterface::asBinder(srcMem));
+    if (err != OK) {
+        return err;
+    }
+
+    err = parcel->writeInt32(srcOffset);
+    if (err != OK) {
+        return err;
+    }
+
+    if (dstType == kDestinationTypeNativeHandle) {
+        parcel->writeNativeHandle(static_cast<native_handle_t *>(dstPtr));
+    }
+
+    err = parcel->writeInt32(dstOffset);
+    if (err != OK) {
+        return err;
+    }
+
+    return OK;
+}
+
+} // namespace MediaDescrambler
+
+} // namespace media
+} // namespace android
+
diff --git a/drm/libmediadrm/SharedLibrary.cpp b/drm/libmediadrm/SharedLibrary.cpp
index 74b3a71..bebafa8 100644
--- a/drm/libmediadrm/SharedLibrary.cpp
+++ b/drm/libmediadrm/SharedLibrary.cpp
@@ -43,6 +43,9 @@
         if (!mLibHandle) {
             return NULL;
         }
+        // Clear last error before we load the symbol again,
+        // in case the caller didn't retrieve it.
+        (void)dlerror();
         return dlsym(mLibHandle, symbol);
     }
 
diff --git a/drm/libmediadrm/aidl/android/media/ICas.aidl b/drm/libmediadrm/aidl/android/media/ICas.aidl
new file mode 100644
index 0000000..6b2ce4a
--- /dev/null
+++ b/drm/libmediadrm/aidl/android/media/ICas.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+import android.media.MediaCas;
+
+/** @hide */
+interface ICas {
+    void setPrivateData(in byte[] pvtData);
+    byte[] openSession(int program_number);
+    byte[] openSessionForStream(int program_number, int elementary_PID);
+    void closeSession(in byte[] sessionId);
+    void setSessionPrivateData(in byte[] sessionId, in byte[] pvtData);
+    void processEcm(in byte[] sessionId, in MediaCas.ParcelableCasData ecm);
+    void processEmm(in MediaCas.ParcelableCasData emm);
+    void sendEvent(int event, int arg, in @nullable byte[] eventData);
+    void provision(String provisionString);
+    void refreshEntitlements(int refreshType, in @nullable byte[] refreshData);
+    void release();
+}
\ No newline at end of file
diff --git a/drm/libmediadrm/aidl/android/media/ICasListener.aidl b/drm/libmediadrm/aidl/android/media/ICasListener.aidl
new file mode 100644
index 0000000..01a5abc
--- /dev/null
+++ b/drm/libmediadrm/aidl/android/media/ICasListener.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+/** @hide */
+interface ICasListener {
+    void onEvent(int event, int arg, in @nullable byte[] data);
+}
\ No newline at end of file
diff --git a/drm/libmediadrm/aidl/android/media/IDescrambler.aidl b/drm/libmediadrm/aidl/android/media/IDescrambler.aidl
new file mode 100644
index 0000000..fdf99eb
--- /dev/null
+++ b/drm/libmediadrm/aidl/android/media/IDescrambler.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+import android.media.MediaDescrambler;
+
+/** @hide */
+interface IDescrambler {
+    void setMediaCasSession(in byte[] sessionId);
+    boolean requiresSecureDecoderComponent(String mime);
+    int descramble(in MediaDescrambler.DescrambleInfo descrambleInfo);
+    void release();
+}
\ No newline at end of file
diff --git a/drm/libmediadrm/aidl/android/media/IMediaCasService.aidl b/drm/libmediadrm/aidl/android/media/IMediaCasService.aidl
new file mode 100644
index 0000000..44f6825
--- /dev/null
+++ b/drm/libmediadrm/aidl/android/media/IMediaCasService.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+import android.media.IDescrambler;
+import android.media.ICas;
+import android.media.ICasListener;
+import android.media.MediaCas;
+
+/** @hide */
+interface IMediaCasService {
+    MediaCas.ParcelableCasPluginDescriptor[] enumeratePlugins();
+    boolean isSystemIdSupported(int CA_system_id);
+    ICas createPlugin(int CA_system_id, ICasListener listener);
+    boolean isDescramblerSupported(int CA_system_id);
+    IDescrambler createDescrambler(int CA_system_id);
+}
+
diff --git a/drm/libmediadrm/aidl/android/media/MediaCas.aidl b/drm/libmediadrm/aidl/android/media/MediaCas.aidl
new file mode 100644
index 0000000..cb8d0c6
--- /dev/null
+++ b/drm/libmediadrm/aidl/android/media/MediaCas.aidl
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+/** @hide */
+parcelable MediaCas.ParcelableCasPluginDescriptor cpp_header "media/MediaCasDefs.h";
+
+/** @hide */
+parcelable MediaCas.ParcelableCasData cpp_header "media/MediaCasDefs.h";
\ No newline at end of file
diff --git a/drm/libmediadrm/aidl/android/media/MediaDescrambler.aidl b/drm/libmediadrm/aidl/android/media/MediaDescrambler.aidl
new file mode 100644
index 0000000..e789244
--- /dev/null
+++ b/drm/libmediadrm/aidl/android/media/MediaDescrambler.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+/** @hide */
+parcelable MediaDescrambler.DescrambleInfo cpp_header "media/MediaCasDefs.h";
\ No newline at end of file
diff --git a/include/camera b/include/camera
new file mode 120000
index 0000000..00848e3
--- /dev/null
+++ b/include/camera
@@ -0,0 +1 @@
+../camera/include/camera/
\ No newline at end of file
diff --git a/include/cpustats b/include/cpustats
new file mode 120000
index 0000000..4a02d41
--- /dev/null
+++ b/include/cpustats
@@ -0,0 +1 @@
+../media/libcpustats/include/cpustats/
\ No newline at end of file
diff --git a/include/media/AVSyncSettings.h b/include/media/AVSyncSettings.h
new file mode 120000
index 0000000..4b48419
--- /dev/null
+++ b/include/media/AVSyncSettings.h
@@ -0,0 +1 @@
+../../media/libmedia/include/AVSyncSettings.h
\ No newline at end of file
diff --git a/include/media/AudioBufferProvider.h b/include/media/AudioBufferProvider.h
new file mode 120000
index 0000000..dd7e234
--- /dev/null
+++ b/include/media/AudioBufferProvider.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/AudioBufferProvider.h
\ No newline at end of file
diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h
new file mode 120000
index 0000000..343749c
--- /dev/null
+++ b/include/media/AudioEffect.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/AudioEffect.h
\ No newline at end of file
diff --git a/include/media/AudioIoDescriptor.h b/include/media/AudioIoDescriptor.h
new file mode 120000
index 0000000..057129b
--- /dev/null
+++ b/include/media/AudioIoDescriptor.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/AudioIoDescriptor.h
\ No newline at end of file
diff --git a/include/media/AudioMixer.h b/include/media/AudioMixer.h
new file mode 120000
index 0000000..a2d0791
--- /dev/null
+++ b/include/media/AudioMixer.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/AudioMixer.h
\ No newline at end of file
diff --git a/include/media/AudioParameter.h b/include/media/AudioParameter.h
new file mode 120000
index 0000000..6b6fe3b
--- /dev/null
+++ b/include/media/AudioParameter.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/AudioParameter.h
\ No newline at end of file
diff --git a/include/media/AudioPolicy.h b/include/media/AudioPolicy.h
new file mode 120000
index 0000000..49ee572
--- /dev/null
+++ b/include/media/AudioPolicy.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/AudioPolicy.h
\ No newline at end of file
diff --git a/include/media/AudioPolicyHelper.h b/include/media/AudioPolicyHelper.h
new file mode 120000
index 0000000..a0302e2
--- /dev/null
+++ b/include/media/AudioPolicyHelper.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/AudioPolicyHelper.h
\ No newline at end of file
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
new file mode 120000
index 0000000..d5a5c36
--- /dev/null
+++ b/include/media/AudioRecord.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/AudioRecord.h
\ No newline at end of file
diff --git a/include/media/AudioResampler.h b/include/media/AudioResampler.h
new file mode 120000
index 0000000..50e12f4
--- /dev/null
+++ b/include/media/AudioResampler.h
@@ -0,0 +1 @@
+../../media/libaudioprocessing/include/AudioResampler.h
\ No newline at end of file
diff --git a/include/media/AudioResamplerPublic.h b/include/media/AudioResamplerPublic.h
new file mode 120000
index 0000000..309c23d
--- /dev/null
+++ b/include/media/AudioResamplerPublic.h
@@ -0,0 +1 @@
+../../media/libaudioprocessing/include/AudioResamplerPublic.h
\ No newline at end of file
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
new file mode 120000
index 0000000..0b7179f
--- /dev/null
+++ b/include/media/AudioSystem.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/AudioSystem.h
\ No newline at end of file
diff --git a/include/media/AudioTimestamp.h b/include/media/AudioTimestamp.h
new file mode 120000
index 0000000..f266780
--- /dev/null
+++ b/include/media/AudioTimestamp.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/AudioTimestamp.h
\ No newline at end of file
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
new file mode 120000
index 0000000..fddb075
--- /dev/null
+++ b/include/media/AudioTrack.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/AudioTrack.h
\ No newline at end of file
diff --git a/include/media/BufferProviders.h b/include/media/BufferProviders.h
new file mode 120000
index 0000000..a1fd855
--- /dev/null
+++ b/include/media/BufferProviders.h
@@ -0,0 +1 @@
+../../media/libmedia/include/BufferProviders.h
\ No newline at end of file
diff --git a/include/media/BufferingSettings.h b/include/media/BufferingSettings.h
new file mode 120000
index 0000000..fb4ec97
--- /dev/null
+++ b/include/media/BufferingSettings.h
@@ -0,0 +1 @@
+../../media/libmedia/include/BufferingSettings.h
\ No newline at end of file
diff --git a/include/media/CasImpl.h b/include/media/CasImpl.h
new file mode 100644
index 0000000..80c901e
--- /dev/null
+++ b/include/media/CasImpl.h
@@ -0,0 +1,96 @@
+/*
+ * 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 CAS_IMPL_H_
+#define CAS_IMPL_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <android/media/BnCas.h>
+
+namespace android {
+namespace media {
+class ICasListener;
+}
+using namespace media;
+using namespace MediaCas;
+using binder::Status;
+class CasPlugin;
+class SharedLibrary;
+
+class CasImpl : public BnCas {
+public:
+    CasImpl(const sp<ICasListener> &listener);
+    virtual ~CasImpl();
+
+    static void OnEvent(
+            void *appData,
+            int32_t event,
+            int32_t arg,
+            uint8_t *data,
+            size_t size);
+
+    void init(const sp<SharedLibrary>& library, CasPlugin *plugin);
+    void onEvent(
+            int32_t event,
+            int32_t arg,
+            uint8_t *data,
+            size_t size);
+
+    // ICas inherits
+
+    virtual Status setPrivateData(
+            const CasData& pvtData) override;
+
+    virtual Status openSession(
+            int32_t program_number, CasSessionId* _aidl_return) override;
+
+    virtual Status openSessionForStream(
+            int32_t program_number,
+            int32_t elementary_PID,
+            CasSessionId* _aidl_return) override;
+
+    virtual Status closeSession(const CasSessionId& sessionId) override;
+
+    virtual Status setSessionPrivateData(
+            const CasSessionId& sessionId,
+            const CasData& pvtData) override;
+
+    virtual Status processEcm(
+            const CasSessionId& sessionId, const ParcelableCasData& ecm) override;
+
+    virtual Status processEmm(const ParcelableCasData& emm) override;
+
+    virtual Status sendEvent(
+            int32_t event, int32_t arg, const ::std::unique_ptr<CasData> &eventData) override;
+
+    virtual Status provision(const String16& provisionString) override;
+
+    virtual Status refreshEntitlements(
+            int32_t refreshType, const ::std::unique_ptr<CasData> &refreshData) override;
+
+    virtual Status release() override;
+
+private:
+    sp<SharedLibrary> mLibrary;
+    CasPlugin *mPlugin;
+    sp<ICasListener> mListener;
+
+    DISALLOW_EVIL_CONSTRUCTORS(CasImpl);
+};
+
+} // namespace android
+
+#endif // CAS_IMPL_H_
diff --git a/include/media/CharacterEncodingDetector.h b/include/media/CharacterEncodingDetector.h
new file mode 120000
index 0000000..f23ed4c
--- /dev/null
+++ b/include/media/CharacterEncodingDetector.h
@@ -0,0 +1 @@
+../../media/libmedia/include/CharacterEncodingDetector.h
\ No newline at end of file
diff --git a/include/media/Crypto.h b/include/media/Crypto.h
new file mode 120000
index 0000000..778f6fe
--- /dev/null
+++ b/include/media/Crypto.h
@@ -0,0 +1 @@
+../../media/libmedia/include/Crypto.h
\ No newline at end of file
diff --git a/include/media/CryptoHal.h b/include/media/CryptoHal.h
new file mode 120000
index 0000000..81f31f5
--- /dev/null
+++ b/include/media/CryptoHal.h
@@ -0,0 +1 @@
+../../media/libmedia/include/CryptoHal.h
\ No newline at end of file
diff --git a/include/media/DescramblerImpl.h b/include/media/DescramblerImpl.h
new file mode 100644
index 0000000..c1c79b3
--- /dev/null
+++ b/include/media/DescramblerImpl.h
@@ -0,0 +1,55 @@
+/*
+ * 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 DESCRAMBLER_IMPL_H_
+#define DESCRAMBLER_IMPL_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <android/media/BnDescrambler.h>
+
+namespace android {
+using namespace media;
+using namespace MediaDescrambler;
+using binder::Status;
+class DescramblerPlugin;
+class SharedLibrary;
+
+class DescramblerImpl : public BnDescrambler {
+public:
+    DescramblerImpl(const sp<SharedLibrary>& library, DescramblerPlugin *plugin);
+    virtual ~DescramblerImpl();
+
+    virtual Status setMediaCasSession(
+            const CasSessionId& sessionId) override;
+
+    virtual Status requiresSecureDecoderComponent(
+            const String16& mime, bool *result) override;
+
+    virtual Status descramble(
+            const DescrambleInfo& descrambleInfo, int32_t *result) override;
+
+    virtual Status release() override;
+
+private:
+    sp<SharedLibrary> mLibrary;
+    DescramblerPlugin *mPlugin;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl);
+};
+
+} // namespace android
+
+#endif // DESCRAMBLER_IMPL_H_
diff --git a/include/media/Drm.h b/include/media/Drm.h
new file mode 120000
index 0000000..d9bfa5c
--- /dev/null
+++ b/include/media/Drm.h
@@ -0,0 +1 @@
+../../media/libmedia/include/Drm.h
\ No newline at end of file
diff --git a/include/media/DrmHal.h b/include/media/DrmHal.h
new file mode 120000
index 0000000..21ba37b
--- /dev/null
+++ b/include/media/DrmHal.h
@@ -0,0 +1 @@
+../../media/libmedia/include/DrmHal.h
\ No newline at end of file
diff --git a/include/media/DrmSessionClientInterface.h b/include/media/DrmSessionClientInterface.h
new file mode 120000
index 0000000..72090a3
--- /dev/null
+++ b/include/media/DrmSessionClientInterface.h
@@ -0,0 +1 @@
+../../media/libmedia/include/DrmSessionClientInterface.h
\ No newline at end of file
diff --git a/include/media/DrmSessionManager.h b/include/media/DrmSessionManager.h
new file mode 120000
index 0000000..47200f7
--- /dev/null
+++ b/include/media/DrmSessionManager.h
@@ -0,0 +1 @@
+../../media/libmedia/include/DrmSessionManager.h
\ No newline at end of file
diff --git a/include/media/EffectsFactoryApi.h b/include/media/EffectsFactoryApi.h
new file mode 120000
index 0000000..2431dfb
--- /dev/null
+++ b/include/media/EffectsFactoryApi.h
@@ -0,0 +1 @@
+../../media/libeffects/factory/include/EffectsFactoryApi.h
\ No newline at end of file
diff --git a/include/media/ExtendedAudioBufferProvider.h b/include/media/ExtendedAudioBufferProvider.h
new file mode 120000
index 0000000..9497be1
--- /dev/null
+++ b/include/media/ExtendedAudioBufferProvider.h
@@ -0,0 +1 @@
+../../media/libmedia/include/ExtendedAudioBufferProvider.h
\ No newline at end of file
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
new file mode 120000
index 0000000..310fd0d
--- /dev/null
+++ b/include/media/IAudioFlinger.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/IAudioFlinger.h
\ No newline at end of file
diff --git a/include/media/IAudioFlingerClient.h b/include/media/IAudioFlingerClient.h
new file mode 120000
index 0000000..d27389e
--- /dev/null
+++ b/include/media/IAudioFlingerClient.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/IAudioFlingerClient.h
\ No newline at end of file
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
new file mode 120000
index 0000000..8ef16e2
--- /dev/null
+++ b/include/media/IAudioPolicyService.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/IAudioPolicyService.h
\ No newline at end of file
diff --git a/include/media/IAudioPolicyServiceClient.h b/include/media/IAudioPolicyServiceClient.h
new file mode 120000
index 0000000..26f6790
--- /dev/null
+++ b/include/media/IAudioPolicyServiceClient.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/IAudioPolicyServiceClient.h
\ No newline at end of file
diff --git a/include/media/IAudioRecord.h b/include/media/IAudioRecord.h
new file mode 120000
index 0000000..520d44e
--- /dev/null
+++ b/include/media/IAudioRecord.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/IAudioRecord.h
\ No newline at end of file
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
new file mode 120000
index 0000000..afa6bf4
--- /dev/null
+++ b/include/media/IAudioTrack.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/IAudioTrack.h
\ No newline at end of file
diff --git a/include/media/ICrypto.h b/include/media/ICrypto.h
new file mode 120000
index 0000000..53c547a
--- /dev/null
+++ b/include/media/ICrypto.h
@@ -0,0 +1 @@
+../../media/libmedia/include/ICrypto.h
\ No newline at end of file
diff --git a/include/media/IDataSource.h b/include/media/IDataSource.h
new file mode 120000
index 0000000..7ac813f
--- /dev/null
+++ b/include/media/IDataSource.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IDataSource.h
\ No newline at end of file
diff --git a/include/media/IDrm.h b/include/media/IDrm.h
new file mode 120000
index 0000000..eb2f0ec
--- /dev/null
+++ b/include/media/IDrm.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IDrm.h
\ No newline at end of file
diff --git a/include/media/IDrmClient.h b/include/media/IDrmClient.h
new file mode 120000
index 0000000..4d8b50c
--- /dev/null
+++ b/include/media/IDrmClient.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IDrmClient.h
\ No newline at end of file
diff --git a/include/media/IEffect.h b/include/media/IEffect.h
new file mode 120000
index 0000000..72d715d
--- /dev/null
+++ b/include/media/IEffect.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/IEffect.h
\ No newline at end of file
diff --git a/include/media/IEffectClient.h b/include/media/IEffectClient.h
new file mode 120000
index 0000000..0614d8a
--- /dev/null
+++ b/include/media/IEffectClient.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/IEffectClient.h
\ No newline at end of file
diff --git a/include/media/IHDCP.h b/include/media/IHDCP.h
new file mode 120000
index 0000000..f1e112e
--- /dev/null
+++ b/include/media/IHDCP.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IHDCP.h
\ No newline at end of file
diff --git a/include/media/IMediaAnalyticsService.h b/include/media/IMediaAnalyticsService.h
new file mode 120000
index 0000000..97915e4
--- /dev/null
+++ b/include/media/IMediaAnalyticsService.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaAnalyticsService.h
\ No newline at end of file
diff --git a/include/media/IMediaCodecList.h b/include/media/IMediaCodecList.h
new file mode 120000
index 0000000..2e30503
--- /dev/null
+++ b/include/media/IMediaCodecList.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaCodecList.h
\ No newline at end of file
diff --git a/include/media/IMediaCodecService.h b/include/media/IMediaCodecService.h
new file mode 120000
index 0000000..5103277
--- /dev/null
+++ b/include/media/IMediaCodecService.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaCodecService.h
\ No newline at end of file
diff --git a/include/media/IMediaDeathNotifier.h b/include/media/IMediaDeathNotifier.h
new file mode 120000
index 0000000..74b1656
--- /dev/null
+++ b/include/media/IMediaDeathNotifier.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaDeathNotifier.h
\ No newline at end of file
diff --git a/include/media/IMediaDrmService.h b/include/media/IMediaDrmService.h
new file mode 120000
index 0000000..6efbc48
--- /dev/null
+++ b/include/media/IMediaDrmService.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaDrmService.h
\ No newline at end of file
diff --git a/include/media/IMediaExtractor.h b/include/media/IMediaExtractor.h
new file mode 120000
index 0000000..c17c4eb
--- /dev/null
+++ b/include/media/IMediaExtractor.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaExtractor.h
\ No newline at end of file
diff --git a/include/media/IMediaExtractorService.h b/include/media/IMediaExtractorService.h
new file mode 120000
index 0000000..1e6e8b4
--- /dev/null
+++ b/include/media/IMediaExtractorService.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaExtractorService.h
\ No newline at end of file
diff --git a/include/media/IMediaHTTPConnection.h b/include/media/IMediaHTTPConnection.h
new file mode 120000
index 0000000..9e544fe
--- /dev/null
+++ b/include/media/IMediaHTTPConnection.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaHTTPConnection.h
\ No newline at end of file
diff --git a/include/media/IMediaHTTPService.h b/include/media/IMediaHTTPService.h
new file mode 120000
index 0000000..6312e06
--- /dev/null
+++ b/include/media/IMediaHTTPService.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaHTTPService.h
\ No newline at end of file
diff --git a/include/media/IMediaLogService.h b/include/media/IMediaLogService.h
new file mode 120000
index 0000000..7a822dd
--- /dev/null
+++ b/include/media/IMediaLogService.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaLogService.h
\ No newline at end of file
diff --git a/include/media/IMediaMetadataRetriever.h b/include/media/IMediaMetadataRetriever.h
new file mode 120000
index 0000000..c2dd811
--- /dev/null
+++ b/include/media/IMediaMetadataRetriever.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaMetadataRetriever.h
\ No newline at end of file
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
new file mode 120000
index 0000000..a38baf4
--- /dev/null
+++ b/include/media/IMediaPlayer.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaPlayer.h
\ No newline at end of file
diff --git a/include/media/IMediaPlayerClient.h b/include/media/IMediaPlayerClient.h
new file mode 120000
index 0000000..1c27dee
--- /dev/null
+++ b/include/media/IMediaPlayerClient.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaPlayerClient.h
\ No newline at end of file
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
new file mode 120000
index 0000000..08a6a98
--- /dev/null
+++ b/include/media/IMediaPlayerService.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaPlayerService.h
\ No newline at end of file
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
new file mode 120000
index 0000000..c8b8b29
--- /dev/null
+++ b/include/media/IMediaRecorder.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaRecorder.h
\ No newline at end of file
diff --git a/include/media/IMediaRecorderClient.h b/include/media/IMediaRecorderClient.h
new file mode 120000
index 0000000..ab703aa
--- /dev/null
+++ b/include/media/IMediaRecorderClient.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaRecorderClient.h
\ No newline at end of file
diff --git a/include/media/IMediaSource.h b/include/media/IMediaSource.h
new file mode 120000
index 0000000..1c3d8fe
--- /dev/null
+++ b/include/media/IMediaSource.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IMediaSource.h
\ No newline at end of file
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
new file mode 120000
index 0000000..989d9b2
--- /dev/null
+++ b/include/media/IOMX.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IOMX.h
\ No newline at end of file
diff --git a/include/media/IRemoteDisplay.h b/include/media/IRemoteDisplay.h
new file mode 120000
index 0000000..5aa58b9
--- /dev/null
+++ b/include/media/IRemoteDisplay.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IRemoteDisplay.h
\ No newline at end of file
diff --git a/include/media/IRemoteDisplayClient.h b/include/media/IRemoteDisplayClient.h
new file mode 120000
index 0000000..2d212e7
--- /dev/null
+++ b/include/media/IRemoteDisplayClient.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IRemoteDisplayClient.h
\ No newline at end of file
diff --git a/include/media/IResourceManagerClient.h b/include/media/IResourceManagerClient.h
new file mode 120000
index 0000000..1531ae2
--- /dev/null
+++ b/include/media/IResourceManagerClient.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IResourceManagerClient.h
\ No newline at end of file
diff --git a/include/media/IResourceManagerService.h b/include/media/IResourceManagerService.h
new file mode 120000
index 0000000..007aecb
--- /dev/null
+++ b/include/media/IResourceManagerService.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IResourceManagerService.h
\ No newline at end of file
diff --git a/include/media/IStreamSource.h b/include/media/IStreamSource.h
new file mode 120000
index 0000000..90dbbf2
--- /dev/null
+++ b/include/media/IStreamSource.h
@@ -0,0 +1 @@
+../../media/libmedia/include/IStreamSource.h
\ No newline at end of file
diff --git a/include/media/Interpolator.h b/include/media/Interpolator.h
new file mode 100644
index 0000000..1b26b87
--- /dev/null
+++ b/include/media/Interpolator.h
@@ -0,0 +1,331 @@
+/*
+ * Copyright 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_INTERPOLATOR_H
+#define ANDROID_INTERPOLATOR_H
+
+#include <map>
+#include <sstream>
+#include <unordered_map>
+
+#include <binder/Parcel.h>
+#include <utils/RefBase.h>
+
+#pragma push_macro("LOG_TAG")
+#undef LOG_TAG
+#define LOG_TAG "Interpolator"
+
+namespace android {
+
+/*
+ * A general purpose spline interpolator class which takes a set of points
+ * and performs interpolation.  This is used for the VolumeShaper class.
+ */
+
+template <typename S, typename T>
+class Interpolator : public std::map<S, T> {
+public:
+    // Polynomial spline interpolators
+    // Extend only at the end of enum, as this must match order in VolumeShapers.java.
+    enum InterpolatorType : int32_t {
+        INTERPOLATOR_TYPE_STEP,   // Not continuous
+        INTERPOLATOR_TYPE_LINEAR, // C0
+        INTERPOLATOR_TYPE_CUBIC,  // C1
+        INTERPOLATOR_TYPE_CUBIC_MONOTONIC, // C1 (to provide locally monotonic curves)
+        // INTERPOLATOR_TYPE_CUBIC_C2, // TODO - requires global computation / cache
+    };
+
+    explicit Interpolator(
+            InterpolatorType interpolatorType = INTERPOLATOR_TYPE_LINEAR,
+            bool cache = true)
+        : mCache(cache)
+        , mFirstSlope(0)
+        , mLastSlope(0) {
+        setInterpolatorType(interpolatorType);
+    }
+
+    std::pair<S, T> first() const {
+        return *this->begin();
+    }
+
+    std::pair<S, T> last() const {
+        return *this->rbegin();
+    }
+
+    // find the corresponding Y point from a X point.
+    T findY(S x) { // logically const, but modifies cache
+        auto high = this->lower_bound(x);
+        // greater than last point
+        if (high == this->end()) {
+            return this->rbegin()->second;
+        }
+        // at or before first point
+        if (high == this->begin()) {
+            return high->second;
+        }
+        // go lower.
+        auto low = high;
+        --low;
+
+        // now that we have two adjacent points:
+        switch (mInterpolatorType) {
+        case INTERPOLATOR_TYPE_STEP:
+            return high->first == x ? high->second : low->second;
+        case INTERPOLATOR_TYPE_LINEAR:
+            return ((high->first - x) * low->second + (x - low->first) * high->second)
+                    / (high->first - low->first);
+        case INTERPOLATOR_TYPE_CUBIC:
+        case INTERPOLATOR_TYPE_CUBIC_MONOTONIC:
+        default: {
+            // See https://en.wikipedia.org/wiki/Cubic_Hermite_spline
+
+            const S interval =  high->first - low->first;
+
+            // check to see if we've cached the polynomial coefficients
+            if (mMemo.count(low->first) != 0) {
+                const S t = (x - low->first) / interval;
+                const S t2 = t * t;
+                const auto &memo = mMemo[low->first];
+                return low->second + std::get<0>(memo) * t
+                        + (std::get<1>(memo) + std::get<2>(memo) * t) * t2;
+            }
+
+            // find the neighboring points (low2 < low < high < high2)
+            auto low2 = this->end();
+            if (low != this->begin()) {
+                low2 = low;
+                --low2; // decrementing this->begin() is undefined
+            }
+            auto high2 = high;
+            ++high2;
+
+            // you could have catmullRom with monotonic or
+            // non catmullRom (finite difference) with regular cubic;
+            // the choices here minimize computation.
+            bool monotonic, catmullRom;
+            if (mInterpolatorType == INTERPOLATOR_TYPE_CUBIC_MONOTONIC) {
+                monotonic = true;
+                catmullRom = false;
+            } else {
+                monotonic = false;
+                catmullRom = true;
+            }
+
+            // secants are only needed for finite difference splines or
+            // monotonic computation.
+            // we use lazy computation here - if we precompute in
+            // a single pass, duplicate secant computations may be avoided.
+            S sec, sec0, sec1;
+            if (!catmullRom || monotonic) {
+                sec = (high->second - low->second) / interval;
+                sec0 = low2 != this->end()
+                        ? (low->second - low2->second) / (low->first - low2->first)
+                        : mFirstSlope;
+                sec1 = high2 != this->end()
+                        ? (high2->second - high->second) / (high2->first - high->first)
+                        : mLastSlope;
+            }
+
+            // compute the tangent slopes at the control points
+            S m0, m1;
+            if (catmullRom) {
+                // Catmull-Rom spline
+                m0 = low2 != this->end()
+                        ? (high->second - low2->second) / (high->first - low2->first)
+                        : mFirstSlope;
+
+                m1 = high2 != this->end()
+                        ? (high2->second - low->second) / (high2->first - low->first)
+                        : mLastSlope;
+            } else {
+                // finite difference spline
+                m0 = (sec0 + sec) * 0.5;
+                m1 = (sec1 + sec) * 0.5;
+            }
+
+            if (monotonic) {
+                // https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
+                // A sufficient condition for Fritsch–Carlson monotonicity is constraining
+                // (1) the normalized slopes to be within the circle of radius 3, or
+                // (2) the normalized slopes to be within the square of radius 3.
+                // Condition (2) is more generous and easier to compute.
+                const S maxSlope = 3 * sec;
+                m0 = constrainSlope(m0, maxSlope);
+                m1 = constrainSlope(m1, maxSlope);
+
+                m0 = constrainSlope(m0, 3 * sec0);
+                m1 = constrainSlope(m1, 3 * sec1);
+            }
+
+            const S t = (x - low->first) / interval;
+            const S t2 = t * t;
+            if (mCache) {
+                // convert to cubic polynomial coefficients and compute
+                m0 *= interval;
+                m1 *= interval;
+                const T dy = high->second - low->second;
+                const S c0 = low->second;
+                const S c1 = m0;
+                const S c2 = 3 * dy - 2 * m0 - m1;
+                const S c3 = m0 + m1 - 2 * dy;
+                mMemo[low->first] = std::make_tuple(c1, c2, c3);
+                return c0 + c1 * t + (c2 + c3 * t) * t2;
+            } else {
+                // classic Hermite interpolation
+                const S t3 = t2 * t;
+                const S h00 =  2 * t3 - 3 * t2     + 1;
+                const S h10 =      t3 - 2 * t2 + t    ;
+                const S h01 = -2 * t3 + 3 * t2        ;
+                const S h11 =      t3     - t2        ;
+                return h00 * low->second + (h10 * m0 + h11 * m1) * interval + h01 * high->second;
+            }
+        } // default
+        }
+    }
+
+    InterpolatorType getInterpolatorType() const {
+        return mInterpolatorType;
+    }
+
+    status_t setInterpolatorType(InterpolatorType interpolatorType) {
+        switch (interpolatorType) {
+        case INTERPOLATOR_TYPE_STEP:   // Not continuous
+        case INTERPOLATOR_TYPE_LINEAR: // C0
+        case INTERPOLATOR_TYPE_CUBIC:  // C1
+        case INTERPOLATOR_TYPE_CUBIC_MONOTONIC: // C1 + other constraints
+        // case INTERPOLATOR_TYPE_CUBIC_C2:
+            mInterpolatorType = interpolatorType;
+            return NO_ERROR;
+        default:
+            ALOGE("invalid interpolatorType: %d", interpolatorType);
+            return BAD_VALUE;
+        }
+    }
+
+    T getFirstSlope() const {
+        return mFirstSlope;
+    }
+
+    void setFirstSlope(T slope) {
+        mFirstSlope = slope;
+    }
+
+    T getLastSlope() const {
+        return mLastSlope;
+    }
+
+    void setLastSlope(T slope) {
+        mLastSlope = slope;
+    }
+
+    void clearCache() {
+        mMemo.clear();
+    }
+
+    status_t writeToParcel(Parcel *parcel) const {
+        if (parcel == nullptr) {
+            return BAD_VALUE;
+        }
+        status_t res = parcel->writeInt32(mInterpolatorType)
+                ?: parcel->writeFloat(mFirstSlope)
+                ?: parcel->writeFloat(mLastSlope)
+                ?: parcel->writeUint32((uint32_t)this->size()); // silent truncation
+        if (res != NO_ERROR) {
+            return res;
+        }
+        for (const auto &pt : *this) {
+            res = parcel->writeFloat(pt.first)
+                    ?: parcel->writeFloat(pt.second);
+            if (res != NO_ERROR) {
+                return res;
+            }
+        }
+        return NO_ERROR;
+    }
+
+    status_t readFromParcel(const Parcel &parcel) {
+        this->clear();
+        int32_t type;
+        uint32_t size;
+        status_t res = parcel.readInt32(&type)
+                        ?: parcel.readFloat(&mFirstSlope)
+                        ?: parcel.readFloat(&mLastSlope)
+                        ?: parcel.readUint32(&size)
+                        ?: setInterpolatorType((InterpolatorType)type);
+        if (res != NO_ERROR) {
+            return res;
+        }
+        // Note: We don't need to check size is within some bounds as
+        // the Parcel read will fail if size is incorrectly specified too large.
+        float lastx;
+        for (uint32_t i = 0; i < size; ++i) {
+            float x, y;
+            res = parcel.readFloat(&x)
+                    ?: parcel.readFloat(&y);
+            if (res != NO_ERROR) {
+                return res;
+            }
+            if (i > 0 && !(x > lastx) /* handle nan */
+                    || y != y /* handle nan */) {
+                // This is a std::map object which imposes sorted order
+                // automatically on emplace.
+                // Nevertheless for reading from a Parcel,
+                // we require that the points be specified monotonic in x.
+                return BAD_VALUE;
+            }
+            this->emplace(x, y);
+            lastx = x;
+        }
+        return NO_ERROR;
+    }
+
+    std::string toString() const {
+        std::stringstream ss;
+        ss << "mInterpolatorType: " << mInterpolatorType << std::endl;
+        for (const auto &pt : *this) {
+            ss << pt.first << " " << pt.second << std::endl;
+        }
+        return ss.str();
+    }
+
+private:
+    static S constrainSlope(S slope, S maxSlope) {
+        if (maxSlope > 0) {
+            slope = std::min(slope, maxSlope);
+            slope = std::max(slope, S(0)); // not globally monotonic
+        } else {
+            slope = std::max(slope, maxSlope);
+            slope = std::min(slope, S(0)); // not globally monotonic
+        }
+        return slope;
+    }
+
+    InterpolatorType mInterpolatorType;
+    bool mCache; // whether we cache spline coefficient computation
+
+    // for cubic interpolation, the boundary conditions in slope.
+    S mFirstSlope;
+    S mLastSlope;
+
+    // spline cubic polynomial coefficient cache
+    std::unordered_map<S, std::tuple<S /* c1 */, S /* c2 */, S /* c3 */>> mMemo;
+};
+
+} // namespace android
+
+#pragma pop_macro("LOG_TAG")
+
+#endif // ANDROID_INTERPOLATOR_H
diff --git a/include/media/JetPlayer.h b/include/media/JetPlayer.h
new file mode 120000
index 0000000..cabfb79
--- /dev/null
+++ b/include/media/JetPlayer.h
@@ -0,0 +1 @@
+../../media/libmedia/include/JetPlayer.h
\ No newline at end of file
diff --git a/include/media/LinearMap.h b/include/media/LinearMap.h
new file mode 120000
index 0000000..3e89686
--- /dev/null
+++ b/include/media/LinearMap.h
@@ -0,0 +1 @@
+../../media/libmedia/include/LinearMap.h
\ No newline at end of file
diff --git a/include/media/MediaAnalyticsItem.h b/include/media/MediaAnalyticsItem.h
new file mode 120000
index 0000000..71957a5
--- /dev/null
+++ b/include/media/MediaAnalyticsItem.h
@@ -0,0 +1 @@
+../../media/libmedia/include/MediaAnalyticsItem.h
\ No newline at end of file
diff --git a/include/media/MediaCasDefs.h b/include/media/MediaCasDefs.h
new file mode 100644
index 0000000..8c5a967
--- /dev/null
+++ b/include/media/MediaCasDefs.h
@@ -0,0 +1,97 @@
+/*
+ * 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 MEDIA_CAS_DEFS_H_
+#define MEDIA_CAS_DEFS_H_
+
+#include <binder/Parcel.h>
+#include <media/cas/CasAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+class IMemory;
+namespace media {
+
+namespace MediaCas {
+class ParcelableCasData : public CasData,
+                          public Parcelable {
+public:
+    ParcelableCasData() {}
+    ParcelableCasData(const uint8_t *data, size_t size) :
+        CasData(data, data + size) {}
+    virtual ~ParcelableCasData() {}
+    status_t readFromParcel(const Parcel* parcel) override;
+    status_t writeToParcel(Parcel* parcel) const override;
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(ParcelableCasData);
+};
+
+class ParcelableCasPluginDescriptor : public Parcelable {
+public:
+    ParcelableCasPluginDescriptor(int32_t CA_system_id, const char *name)
+        : mCASystemId(CA_system_id), mName(name) {}
+
+    ParcelableCasPluginDescriptor() : mCASystemId(0) {}
+
+    ParcelableCasPluginDescriptor(ParcelableCasPluginDescriptor&& desc) = default;
+
+    virtual ~ParcelableCasPluginDescriptor() {}
+
+    status_t readFromParcel(const Parcel* parcel) override;
+    status_t writeToParcel(Parcel* parcel) const override;
+
+private:
+    int32_t mCASystemId;
+    String16 mName;
+    DISALLOW_EVIL_CONSTRUCTORS(ParcelableCasPluginDescriptor);
+};
+}
+
+namespace MediaDescrambler {
+class DescrambleInfo : public Parcelable {
+public:
+    enum DestinationType {
+        kDestinationTypeVmPointer,    // non-secure
+        kDestinationTypeNativeHandle  // secure
+    };
+
+    DestinationType dstType;
+    DescramblerPlugin::ScramblingControl scramblingControl;
+    size_t numSubSamples;
+    DescramblerPlugin::SubSample *subSamples;
+    sp<IMemory> srcMem;
+    int32_t srcOffset;
+    void *dstPtr;
+    int32_t dstOffset;
+
+    DescrambleInfo();
+    virtual ~DescrambleInfo();
+    status_t readFromParcel(const Parcel* parcel) override;
+    status_t writeToParcel(Parcel* parcel) const override;
+
+private:
+
+    DISALLOW_EVIL_CONSTRUCTORS(DescrambleInfo);
+};
+}
+
+} // namespace media
+} // namespace android
+
+
+#endif // MEDIA_CAS_DEFS_H_
diff --git a/include/media/MediaCodecBuffer.h b/include/media/MediaCodecBuffer.h
new file mode 120000
index 0000000..60b7e70
--- /dev/null
+++ b/include/media/MediaCodecBuffer.h
@@ -0,0 +1 @@
+../../media/libmedia/include/MediaCodecBuffer.h
\ No newline at end of file
diff --git a/include/media/MediaCodecInfo.h b/include/media/MediaCodecInfo.h
new file mode 120000
index 0000000..22b10bb
--- /dev/null
+++ b/include/media/MediaCodecInfo.h
@@ -0,0 +1 @@
+../../media/libmedia/include/MediaCodecInfo.h
\ No newline at end of file
diff --git a/include/media/MediaDefs.h b/include/media/MediaDefs.h
new file mode 120000
index 0000000..993729d
--- /dev/null
+++ b/include/media/MediaDefs.h
@@ -0,0 +1 @@
+../../media/libmedia/include/MediaDefs.h
\ No newline at end of file
diff --git a/include/media/MediaMetadataRetrieverInterface.h b/include/media/MediaMetadataRetrieverInterface.h
new file mode 120000
index 0000000..a09f9bb
--- /dev/null
+++ b/include/media/MediaMetadataRetrieverInterface.h
@@ -0,0 +1 @@
+../../media/libmedia/include/MediaMetadataRetrieverInterface.h
\ No newline at end of file
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
new file mode 120000
index 0000000..9b2e1c7
--- /dev/null
+++ b/include/media/MediaPlayerInterface.h
@@ -0,0 +1 @@
+../../media/libmediaplayerservice/include/MediaPlayerInterface.h
\ No newline at end of file
diff --git a/include/media/MediaProfiles.h b/include/media/MediaProfiles.h
new file mode 120000
index 0000000..86958e4
--- /dev/null
+++ b/include/media/MediaProfiles.h
@@ -0,0 +1 @@
+../../media/libmedia/include/MediaProfiles.h
\ No newline at end of file
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
new file mode 120000
index 0000000..6080258
--- /dev/null
+++ b/include/media/MediaRecorderBase.h
@@ -0,0 +1 @@
+../../media/libmedia/include/MediaRecorderBase.h
\ No newline at end of file
diff --git a/include/media/MediaResource.h b/include/media/MediaResource.h
new file mode 120000
index 0000000..aaf931a
--- /dev/null
+++ b/include/media/MediaResource.h
@@ -0,0 +1 @@
+../../media/libmedia/include/MediaResource.h
\ No newline at end of file
diff --git a/include/media/MediaResourcePolicy.h b/include/media/MediaResourcePolicy.h
new file mode 120000
index 0000000..d56b09f
--- /dev/null
+++ b/include/media/MediaResourcePolicy.h
@@ -0,0 +1 @@
+../../media/libmedia/include/MediaResourcePolicy.h
\ No newline at end of file
diff --git a/include/media/MemoryLeakTrackUtil.h b/include/media/MemoryLeakTrackUtil.h
new file mode 120000
index 0000000..cfeac14
--- /dev/null
+++ b/include/media/MemoryLeakTrackUtil.h
@@ -0,0 +1 @@
+../../media/libmedia/include/MemoryLeakTrackUtil.h
\ No newline at end of file
diff --git a/include/media/Metadata.h b/include/media/Metadata.h
new file mode 120000
index 0000000..4a5893d
--- /dev/null
+++ b/include/media/Metadata.h
@@ -0,0 +1 @@
+../../media/libmedia/include/Metadata.h
\ No newline at end of file
diff --git a/include/media/MidiDeviceInfo.h b/include/media/MidiDeviceInfo.h
new file mode 120000
index 0000000..55ac9f5
--- /dev/null
+++ b/include/media/MidiDeviceInfo.h
@@ -0,0 +1 @@
+../../media/libmedia/include/MidiDeviceInfo.h
\ No newline at end of file
diff --git a/include/media/MidiIoWrapper.h b/include/media/MidiIoWrapper.h
new file mode 120000
index 0000000..a3fe892
--- /dev/null
+++ b/include/media/MidiIoWrapper.h
@@ -0,0 +1 @@
+../../media/libmedia/include/MidiIoWrapper.h
\ No newline at end of file
diff --git a/include/media/MmapStreamCallback.h b/include/media/MmapStreamCallback.h
new file mode 100644
index 0000000..8098e79
--- /dev/null
+++ b/include/media/MmapStreamCallback.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 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 ANDROID_AUDIO_MMAP_STREAM_CALLBACK_H
+#define ANDROID_AUDIO_MMAP_STREAM_CALLBACK_H
+
+#include <system/audio.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+
+class MmapStreamCallback : public virtual RefBase {
+  public:
+
+    /**
+     * The mmap stream should be torn down because conditions that permitted its creation with
+     * the requested parameters have changed and do not allow it to operate with the requested
+     * constraints any more.
+     */
+    virtual void onTearDown() = 0;
+
+    /**
+     * The volume to be applied to the use case specified when opening the stream has changed
+     * \param[in] channels a channel mask containing all channels the volume should be applied to.
+     * \param[in] values the volume values to be applied to each channel. The size of the vector
+     *                   should correspond to the channel count retrieved with
+     *                   audio_channel_count_from_in_mask() or audio_channel_count_from_out_mask()
+     */
+    virtual void onVolumeChanged(audio_channel_mask_t channels, Vector<float> values) = 0;
+
+    /**
+     * The device the stream is routed to/from has changed
+     * \param[in] onRoutingChanged the unique device ID of the new device.
+     */
+    virtual void onRoutingChanged(audio_port_handle_t deviceId) = 0;
+
+  protected:
+    MmapStreamCallback() {}
+    virtual ~MmapStreamCallback() {}
+};
+
+
+} // namespace android
+
+#endif // ANDROID_AUDIO_MMAP_STREAM_CALLBACK_H
diff --git a/include/media/MmapStreamInterface.h b/include/media/MmapStreamInterface.h
new file mode 100644
index 0000000..9f3731e
--- /dev/null
+++ b/include/media/MmapStreamInterface.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 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 ANDROID_AUDIO_MMAP_STREAM_INTERFACE_H
+#define ANDROID_AUDIO_MMAP_STREAM_INTERFACE_H
+
+#include <system/audio.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class MmapStreamCallback;
+
+class MmapStreamInterface : public virtual RefBase
+{
+  public:
+
+    /**
+     * Values for direction argument passed to openMmapStream()
+     */
+    typedef enum {
+        DIRECTION_OUTPUT = 0,  /**< open a playback mmap stream */
+        DIRECTION_INPUT,       /**< open a capture mmap stream */
+    } stream_direction_t;
+
+    class Client {
+     public:
+        uid_t clientUid;
+        pid_t clientPid;
+        String16 packageName;
+    };
+    /**
+     * Open a playback or capture stream in MMAP mode at the audio HAL.
+     *
+     * \note This method is implemented by AudioFlinger
+     *
+     * \param[in] direction open a playback or capture stream.
+     * \param[in] attr audio attributes defining the main use case for this stream
+     * \param[in,out] config audio parameters (sampling rate, format ...) for the stream.
+     *                       Requested parameters as input,
+     *                       Actual parameters as output
+     * \param[in] client a Client struct describing the first client using this stream.
+     * \param[in,out] deviceId audio device the stream should preferably be routed to/from
+     *                       Requested as input,
+     *                       Actual as output
+     * \param[in] callback the MmapStreamCallback interface used by AudioFlinger to notify
+     *                     condition changes affecting the stream operation
+     * \param[out] interface the MmapStreamInterface interface controlling the created stream
+     * \return OK if the stream was successfully created.
+     *         NO_INIT if AudioFlinger is not properly initialized
+     *         BAD_VALUE if the stream cannot be opened because of invalid arguments
+     *         INVALID_OPERATION if the stream cannot be opened because of platform limitations
+     */
+    static status_t openMmapStream(stream_direction_t direction,
+                                           const audio_attributes_t *attr,
+                                           audio_config_base_t *config,
+                                           const Client& client,
+                                           audio_port_handle_t *deviceId,
+                                           const sp<MmapStreamCallback>& callback,
+                                           sp<MmapStreamInterface>& interface);
+
+    /**
+     * Retrieve information on the mmap buffer used for audio samples transfer.
+     *
+     * \param[in] min_size_frames minimum buffer size requested. The actual buffer
+     *        size returned in struct audio_mmap_buffer_info can be larger.
+     * \param[out] info address at which the mmap buffer information should be returned.
+     *
+     * \return OK if the buffer was allocated.
+     *         NO_INIT in case of initialization error
+     *         BAD_VALUE if the requested buffer size is too large
+     *         INVALID_OPERATION if called out of sequence (e.g. buffer already allocated)
+     */
+    virtual status_t createMmapBuffer(int32_t minSizeFrames,
+                                      struct audio_mmap_buffer_info *info) = 0;
+
+    /**
+     * Read current read/write position in the mmap buffer with associated time stamp.
+     *
+     * \param[out] position address at which the mmap read/write position should be returned.
+     *
+     * \return OK if the position is successfully returned.
+     *         NOT_ENOUGH_DATA if the position cannot be retrieved
+     *         INVALID_OPERATION if called before createMmapBuffer()
+     */
+    virtual status_t getMmapPosition(struct audio_mmap_position *position) = 0;
+
+    /**
+     * Start a stream operating in mmap mode.
+     * createMmapBuffer() must be called before calling start()
+     *
+     * \param[in] client a Client struct describing the client starting on this stream.
+     * \param[out] handle unique handle for this instance. Used with stop().
+     * \return OK in case of success.
+     *         INVALID_OPERATION if called out of sequence
+     */
+    virtual status_t start(const Client& client, audio_port_handle_t *handle) = 0;
+
+    /**
+     * Stop a stream operating in mmap mode.
+     * Must be called after start()
+     *
+     * \param[in] handle unique handle allocated by start().
+     * \return OK in case of success.
+     *         INVALID_OPERATION if called out of sequence
+     */
+    virtual status_t stop(audio_port_handle_t handle) = 0;
+
+  protected:
+    // Subclasses can not be constructed directly by clients.
+    MmapStreamInterface() {}
+
+    // The destructor automatically closes the stream.
+    virtual ~MmapStreamInterface() {}
+};
+
+} // namespace android
+
+#endif // ANDROID_AUDIO_MMAP_STREAM_INTERFACE_H
diff --git a/include/media/Modulo.h b/include/media/Modulo.h
new file mode 120000
index 0000000..58f31a4
--- /dev/null
+++ b/include/media/Modulo.h
@@ -0,0 +1 @@
+../../media/libmedia/include/Modulo.h
\ No newline at end of file
diff --git a/include/media/OMXBuffer.h b/include/media/OMXBuffer.h
new file mode 120000
index 0000000..9defe79
--- /dev/null
+++ b/include/media/OMXBuffer.h
@@ -0,0 +1 @@
+../../media/libmedia/include/OMXBuffer.h
\ No newline at end of file
diff --git a/include/media/OMXFenceParcelable.h b/include/media/OMXFenceParcelable.h
new file mode 120000
index 0000000..2e996dd
--- /dev/null
+++ b/include/media/OMXFenceParcelable.h
@@ -0,0 +1 @@
+../../media/libmedia/include/OMXFenceParcelable.h
\ No newline at end of file
diff --git a/include/media/PluginLoader.h b/include/media/PluginLoader.h
new file mode 120000
index 0000000..f67f2c4
--- /dev/null
+++ b/include/media/PluginLoader.h
@@ -0,0 +1 @@
+../../media/libmedia/include/PluginLoader.h
\ No newline at end of file
diff --git a/include/media/RecordBufferConverter.h b/include/media/RecordBufferConverter.h
new file mode 120000
index 0000000..b9ee8df
--- /dev/null
+++ b/include/media/RecordBufferConverter.h
@@ -0,0 +1 @@
+../../media/libmedia/include/RecordBufferConverter.h
\ No newline at end of file
diff --git a/include/media/RingBuffer.h b/include/media/RingBuffer.h
new file mode 120000
index 0000000..84f4943
--- /dev/null
+++ b/include/media/RingBuffer.h
@@ -0,0 +1 @@
+../../media/libmedia/include/RingBuffer.h
\ No newline at end of file
diff --git a/include/media/SharedLibrary.h b/include/media/SharedLibrary.h
new file mode 120000
index 0000000..a2a040f
--- /dev/null
+++ b/include/media/SharedLibrary.h
@@ -0,0 +1 @@
+../../media/libmedia/include/SharedLibrary.h
\ No newline at end of file
diff --git a/include/media/SingleStateQueue.h b/include/media/SingleStateQueue.h
new file mode 120000
index 0000000..7dda0d8
--- /dev/null
+++ b/include/media/SingleStateQueue.h
@@ -0,0 +1 @@
+../../media/libmedia/include/SingleStateQueue.h
\ No newline at end of file
diff --git a/include/media/StringArray.h b/include/media/StringArray.h
new file mode 120000
index 0000000..5061652
--- /dev/null
+++ b/include/media/StringArray.h
@@ -0,0 +1 @@
+../../media/libmedia/include/StringArray.h
\ No newline at end of file
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
new file mode 120000
index 0000000..f00ee2d
--- /dev/null
+++ b/include/media/ToneGenerator.h
@@ -0,0 +1 @@
+../../media/libaudioclient/include/ToneGenerator.h
\ No newline at end of file
diff --git a/include/media/TypeConverter.h b/include/media/TypeConverter.h
new file mode 120000
index 0000000..9109aaa
--- /dev/null
+++ b/include/media/TypeConverter.h
@@ -0,0 +1 @@
+../../media/libmedia/include/TypeConverter.h
\ No newline at end of file
diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
new file mode 120000
index 0000000..fca8b86
--- /dev/null
+++ b/include/media/Visualizer.h
@@ -0,0 +1 @@
+../../media/libmedia/include/Visualizer.h
\ No newline at end of file
diff --git a/include/media/VolumeShaper.h b/include/media/VolumeShaper.h
new file mode 100644
index 0000000..f5a74d8
--- /dev/null
+++ b/include/media/VolumeShaper.h
@@ -0,0 +1,839 @@
+/*
+ * Copyright 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_VOLUME_SHAPER_H
+#define ANDROID_VOLUME_SHAPER_H
+
+#include <cmath>
+#include <list>
+#include <math.h>
+#include <sstream>
+
+#include <binder/Parcel.h>
+#include <media/Interpolator.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+
+#pragma push_macro("LOG_TAG")
+#undef LOG_TAG
+#define LOG_TAG "VolumeShaper"
+
+// turn on VolumeShaper logging
+#if 0
+#define VS_LOG ALOGD
+#else
+#define VS_LOG(...)
+#endif
+
+namespace android {
+
+// The native VolumeShaper class mirrors the java VolumeShaper class;
+// in addition, the native class contains implementation for actual operation.
+//
+// VolumeShaper methods are not safe for multiple thread access.
+// Use VolumeHandler for thread-safe encapsulation of multiple VolumeShapers.
+//
+// Classes below written are to avoid naked pointers so there are no
+// explicit destructors required.
+
+class VolumeShaper {
+public:
+    using S = float;
+    using T = float;
+
+    static const int kSystemIdMax = 16;
+
+    // VolumeShaper::Status is equivalent to status_t if negative
+    // but if non-negative represents the id operated on.
+    // It must be expressible as an int32_t for binder purposes.
+    using Status = status_t;
+
+    class Configuration : public Interpolator<S, T>, public RefBase {
+    public:
+        /* VolumeShaper.Configuration derives from the Interpolator class and adds
+         * parameters relating to the volume shape.
+         */
+
+        // TODO document as per VolumeShaper.java flags.
+
+        // must match with VolumeShaper.java in frameworks/base
+        enum Type : int32_t {
+            TYPE_ID,
+            TYPE_SCALE,
+        };
+
+        // must match with VolumeShaper.java in frameworks/base
+        enum OptionFlag : int32_t {
+            OPTION_FLAG_NONE           = 0,
+            OPTION_FLAG_VOLUME_IN_DBFS = (1 << 0),
+            OPTION_FLAG_CLOCK_TIME     = (1 << 1),
+
+            OPTION_FLAG_ALL            = (OPTION_FLAG_VOLUME_IN_DBFS | OPTION_FLAG_CLOCK_TIME),
+        };
+
+        // bring to derived class; must match with VolumeShaper.java in frameworks/base
+        using InterpolatorType = Interpolator<S, T>::InterpolatorType;
+
+        Configuration()
+            : Interpolator<S, T>()
+            , mType(TYPE_SCALE)
+            , mOptionFlags(OPTION_FLAG_NONE)
+            , mDurationMs(1000.)
+            , mId(-1) {
+        }
+
+        Configuration(const Configuration &configuration)
+            : Interpolator<S, T>(*static_cast<const Interpolator<S, T> *>(&configuration))
+            , mType(configuration.mType)
+            , mOptionFlags(configuration.mOptionFlags)
+            , mDurationMs(configuration.mDurationMs)
+            , mId(configuration.mId) {
+        }
+
+        Type getType() const {
+            return mType;
+        }
+
+        status_t setType(Type type) {
+            switch (type) {
+            case TYPE_ID:
+            case TYPE_SCALE:
+                mType = type;
+                return NO_ERROR;
+            default:
+                ALOGE("invalid Type: %d", type);
+                return BAD_VALUE;
+            }
+        }
+
+        OptionFlag getOptionFlags() const {
+            return mOptionFlags;
+        }
+
+        status_t setOptionFlags(OptionFlag optionFlags) {
+            if ((optionFlags & ~OPTION_FLAG_ALL) != 0) {
+                ALOGE("optionFlags has invalid bits: %#x", optionFlags);
+                return BAD_VALUE;
+            }
+            mOptionFlags = optionFlags;
+            return NO_ERROR;
+        }
+
+        double getDurationMs() const {
+            return mDurationMs;
+        }
+
+        void setDurationMs(double durationMs) {
+            mDurationMs = durationMs;
+        }
+
+        int32_t getId() const {
+            return mId;
+        }
+
+        void setId(int32_t id) {
+            mId = id;
+        }
+
+        T adjustVolume(T volume) const {
+            if ((getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
+                const T out = powf(10.f, volume / 10.);
+                VS_LOG("in: %f  out: %f", volume, out);
+                volume = out;
+            }
+            // clamp
+            if (volume < 0.f) {
+                volume = 0.f;
+            } else if (volume > 1.f) {
+                volume = 1.f;
+            }
+            return volume;
+        }
+
+        status_t checkCurve() {
+            if (mType == TYPE_ID) return NO_ERROR;
+            if (this->size() < 2) {
+                ALOGE("curve must have at least 2 points");
+                return BAD_VALUE;
+            }
+            if (first().first != 0.f || last().first != 1.f) {
+                ALOGE("curve must start at 0.f and end at 1.f");
+                return BAD_VALUE;
+            }
+            if ((getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
+                for (const auto &pt : *this) {
+                    if (!(pt.second <= 0.f) /* handle nan */) {
+                        ALOGE("positive volume dbFS");
+                        return BAD_VALUE;
+                    }
+                }
+            } else {
+                for (const auto &pt : *this) {
+                    if (!(pt.second >= 0.f) || !(pt.second <= 1.f) /* handle nan */) {
+                        ALOGE("volume < 0.f or > 1.f");
+                        return BAD_VALUE;
+                    }
+                }
+            }
+            return NO_ERROR;
+        }
+
+        void clampVolume() {
+            if ((mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0) {
+                for (auto it = this->begin(); it != this->end(); ++it) {
+                    if (!(it->second <= 0.f) /* handle nan */) {
+                        it->second = 0.f;
+                    }
+                }
+            } else {
+                for (auto it = this->begin(); it != this->end(); ++it) {
+                    if (!(it->second >= 0.f) /* handle nan */) {
+                        it->second = 0.f;
+                    } else if (!(it->second <= 1.f)) {
+                        it->second = 1.f;
+                    }
+                }
+            }
+        }
+
+        /* scaleToStartVolume() is used to set the start volume of a
+         * new VolumeShaper curve, when replacing one VolumeShaper
+         * with another using the "join" (volume match) option.
+         *
+         * It works best for monotonic volume ramps or ducks.
+         */
+        void scaleToStartVolume(T volume) {
+            if (this->size() < 2) {
+                return;
+            }
+            const T startVolume = first().second;
+            const T endVolume = last().second;
+            if (endVolume == startVolume) {
+                // match with linear ramp
+                const T offset = volume - startVolume;
+                for (auto it = this->begin(); it != this->end(); ++it) {
+                    it->second = it->second + offset * (1.f - it->first);
+                }
+            } else {
+                const T  scale = (volume - endVolume) / (startVolume - endVolume);
+                for (auto it = this->begin(); it != this->end(); ++it) {
+                    it->second = scale * (it->second - endVolume) + endVolume;
+                }
+            }
+            clampVolume();
+        }
+
+        status_t writeToParcel(Parcel *parcel) const {
+            if (parcel == nullptr) return BAD_VALUE;
+            return parcel->writeInt32((int32_t)mType)
+                    ?: parcel->writeInt32(mId)
+                    ?: mType == TYPE_ID
+                        ? NO_ERROR
+                        : parcel->writeInt32((int32_t)mOptionFlags)
+                            ?: parcel->writeDouble(mDurationMs)
+                            ?: Interpolator<S, T>::writeToParcel(parcel);
+        }
+
+        status_t readFromParcel(const Parcel &parcel) {
+            int32_t type, optionFlags;
+            return parcel.readInt32(&type)
+                    ?: setType((Type)type)
+                    ?: parcel.readInt32(&mId)
+                    ?: mType == TYPE_ID
+                        ? NO_ERROR
+                        : parcel.readInt32(&optionFlags)
+                            ?: setOptionFlags((OptionFlag)optionFlags)
+                            ?: parcel.readDouble(&mDurationMs)
+                            ?: Interpolator<S, T>::readFromParcel(parcel)
+                            ?: checkCurve();
+        }
+
+        std::string toString() const {
+            std::stringstream ss;
+            ss << "mType: " << mType << std::endl;
+            ss << "mId: " << mId << std::endl;
+            if (mType != TYPE_ID) {
+                ss << "mOptionFlags: " << mOptionFlags << std::endl;
+                ss << "mDurationMs: " << mDurationMs << std::endl;
+                ss << Interpolator<S, T>::toString().c_str();
+            }
+            return ss.str();
+        }
+
+    private:
+        Type mType;
+        int32_t mId;
+        OptionFlag mOptionFlags;
+        double mDurationMs;
+    }; // Configuration
+
+    // must match with VolumeShaper.java in frameworks/base
+    // TODO document per VolumeShaper.java flags.
+    class Operation : public RefBase {
+    public:
+        enum Flag : int32_t {
+            FLAG_NONE      = 0,
+            FLAG_REVERSE   = (1 << 0),
+            FLAG_TERMINATE = (1 << 1),
+            FLAG_JOIN      = (1 << 2),
+            FLAG_DELAY     = (1 << 3),
+            FLAG_CREATE_IF_NECESSARY = (1 << 4),
+
+            FLAG_ALL       = (FLAG_REVERSE | FLAG_TERMINATE | FLAG_JOIN | FLAG_DELAY
+                            | FLAG_CREATE_IF_NECESSARY),
+        };
+
+        Operation()
+            : Operation(FLAG_NONE, -1 /* replaceId */) {
+        }
+
+        explicit Operation(Flag flags, int replaceId)
+            : Operation(flags, replaceId, std::numeric_limits<S>::quiet_NaN() /* xOffset */) {
+        }
+
+        Operation(const Operation &operation)
+            : Operation(operation.mFlags, operation.mReplaceId, operation.mXOffset) {
+        }
+
+        explicit Operation(Flag flags, int replaceId, S xOffset)
+            : mFlags(flags)
+            , mReplaceId(replaceId)
+            , mXOffset(xOffset) {
+        }
+
+        int32_t getReplaceId() const {
+            return mReplaceId;
+        }
+
+        void setReplaceId(int32_t replaceId) {
+            mReplaceId = replaceId;
+        }
+
+        S getXOffset() const {
+            return mXOffset;
+        }
+
+        void setXOffset(S xOffset) {
+            mXOffset = xOffset;
+        }
+
+        Flag getFlags() const {
+            return mFlags;
+        }
+
+        status_t setFlags(Flag flags) {
+            if ((flags & ~FLAG_ALL) != 0) {
+                ALOGE("flags has invalid bits: %#x", flags);
+                return BAD_VALUE;
+            }
+            mFlags = flags;
+            return NO_ERROR;
+        }
+
+        status_t writeToParcel(Parcel *parcel) const {
+            if (parcel == nullptr) return BAD_VALUE;
+            return parcel->writeInt32((int32_t)mFlags)
+                    ?: parcel->writeInt32(mReplaceId)
+                    ?: parcel->writeFloat(mXOffset);
+        }
+
+        status_t readFromParcel(const Parcel &parcel) {
+            int32_t flags;
+            return parcel.readInt32(&flags)
+                    ?: parcel.readInt32(&mReplaceId)
+                    ?: parcel.readFloat(&mXOffset)
+                    ?: setFlags((Flag)flags);
+        }
+
+        std::string toString() const {
+            std::stringstream ss;
+            ss << "mFlags: " << mFlags << std::endl;
+            ss << "mReplaceId: " << mReplaceId << std::endl;
+            ss << "mXOffset: " << mXOffset << std::endl;
+            return ss.str();
+        }
+
+    private:
+        Flag mFlags;
+        int32_t mReplaceId;
+        S mXOffset;
+    }; // Operation
+
+    // must match with VolumeShaper.java in frameworks/base
+    class State : public RefBase {
+    public:
+        explicit State(T volume, S xOffset)
+            : mVolume(volume)
+            , mXOffset(xOffset) {
+        }
+
+        State()
+            : State(-1.f, -1.f) { }
+
+        T getVolume() const {
+            return mVolume;
+        }
+
+        void setVolume(T volume) {
+            mVolume = volume;
+        }
+
+        S getXOffset() const {
+            return mXOffset;
+        }
+
+        void setXOffset(S xOffset) {
+            mXOffset = xOffset;
+        }
+
+        status_t writeToParcel(Parcel *parcel) const {
+            if (parcel == nullptr) return BAD_VALUE;
+            return parcel->writeFloat(mVolume)
+                    ?: parcel->writeFloat(mXOffset);
+        }
+
+        status_t readFromParcel(const Parcel &parcel) {
+            return parcel.readFloat(&mVolume)
+                     ?: parcel.readFloat(&mXOffset);
+        }
+
+        std::string toString() const {
+            std::stringstream ss;
+            ss << "mVolume: " << mVolume << std::endl;
+            ss << "mXOffset: " << mXOffset << std::endl;
+            return ss.str();
+        }
+
+    private:
+        T mVolume;
+        S mXOffset;
+    }; // State
+
+    template <typename R>
+    class Translate {
+    public:
+        Translate()
+            : mOffset(0)
+            , mScale(1) {
+        }
+
+        R getOffset() const {
+            return mOffset;
+        }
+
+        void setOffset(R offset) {
+            mOffset = offset;
+        }
+
+        R getScale() const {
+            return mScale;
+        }
+
+        void setScale(R scale) {
+            mScale = scale;
+        }
+
+        R operator()(R in) const {
+            return mScale * (in - mOffset);
+        }
+
+        std::string toString() const {
+            std::stringstream ss;
+            ss << "mOffset: " << mOffset << std::endl;
+            ss << "mScale: " << mScale << std::endl;
+            return ss.str();
+        }
+
+    private:
+        R mOffset;
+        R mScale;
+    }; // Translate
+
+    static int64_t convertTimespecToUs(const struct timespec &tv)
+    {
+        return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000;
+    }
+
+    // current monotonic time in microseconds.
+    static int64_t getNowUs()
+    {
+        struct timespec tv;
+        if (clock_gettime(CLOCK_MONOTONIC, &tv) != 0) {
+            return 0; // system is really sick, just return 0 for consistency.
+        }
+        return convertTimespecToUs(tv);
+    }
+
+    // TODO: Since we pass configuration and operation as shared pointers
+    // there is a potential risk that the caller may modify these after
+    // delivery.  Currently, we don't require copies made here.
+    explicit VolumeShaper(
+            const sp<VolumeShaper::Configuration> &configuration,
+            const sp<VolumeShaper::Operation> &operation)
+        : mConfiguration(configuration) // we do not make a copy
+        , mOperation(operation)         // ditto
+        , mStartFrame(-1)
+        , mLastVolume(T(1))
+        , mLastXOffset(0.f)
+        , mDelayXOffset(std::numeric_limits<S>::quiet_NaN()) {
+        if (configuration.get() != nullptr
+                && (getFlags() & VolumeShaper::Operation::FLAG_DELAY) == 0) {
+            mLastVolume = configuration->first().second;
+        }
+    }
+
+    void updatePosition(int64_t startFrame, double sampleRate) {
+        double scale = (mConfiguration->last().first - mConfiguration->first().first)
+                        / (mConfiguration->getDurationMs() * 0.001 * sampleRate);
+        const double minScale = 1. / INT64_MAX;
+        scale = std::max(scale, minScale);
+        const S xOffset = std::isnan(mDelayXOffset) ? mConfiguration->first().first : mDelayXOffset;
+        VS_LOG("update position: scale %lf  frameCount:%lld, sampleRate:%lf, xOffset:%f",
+                scale, (long long) startFrame, sampleRate, xOffset);
+
+        mXTranslate.setOffset(startFrame - xOffset / scale);
+        mXTranslate.setScale(scale);
+        VS_LOG("translate: %s", mXTranslate.toString().c_str());
+    }
+
+    // We allow a null operation here, though VolumeHandler always provides one.
+    VolumeShaper::Operation::Flag getFlags() const {
+        return mOperation == nullptr
+                ? VolumeShaper::Operation::FLAG_NONE :mOperation->getFlags();
+    }
+
+    sp<VolumeShaper::State> getState() const {
+        return new VolumeShaper::State(mLastVolume, mLastXOffset);
+    }
+
+    void setDelayXOffset(S xOffset) {
+        mDelayXOffset = xOffset;
+    }
+
+    std::pair<T /* volume */, bool /* active */> getVolume(
+            int64_t trackFrameCount, double trackSampleRate) {
+        if ((getFlags() & VolumeShaper::Operation::FLAG_DELAY) != 0) {
+            VS_LOG("delayed VolumeShaper, ignoring");
+            mLastVolume = T(1);
+            mLastXOffset = 0.;
+            return std::make_pair(T(1), false);
+        }
+        const bool clockTime = (mConfiguration->getOptionFlags()
+                & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) != 0;
+        const int64_t frameCount = clockTime ? getNowUs() : trackFrameCount;
+        const double sampleRate = clockTime ? 1000000 : trackSampleRate;
+
+        if (mStartFrame < 0) {
+            updatePosition(frameCount, sampleRate);
+            mStartFrame = frameCount;
+        }
+        VS_LOG("frameCount: %lld", (long long)frameCount);
+        S x = mXTranslate((T)frameCount);
+        VS_LOG("translation: %f", x);
+
+        // handle reversal of position
+        if (getFlags() & VolumeShaper::Operation::FLAG_REVERSE) {
+            x = 1.f - x;
+            VS_LOG("reversing to %f", x);
+            if (x < mConfiguration->first().first) {
+                mLastXOffset = 1.f;
+                const T volume = mConfiguration->adjustVolume(
+                        mConfiguration->first().second);  // persist last value
+                VS_LOG("persisting volume %f", volume);
+                mLastVolume = volume;
+                return std::make_pair(volume, false);
+            }
+            if (x > mConfiguration->last().first) {
+                mLastXOffset = 0.f;
+                mLastVolume = 1.f;
+                return std::make_pair(T(1), true); // too early
+            }
+        } else {
+            if (x < mConfiguration->first().first) {
+                mLastXOffset = 0.f;
+                mLastVolume = 1.f;
+                return std::make_pair(T(1), true); // too early
+            }
+            if (x > mConfiguration->last().first) {
+                mLastXOffset = 1.f;
+                const T volume = mConfiguration->adjustVolume(
+                        mConfiguration->last().second);  // persist last value
+                VS_LOG("persisting volume %f", volume);
+                mLastVolume = volume;
+                return std::make_pair(volume, false);
+            }
+        }
+        mLastXOffset = x;
+        // x contains the location on the volume curve to use.
+        const T unscaledVolume = mConfiguration->findY(x);
+        const T volume = mConfiguration->adjustVolume(unscaledVolume); // handle log scale
+        VS_LOG("volume: %f  unscaled: %f", volume, unscaledVolume);
+        mLastVolume = volume;
+        return std::make_pair(volume, true);
+    }
+
+    std::string toString() const {
+        std::stringstream ss;
+        ss << "StartFrame: " << mStartFrame << std::endl;
+        ss << mXTranslate.toString().c_str();
+        if (mConfiguration.get() == nullptr) {
+            ss << "VolumeShaper::Configuration: nullptr" << std::endl;
+        } else {
+            ss << "VolumeShaper::Configuration:" << std::endl;
+            ss << mConfiguration->toString().c_str();
+        }
+        if (mOperation.get() == nullptr) {
+            ss << "VolumeShaper::Operation: nullptr" << std::endl;
+        } else {
+            ss << "VolumeShaper::Operation:" << std::endl;
+            ss << mOperation->toString().c_str();
+        }
+        return ss.str();
+    }
+
+    Translate<S> mXTranslate; // x axis translation from frames (in usec for clock time)
+    sp<VolumeShaper::Configuration> mConfiguration;
+    sp<VolumeShaper::Operation> mOperation;
+    int64_t mStartFrame; // starting frame, non-negative when started (in usec for clock time)
+    T mLastVolume;       // last computed interpolated volume (y-axis)
+    S mLastXOffset;      // last computed interpolated xOffset/time (x-axis)
+    S mDelayXOffset;     // delay xOffset on first volumeshaper start.
+}; // VolumeShaper
+
+// VolumeHandler combines the volume factors of multiple VolumeShapers and handles
+// multiple thread access by synchronizing all public methods.
+class VolumeHandler : public RefBase {
+public:
+    using S = float;
+    using T = float;
+
+    // A volume handler which just keeps track of active VolumeShapers does not need sampleRate.
+    VolumeHandler()
+        : VolumeHandler(0 /* sampleRate */) {
+    }
+
+    explicit VolumeHandler(uint32_t sampleRate)
+        : mSampleRate((double)sampleRate)
+        , mLastFrame(0)
+        , mVolumeShaperIdCounter(VolumeShaper::kSystemIdMax) {
+    }
+
+    VolumeShaper::Status applyVolumeShaper(
+            const sp<VolumeShaper::Configuration> &configuration,
+            const sp<VolumeShaper::Operation> &operation) {
+        VS_LOG("applyVolumeShaper:configuration: %s", configuration->toString().c_str());
+        VS_LOG("applyVolumeShaper:operation: %s", operation->toString().c_str());
+        AutoMutex _l(mLock);
+        if (configuration == nullptr) {
+            ALOGE("null configuration");
+            return VolumeShaper::Status(BAD_VALUE);
+        }
+        if (operation == nullptr) {
+            ALOGE("null operation");
+            return VolumeShaper::Status(BAD_VALUE);
+        }
+        const int32_t id = configuration->getId();
+        if (id < 0) {
+            ALOGE("negative id: %d", id);
+            return VolumeShaper::Status(BAD_VALUE);
+        }
+        VS_LOG("applyVolumeShaper id: %d", id);
+
+        switch (configuration->getType()) {
+        case VolumeShaper::Configuration::TYPE_SCALE: {
+            const int replaceId = operation->getReplaceId();
+            if (replaceId >= 0) {
+                auto replaceIt = findId_l(replaceId);
+                if (replaceIt == mVolumeShapers.end()) {
+                    ALOGW("cannot find replace id: %d", replaceId);
+                } else {
+                    if ((replaceIt->getFlags() & VolumeShaper::Operation::FLAG_JOIN) != 0) {
+                        // For join, we scale the start volume of the current configuration
+                        // to match the last-used volume of the replacing VolumeShaper.
+                        auto state = replaceIt->getState();
+                        if (state->getXOffset() >= 0) { // valid
+                            const T volume = state->getVolume();
+                            ALOGD("join: scaling start volume to %f", volume);
+                            configuration->scaleToStartVolume(volume);
+                        }
+                    }
+                    (void)mVolumeShapers.erase(replaceIt);
+                }
+                operation->setReplaceId(-1);
+            }
+            // check if we have another of the same id.
+            auto oldIt = findId_l(id);
+            if (oldIt != mVolumeShapers.end()) {
+                if ((operation->getFlags()
+                        & VolumeShaper::Operation::FLAG_CREATE_IF_NECESSARY) != 0) {
+                    // TODO: move the case to a separate function.
+                    goto HANDLE_TYPE_ID; // no need to create, take over existing id.
+                }
+                ALOGW("duplicate id, removing old %d", id);
+                (void)mVolumeShapers.erase(oldIt);
+            }
+            // create new VolumeShaper
+            mVolumeShapers.emplace_back(configuration, operation);
+        }
+        // fall through to handle the operation
+        HANDLE_TYPE_ID:
+        case VolumeShaper::Configuration::TYPE_ID: {
+            VS_LOG("trying to find id: %d", id);
+            auto it = findId_l(id);
+            if (it == mVolumeShapers.end()) {
+                VS_LOG("couldn't find id: %d", id);
+                return VolumeShaper::Status(INVALID_OPERATION);
+            }
+            if ((it->getFlags() & VolumeShaper::Operation::FLAG_TERMINATE) != 0) {
+                VS_LOG("terminate id: %d", id);
+                mVolumeShapers.erase(it);
+                break;
+            }
+            const bool clockTime = (it->mConfiguration->getOptionFlags()
+                    & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) != 0;
+            if ((it->getFlags() & VolumeShaper::Operation::FLAG_REVERSE) !=
+                    (operation->getFlags() & VolumeShaper::Operation::FLAG_REVERSE)) {
+                const int64_t frameCount = clockTime ? VolumeShaper::getNowUs() : mLastFrame;
+                const S x = it->mXTranslate((T)frameCount);
+                VS_LOG("reverse translation: %f", x);
+                // reflect position
+                S target = 1.f - x;
+                if (target < it->mConfiguration->first().first) {
+                    VS_LOG("clamp to start - begin immediately");
+                    target = 0.;
+                }
+                VS_LOG("target reverse: %f", target);
+                it->mXTranslate.setOffset(it->mXTranslate.getOffset()
+                        + (x - target) / it->mXTranslate.getScale());
+            }
+            const S xOffset = operation->getXOffset();
+            if (!std::isnan(xOffset)) {
+                const int64_t frameCount = clockTime ? VolumeShaper::getNowUs() : mLastFrame;
+                const S x = it->mXTranslate((T)frameCount);
+                VS_LOG("xOffset translation: %f", x);
+                const S target = xOffset; // offset
+                VS_LOG("xOffset target x offset: %f", target);
+                it->mXTranslate.setOffset(it->mXTranslate.getOffset()
+                        + (x - target) / it->mXTranslate.getScale());
+                it->setDelayXOffset(xOffset);
+            }
+            it->mOperation = operation; // replace the operation
+        } break;
+        }
+        return VolumeShaper::Status(id);
+    }
+
+    sp<VolumeShaper::State> getVolumeShaperState(int id) {
+        AutoMutex _l(mLock);
+        auto it = findId_l(id);
+        if (it == mVolumeShapers.end()) {
+            VS_LOG("cannot find state for id: %d", id);
+            return nullptr;
+        }
+        return it->getState();
+    }
+
+    std::pair<T /* volume */, bool /* active */> getVolume(int64_t trackFrameCount) {
+        AutoMutex _l(mLock);
+        mLastFrame = trackFrameCount;
+        T volume(1);
+        size_t activeCount = 0;
+        for (auto it = mVolumeShapers.begin(); it != mVolumeShapers.end();) {
+            std::pair<T, bool> shaperVolume =
+                    it->getVolume(trackFrameCount, mSampleRate);
+            volume *= shaperVolume.first;
+            activeCount += shaperVolume.second;
+            ++it;
+        }
+        return std::make_pair(volume, activeCount != 0);
+    }
+
+    std::string toString() const {
+        AutoMutex _l(mLock);
+        std::stringstream ss;
+        ss << "mSampleRate: " << mSampleRate << std::endl;
+        ss << "mLastFrame: " << mLastFrame << std::endl;
+        for (const auto &shaper : mVolumeShapers) {
+            ss << shaper.toString().c_str();
+        }
+        return ss.str();
+    }
+
+    void forall(const std::function<VolumeShaper::Status (
+            const sp<VolumeShaper::Configuration> &configuration,
+            const sp<VolumeShaper::Operation> &operation)> &lambda) {
+        AutoMutex _l(mLock);
+        for (const auto &shaper : mVolumeShapers) {
+            VS_LOG("forall applying lambda");
+            (void)lambda(shaper.mConfiguration, shaper.mOperation);
+        }
+    }
+
+    void reset() {
+        AutoMutex _l(mLock);
+        mVolumeShapers.clear();
+        mLastFrame = -1;
+        // keep mVolumeShaperIdCounter as is.
+    }
+
+    // Sets the configuration id if necessary - This is based on the counter
+    // internal to the VolumeHandler.
+    void setIdIfNecessary(const sp<VolumeShaper::Configuration> &configuration) {
+        if (configuration->getType() == VolumeShaper::Configuration::TYPE_SCALE) {
+            const int id = configuration->getId();
+            if (id == -1) {
+                // Reassign to a unique id, skipping system ids.
+                AutoMutex _l(mLock);
+                while (true) {
+                    if (mVolumeShaperIdCounter == INT32_MAX) {
+                        mVolumeShaperIdCounter = VolumeShaper::kSystemIdMax;
+                    } else {
+                        ++mVolumeShaperIdCounter;
+                    }
+                    if (findId_l(mVolumeShaperIdCounter) != mVolumeShapers.end()) {
+                        continue; // collision with an existing id.
+                    }
+                    configuration->setId(mVolumeShaperIdCounter);
+                    ALOGD("setting id to %d", mVolumeShaperIdCounter);
+                    break;
+                }
+            }
+        }
+    }
+
+private:
+    std::list<VolumeShaper>::iterator findId_l(int32_t id) {
+        std::list<VolumeShaper>::iterator it = mVolumeShapers.begin();
+        for (; it != mVolumeShapers.end(); ++it) {
+            if (it->mConfiguration->getId() == id) {
+                break;
+            }
+        }
+        return it;
+    }
+
+    mutable Mutex mLock;
+    double mSampleRate; // in samples (frames) per second
+    int64_t mLastFrame; // logging purpose only
+    int32_t mVolumeShaperIdCounter; // a counter to return a unique volume shaper id.
+    std::list<VolumeShaper> mVolumeShapers; // list provides stable iterators on erase
+}; // VolumeHandler
+
+} // namespace android
+
+#pragma pop_macro("LOG_TAG")
+
+#endif // ANDROID_VOLUME_SHAPER_H
diff --git a/include/media/audiohal b/include/media/audiohal
new file mode 120000
index 0000000..37e2c39
--- /dev/null
+++ b/include/media/audiohal
@@ -0,0 +1 @@
+../../media/libaudiohal/include
\ No newline at end of file
diff --git a/include/media/convert.h b/include/media/convert.h
new file mode 120000
index 0000000..3e09482
--- /dev/null
+++ b/include/media/convert.h
@@ -0,0 +1 @@
+../../media/libmedia/include/convert.h
\ No newline at end of file
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
new file mode 120000
index 0000000..1992b05
--- /dev/null
+++ b/include/media/mediametadataretriever.h
@@ -0,0 +1 @@
+../../media/libmedia/include/mediametadataretriever.h
\ No newline at end of file
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
new file mode 120000
index 0000000..2b1d298
--- /dev/null
+++ b/include/media/mediaplayer.h
@@ -0,0 +1 @@
+../../media/libmedia/include/mediaplayer.h
\ No newline at end of file
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
new file mode 120000
index 0000000..08c826f
--- /dev/null
+++ b/include/media/mediarecorder.h
@@ -0,0 +1 @@
+../../media/libmedia/include/mediarecorder.h
\ No newline at end of file
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
new file mode 120000
index 0000000..42c3507
--- /dev/null
+++ b/include/media/mediascanner.h
@@ -0,0 +1 @@
+../../media/libmedia/include/mediascanner.h
\ No newline at end of file
diff --git a/include/media/nbaio b/include/media/nbaio
new file mode 120000
index 0000000..67d0ba6
--- /dev/null
+++ b/include/media/nbaio
@@ -0,0 +1 @@
+../../media/libnbaio/include
\ No newline at end of file
diff --git a/include/media/nbaio/NBLog.h b/include/media/nbaio/NBLog.h
deleted file mode 100644
index ff10b8c..0000000
--- a/include/media/nbaio/NBLog.h
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Non-blocking event logger intended for safe communication between processes via shared memory
-
-#ifndef ANDROID_MEDIA_NBLOG_H
-#define ANDROID_MEDIA_NBLOG_H
-
-#include <binder/IMemory.h>
-#include <utils/Mutex.h>
-#include <audio_utils/fifo.h>
-
-namespace android {
-
-class String8;
-
-class NBLog {
-
-public:
-
-class Writer;
-class Reader;
-
-private:
-
-enum Event {
-    EVENT_RESERVED,
-    EVENT_STRING,               // ASCII string, not NUL-terminated
-    EVENT_TIMESTAMP,            // clock_gettime(CLOCK_MONOTONIC)
-    EVENT_INTEGER,
-    EVENT_FLOAT,
-    EVENT_PID,
-    EVENT_START_FMT,            // logFormat start event: entry includes format string, following
-                                // entries contain format arguments
-    EVENT_END_FMT,              // end of logFormat argument list
-};
-
-// ---------------------------------------------------------------------------
-
-// representation of a single log entry in private memory
-struct Entry {
-    Entry(Event event, const void *data, size_t length)
-        : mEvent(event), mLength(length), mData(data) { }
-    /*virtual*/ ~Entry() { }
-
-    int     readAt(size_t offset) const;
-
-private:
-    friend class Writer;
-    Event       mEvent;     // event type
-    uint8_t     mLength;    // length of additional data, 0 <= mLength <= kMaxLength
-    const void *mData;      // event type-specific data
-    static const size_t kMaxLength = 255;
-public:
-    static const size_t kOverhead = 3;  // mEvent, mLength, mData[...], duplicate mLength
-};
-
-// representation of a single log entry in shared memory
-//  byte[0]             mEvent
-//  byte[1]             mLength
-//  byte[2]             mData[0]
-//  ...
-//  byte[2+i]           mData[i]
-//  ...
-//  byte[2+mLength-1]   mData[mLength-1]
-//  byte[2+mLength]     duplicate copy of mLength to permit reverse scan
-//  byte[3+mLength]     start of next log entry
-
-    static void    appendInt(String8 *body, const void *data);
-    static void    appendFloat(String8 *body, const void *data);
-    static void    appendPID(String8 *body, const void *data);
-    static int     handleFormat(const char *fmt, size_t length, const uint8_t *data,
-                                String8 *timestamp, String8 *body);
-    static void    appendTimestamp(String8 *body, const void *data);
-
-public:
-
-// Located in shared memory, must be POD.
-// Exactly one process must explicitly call the constructor or use placement new.
-// Since this is a POD, the destructor is empty and unnecessary to call it explicitly.
-struct Shared {
-    Shared() /* mRear initialized via default constructor */ { }
-    /*virtual*/ ~Shared() { }
-
-    audio_utils_fifo_index  mRear;  // index one byte past the end of most recent Entry
-    char    mBuffer[0];             // circular buffer for entries
-};
-
-public:
-
-// ---------------------------------------------------------------------------
-
-// FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
-// For now it is just a namespace for sharedSize().
-class Timeline : public RefBase {
-public:
-#if 0
-    Timeline(size_t size, void *shared = NULL);
-    virtual ~Timeline();
-#endif
-
-    // Input parameter 'size' is the desired size of the timeline in byte units.
-    // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
-    static size_t sharedSize(size_t size);
-
-#if 0
-private:
-    friend class    Writer;
-    friend class    Reader;
-
-    const size_t    mSize;      // circular buffer size in bytes, must be a power of 2
-    bool            mOwn;       // whether I own the memory at mShared
-    Shared* const   mShared;    // pointer to shared memory
-#endif
-};
-
-// ---------------------------------------------------------------------------
-
-// Writer is thread-safe with respect to Reader, but not with respect to multiple threads
-// calling Writer methods.  If you need multi-thread safety for writing, use LockedWriter.
-class Writer : public RefBase {
-public:
-    Writer();                   // dummy nop implementation without shared memory
-
-    // Input parameter 'size' is the desired size of the timeline in byte units.
-    // The size of the shared memory must be at least Timeline::sharedSize(size).
-    Writer(void *shared, size_t size);
-    Writer(const sp<IMemory>& iMemory, size_t size);
-
-    virtual ~Writer();
-
-    virtual void    log(const char *string);
-    virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
-    virtual void    logvf(const char *fmt, va_list ap);
-    virtual void    logTimestamp();
-    virtual void    logTimestamp(const struct timespec &ts);
-    virtual void    logInteger(const int x);
-    virtual void    logFloat(const float x);
-    virtual void    logPID();
-    virtual void    logFormat(const char *fmt, ...);
-    virtual void    logVFormat(const char *fmt, va_list ap);
-    virtual void    logStart(const char *fmt);
-    virtual void    logEnd();
-
-
-    virtual bool    isEnabled() const;
-
-    // return value for all of these is the previous isEnabled()
-    virtual bool    setEnabled(bool enabled);   // but won't enable if no shared memory
-            bool    enable()    { return setEnabled(true); }
-            bool    disable()   { return setEnabled(false); }
-
-    sp<IMemory>     getIMemory() const  { return mIMemory; }
-
-private:
-    // 0 <= length <= kMaxLength
-    void    log(Event event, const void *data, size_t length);
-    void    log(const Entry *entry, bool trusted = false);
-
-    Shared* const   mShared;    // raw pointer to shared memory
-    sp<IMemory>     mIMemory;   // ref-counted version, initialized in constructor and then const
-    audio_utils_fifo * const mFifo;                 // FIFO itself,
-                                                    // non-NULL unless constructor fails
-    audio_utils_fifo_writer * const mFifoWriter;    // used to write to FIFO,
-                                                    // non-NULL unless dummy constructor used
-    bool            mEnabled;   // whether to actually log
-};
-
-// ---------------------------------------------------------------------------
-
-// Similar to Writer, but safe for multiple threads to call concurrently
-class LockedWriter : public Writer {
-public:
-    LockedWriter();
-    LockedWriter(void *shared, size_t size);
-
-    virtual void    log(const char *string);
-    virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
-    virtual void    logvf(const char *fmt, va_list ap);
-    virtual void    logTimestamp();
-    virtual void    logTimestamp(const struct timespec &ts);
-    virtual void    logInteger(const int x);
-    virtual void    logFloat(const float x);
-    virtual void    logPID();
-    virtual void    logStart(const char *fmt);
-    virtual void    logEnd();
-
-    virtual bool    isEnabled() const;
-    virtual bool    setEnabled(bool enabled);
-
-private:
-    mutable Mutex   mLock;
-};
-
-// ---------------------------------------------------------------------------
-
-class Reader : public RefBase {
-public:
-
-    // Input parameter 'size' is the desired size of the timeline in byte units.
-    // The size of the shared memory must be at least Timeline::sharedSize(size).
-    Reader(const void *shared, size_t size);
-    Reader(const sp<IMemory>& iMemory, size_t size);
-
-    virtual ~Reader();
-
-    void    dump(int fd, size_t indent = 0);
-    bool    isIMemory(const sp<IMemory>& iMemory) const;
-
-private:
-    /*const*/ Shared* const mShared;    // raw pointer to shared memory, actually const but not
-                                        // declared as const because audio_utils_fifo() constructor
-    sp<IMemory> mIMemory;       // ref-counted version, assigned only in constructor
-    int     mFd;                // file descriptor
-    int     mIndent;            // indentation level
-    audio_utils_fifo * const mFifo;                 // FIFO itself,
-                                                    // non-NULL unless constructor fails
-    audio_utils_fifo_reader * const mFifoReader;    // used to read from FIFO,
-                                                    // non-NULL unless constructor fails
-
-    void    dumpLine(const String8& timestamp, String8& body);
-
-    static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
-};
-
-};  // class NBLog
-
-}   // namespace android
-
-#endif  // ANDROID_MEDIA_NBLOG_H
diff --git a/include/media/stagefright b/include/media/stagefright
new file mode 120000
index 0000000..ae324a8
--- /dev/null
+++ b/include/media/stagefright
@@ -0,0 +1 @@
+../../media/libstagefright/include
\ No newline at end of file
diff --git a/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h
index ad17321..a63f39a 100644
--- a/include/ndk/NdkMediaCodec.h
+++ b/include/ndk/NdkMediaCodec.h
@@ -29,8 +29,6 @@
 
 #include <sys/cdefs.h>
 
-#include <android/native_window.h>
-
 #include "NdkMediaCrypto.h"
 #include "NdkMediaError.h"
 #include "NdkMediaFormat.h"
@@ -39,6 +37,8 @@
 extern "C" {
 #endif
 
+struct ANativeWindow;
+
 #if __ANDROID_API__ >= 21
 
 struct AMediaCodec;
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
index 7dc4e1d..63fa16b 100644
--- a/media/audioserver/Android.mk
+++ b/media/audioserver/Android.mk
@@ -12,6 +12,7 @@
 	libcutils \
 	liblog \
 	libmedialogservice \
+	libnbaio \
 	libradioservice \
 	libsoundtriggerservice \
 	libutils \
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
index 4b0f6a2..9d42bce 100644
--- a/media/audioserver/audioserver.rc
+++ b/media/audioserver/audioserver.rc
@@ -5,4 +5,9 @@
     group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
     ioprio rt 4
     writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
-    onrestart restart audio-hal-2-0
\ No newline at end of file
+    onrestart restart audio-hal-2-0
+
+on property:vts.native_server.on=1
+    stop audioserver
+on property:vts.native_server.on=0
+    start audioserver
diff --git a/media/liboboe/Android.bp b/media/libaaudio/Android.bp
similarity index 92%
rename from media/liboboe/Android.bp
rename to media/libaaudio/Android.bp
index fd6591d..e41d62b 100644
--- a/media/liboboe/Android.bp
+++ b/media/libaaudio/Android.bp
@@ -21,8 +21,8 @@
 }
 
 ndk_library {
-    name: "liboboe.ndk",
-    symbol_file: "liboboe.map.txt",
+    name: "libaaudio.ndk",
+    symbol_file: "libaaudio.map.txt",
     first_version: "26",
     unversioned_until: "current",
 }
diff --git a/media/liboboe/Android.mk b/media/libaaudio/Android.mk
similarity index 100%
rename from media/liboboe/Android.mk
rename to media/libaaudio/Android.mk
diff --git a/media/libaaudio/Doxyfile b/media/libaaudio/Doxyfile
new file mode 100644
index 0000000..5cce2ca
--- /dev/null
+++ b/media/libaaudio/Doxyfile
@@ -0,0 +1,2313 @@
+# Doxyfile 1.8.6
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "AAudio"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = include/aaudio/AAudioDefinitions.h \
+                         include/aaudio/AAudio.h \
+                         src/legacy/AudioStreamTrack.h \
+                         src/legacy/AudioStreamRecord.h \
+                         src/legacy/AAudioLegacy.h \
+                         src/core/AudioStreamBuilder.h \
+                         src/core/AudioStream.h \
+                         src/utility/HandleTracker.h \
+                         src/utility/MonotonicCounter.h \
+                         src/utility/AudioClock.h \
+                         src/utility/AAudioUtilities.h
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavours of web server based searching depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools. See
+# the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
+# validating XML parser to check the syntax of the XML files.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
+# validating XML parser to check the syntax of the XML files.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all refrences to function-like macros that are alone on a line, have an
+# all uppercase name, and do not end with a semicolon. Such function macros are
+# typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have an unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font n the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/media/libaaudio/Doxyfile.orig b/media/libaaudio/Doxyfile.orig
new file mode 100644
index 0000000..137facb
--- /dev/null
+++ b/media/libaaudio/Doxyfile.orig
@@ -0,0 +1,2303 @@
+# Doxyfile 1.8.6
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "My Project"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavours of web server based searching depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools. See
+# the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
+# validating XML parser to check the syntax of the XML files.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
+# validating XML parser to check the syntax of the XML files.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all refrences to function-like macros that are alone on a line, have an
+# all uppercase name, and do not end with a semicolon. Such function macros are
+# typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have an unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font n the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/media/libaaudio/README.md b/media/libaaudio/README.md
new file mode 100644
index 0000000..0c9050e
--- /dev/null
+++ b/media/libaaudio/README.md
@@ -0,0 +1,3 @@
+AAudio input/output API
+
+To generate Doxygen output, run command "doxygen" in this directory.
diff --git a/media/liboboe/examples/Android.mk b/media/libaaudio/examples/Android.mk
similarity index 100%
rename from media/liboboe/examples/Android.mk
rename to media/libaaudio/examples/Android.mk
diff --git a/media/liboboe/examples/write_sine/Android.mk b/media/libaaudio/examples/write_sine/Android.mk
similarity index 100%
rename from media/liboboe/examples/write_sine/Android.mk
rename to media/libaaudio/examples/write_sine/Android.mk
diff --git a/media/liboboe/examples/write_sine/README.md b/media/libaaudio/examples/write_sine/README.md
similarity index 100%
rename from media/liboboe/examples/write_sine/README.md
rename to media/libaaudio/examples/write_sine/README.md
diff --git a/media/liboboe/examples/write_sine/jni/Android.mk b/media/libaaudio/examples/write_sine/jni/Android.mk
similarity index 100%
rename from media/liboboe/examples/write_sine/jni/Android.mk
rename to media/libaaudio/examples/write_sine/jni/Android.mk
diff --git a/media/liboboe/examples/write_sine/jni/Application.mk b/media/libaaudio/examples/write_sine/jni/Application.mk
similarity index 100%
rename from media/liboboe/examples/write_sine/jni/Application.mk
rename to media/libaaudio/examples/write_sine/jni/Application.mk
diff --git a/media/liboboe/examples/write_sine/src/SineGenerator.h b/media/libaaudio/examples/write_sine/src/SineGenerator.h
similarity index 100%
rename from media/liboboe/examples/write_sine/src/SineGenerator.h
rename to media/libaaudio/examples/write_sine/src/SineGenerator.h
diff --git a/media/liboboe/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
similarity index 73%
rename from media/liboboe/examples/write_sine/src/write_sine.cpp
rename to media/libaaudio/examples/write_sine/src/write_sine.cpp
index 090f371..511fe94 100644
--- a/media/liboboe/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -25,6 +25,8 @@
 
 #define SAMPLE_RATE   48000
 #define NUM_SECONDS   10
+#define NANOS_PER_MICROSECOND ((int64_t)1000)
+#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
 
 static const char *getSharingModeText(aaudio_sharing_mode_t mode) {
     const char *modeText = "unknown";
@@ -32,15 +34,9 @@
     case AAUDIO_SHARING_MODE_EXCLUSIVE:
         modeText = "EXCLUSIVE";
         break;
-    case AAUDIO_SHARING_MODE_LEGACY:
-        modeText = "LEGACY";
-        break;
     case AAUDIO_SHARING_MODE_SHARED:
         modeText = "SHARED";
         break;
-    case AAUDIO_SHARING_MODE_PUBLIC_MIX:
-        modeText = "PUBLIC_MIX";
-        break;
     default:
         break;
     }
@@ -57,19 +53,18 @@
     int actualSamplesPerFrame = 0;
     const int requestedSampleRate = SAMPLE_RATE;
     int actualSampleRate = 0;
-    const aaudio_audio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM16;
-    aaudio_audio_format_t actualDataFormat = AAUDIO_FORMAT_PCM16;
+    const aaudio_audio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM_I16;
+    aaudio_audio_format_t actualDataFormat = AAUDIO_FORMAT_PCM_I16;
 
     const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
-    //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_LEGACY;
-    aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_LEGACY;
+    aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
 
-    AAudioStreamBuilder aaudioBuilder = AAUDIO_STREAM_BUILDER_NONE;
-    AAudioStream aaudioStream = AAUDIO_STREAM_NONE;
+    AAudioStreamBuilder *aaudioBuilder = nullptr;
+    AAudioStream *aaudioStream = nullptr;
     aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
-    aaudio_size_frames_t framesPerBurst = 0;
-    aaudio_size_frames_t framesToPlay = 0;
-    aaudio_size_frames_t framesLeft = 0;
+    int32_t framesPerBurst = 0;
+    int32_t framesToPlay = 0;
+    int32_t framesLeft = 0;
     int32_t xRunCount = 0;
     int16_t *data = nullptr;
 
@@ -89,57 +84,42 @@
     }
 
     // Request stream properties.
-    result = AAudioStreamBuilder_setSampleRate(aaudioBuilder, requestedSampleRate);
-    if (result != AAUDIO_OK) {
-        goto finish;
-    }
-    result = AAudioStreamBuilder_setSamplesPerFrame(aaudioBuilder, requestedSamplesPerFrame);
-    if (result != AAUDIO_OK) {
-        goto finish;
-    }
-    result = AAudioStreamBuilder_setFormat(aaudioBuilder, requestedDataFormat);
-    if (result != AAUDIO_OK) {
-        goto finish;
-    }
-    result = AAudioStreamBuilder_setSharingMode(aaudioBuilder, requestedSharingMode);
-    if (result != AAUDIO_OK) {
-        goto finish;
-    }
+    AAudioStreamBuilder_setSampleRate(aaudioBuilder, requestedSampleRate);
+    AAudioStreamBuilder_setSamplesPerFrame(aaudioBuilder, requestedSamplesPerFrame);
+    AAudioStreamBuilder_setFormat(aaudioBuilder, requestedDataFormat);
+    AAudioStreamBuilder_setSharingMode(aaudioBuilder, requestedSharingMode);
+
 
     // Create an AAudioStream using the Builder.
     result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
-    printf("aaudioStream 0x%08x\n", aaudioStream);
     if (result != AAUDIO_OK) {
         goto finish;
     }
 
-    result = AAudioStream_getState(aaudioStream, &state);
+    state = AAudioStream_getState(aaudioStream);
     printf("after open, state = %s\n", AAudio_convertStreamStateToText(state));
 
     // Check to see what kind of stream we actually got.
-    result = AAudioStream_getSampleRate(aaudioStream, &actualSampleRate);
+    actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
     printf("SampleRate: requested = %d, actual = %d\n", requestedSampleRate, actualSampleRate);
 
     sineOsc1.setup(440.0, actualSampleRate);
     sineOsc2.setup(660.0, actualSampleRate);
 
-    result = AAudioStream_getSamplesPerFrame(aaudioStream, &actualSamplesPerFrame);
+    actualSamplesPerFrame = AAudioStream_getSamplesPerFrame(aaudioStream);
     printf("SamplesPerFrame: requested = %d, actual = %d\n",
             requestedSamplesPerFrame, actualSamplesPerFrame);
 
-    result = AAudioStream_getSharingMode(aaudioStream, &actualSharingMode);
+    actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
     printf("SharingMode: requested = %s, actual = %s\n",
             getSharingModeText(requestedSharingMode),
             getSharingModeText(actualSharingMode));
 
     // This is the number of frames that are read in one chunk by a DMA controller
     // or a DSP or a mixer.
-    result = AAudioStream_getFramesPerBurst(aaudioStream, &framesPerBurst);
+    framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
     printf("DataFormat: original framesPerBurst = %d\n",framesPerBurst);
-    if (result != AAUDIO_OK) {
-        fprintf(stderr, "ERROR - AAudioStream_getFramesPerBurst() returned %d\n", result);
-        goto finish;
-    }
+
     // Some DMA might use very short bursts of 16 frames. We don't need to write such small
     // buffers. But it helps to use a multiple of the burst size for predictable scheduling.
     while (framesPerBurst < 48) {
@@ -147,7 +127,7 @@
     }
     printf("DataFormat: final framesPerBurst = %d\n",framesPerBurst);
 
-    AAudioStream_getFormat(aaudioStream, &actualDataFormat);
+    actualDataFormat = AAudioStream_getFormat(aaudioStream);
     printf("DataFormat: requested = %d, actual = %d\n", requestedDataFormat, actualDataFormat);
     // TODO handle other data formats
 
@@ -167,7 +147,7 @@
         goto finish;
     }
 
-    result = AAudioStream_getState(aaudioStream, &state);
+    state = AAudioStream_getState(aaudioStream);
     printf("after start, state = %s\n", AAudio_convertStreamStateToText(state));
 
     // Play for a while.
@@ -181,7 +161,7 @@
         }
 
         // Write audio data to the stream.
-        aaudio_nanoseconds_t timeoutNanos = 100 * AAUDIO_NANOS_PER_MILLISECOND;
+        int64_t timeoutNanos = 100 * NANOS_PER_MILLISECOND;
         int minFrames = (framesToPlay < framesPerBurst) ? framesToPlay : framesPerBurst;
         int actual = AAudioStream_write(aaudioStream, data, minFrames, timeoutNanos);
         if (actual < 0) {
@@ -194,7 +174,7 @@
         framesLeft -= actual;
     }
 
-    result = AAudioStream_getXRunCount(aaudioStream, &xRunCount);
+    xRunCount = AAudioStream_getXRunCount(aaudioStream);
     printf("AAudioStream_getXRunCount %d\n", xRunCount);
 
 finish:
diff --git a/media/liboboe/examples/write_sine/src/write_sine_threaded.cpp b/media/libaaudio/examples/write_sine/src/write_sine_threaded.cpp
similarity index 80%
rename from media/liboboe/examples/write_sine/src/write_sine_threaded.cpp
rename to media/libaaudio/examples/write_sine/src/write_sine_threaded.cpp
index 7cde67b..40e5016 100644
--- a/media/liboboe/examples/write_sine/src/write_sine_threaded.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_threaded.cpp
@@ -26,14 +26,18 @@
 #include <aaudio/AAudio.h>
 #include "SineGenerator.h"
 
-#define NUM_SECONDS   10
+#define NUM_SECONDS           10
+#define NANOS_PER_MICROSECOND ((int64_t)1000)
+#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
+#define MILLIS_PER_SECOND     1000
+#define NANOS_PER_SECOND      (NANOS_PER_MILLISECOND * MILLIS_PER_SECOND)
 
-#define SHARING_MODE  AAUDIO_SHARING_MODE_EXCLUSIVE
-//#define SHARING_MODE  AAUDIO_SHARING_MODE_LEGACY
+//#define SHARING_MODE  AAUDIO_SHARING_MODE_EXCLUSIVE
+#define SHARING_MODE  AAUDIO_SHARING_MODE_SHARED
 
 // Prototype for a callback.
 typedef int audio_callback_proc_t(float *outputBuffer,
-                                     aaudio_size_frames_t numFrames,
+                                     int32_t numFrames,
                                      void *userContext);
 
 static void *SimpleAAudioPlayerThreadProc(void *arg);
@@ -75,25 +79,27 @@
         result = AAudio_createStreamBuilder(&mBuilder);
         if (result != AAUDIO_OK) return result;
 
-        result = AAudioStreamBuilder_setSharingMode(mBuilder, mRequestedSharingMode);
-        if (result != AAUDIO_OK) goto finish1;
+        AAudioStreamBuilder_setSharingMode(mBuilder, mRequestedSharingMode);
 
         // Open an AAudioStream using the Builder.
         result = AAudioStreamBuilder_openStream(mBuilder, &mStream);
         if (result != AAUDIO_OK) goto finish1;
 
         // Check to see what kind of stream we actually got.
-        result = AAudioStream_getSampleRate(mStream, &mFramesPerSecond);
+        mFramesPerSecond = AAudioStream_getSampleRate(mStream);
         printf("open() mFramesPerSecond = %d\n", mFramesPerSecond);
-        if (result != AAUDIO_OK) goto finish2;
-        result = AAudioStream_getSamplesPerFrame(mStream, &mSamplesPerFrame);
+
+        mSamplesPerFrame = AAudioStream_getSamplesPerFrame(mStream);
         printf("open() mSamplesPerFrame = %d\n", mSamplesPerFrame);
-        if (result != AAUDIO_OK) goto finish2;
+
+        {
+            int32_t bufferCapacity = AAudioStream_getBufferCapacityInFrames(mStream);
+            printf("open() got bufferCapacity = %d\n", bufferCapacity);
+        }
 
         // This is the number of frames that are read in one chunk by a DMA controller
         // or a DSP or a mixer.
-        result = AAudioStream_getFramesPerBurst(mStream, &mFramesPerBurst);
-        if (result != AAUDIO_OK) goto finish2;
+        mFramesPerBurst = AAudioStream_getFramesPerBurst(mStream);
         // Some DMA might use very short bursts. We don't need to write such small
         // buffers. But it helps to use a multiple of the burst size for predictable scheduling.
         while (mFramesPerBurst < 48) {
@@ -101,11 +107,7 @@
         }
         printf("DataFormat: final framesPerBurst = %d\n",mFramesPerBurst);
 
-        result = AAudioStream_getFormat(mStream, &mDataFormat);
-        if (result != AAUDIO_OK) {
-            fprintf(stderr, "ERROR - AAudioStream_getFormat() returned %d\n", result);
-            goto finish2;
-        }
+        mDataFormat = AAudioStream_getFormat(mStream);
 
         // Allocate a buffer for the audio data.
         mOutputBuffer = new float[mFramesPerBurst * mSamplesPerFrame];
@@ -115,7 +117,7 @@
         }
 
         // If needed allocate a buffer for converting float to int16_t.
-        if (mDataFormat == AAUDIO_FORMAT_PCM16) {
+        if (mDataFormat == AAUDIO_FORMAT_PCM_I16) {
             mConversionBuffer = new int16_t[mFramesPerBurst * mSamplesPerFrame];
             if (mConversionBuffer == nullptr) {
                 fprintf(stderr, "ERROR - could not allocate conversion buffer\n");
@@ -124,23 +126,20 @@
         }
         return result;
 
-     finish2:
-        AAudioStream_close(mStream);
-        mStream = AAUDIO_HANDLE_INVALID;
      finish1:
         AAudioStreamBuilder_delete(mBuilder);
-        mBuilder = AAUDIO_HANDLE_INVALID;
+        mBuilder = nullptr;
         return result;
     }
 
     aaudio_result_t close() {
-        if (mStream != AAUDIO_HANDLE_INVALID) {
+        if (mStream != nullptr) {
             stop();
-            printf("call AAudioStream_close(0x%08x)\n", mStream);  fflush(stdout);
+            printf("call AAudioStream_close(%p)\n", mStream);  fflush(stdout);
             AAudioStream_close(mStream);
-            mStream = AAUDIO_HANDLE_INVALID;
+            mStream = nullptr;
             AAudioStreamBuilder_delete(mBuilder);
-            mBuilder = AAUDIO_HANDLE_INVALID;
+            mBuilder = nullptr;
             delete mOutputBuffer;
             mOutputBuffer = nullptr;
             delete mConversionBuffer;
@@ -152,7 +151,7 @@
     // Start a thread that will call the callback proc.
     aaudio_result_t start() {
         mEnabled = true;
-        aaudio_nanoseconds_t nanosPerBurst = mFramesPerBurst * AAUDIO_NANOS_PER_SECOND
+        int64_t nanosPerBurst = mFramesPerBurst * NANOS_PER_SECOND
                                            / mFramesPerSecond;
         return AAudioStream_createThread(mStream, nanosPerBurst,
                                        SimpleAAudioPlayerThreadProc,
@@ -162,7 +161,7 @@
     // Tell the thread to stop.
     aaudio_result_t stop() {
         mEnabled = false;
-        return AAudioStream_joinThread(mStream, nullptr, 2 * AAUDIO_NANOS_PER_SECOND);
+        return AAudioStream_joinThread(mStream, nullptr, 2 * NANOS_PER_SECOND);
     }
 
     aaudio_result_t callbackLoop() {
@@ -178,8 +177,8 @@
 
         // Give up after several burst periods have passed.
         const int burstsPerTimeout = 8;
-        aaudio_nanoseconds_t nanosPerTimeout =
-                        burstsPerTimeout * mFramesPerBurst * AAUDIO_NANOS_PER_SECOND
+        int64_t nanosPerTimeout =
+                        burstsPerTimeout * mFramesPerBurst * NANOS_PER_SECOND
                         / mFramesPerSecond;
 
         while (mEnabled && result >= 0) {
@@ -205,7 +204,7 @@
             }
         }
 
-        result = AAudioStream_getXRunCount(mStream, &xRunCount);
+        xRunCount = AAudioStream_getXRunCount(mStream);
         printf("AAudioStream_getXRunCount %d\n", xRunCount);
 
         result = AAudioStream_requestStop(mStream);
@@ -218,20 +217,20 @@
     }
 
 private:
-    AAudioStreamBuilder   mBuilder = AAUDIO_HANDLE_INVALID;
-    AAudioStream          mStream = AAUDIO_HANDLE_INVALID;
-    float            *  mOutputBuffer = nullptr;
-    int16_t          *  mConversionBuffer = nullptr;
+    AAudioStreamBuilder  *mBuilder = nullptr;
+    AAudioStream         *mStream = nullptr;
+    float                *mOutputBuffer = nullptr;
+    int16_t              *mConversionBuffer = nullptr;
 
-    audio_callback_proc_t * mCallbackProc = nullptr;
-    void             *  mUserContext = nullptr;
+    audio_callback_proc_t *mCallbackProc = nullptr;
+    void                 *mUserContext = nullptr;
     aaudio_sharing_mode_t mRequestedSharingMode = SHARING_MODE;
-    int32_t             mSamplesPerFrame = 0;
-    int32_t             mFramesPerSecond = 0;
-    aaudio_size_frames_t  mFramesPerBurst = 0;
-    aaudio_audio_format_t mDataFormat = AAUDIO_FORMAT_PCM16;
+    int32_t               mSamplesPerFrame = 0;
+    int32_t               mFramesPerSecond = 0;
+    int32_t               mFramesPerBurst = 0;
+    aaudio_audio_format_t mDataFormat = AAUDIO_FORMAT_PCM_I16;
 
-    volatile bool       mEnabled = false; // used to request that callback exit its loop
+    volatile bool         mEnabled = false; // used to request that callback exit its loop
 };
 
 static void *SimpleAAudioPlayerThreadProc(void *arg) {
diff --git a/media/liboboe/examples/write_sine/static/Android.mk b/media/libaaudio/examples/write_sine/static/Android.mk
similarity index 84%
rename from media/liboboe/examples/write_sine/static/Android.mk
rename to media/libaaudio/examples/write_sine/static/Android.mk
index 7c8d17c..139b70a 100644
--- a/media/liboboe/examples/write_sine/static/Android.mk
+++ b/media/libaaudio/examples/write_sine/static/Android.mk
@@ -4,7 +4,7 @@
 LOCAL_MODULE_TAGS := examples
 LOCAL_C_INCLUDES := \
     $(call include-path-for, audio-utils) \
-    frameworks/av/media/liboboe/include
+    frameworks/av/media/libaaudio/include
 
 # TODO reorganize folders to avoid using ../
 LOCAL_SRC_FILES:= ../src/write_sine.cpp
@@ -12,7 +12,7 @@
 LOCAL_SHARED_LIBRARIES := libaudioutils libmedia \
                           libbinder libcutils libutils \
                           libaudioclient liblog libtinyalsa
-LOCAL_STATIC_LIBRARIES := liboboe
+LOCAL_STATIC_LIBRARIES := libaaudio
 
 LOCAL_MODULE := write_sine
 include $(BUILD_EXECUTABLE)
@@ -21,14 +21,14 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_C_INCLUDES := \
     $(call include-path-for, audio-utils) \
-    frameworks/av/media/liboboe/include
+    frameworks/av/media/libaaudio/include
 
 LOCAL_SRC_FILES:= ../src/write_sine_threaded.cpp
 
 LOCAL_SHARED_LIBRARIES := libaudioutils libmedia \
                           libbinder libcutils libutils \
                           libaudioclient liblog libtinyalsa
-LOCAL_STATIC_LIBRARIES := liboboe
+LOCAL_STATIC_LIBRARIES := libaaudio
 
 LOCAL_MODULE := write_sine_threaded
 include $(BUILD_EXECUTABLE)
diff --git a/media/liboboe/examples/write_sine/static/README.md b/media/libaaudio/examples/write_sine/static/README.md
similarity index 100%
rename from media/liboboe/examples/write_sine/static/README.md
rename to media/libaaudio/examples/write_sine/static/README.md
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
new file mode 100644
index 0000000..921248a
--- /dev/null
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -0,0 +1,527 @@
+/*
+ * Copyright (C) 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.
+ */
+
+/**
+ * This is the 'C' ABI for AAudio.
+ */
+#ifndef AAUDIO_AAUDIO_H
+#define AAUDIO_AAUDIO_H
+
+#include <time.h>
+#include "AAudioDefinitions.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct AAudioStreamStruct         AAudioStream;
+typedef struct AAudioStreamBuilderStruct  AAudioStreamBuilder;
+
+#ifndef AAUDIO_API
+#define AAUDIO_API /* export this symbol */
+#endif
+
+// ============================================================
+// Audio System
+// ============================================================
+
+/**
+ * The text is the ASCII symbol corresponding to the returnCode,
+ * or an English message saying the returnCode is unrecognized.
+ * This is intended for developers to use when debugging.
+ * It is not for display to users.
+ *
+ * @return pointer to a text representation of an AAudio result code.
+ */
+AAUDIO_API const char * AAudio_convertResultToText(aaudio_result_t returnCode);
+
+/**
+ * The text is the ASCII symbol corresponding to the stream state,
+ * or an English message saying the state is unrecognized.
+ * This is intended for developers to use when debugging.
+ * It is not for display to users.
+ *
+ * @return pointer to a text representation of an AAudio state.
+ */
+AAUDIO_API const char * AAudio_convertStreamStateToText(aaudio_stream_state_t state);
+
+// ============================================================
+// StreamBuilder
+// ============================================================
+
+/**
+ * Create a StreamBuilder that can be used to open a Stream.
+ *
+ * The deviceId is initially unspecified, meaning that the current default device will be used.
+ *
+ * The default direction is AAUDIO_DIRECTION_OUTPUT.
+ * The default sharing mode is AAUDIO_SHARING_MODE_SHARED.
+ * The data format, samplesPerFrames and sampleRate are unspecified and will be
+ * chosen by the device when it is opened.
+ *
+ * AAudioStreamBuilder_delete() must be called when you are done using the builder.
+ */
+AAUDIO_API aaudio_result_t AAudio_createStreamBuilder(AAudioStreamBuilder** builder);
+
+/**
+ * Request an audio device identified device using an ID.
+ * On Android, for example, the ID could be obtained from the Java AudioManager.
+ *
+ * By default, the primary device will be used.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param deviceId device identifier or AAUDIO_DEVICE_UNSPECIFIED
+ */
+AAUDIO_API void AAudioStreamBuilder_setDeviceId(AAudioStreamBuilder* builder,
+                                                     int32_t deviceId);
+
+/**
+ * Request a sample rate in Hz.
+ * The stream may be opened with a different sample rate.
+ * So the application should query for the actual rate after the stream is opened.
+ *
+ * Technically, this should be called the "frame rate" or "frames per second",
+ * because it refers to the number of complete frames transferred per second.
+ * But it is traditionally called "sample rate". Se we use that term.
+ *
+ * Default is AAUDIO_UNSPECIFIED.
+
+ */
+AAUDIO_API void AAudioStreamBuilder_setSampleRate(AAudioStreamBuilder* builder,
+                                                       int32_t sampleRate);
+
+/**
+ * Request a number of samples per frame.
+ * The stream may be opened with a different value.
+ * So the application should query for the actual value after the stream is opened.
+ *
+ * Default is AAUDIO_UNSPECIFIED.
+ *
+ * Note, this quantity is sometimes referred to as "channel count".
+ */
+AAUDIO_API void AAudioStreamBuilder_setSamplesPerFrame(AAudioStreamBuilder* builder,
+                                                   int32_t samplesPerFrame);
+
+/**
+ * Request a sample data format, for example AAUDIO_FORMAT_PCM_I16.
+ * The application should query for the actual format after the stream is opened.
+ */
+AAUDIO_API void AAudioStreamBuilder_setFormat(AAudioStreamBuilder* builder,
+                                                   aaudio_audio_format_t format);
+
+/**
+ * Request a mode for sharing the device.
+ * The requested sharing mode may not be available.
+ * So the application should query for the actual mode after the stream is opened.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param sharingMode AAUDIO_SHARING_MODE_LEGACY or AAUDIO_SHARING_MODE_EXCLUSIVE
+ */
+AAUDIO_API void AAudioStreamBuilder_setSharingMode(AAudioStreamBuilder* builder,
+                                                        aaudio_sharing_mode_t sharingMode);
+
+/**
+ * Request the direction for a stream. The default is AAUDIO_DIRECTION_OUTPUT.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param direction AAUDIO_DIRECTION_OUTPUT or AAUDIO_DIRECTION_INPUT
+ */
+AAUDIO_API void AAudioStreamBuilder_setDirection(AAudioStreamBuilder* builder,
+                                                            aaudio_direction_t direction);
+
+/**
+ * Set the requested maximum buffer capacity in frames.
+ * The final AAudioStream capacity may differ, but will probably be at least this big.
+ *
+ * Default is AAUDIO_UNSPECIFIED.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param frames the desired buffer capacity in frames or AAUDIO_UNSPECIFIED
+ */
+AAUDIO_API void AAudioStreamBuilder_setBufferCapacityInFrames(AAudioStreamBuilder* builder,
+                                                                 int32_t frames);
+
+/**
+ * Open a stream based on the options in the StreamBuilder.
+ *
+ * AAudioStream_close must be called when finished with the stream to recover
+ * the memory and to free the associated resources.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param stream pointer to a variable to receive the new stream reference
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t  AAudioStreamBuilder_openStream(AAudioStreamBuilder* builder,
+                                                     AAudioStream** stream);
+
+/**
+ * Delete the resources associated with the StreamBuilder.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t  AAudioStreamBuilder_delete(AAudioStreamBuilder* builder);
+
+// ============================================================
+// Stream Control
+// ============================================================
+
+/**
+ * Free the resources associated with a stream created by AAudioStreamBuilder_openStream()
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t  AAudioStream_close(AAudioStream* stream);
+
+/**
+ * Asynchronously request to start playing the stream. For output streams, one should
+ * write to the stream to fill the buffer before starting.
+ * Otherwise it will underflow.
+ * After this call the state will be in AAUDIO_STREAM_STATE_STARTING or AAUDIO_STREAM_STATE_STARTED.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t  AAudioStream_requestStart(AAudioStream* stream);
+
+/**
+ * Asynchronous request for the stream to pause.
+ * Pausing a stream will freeze the data flow but not flush any buffers.
+ * Use AAudioStream_Start() to resume playback after a pause.
+ * After this call the state will be in AAUDIO_STREAM_STATE_PAUSING or AAUDIO_STREAM_STATE_PAUSED.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t  AAudioStream_requestPause(AAudioStream* stream);
+
+/**
+ * Asynchronous request for the stream to flush.
+ * Flushing will discard any pending data.
+ * This call only works if the stream is pausing or paused. TODO review
+ * Frame counters are not reset by a flush. They may be advanced.
+ * After this call the state will be in AAUDIO_STREAM_STATE_FLUSHING or AAUDIO_STREAM_STATE_FLUSHED.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t  AAudioStream_requestFlush(AAudioStream* stream);
+
+/**
+ * Asynchronous request for the stream to stop.
+ * The stream will stop after all of the data currently buffered has been played.
+ * After this call the state will be in AAUDIO_STREAM_STATE_STOPPING or AAUDIO_STREAM_STATE_STOPPED.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t  AAudioStream_requestStop(AAudioStream* stream);
+
+/**
+ * Query the current state of the client, eg. AAUDIO_STREAM_STATE_PAUSING
+ *
+ * This function will immediately return the state without updating the state.
+ * If you want to update the client state based on the server state then
+ * call AAudioStream_waitForStateChange() with currentState
+ * set to AAUDIO_STREAM_STATE_UNKNOWN and a zero timeout.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @param state pointer to a variable that will be set to the current state
+ */
+AAUDIO_API aaudio_stream_state_t AAudioStream_getState(AAudioStream* stream);
+
+/**
+ * Wait until the current state no longer matches the input state.
+ *
+ * This will update the current client state.
+ *
+ * <pre><code>
+ * aaudio_stream_state_t currentState;
+ * aaudio_result_t result = AAudioStream_getState(stream, &currentState);
+ * while (result == AAUDIO_OK && currentState != AAUDIO_STREAM_STATE_PAUSING) {
+ *     result = AAudioStream_waitForStateChange(
+ *                                   stream, currentState, &currentState, MY_TIMEOUT_NANOS);
+ * }
+ * </code></pre>
+ *
+ * @param stream A reference provided by AAudioStreamBuilder_openStream()
+ * @param inputState The state we want to avoid.
+ * @param nextState Pointer to a variable that will be set to the new state.
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_waitForStateChange(AAudioStream* stream,
+                                            aaudio_stream_state_t inputState,
+                                            aaudio_stream_state_t *nextState,
+                                            int64_t timeoutNanoseconds);
+
+// ============================================================
+// Stream I/O
+// ============================================================
+
+/**
+ * Read data from the stream.
+ *
+ * The call will wait until the read is complete or until it runs out of time.
+ * If timeoutNanos is zero then this call will not wait.
+ *
+ * Note that timeoutNanoseconds is a relative duration in wall clock time.
+ * Time will not stop if the thread is asleep.
+ * So it will be implemented using CLOCK_BOOTTIME.
+ *
+ * This call is "strong non-blocking" unless it has to wait for data.
+ *
+ * @param stream A stream created using AAudioStreamBuilder_openStream().
+ * @param buffer The address of the first sample.
+ * @param numFrames Number of frames to read. Only complete frames will be written.
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return The number of frames actually read or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_read(AAudioStream* stream,
+                               void *buffer,
+                               int32_t numFrames,
+                               int64_t timeoutNanoseconds);
+
+/**
+ * Write data to the stream.
+ *
+ * The call will wait until the write is complete or until it runs out of time.
+ * If timeoutNanos is zero then this call will not wait.
+ *
+ * Note that timeoutNanoseconds is a relative duration in wall clock time.
+ * Time will not stop if the thread is asleep.
+ * So it will be implemented using CLOCK_BOOTTIME.
+ *
+ * This call is "strong non-blocking" unless it has to wait for room in the buffer.
+ *
+ * @param stream A stream created using AAudioStreamBuilder_openStream().
+ * @param buffer The address of the first sample.
+ * @param numFrames Number of frames to write. Only complete frames will be written.
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return The number of frames actually written or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_write(AAudioStream* stream,
+                               const void *buffer,
+                               int32_t numFrames,
+                               int64_t timeoutNanoseconds);
+
+
+// ============================================================
+// High priority audio threads
+// ============================================================
+
+typedef void *(*aaudio_audio_thread_proc_t)(void *);
+
+/**
+ * Create a thread associated with a stream. The thread has special properties for
+ * low latency audio performance. This thread can be used to implement a callback API.
+ *
+ * Only one thread may be associated with a stream.
+ *
+ * If you are using multiple streams then we recommend that you only do
+ * blocking reads or writes on one stream. You can do non-blocking I/O on the
+ * other streams by setting the timeout to zero.
+ * This thread should be created for the stream that you will block on.
+ *
+ * Note that this API is in flux.
+ *
+ * @param stream A stream created using AAudioStreamBuilder_openStream().
+ * @param periodNanoseconds the estimated period at which the audio thread will need to wake up
+ * @param threadProc your thread entry point
+ * @param arg an argument that will be passed to your thread entry point
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_createThread(AAudioStream* stream,
+                                     int64_t periodNanoseconds,
+                                     aaudio_audio_thread_proc_t threadProc,
+                                     void *arg);
+
+/**
+ * Wait until the thread exits or an error occurs.
+ *
+ * @param stream A stream created using AAudioStreamBuilder_openStream().
+ * @param returnArg a pointer to a variable to receive the return value
+ * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
+ * @return AAUDIO_OK or a negative error.
+ */
+AAUDIO_API aaudio_result_t AAudioStream_joinThread(AAudioStream* stream,
+                                   void **returnArg,
+                                   int64_t timeoutNanoseconds);
+
+// ============================================================
+// Stream - queries
+// ============================================================
+
+
+/**
+ * This can be used to adjust the latency of the buffer by changing
+ * the threshold where blocking will occur.
+ * By combining this with AAudioStream_getXRunCount(), the latency can be tuned
+ * at run-time for each device.
+ *
+ * This cannot be set higher than AAudioStream_getBufferCapacityInFrames().
+ *
+ * Note that you will probably not get the exact size you request.
+ * Call AAudioStream_getBufferSizeInFrames() to see what the actual final size is.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @param requestedFrames requested number of frames that can be filled without blocking
+ * @return actual buffer size in frames or a negative error
+ */
+AAUDIO_API aaudio_result_t AAudioStream_setBufferSizeInFrames(AAudioStream* stream,
+                                                      int32_t requestedFrames);
+
+/**
+ * Query the maximum number of frames that can be filled without blocking.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return buffer size in frames.
+ */
+AAUDIO_API int32_t AAudioStream_getBufferSizeInFrames(AAudioStream* stream);
+
+/**
+ * Query the number of frames that the application should read or write at
+ * one time for optimal performance. It is OK if an application writes
+ * a different number of frames. But the buffer size may need to be larger
+ * in order to avoid underruns or overruns.
+ *
+ * Note that this may or may not match the actual device burst size.
+ * For some endpoints, the burst size can vary dynamically.
+ * But these tend to be devices with high latency.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return burst size
+ */
+AAUDIO_API int32_t AAudioStream_getFramesPerBurst(AAudioStream* stream);
+
+/**
+ * Query maximum buffer capacity in frames.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return  the buffer capacity in frames
+ */
+AAUDIO_API int32_t AAudioStream_getBufferCapacityInFrames(AAudioStream* stream);
+
+/**
+ * An XRun is an Underrun or an Overrun.
+ * During playing, an underrun will occur if the stream is not written in time
+ * and the system runs out of valid data.
+ * During recording, an overrun will occur if the stream is not read in time
+ * and there is no place to put the incoming data so it is discarded.
+ *
+ * An underrun or overrun can cause an audible "pop" or "glitch".
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return the underrun or overrun count
+ */
+AAUDIO_API int32_t AAudioStream_getXRunCount(AAudioStream* stream);
+
+/**
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return actual sample rate
+ */
+AAUDIO_API int32_t AAudioStream_getSampleRate(AAudioStream* stream);
+
+/**
+ * The samplesPerFrame is also known as channelCount.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return actual samples per frame
+ */
+AAUDIO_API int32_t AAudioStream_getSamplesPerFrame(AAudioStream* stream);
+
+/**
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return actual device ID
+ */
+AAUDIO_API int32_t AAudioStream_getDeviceId(AAudioStream* stream);
+
+/**
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return actual data format
+ */
+AAUDIO_API aaudio_audio_format_t AAudioStream_getFormat(AAudioStream* stream);
+
+/**
+ * Provide actual sharing mode.
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return  actual sharing mode
+ */
+AAUDIO_API aaudio_sharing_mode_t AAudioStream_getSharingMode(AAudioStream* stream);
+
+/**
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return direction
+ */
+AAUDIO_API aaudio_direction_t AAudioStream_getDirection(AAudioStream* stream);
+
+/**
+ * Passes back the number of frames that have been written since the stream was created.
+ * For an output stream, this will be advanced by the application calling write().
+ * For an input stream, this will be advanced by the endpoint.
+ *
+ * The frame position is monotonically increasing.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return frames written
+ */
+AAUDIO_API int64_t AAudioStream_getFramesWritten(AAudioStream* stream);
+
+/**
+ * Passes back the number of frames that have been read since the stream was created.
+ * For an output stream, this will be advanced by the endpoint.
+ * For an input stream, this will be advanced by the application calling read().
+ *
+ * The frame position is monotonically increasing.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return frames read
+ */
+AAUDIO_API int64_t AAudioStream_getFramesRead(AAudioStream* stream);
+
+/**
+ * Passes back the time at which a particular frame was presented.
+ * This can be used to synchronize audio with video or MIDI.
+ * It can also be used to align a recorded stream with a playback stream.
+ *
+ * Timestamps are only valid when the stream is in AAUDIO_STREAM_STATE_STARTED.
+ * AAUDIO_ERROR_INVALID_STATE will be returned if the stream is not started.
+ * Note that because requestStart() is asynchronous, timestamps will not be valid until
+ * a short time after calling requestStart().
+ * So AAUDIO_ERROR_INVALID_STATE should not be considered a fatal error.
+ * Just try calling again later.
+ *
+ * If an error occurs, then the position and time will not be modified.
+ *
+ * The position and time passed back are monotonically increasing.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @param clockid AAUDIO_CLOCK_MONOTONIC or AAUDIO_CLOCK_BOOTTIME
+ * @param framePosition pointer to a variable to receive the position
+ * @param timeNanoseconds pointer to a variable to receive the time
+ * @return AAUDIO_OK or a negative error
+ */
+AAUDIO_API aaudio_result_t AAudioStream_getTimestamp(AAudioStream* stream,
+                                      clockid_t clockid,
+                                      int64_t *framePosition,
+                                      int64_t *timeNanoseconds);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //AAUDIO_AAUDIO_H
diff --git a/media/libaaudio/include/aaudio/AAudioDefinitions.h b/media/libaaudio/include/aaudio/AAudioDefinitions.h
new file mode 100644
index 0000000..5b7b819
--- /dev/null
+++ b/media/libaaudio/include/aaudio/AAudioDefinitions.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 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 AAUDIO_AAUDIODEFINITIONS_H
+#define AAUDIO_AAUDIODEFINITIONS_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int32_t  aaudio_result_t;
+
+/**
+ * This is used to represent a value that has not been specified.
+ * For example, an application could use AAUDIO_UNSPECIFIED to indicate
+ * that is did not not care what the specific value of a parameter was
+ * and would accept whatever it was given.
+ */
+#define AAUDIO_UNSPECIFIED           0
+#define AAUDIO_DEVICE_UNSPECIFIED    ((int32_t) -1)
+
+enum aaudio_direction_t {
+    AAUDIO_DIRECTION_OUTPUT,
+    AAUDIO_DIRECTION_INPUT
+};
+
+enum aaudio_audio_format_t {
+    AAUDIO_FORMAT_INVALID = -1,
+    AAUDIO_FORMAT_UNSPECIFIED = 0,
+    AAUDIO_FORMAT_PCM_I16,
+    AAUDIO_FORMAT_PCM_FLOAT,
+    AAUDIO_FORMAT_PCM_I8_24,
+    AAUDIO_FORMAT_PCM_I32
+};
+
+enum {
+    AAUDIO_OK,
+    AAUDIO_ERROR_BASE = -900, // TODO review
+    AAUDIO_ERROR_DISCONNECTED,
+    AAUDIO_ERROR_ILLEGAL_ARGUMENT,
+    AAUDIO_ERROR_INCOMPATIBLE,
+    AAUDIO_ERROR_INTERNAL, // an underlying API returned an error code
+    AAUDIO_ERROR_INVALID_STATE,
+    AAUDIO_ERROR_UNEXPECTED_STATE,
+    AAUDIO_ERROR_UNEXPECTED_VALUE,
+    AAUDIO_ERROR_INVALID_HANDLE,
+    AAUDIO_ERROR_INVALID_QUERY,
+    AAUDIO_ERROR_UNIMPLEMENTED,
+    AAUDIO_ERROR_UNAVAILABLE,
+    AAUDIO_ERROR_NO_FREE_HANDLES,
+    AAUDIO_ERROR_NO_MEMORY,
+    AAUDIO_ERROR_NULL,
+    AAUDIO_ERROR_TIMEOUT,
+    AAUDIO_ERROR_WOULD_BLOCK,
+    AAUDIO_ERROR_INVALID_ORDER,
+    AAUDIO_ERROR_OUT_OF_RANGE,
+    AAUDIO_ERROR_NO_SERVICE
+};
+
+typedef enum
+{
+    AAUDIO_STREAM_STATE_UNINITIALIZED = 0,
+    AAUDIO_STREAM_STATE_UNKNOWN,
+    AAUDIO_STREAM_STATE_OPEN,
+    AAUDIO_STREAM_STATE_STARTING,
+    AAUDIO_STREAM_STATE_STARTED,
+    AAUDIO_STREAM_STATE_PAUSING,
+    AAUDIO_STREAM_STATE_PAUSED,
+    AAUDIO_STREAM_STATE_FLUSHING,
+    AAUDIO_STREAM_STATE_FLUSHED,
+    AAUDIO_STREAM_STATE_STOPPING,
+    AAUDIO_STREAM_STATE_STOPPED,
+    AAUDIO_STREAM_STATE_CLOSING,
+    AAUDIO_STREAM_STATE_CLOSED,
+} aaudio_stream_state_t;
+
+typedef enum {
+    /**
+     * This will be the only stream using a particular source or sink.
+     * This mode will provide the lowest possible latency.
+     * You should close EXCLUSIVE streams immediately when you are not using them.
+     */
+    AAUDIO_SHARING_MODE_EXCLUSIVE,
+    /**
+     * Multiple applications will be mixed by the AAudio Server.
+     * This will have higher latency than the EXCLUSIVE mode.
+     */
+    AAUDIO_SHARING_MODE_SHARED
+} aaudio_sharing_mode_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // AAUDIO_AAUDIODEFINITIONS_H
diff --git a/media/liboboe/include/aaudio/NOTICE b/media/libaaudio/include/aaudio/NOTICE
similarity index 100%
rename from media/liboboe/include/aaudio/NOTICE
rename to media/libaaudio/include/aaudio/NOTICE
diff --git a/media/liboboe/include/aaudio/README.md b/media/libaaudio/include/aaudio/README.md
similarity index 100%
rename from media/liboboe/include/aaudio/README.md
rename to media/libaaudio/include/aaudio/README.md
diff --git a/media/liboboe/liboboe.map.txt b/media/libaaudio/libaaudio.map.txt
similarity index 76%
rename from media/liboboe/liboboe.map.txt
rename to media/libaaudio/libaaudio.map.txt
index ecae991..a9e9109 100644
--- a/media/liboboe/liboboe.map.txt
+++ b/media/libaaudio/libaaudio.map.txt
@@ -1,20 +1,15 @@
 LIBAAUDIO {
   global:
-    AAudio_getNanoseconds;
     AAudio_convertResultToText;
     AAudio_convertStreamStateToText;
     AAudio_createStreamBuilder;
     AAudioStreamBuilder_setDeviceId;
     AAudioStreamBuilder_setSampleRate;
-    AAudioStreamBuilder_getSampleRate;
     AAudioStreamBuilder_setSamplesPerFrame;
-    AAudioStreamBuilder_getSamplesPerFrame;
     AAudioStreamBuilder_setFormat;
-    AAudioStreamBuilder_getFormat;
     AAudioStreamBuilder_setSharingMode;
-    AAudioStreamBuilder_getSharingMode;
     AAudioStreamBuilder_setDirection;
-    AAudioStreamBuilder_getDirection;
+    AAudioStreamBuilder_setBufferCapacityInFrames;
     AAudioStreamBuilder_openStream;
     AAudioStreamBuilder_delete;
     AAudioStream_close;
@@ -28,13 +23,14 @@
     AAudioStream_write;
     AAudioStream_createThread;
     AAudioStream_joinThread;
-    AAudioStream_setBufferSize;
-    AAudioStream_getBufferSize;
+    AAudioStream_setBufferSizeInFrames;
+    AAudioStream_getBufferSizeInFrames;
     AAudioStream_getFramesPerBurst;
-    AAudioStream_getBufferCapacity;
+    AAudioStream_getBufferCapacityInFrames;
     AAudioStream_getXRunCount;
     AAudioStream_getSampleRate;
     AAudioStream_getSamplesPerFrame;
+    AAudioStream_getDeviceId;
     AAudioStream_getFormat;
     AAudioStream_getSharingMode;
     AAudioStream_getDirection;
diff --git a/media/liboboe/scripts/convert_oboe_aaudio.sh b/media/libaaudio/scripts/convert_oboe_aaudio.sh
similarity index 100%
rename from media/liboboe/scripts/convert_oboe_aaudio.sh
rename to media/libaaudio/scripts/convert_oboe_aaudio.sh
diff --git a/media/libaaudio/scripts/convert_typedefs_int32.sh b/media/libaaudio/scripts/convert_typedefs_int32.sh
new file mode 100755
index 0000000..7bdbe3a
--- /dev/null
+++ b/media/libaaudio/scripts/convert_typedefs_int32.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+echo "Use SED to convert typedefs in AAudio API"
+
+echo "Top is ${ANDROID_BUILD_TOP}"
+LIBAAUDIO_DIR=${ANDROID_BUILD_TOP}/frameworks/av/media/libaaudio
+echo "LIBAAUDIO_DIR is ${LIBAAUDIO_DIR}"
+OBOESERVICE_DIR=${ANDROID_BUILD_TOP}/frameworks/av/services/oboeservice
+echo "OBOESERVICE_DIR is ${OBOESERVICE_DIR}"
+OBOETEST_DIR=${ANDROID_BUILD_TOP}/cts/tests/tests/nativemedia/aaudio/src/
+echo "OBOETEST_DIR is ${OBOETEST_DIR}"
+
+function convertPathPattern {
+    path=$1
+    pattern=$2
+    find $path -type f  -name $pattern -exec sed -i -f ${LIBAAUDIO_DIR}/scripts/typedefs_to_int32.sed {} \;
+}
+
+function convertPath {
+    path=$1
+    convertPathPattern $1 '*.cpp'
+    convertPathPattern $1 '*.h'
+}
+
+convertPath ${LIBAAUDIO_DIR}
+convertPath ${OBOESERVICE_DIR}
+convertPathPattern ${OBOETEST_DIR} test_aaudio.cpp
+
diff --git a/media/liboboe/scripts/oboe_to_aaudio.sed b/media/libaaudio/scripts/oboe_to_aaudio.sed
similarity index 100%
rename from media/liboboe/scripts/oboe_to_aaudio.sed
rename to media/libaaudio/scripts/oboe_to_aaudio.sed
diff --git a/media/libaaudio/scripts/revert_all_aaudio.sh b/media/libaaudio/scripts/revert_all_aaudio.sh
new file mode 100755
index 0000000..19c7f81
--- /dev/null
+++ b/media/libaaudio/scripts/revert_all_aaudio.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+echo "Revert typedefs"
+
+echo "Top is ${ANDROID_BUILD_TOP}"
+LIBAAUDIO_DIR=${ANDROID_BUILD_TOP}/frameworks/av/media/libaaudio
+echo "LIBAAUDIO_DIR is ${LIBAAUDIO_DIR}"
+OBOESERVICE_DIR=${ANDROID_BUILD_TOP}/frameworks/av/services/oboeservice
+echo "OBOESERVICE_DIR is ${OBOESERVICE_DIR}"
+OBOETEST_DIR=${ANDROID_BUILD_TOP}/cts/tests/tests/nativemedia/aaudio/src/
+echo "OBOETEST_DIR is ${OBOETEST_DIR}"
+
+git checkout -- ${LIBAAUDIO_DIR}/examples
+git checkout -- ${LIBAAUDIO_DIR}/include
+git checkout -- ${LIBAAUDIO_DIR}/src
+git checkout -- ${LIBAAUDIO_DIR}/tests
+git checkout -- ${OBOESERVICE_DIR}
+
diff --git a/media/libaaudio/scripts/typedefs_to_int32.sed b/media/libaaudio/scripts/typedefs_to_int32.sed
new file mode 100644
index 0000000..392c9a0
--- /dev/null
+++ b/media/libaaudio/scripts/typedefs_to_int32.sed
@@ -0,0 +1,8 @@
+s/aaudio_device_id_t/int32_t/g
+s/aaudio_sample_rate_t/int32_t/g
+s/aaudio_size_frames_t/int32_t/g
+s/aaudio_size_bytes_t/int32_t/g
+s/aaudio_sample_rate_t/int32_t/g
+
+s/aaudio_position_frames_t/int64_t/g
+s/aaudio_nanoseconds_t/int64_t/g
diff --git a/media/liboboe/src/Android.mk b/media/libaaudio/src/Android.mk
similarity index 91%
rename from media/liboboe/src/Android.mk
rename to media/libaaudio/src/Android.mk
index a508be3..a016b49 100644
--- a/media/liboboe/src/Android.mk
+++ b/media/libaaudio/src/Android.mk
@@ -5,18 +5,18 @@
 # TODO Remove this target later, when not needed.
 include $(CLEAR_VARS)
 
-LOCAL_MODULE := liboboe
+LOCAL_MODULE := libaaudio
 LOCAL_MODULE_TAGS := optional
 
-LIBAAUDIO_DIR := $(TOP)/frameworks/av/media/liboboe
+LIBAAUDIO_DIR := $(TOP)/frameworks/av/media/libaaudio
 LIBAAUDIO_SRC_DIR := $(LIBAAUDIO_DIR)/src
 
 LOCAL_C_INCLUDES := \
     $(call include-path-for, audio-utils) \
     frameworks/native/include \
     system/core/base/include \
-    frameworks/native/media/liboboe/include/include \
-    frameworks/av/media/liboboe/include \
+    frameworks/native/media/libaaudio/include/include \
+    frameworks/av/media/libaaudio/include \
     frameworks/native/include \
     $(LOCAL_PATH) \
     $(LOCAL_PATH)/binding \
@@ -59,15 +59,15 @@
 # ======================= SHARED LIBRARY ==========================
 include $(CLEAR_VARS)
 
-LOCAL_MODULE := liboboe
+LOCAL_MODULE := libaaudio
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_C_INCLUDES := \
     $(call include-path-for, audio-utils) \
     frameworks/native/include \
     system/core/base/include \
-    frameworks/native/media/liboboe/include/include \
-    frameworks/av/media/liboboe/include \
+    frameworks/native/media/libaaudio/include/include \
+    frameworks/av/media/libaaudio/include \
     $(LOCAL_PATH) \
     $(LOCAL_PATH)/binding \
     $(LOCAL_PATH)/client \
diff --git a/media/liboboe/src/binding/AAudioServiceDefinitions.h b/media/libaaudio/src/binding/AAudioServiceDefinitions.h
similarity index 92%
rename from media/liboboe/src/binding/AAudioServiceDefinitions.h
rename to media/libaaudio/src/binding/AAudioServiceDefinitions.h
index ca637ef..b58d170 100644
--- a/media/liboboe/src/binding/AAudioServiceDefinitions.h
+++ b/media/libaaudio/src/binding/AAudioServiceDefinitions.h
@@ -44,6 +44,10 @@
 
 namespace aaudio {
 
+typedef int32_t  aaudio_handle_t;
+
+#define AAUDIO_HANDLE_INVALID  ((aaudio_handle_t) -1)
+
 enum aaudio_commands_t {
     OPEN_STREAM = IBinder::FIRST_CALL_TRANSACTION,
     CLOSE_STREAM,
@@ -57,9 +61,9 @@
 
 // TODO Expand this to include all the open parameters.
 typedef struct AAudioServiceStreamInfo_s {
-    int32_t             deviceId;
-    int32_t             samplesPerFrame;  // number of channels
-    aaudio_sample_rate_t  sampleRate;
+    int32_t               deviceId;
+    int32_t               samplesPerFrame;  // number of channels
+    int32_t               sampleRate;
     aaudio_audio_format_t audioFormat;
 } AAudioServiceStreamInfo;
 
diff --git a/media/liboboe/src/binding/AAudioServiceMessage.h b/media/libaaudio/src/binding/AAudioServiceMessage.h
similarity index 84%
rename from media/liboboe/src/binding/AAudioServiceMessage.h
rename to media/libaaudio/src/binding/AAudioServiceMessage.h
index 16cb5eb..cc77d59 100644
--- a/media/liboboe/src/binding/AAudioServiceMessage.h
+++ b/media/libaaudio/src/binding/AAudioServiceMessage.h
@@ -23,12 +23,12 @@
 
 namespace aaudio {
 
-// TODO move this an "include" folder for the service.
+// TODO move this to an "include" folder for the service.
 
 struct AAudioMessageTimestamp {
-    aaudio_position_frames_t position;
-    int64_t                deviceOffset; // add to client position to get device position
-    aaudio_nanoseconds_t     timestamp;
+    int64_t    position;
+    int64_t    deviceOffset; // add to client position to get device position
+    int64_t    timestamp;
 };
 
 typedef enum aaudio_service_event_e : uint32_t {
@@ -41,8 +41,8 @@
 
 struct AAudioMessageEvent {
     aaudio_service_event_t event;
-    int32_t data1;
-    int64_t data2;
+    int32_t                data1;
+    int64_t                data2;
 };
 
 typedef struct AAudioServiceMessage_s {
diff --git a/media/liboboe/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
similarity index 84%
rename from media/liboboe/src/binding/AAudioStreamConfiguration.cpp
rename to media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index 1cb2bfa..fe3a59f 100644
--- a/media/liboboe/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -39,6 +39,7 @@
     parcel->writeInt32(mSampleRate);
     parcel->writeInt32(mSamplesPerFrame);
     parcel->writeInt32((int32_t) mAudioFormat);
+    parcel->writeInt32(mBufferCapacity);
     return NO_ERROR; // TODO check for errors above
 }
 
@@ -49,6 +50,7 @@
     parcel->readInt32(&mSamplesPerFrame);
     parcel->readInt32(&temp);
     mAudioFormat = (aaudio_audio_format_t) temp;
+    parcel->readInt32(&mBufferCapacity);
     return NO_ERROR; // TODO check for errors above
 }
 
@@ -74,11 +76,17 @@
         ALOGE("AAudioStreamConfiguration.validate() invalid audioFormat = %d", mAudioFormat);
         return AAUDIO_ERROR_INTERNAL;
     }
+
+    if (mBufferCapacity < 0) {
+        ALOGE("AAudioStreamConfiguration.validate() invalid mBufferCapacity = %d", mBufferCapacity);
+        return AAUDIO_ERROR_INTERNAL;
+    }
     return AAUDIO_OK;
 }
 
 void AAudioStreamConfiguration::dump() {
-    ALOGD("AAudioStreamConfiguration mSampleRate = %d -----", mSampleRate);
+    ALOGD("AAudioStreamConfiguration mSampleRate      = %d -----", mSampleRate);
     ALOGD("AAudioStreamConfiguration mSamplesPerFrame = %d", mSamplesPerFrame);
-    ALOGD("AAudioStreamConfiguration mAudioFormat = %d", (int)mAudioFormat);
+    ALOGD("AAudioStreamConfiguration mAudioFormat     = %d", (int)mAudioFormat);
+    ALOGD("AAudioStreamConfiguration mBufferCapacity  = %d", mBufferCapacity);
 }
diff --git a/media/liboboe/src/binding/AAudioStreamConfiguration.h b/media/libaaudio/src/binding/AAudioStreamConfiguration.h
similarity index 76%
rename from media/liboboe/src/binding/AAudioStreamConfiguration.h
rename to media/libaaudio/src/binding/AAudioStreamConfiguration.h
index ef21443..57b1c59 100644
--- a/media/liboboe/src/binding/AAudioStreamConfiguration.h
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.h
@@ -34,19 +34,19 @@
     AAudioStreamConfiguration();
     virtual ~AAudioStreamConfiguration();
 
-    aaudio_device_id_t getDeviceId() const {
+    int32_t getDeviceId() const {
         return mDeviceId;
     }
 
-    void setDeviceId(aaudio_device_id_t deviceId) {
+    void setDeviceId(int32_t deviceId) {
         mDeviceId = deviceId;
     }
 
-    aaudio_sample_rate_t getSampleRate() const {
+    int32_t getSampleRate() const {
         return mSampleRate;
     }
 
-    void setSampleRate(aaudio_sample_rate_t sampleRate) {
+    void setSampleRate(int32_t sampleRate) {
         mSampleRate = sampleRate;
     }
 
@@ -66,6 +66,14 @@
         mAudioFormat = audioFormat;
     }
 
+    int32_t getBufferCapacity() const {
+        return mBufferCapacity;
+    }
+
+    void setBufferCapacity(int32_t frames) {
+        mBufferCapacity = frames;
+    }
+
     virtual status_t writeToParcel(Parcel* parcel) const override;
 
     virtual status_t readFromParcel(const Parcel* parcel) override;
@@ -75,10 +83,11 @@
     void dump();
 
 protected:
-    aaudio_device_id_t    mDeviceId        = AAUDIO_DEVICE_UNSPECIFIED;
-    aaudio_sample_rate_t  mSampleRate      = AAUDIO_UNSPECIFIED;
-    int32_t             mSamplesPerFrame = AAUDIO_UNSPECIFIED;
+    int32_t               mDeviceId        = AAUDIO_DEVICE_UNSPECIFIED;
+    int32_t               mSampleRate      = AAUDIO_UNSPECIFIED;
+    int32_t               mSamplesPerFrame = AAUDIO_UNSPECIFIED;
     aaudio_audio_format_t mAudioFormat     = AAUDIO_FORMAT_UNSPECIFIED;
+    int32_t               mBufferCapacity  = AAUDIO_UNSPECIFIED;
 };
 
 } /* namespace aaudio */
diff --git a/media/liboboe/src/binding/AAudioStreamRequest.cpp b/media/libaaudio/src/binding/AAudioStreamRequest.cpp
similarity index 100%
rename from media/liboboe/src/binding/AAudioStreamRequest.cpp
rename to media/libaaudio/src/binding/AAudioStreamRequest.cpp
diff --git a/media/liboboe/src/binding/AAudioStreamRequest.h b/media/libaaudio/src/binding/AAudioStreamRequest.h
similarity index 100%
rename from media/liboboe/src/binding/AAudioStreamRequest.h
rename to media/libaaudio/src/binding/AAudioStreamRequest.h
diff --git a/media/liboboe/src/binding/AudioEndpointParcelable.cpp b/media/libaaudio/src/binding/AudioEndpointParcelable.cpp
similarity index 100%
rename from media/liboboe/src/binding/AudioEndpointParcelable.cpp
rename to media/libaaudio/src/binding/AudioEndpointParcelable.cpp
diff --git a/media/liboboe/src/binding/AudioEndpointParcelable.h b/media/libaaudio/src/binding/AudioEndpointParcelable.h
similarity index 100%
rename from media/liboboe/src/binding/AudioEndpointParcelable.h
rename to media/libaaudio/src/binding/AudioEndpointParcelable.h
diff --git a/media/liboboe/src/binding/IAAudioService.cpp b/media/libaaudio/src/binding/IAAudioService.cpp
similarity index 97%
rename from media/liboboe/src/binding/IAAudioService.cpp
rename to media/libaaudio/src/binding/IAAudioService.cpp
index 899ebc0..c21033e 100644
--- a/media/liboboe/src/binding/IAAudioService.cpp
+++ b/media/libaaudio/src/binding/IAAudioService.cpp
@@ -18,12 +18,15 @@
 
 #include "binding/AudioEndpointParcelable.h"
 #include "binding/AAudioStreamRequest.h"
+#include "binding/AAudioServiceDefinitions.h"
 #include "binding/AAudioStreamConfiguration.h"
 #include "binding/IAAudioService.h"
 #include "utility/AAudioUtilities.h"
 
 namespace android {
 
+using aaudio::aaudio_handle_t;
+
 /**
  * This is used by the AAudio Client to talk to the AAudio Service.
  *
@@ -137,7 +140,7 @@
     }
 
     virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle, pid_t clientThreadId,
-                                              aaudio_nanoseconds_t periodNanoseconds)
+                                              int64_t periodNanoseconds)
     override {
         Parcel data, reply;
         // send command
@@ -182,11 +185,11 @@
 
 status_t BnAAudioService::onTransact(uint32_t code, const Parcel& data,
                                         Parcel* reply, uint32_t flags) {
-    AAudioStream stream;
+    aaudio_handle_t stream;
     aaudio::AAudioStreamRequest request;
     aaudio::AAudioStreamConfiguration configuration;
     pid_t pid;
-    aaudio_nanoseconds_t nanoseconds;
+    int64_t nanoseconds;
     aaudio_result_t result;
     ALOGV("BnAAudioService::onTransact(%i) %i", code, flags);
     data.checkInterface(this);
diff --git a/media/liboboe/src/binding/IAAudioService.h b/media/libaaudio/src/binding/IAAudioService.h
similarity index 68%
rename from media/liboboe/src/binding/IAAudioService.h
rename to media/libaaudio/src/binding/IAAudioService.h
index 7d2fd29..53c3b45 100644
--- a/media/liboboe/src/binding/IAAudioService.h
+++ b/media/libaaudio/src/binding/IAAudioService.h
@@ -29,7 +29,6 @@
 #include "binding/AAudioStreamRequest.h"
 #include "binding/AAudioStreamConfiguration.h"
 
-
 namespace android {
 
 // Interface (our AIDL) - Shared by server and client
@@ -38,39 +37,44 @@
 
     DECLARE_META_INTERFACE(AAudioService);
 
-    virtual aaudio_handle_t openStream(aaudio::AAudioStreamRequest &request,
+    /**
+     * @param request info needed to create the stream
+     * @param configuration contains information about the created stream
+     * @return handle to the stream or a negative error
+     */
+    virtual aaudio::aaudio_handle_t openStream(aaudio::AAudioStreamRequest &request,
                                      aaudio::AAudioStreamConfiguration &configuration) = 0;
 
-    virtual aaudio_result_t closeStream(aaudio_handle_t streamHandle) = 0;
+    virtual aaudio_result_t closeStream(aaudio::aaudio_handle_t streamHandle) = 0;
 
     /* Get an immutable description of the in-memory queues
     * used to communicate with the underlying HAL or Service.
     */
-    virtual aaudio_result_t getStreamDescription(aaudio_handle_t streamHandle,
+    virtual aaudio_result_t getStreamDescription(aaudio::aaudio_handle_t streamHandle,
                                                aaudio::AudioEndpointParcelable &parcelable) = 0;
 
     /**
      * Start the flow of data.
      */
-    virtual aaudio_result_t startStream(aaudio_handle_t streamHandle) = 0;
+    virtual aaudio_result_t startStream(aaudio::aaudio_handle_t streamHandle) = 0;
 
     /**
      * Stop the flow of data such that start() can resume without loss of data.
      */
-    virtual aaudio_result_t pauseStream(aaudio_handle_t streamHandle) = 0;
+    virtual aaudio_result_t pauseStream(aaudio::aaudio_handle_t streamHandle) = 0;
 
     /**
      *  Discard any data held by the underlying HAL or Service.
      */
-    virtual aaudio_result_t flushStream(aaudio_handle_t streamHandle) = 0;
+    virtual aaudio_result_t flushStream(aaudio::aaudio_handle_t streamHandle) = 0;
 
     /**
      * Manage the specified thread as a low latency audio thread.
      */
-    virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle, pid_t clientThreadId,
-                                              aaudio_nanoseconds_t periodNanoseconds) = 0;
+    virtual aaudio_result_t registerAudioThread(aaudio::aaudio_handle_t streamHandle, pid_t clientThreadId,
+                                              int64_t periodNanoseconds) = 0;
 
-    virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle,
+    virtual aaudio_result_t unregisterAudioThread(aaudio::aaudio_handle_t streamHandle,
                                                 pid_t clientThreadId) = 0;
 };
 
diff --git a/media/liboboe/src/binding/RingBufferParcelable.cpp b/media/libaaudio/src/binding/RingBufferParcelable.cpp
similarity index 100%
rename from media/liboboe/src/binding/RingBufferParcelable.cpp
rename to media/libaaudio/src/binding/RingBufferParcelable.cpp
diff --git a/media/liboboe/src/binding/RingBufferParcelable.h b/media/libaaudio/src/binding/RingBufferParcelable.h
similarity index 100%
rename from media/liboboe/src/binding/RingBufferParcelable.h
rename to media/libaaudio/src/binding/RingBufferParcelable.h
diff --git a/media/liboboe/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
similarity index 96%
rename from media/liboboe/src/binding/SharedMemoryParcelable.cpp
rename to media/libaaudio/src/binding/SharedMemoryParcelable.cpp
index 277a992..1102dec 100644
--- a/media/liboboe/src/binding/SharedMemoryParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
@@ -87,9 +87,9 @@
 }
 
 aaudio_result_t SharedMemoryParcelable::validate() {
-    if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE) {
+    if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE_BYTES) {
         ALOGE("SharedMemoryParcelable invalid mSizeInBytes = %d", mSizeInBytes);
-        return AAUDIO_ERROR_INTERNAL;
+        return AAUDIO_ERROR_OUT_OF_RANGE;
     }
     if (mSizeInBytes > 0) {
         if (mFd == -1) {
diff --git a/media/liboboe/src/binding/SharedMemoryParcelable.h b/media/libaaudio/src/binding/SharedMemoryParcelable.h
similarity index 94%
rename from media/liboboe/src/binding/SharedMemoryParcelable.h
rename to media/libaaudio/src/binding/SharedMemoryParcelable.h
index 5768ea9..7e0bf1a 100644
--- a/media/liboboe/src/binding/SharedMemoryParcelable.h
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.h
@@ -31,8 +31,8 @@
 
 // Arbitrary limits for sanity checks. TODO remove after debugging.
 #define MAX_SHARED_MEMORIES (32)
-#define MAX_MMAP_OFFSET (32 * 1024)
-#define MAX_MMAP_SIZE (32 * 1024)
+#define MAX_MMAP_OFFSET_BYTES (32 * 1024 * 8)
+#define MAX_MMAP_SIZE_BYTES (32 * 1024 * 8)
 
 /**
  * This is a parcelable description of a shared memory referenced by a file descriptor.
diff --git a/media/liboboe/src/binding/SharedRegionParcelable.cpp b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
similarity index 95%
rename from media/liboboe/src/binding/SharedRegionParcelable.cpp
rename to media/libaaudio/src/binding/SharedRegionParcelable.cpp
index a3e0111..8ca0023 100644
--- a/media/liboboe/src/binding/SharedRegionParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.cpp
@@ -75,14 +75,14 @@
 }
 
 aaudio_result_t SharedRegionParcelable::validate() {
-    if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE) {
+    if (mSizeInBytes < 0 || mSizeInBytes >= MAX_MMAP_SIZE_BYTES) {
         ALOGE("SharedRegionParcelable invalid mSizeInBytes = %d", mSizeInBytes);
-        return AAUDIO_ERROR_INTERNAL;
+        return AAUDIO_ERROR_OUT_OF_RANGE;
     }
     if (mSizeInBytes > 0) {
-        if (mOffsetInBytes < 0 || mOffsetInBytes >= MAX_MMAP_OFFSET) {
+        if (mOffsetInBytes < 0 || mOffsetInBytes >= MAX_MMAP_OFFSET_BYTES) {
             ALOGE("SharedRegionParcelable invalid mOffsetInBytes = %d", mOffsetInBytes);
-            return AAUDIO_ERROR_INTERNAL;
+            return AAUDIO_ERROR_OUT_OF_RANGE;
         }
         if (mSharedMemoryIndex < 0 || mSharedMemoryIndex >= MAX_SHARED_MEMORIES) {
             ALOGE("SharedRegionParcelable invalid mSharedMemoryIndex = %d", mSharedMemoryIndex);
diff --git a/media/liboboe/src/binding/SharedRegionParcelable.h b/media/libaaudio/src/binding/SharedRegionParcelable.h
similarity index 100%
rename from media/liboboe/src/binding/SharedRegionParcelable.h
rename to media/libaaudio/src/binding/SharedRegionParcelable.h
diff --git a/media/liboboe/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
similarity index 97%
rename from media/liboboe/src/client/AudioEndpoint.cpp
rename to media/libaaudio/src/client/AudioEndpoint.cpp
index 5cd9782..47c4774 100644
--- a/media/liboboe/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -167,8 +167,8 @@
     return mDownDataQueue->getWriteCounter();
 }
 
-aaudio_size_frames_t AudioEndpoint::setBufferSizeInFrames(aaudio_size_frames_t requestedFrames,
-                                            aaudio_size_frames_t *actualFrames)
+int32_t AudioEndpoint::setBufferSizeInFrames(int32_t requestedFrames,
+                                            int32_t *actualFrames)
 {
     if (requestedFrames < ENDPOINT_DATA_QUEUE_SIZE_MIN) {
         requestedFrames = ENDPOINT_DATA_QUEUE_SIZE_MIN;
diff --git a/media/liboboe/src/client/AudioEndpoint.h b/media/libaaudio/src/client/AudioEndpoint.h
similarity index 88%
rename from media/liboboe/src/client/AudioEndpoint.h
rename to media/libaaudio/src/client/AudioEndpoint.h
index e786513..caee488 100644
--- a/media/liboboe/src/client/AudioEndpoint.h
+++ b/media/libaaudio/src/client/AudioEndpoint.h
@@ -71,13 +71,13 @@
      */
     bool isOutputFreeRunning() const { return mOutputFreeRunning; }
 
-    int32_t setBufferSizeInFrames(aaudio_size_frames_t requestedFrames,
-                                  aaudio_size_frames_t *actualFrames);
-    aaudio_size_frames_t getBufferSizeInFrames() const;
+    int32_t setBufferSizeInFrames(int32_t requestedFrames,
+                                  int32_t *actualFrames);
+    int32_t getBufferSizeInFrames() const;
 
-    aaudio_size_frames_t getBufferCapacityInFrames() const;
+    int32_t getBufferCapacityInFrames() const;
 
-    aaudio_size_frames_t getFullFramesAvailable();
+    int32_t getFullFramesAvailable();
 
 private:
     FifoBuffer   * mUpCommandQueue;
diff --git a/media/liboboe/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
similarity index 90%
rename from media/liboboe/src/client/AudioStreamInternal.cpp
rename to media/libaaudio/src/client/AudioStreamInternal.cpp
index 8d7e93f..54f4870 100644
--- a/media/liboboe/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -33,6 +33,7 @@
 #include "binding/IAAudioService.h"
 #include "binding/AAudioServiceMessage.h"
 
+#include "core/AudioStreamBuilder.h"
 #include "AudioStreamInternal.h"
 
 #define LOG_TIMESTAMPS   0
@@ -110,6 +111,7 @@
     request.getConfiguration().setSampleRate(getSampleRate());
     request.getConfiguration().setSamplesPerFrame(getSamplesPerFrame());
     request.getConfiguration().setAudioFormat(getFormat());
+    request.getConfiguration().setBufferCapacity(builder.getBufferCapacity());
     request.dump();
 
     mServiceStreamHandle = service->openStream(request, configuration);
@@ -142,7 +144,6 @@
         // Configure endpoint based on descriptor.
         mAudioEndpoint.configure(&mEndpointDescriptor);
 
-
         mFramesPerBurst = mEndpointDescriptor.downDataQueueDescriptor.framesPerBurst;
         assert(mFramesPerBurst >= 16);
         assert(mEndpointDescriptor.downDataQueueDescriptor.capacityInFrames < 10 * 1024);
@@ -171,14 +172,14 @@
 
 aaudio_result_t AudioStreamInternal::requestStart()
 {
-    aaudio_nanoseconds_t startTime;
+    int64_t startTime;
     ALOGD("AudioStreamInternal(): start()");
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
     const sp<IAAudioService>& aaudioService = getAAudioService();
     if (aaudioService == 0) return AAUDIO_ERROR_NO_SERVICE;
-    startTime = AAudio_getNanoseconds(AAUDIO_CLOCK_MONOTONIC);
+    startTime = AudioClock::getNanoseconds();
     mClockModel.start(startTime);
     processTimestamp(0, startTime);
     setState(AAUDIO_STREAM_STATE_STARTING);
@@ -193,7 +194,7 @@
     }
     const sp<IAAudioService>& aaudioService = getAAudioService();
     if (aaudioService == 0) return AAUDIO_ERROR_NO_SERVICE;
-    mClockModel.stop(AAudio_getNanoseconds(AAUDIO_CLOCK_MONOTONIC));
+    mClockModel.stop(AudioClock::getNanoseconds());
     setState(AAUDIO_STREAM_STATE_PAUSING);
     return aaudioService->pauseStream(mServiceStreamHandle);
 }
@@ -211,10 +212,10 @@
 
 void AudioStreamInternal::onFlushFromServer() {
     ALOGD("AudioStreamInternal(): onFlushFromServer()");
-    aaudio_position_frames_t readCounter = mAudioEndpoint.getDownDataReadCounter();
-    aaudio_position_frames_t writeCounter = mAudioEndpoint.getDownDataWriteCounter();
+    int64_t readCounter = mAudioEndpoint.getDownDataReadCounter();
+    int64_t writeCounter = mAudioEndpoint.getDownDataWriteCounter();
     // Bump offset so caller does not see the retrograde motion in getFramesRead().
-    aaudio_position_frames_t framesFlushed = writeCounter - readCounter;
+    int64_t framesFlushed = writeCounter - readCounter;
     mFramesOffsetFromService += framesFlushed;
     // Flush written frames by forcing writeCounter to readCounter.
     // This is because we cannot move the read counter in the hardware.
@@ -261,10 +262,10 @@
 
 // TODO use aaudio_clockid_t all the way down to AudioClock
 aaudio_result_t AudioStreamInternal::getTimestamp(clockid_t clockId,
-                           aaudio_position_frames_t *framePosition,
-                           aaudio_nanoseconds_t *timeNanoseconds) {
+                           int64_t *framePosition,
+                           int64_t *timeNanoseconds) {
 // TODO implement using real HAL
-    aaudio_nanoseconds_t time = AudioClock::getNanoseconds();
+    int64_t time = AudioClock::getNanoseconds();
     *framePosition = mClockModel.convertTimeToPosition(time);
     *timeNanoseconds = time + (10 * AAUDIO_NANOS_PER_MILLISECOND); // Fake hardware delay
     return AAUDIO_OK;
@@ -277,9 +278,9 @@
 #if LOG_TIMESTAMPS
 static void AudioStreamInternal_LogTimestamp(AAudioServiceMessage &command) {
     static int64_t oldPosition = 0;
-    static aaudio_nanoseconds_t oldTime = 0;
+    static int64_t oldTime = 0;
     int64_t framePosition = command.timestamp.position;
-    aaudio_nanoseconds_t nanoTime = command.timestamp.timestamp;
+    int64_t nanoTime = command.timestamp.timestamp;
     ALOGD("AudioStreamInternal() timestamp says framePosition = %08lld at nanoTime %llu",
          (long long) framePosition,
          (long long) nanoTime);
@@ -297,7 +298,7 @@
 #endif
 
 aaudio_result_t AudioStreamInternal::onTimestampFromServer(AAudioServiceMessage *message) {
-    aaudio_position_frames_t framePosition = 0;
+    int64_t framePosition = 0;
 #if LOG_TIMESTAMPS
     AudioStreamInternal_LogTimestamp(command);
 #endif
@@ -369,12 +370,12 @@
 
 // Write the data, block if needed and timeoutMillis > 0
 aaudio_result_t AudioStreamInternal::write(const void *buffer, int32_t numFrames,
-                                         aaudio_nanoseconds_t timeoutNanoseconds)
+                                         int64_t timeoutNanoseconds)
 {
     aaudio_result_t result = AAUDIO_OK;
     uint8_t* source = (uint8_t*)buffer;
-    aaudio_nanoseconds_t currentTimeNanos = AudioClock::getNanoseconds();
-    aaudio_nanoseconds_t deadlineNanos = currentTimeNanos + timeoutNanoseconds;
+    int64_t currentTimeNanos = AudioClock::getNanoseconds();
+    int64_t deadlineNanos = currentTimeNanos + timeoutNanoseconds;
     int32_t framesLeft = numFrames;
 //    ALOGD("AudioStreamInternal::write(%p, %d) at time %08llu , mState = %d ------------------",
 //         buffer, numFrames, (unsigned long long) currentTimeNanos, mState);
@@ -382,7 +383,7 @@
     // Write until all the data has been written or until a timeout occurs.
     while (framesLeft > 0) {
         // The call to writeNow() will not block. It will just write as much as it can.
-        aaudio_nanoseconds_t wakeTimeNanos = 0;
+        int64_t wakeTimeNanos = 0;
         aaudio_result_t framesWritten = writeNow(source, framesLeft,
                                                currentTimeNanos, &wakeTimeNanos);
 //        ALOGD("AudioStreamInternal::write() writeNow() framesLeft = %d --> framesWritten = %d", framesLeft, framesWritten);
@@ -421,7 +422,7 @@
 
 // Write as much data as we can without blocking.
 aaudio_result_t AudioStreamInternal::writeNow(const void *buffer, int32_t numFrames,
-                                         aaudio_nanoseconds_t currentNanoTime, aaudio_nanoseconds_t *wakeTimePtr) {
+                                         int64_t currentNanoTime, int64_t *wakeTimePtr) {
     {
         aaudio_result_t result = processCommands();
         if (result != AAUDIO_OK) {
@@ -451,7 +452,7 @@
     // Calculate an ideal time to wake up.
     if (wakeTimePtr != nullptr && framesWritten >= 0) {
         // By default wake up a few milliseconds from now.  // TODO review
-        aaudio_nanoseconds_t wakeTime = currentNanoTime + (2 * AAUDIO_NANOS_PER_MILLISECOND);
+        int64_t wakeTime = currentNanoTime + (2 * AAUDIO_NANOS_PER_MILLISECOND);
         switch (getState()) {
             case AAUDIO_STREAM_STATE_OPEN:
             case AAUDIO_STREAM_STATE_STARTING:
@@ -486,7 +487,7 @@
 
 aaudio_result_t AudioStreamInternal::waitForStateChange(aaudio_stream_state_t currentState,
                                                       aaudio_stream_state_t *nextState,
-                                                      aaudio_nanoseconds_t timeoutNanoseconds)
+                                                      int64_t timeoutNanoseconds)
 
 {
     aaudio_result_t result = processCommands();
@@ -521,33 +522,38 @@
 }
 
 
-void AudioStreamInternal::processTimestamp(uint64_t position, aaudio_nanoseconds_t time) {
+void AudioStreamInternal::processTimestamp(uint64_t position, int64_t time) {
     mClockModel.processTimestamp( position, time);
 }
 
-aaudio_result_t AudioStreamInternal::setBufferSize(aaudio_size_frames_t requestedFrames,
-                                        aaudio_size_frames_t *actualFrames) {
-    return mAudioEndpoint.setBufferSizeInFrames(requestedFrames, actualFrames);
+aaudio_result_t AudioStreamInternal::setBufferSize(int32_t requestedFrames) {
+    int32_t actualFrames = 0;
+    aaudio_result_t result = mAudioEndpoint.setBufferSizeInFrames(requestedFrames, &actualFrames);
+    if (result < 0) {
+        return result;
+    } else {
+        return (aaudio_result_t) actualFrames;
+    }
 }
 
-aaudio_size_frames_t AudioStreamInternal::getBufferSize() const
+int32_t AudioStreamInternal::getBufferSize() const
 {
     return mAudioEndpoint.getBufferSizeInFrames();
 }
 
-aaudio_size_frames_t AudioStreamInternal::getBufferCapacity() const
+int32_t AudioStreamInternal::getBufferCapacity() const
 {
     return mAudioEndpoint.getBufferCapacityInFrames();
 }
 
-aaudio_size_frames_t AudioStreamInternal::getFramesPerBurst() const
+int32_t AudioStreamInternal::getFramesPerBurst() const
 {
     return mEndpointDescriptor.downDataQueueDescriptor.framesPerBurst;
 }
 
-aaudio_position_frames_t AudioStreamInternal::getFramesRead()
+int64_t AudioStreamInternal::getFramesRead()
 {
-    aaudio_position_frames_t framesRead =
+    int64_t framesRead =
             mClockModel.convertTimeToPosition(AudioClock::getNanoseconds())
             + mFramesOffsetFromService;
     // Prevent retrograde motion.
diff --git a/media/liboboe/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
similarity index 73%
rename from media/liboboe/src/client/AudioStreamInternal.h
rename to media/libaaudio/src/client/AudioStreamInternal.h
index 666df3a..6f3a7ac 100644
--- a/media/liboboe/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -49,8 +49,8 @@
 
     // TODO use aaudio_clockid_t all the way down to AudioClock
     virtual aaudio_result_t getTimestamp(clockid_t clockId,
-                                       aaudio_position_frames_t *framePosition,
-                                       aaudio_nanoseconds_t *timeNanoseconds) override;
+                                       int64_t *framePosition,
+                                       int64_t *timeNanoseconds) override;
 
 
     virtual aaudio_result_t updateState() override;
@@ -62,22 +62,21 @@
 
     virtual aaudio_result_t write(const void *buffer,
                              int32_t numFrames,
-                             aaudio_nanoseconds_t timeoutNanoseconds) override;
+                             int64_t timeoutNanoseconds) override;
 
     virtual aaudio_result_t waitForStateChange(aaudio_stream_state_t currentState,
                                           aaudio_stream_state_t *nextState,
-                                          aaudio_nanoseconds_t timeoutNanoseconds) override;
+                                          int64_t timeoutNanoseconds) override;
 
-    virtual aaudio_result_t setBufferSize(aaudio_size_frames_t requestedFrames,
-                                        aaudio_size_frames_t *actualFrames) override;
+    virtual aaudio_result_t setBufferSize(int32_t requestedFrames) override;
 
-    virtual aaudio_size_frames_t getBufferSize() const override;
+    virtual int32_t getBufferSize() const override;
 
-    virtual aaudio_size_frames_t getBufferCapacity() const override;
+    virtual int32_t getBufferCapacity() const override;
 
-    virtual aaudio_size_frames_t getFramesPerBurst() const override;
+    virtual int32_t getFramesPerBurst() const override;
 
-    virtual aaudio_position_frames_t getFramesRead() override;
+    virtual int64_t getFramesRead() override;
 
     virtual int32_t getXRunCount() const override {
         return mXRunCount;
@@ -100,8 +99,8 @@
  */
     virtual aaudio_result_t writeNow(const void *buffer,
                                 int32_t numFrames,
-                                aaudio_nanoseconds_t currentTimeNanos,
-                                aaudio_nanoseconds_t *wakeTimePtr);
+                                int64_t currentTimeNanos,
+                                int64_t *wakeTimePtr);
 
     void onFlushFromServer();
 
@@ -112,15 +111,15 @@
 private:
     IsochronousClockModel    mClockModel;
     AudioEndpoint            mAudioEndpoint;
-    aaudio_handle_t            mServiceStreamHandle;
+    aaudio_handle_t          mServiceStreamHandle;
     EndpointDescriptor       mEndpointDescriptor;
     // Offset from underlying frame position.
-    aaudio_position_frames_t   mFramesOffsetFromService = 0;
-    aaudio_position_frames_t   mLastFramesRead = 0;
-    aaudio_size_frames_t       mFramesPerBurst;
+    int64_t                  mFramesOffsetFromService = 0;
+    int64_t                  mLastFramesRead = 0;
+    int32_t                  mFramesPerBurst;
     int32_t                  mXRunCount = 0;
 
-    void processTimestamp(uint64_t position, aaudio_nanoseconds_t time);
+    void processTimestamp(uint64_t position, int64_t time);
 };
 
 } /* namespace aaudio */
diff --git a/media/liboboe/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
similarity index 75%
rename from media/liboboe/src/client/IsochronousClockModel.cpp
rename to media/libaaudio/src/client/IsochronousClockModel.cpp
index bdb491d..4c8aabc 100644
--- a/media/liboboe/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include <aaudio/AAudioDefinitions.h>
 
+#include "utility/AudioClock.h"
 #include "IsochronousClockModel.h"
 
 #define MIN_LATENESS_NANOS (10 * AAUDIO_NANOS_PER_MICROSECOND)
@@ -29,11 +30,11 @@
 using namespace aaudio;
 
 IsochronousClockModel::IsochronousClockModel()
-        : mSampleRate(48000)
+        : mMarkerFramePosition(0)
+        , mMarkerNanoTime(0)
+        , mSampleRate(48000)
         , mFramesPerBurst(64)
         , mMaxLatenessInNanos(0)
-        , mMarkerFramePosition(0)
-        , mMarkerNanoTime(0)
         , mState(STATE_STOPPED)
 {
 }
@@ -41,21 +42,21 @@
 IsochronousClockModel::~IsochronousClockModel() {
 }
 
-void IsochronousClockModel::start(aaudio_nanoseconds_t nanoTime)
+void IsochronousClockModel::start(int64_t nanoTime)
 {
     mMarkerNanoTime = nanoTime;
     mState = STATE_STARTING;
 }
 
-void IsochronousClockModel::stop(aaudio_nanoseconds_t nanoTime)
+void IsochronousClockModel::stop(int64_t nanoTime)
 {
     mMarkerNanoTime = nanoTime;
     mMarkerFramePosition = convertTimeToPosition(nanoTime); // TODO should we do this?
     mState = STATE_STOPPED;
 }
 
-void IsochronousClockModel::processTimestamp(aaudio_position_frames_t framePosition,
-                                             aaudio_nanoseconds_t nanoTime) {
+void IsochronousClockModel::processTimestamp(int64_t framePosition,
+                                             int64_t nanoTime) {
     int64_t framesDelta = framePosition - mMarkerFramePosition;
     int64_t nanosDelta = nanoTime - mMarkerNanoTime;
     if (nanosDelta < 1000) {
@@ -115,7 +116,6 @@
     default:
         break;
     }
-    ++mTimestampCount;
 }
 
 void IsochronousClockModel::setSampleRate(int32_t sampleRate) {
@@ -133,41 +133,41 @@
     mMaxLatenessInNanos = (nanosLate > MIN_LATENESS_NANOS) ? nanosLate : MIN_LATENESS_NANOS;
 }
 
-aaudio_nanoseconds_t IsochronousClockModel::convertDeltaPositionToTime(
-        aaudio_position_frames_t framesDelta) const {
+int64_t IsochronousClockModel::convertDeltaPositionToTime(
+        int64_t framesDelta) const {
     return (AAUDIO_NANOS_PER_SECOND * framesDelta) / mSampleRate;
 }
 
-int64_t IsochronousClockModel::convertDeltaTimeToPosition(aaudio_nanoseconds_t nanosDelta) const {
+int64_t IsochronousClockModel::convertDeltaTimeToPosition(int64_t nanosDelta) const {
     return (mSampleRate * nanosDelta) / AAUDIO_NANOS_PER_SECOND;
 }
 
-aaudio_nanoseconds_t IsochronousClockModel::convertPositionToTime(
-        aaudio_position_frames_t framePosition) const {
+int64_t IsochronousClockModel::convertPositionToTime(
+        int64_t framePosition) const {
     if (mState == STATE_STOPPED) {
         return mMarkerNanoTime;
     }
-    aaudio_position_frames_t nextBurstIndex = (framePosition + mFramesPerBurst - 1) / mFramesPerBurst;
-    aaudio_position_frames_t nextBurstPosition = mFramesPerBurst * nextBurstIndex;
-    aaudio_position_frames_t framesDelta = nextBurstPosition - mMarkerFramePosition;
-    aaudio_nanoseconds_t nanosDelta = convertDeltaPositionToTime(framesDelta);
-    aaudio_nanoseconds_t time = (aaudio_nanoseconds_t) (mMarkerNanoTime + nanosDelta);
+    int64_t nextBurstIndex = (framePosition + mFramesPerBurst - 1) / mFramesPerBurst;
+    int64_t nextBurstPosition = mFramesPerBurst * nextBurstIndex;
+    int64_t framesDelta = nextBurstPosition - mMarkerFramePosition;
+    int64_t nanosDelta = convertDeltaPositionToTime(framesDelta);
+    int64_t time = (int64_t) (mMarkerNanoTime + nanosDelta);
 //    ALOGI("IsochronousClockModel::convertPositionToTime: pos = %llu --> time = %llu",
 //         (unsigned long long)framePosition,
 //         (unsigned long long)time);
     return time;
 }
 
-aaudio_position_frames_t IsochronousClockModel::convertTimeToPosition(
-        aaudio_nanoseconds_t nanoTime) const {
+int64_t IsochronousClockModel::convertTimeToPosition(
+        int64_t nanoTime) const {
     if (mState == STATE_STOPPED) {
         return mMarkerFramePosition;
     }
-    aaudio_nanoseconds_t nanosDelta = nanoTime - mMarkerNanoTime;
-    aaudio_position_frames_t framesDelta = convertDeltaTimeToPosition(nanosDelta);
-    aaudio_position_frames_t nextBurstPosition = mMarkerFramePosition + framesDelta;
-    aaudio_position_frames_t nextBurstIndex = nextBurstPosition / mFramesPerBurst;
-    aaudio_position_frames_t position = nextBurstIndex * mFramesPerBurst;
+    int64_t nanosDelta = nanoTime - mMarkerNanoTime;
+    int64_t framesDelta = convertDeltaTimeToPosition(nanosDelta);
+    int64_t nextBurstPosition = mMarkerFramePosition + framesDelta;
+    int64_t nextBurstIndex = nextBurstPosition / mFramesPerBurst;
+    int64_t position = nextBurstIndex * mFramesPerBurst;
 //    ALOGI("IsochronousClockModel::convertTimeToPosition: time = %llu --> pos = %llu",
 //         (unsigned long long)nanoTime,
 //         (unsigned long long)position);
diff --git a/media/liboboe/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h
similarity index 67%
rename from media/liboboe/src/client/IsochronousClockModel.h
rename to media/libaaudio/src/client/IsochronousClockModel.h
index b188a3d..524c286 100644
--- a/media/liboboe/src/client/IsochronousClockModel.h
+++ b/media/libaaudio/src/client/IsochronousClockModel.h
@@ -34,17 +34,17 @@
     IsochronousClockModel();
     virtual ~IsochronousClockModel();
 
-    void start(aaudio_nanoseconds_t nanoTime);
-    void stop(aaudio_nanoseconds_t nanoTime);
+    void start(int64_t nanoTime);
+    void stop(int64_t nanoTime);
 
-    void processTimestamp(aaudio_position_frames_t framePosition, aaudio_nanoseconds_t nanoTime);
+    void processTimestamp(int64_t framePosition, int64_t nanoTime);
 
     /**
      * @param sampleRate rate of the stream in frames per second
      */
-    void setSampleRate(aaudio_sample_rate_t sampleRate);
+    void setSampleRate(int32_t sampleRate);
 
-    aaudio_sample_rate_t getSampleRate() const {
+    int32_t getSampleRate() const {
         return mSampleRate;
     }
 
@@ -53,9 +53,9 @@
      *
      * @param framesPerBurst number of frames that stream advance at one time.
      */
-    void setFramesPerBurst(aaudio_size_frames_t framesPerBurst);
+    void setFramesPerBurst(int32_t framesPerBurst);
 
-    aaudio_size_frames_t getFramesPerBurst() const {
+    int32_t getFramesPerBurst() const {
         return mFramesPerBurst;
     }
 
@@ -65,7 +65,7 @@
      * @param framePosition position of the stream in frames
      * @return time in nanoseconds
      */
-    aaudio_nanoseconds_t convertPositionToTime(aaudio_position_frames_t framePosition) const;
+    int64_t convertPositionToTime(int64_t framePosition) const;
 
     /**
      * Calculate an estimated position where the stream will be at the specified time.
@@ -73,19 +73,19 @@
      * @param nanoTime time of interest
      * @return position in frames
      */
-    aaudio_position_frames_t convertTimeToPosition(aaudio_nanoseconds_t nanoTime) const;
+    int64_t convertTimeToPosition(int64_t nanoTime) const;
 
     /**
      * @param framesDelta difference in frames
      * @return duration in nanoseconds
      */
-    aaudio_nanoseconds_t convertDeltaPositionToTime(aaudio_position_frames_t framesDelta) const;
+    int64_t convertDeltaPositionToTime(int64_t framesDelta) const;
 
     /**
      * @param nanosDelta duration in nanoseconds
      * @return frames that stream will advance in that time
      */
-    aaudio_position_frames_t convertDeltaTimeToPosition(aaudio_nanoseconds_t nanosDelta) const;
+    int64_t convertDeltaTimeToPosition(int64_t nanosDelta) const;
 
 private:
     enum clock_model_state_t {
@@ -95,13 +95,12 @@
         STATE_RUNNING
     };
 
-    aaudio_sample_rate_t     mSampleRate;
-    aaudio_size_frames_t     mFramesPerBurst;
-    int32_t                mMaxLatenessInNanos;
-    aaudio_position_frames_t mMarkerFramePosition;
-    aaudio_nanoseconds_t     mMarkerNanoTime;
-    int32_t                mTimestampCount;
-    clock_model_state_t     mState;
+    int64_t             mMarkerFramePosition;
+    int64_t             mMarkerNanoTime;
+    int32_t             mSampleRate;
+    int32_t             mFramesPerBurst;
+    int32_t             mMaxLatenessInNanos;
+    clock_model_state_t mState;
 
     void update();
 };
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
new file mode 100644
index 0000000..52bad70
--- /dev/null
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 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_TAG "AAudio"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <time.h>
+#include <pthread.h>
+
+#include <aaudio/AAudioDefinitions.h>
+#include <aaudio/AAudio.h>
+
+#include "AudioStreamBuilder.h"
+#include "AudioStream.h"
+#include "AudioClock.h"
+#include "client/AudioStreamInternal.h"
+#include "HandleTracker.h"
+
+using namespace aaudio;
+
+
+// Macros for common code that includes a return.
+// TODO Consider using do{}while(0) construct. I tried but it hung AndroidStudio
+#define CONVERT_BUILDER_HANDLE_OR_RETURN() \
+    convertAAudioBuilderToStreamBuilder(builder);
+
+#define COMMON_GET_FROM_BUILDER_OR_RETURN(resultPtr) \
+    CONVERT_BUILDER_HANDLE_OR_RETURN() \
+    if ((resultPtr) == nullptr) { \
+        return AAUDIO_ERROR_NULL; \
+    }
+
+#define AAUDIO_CASE_ENUM(name) case name: return #name
+
+AAUDIO_API const char * AAudio_convertResultToText(aaudio_result_t returnCode) {
+    switch (returnCode) {
+        AAUDIO_CASE_ENUM(AAUDIO_OK);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_ILLEGAL_ARGUMENT);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_INCOMPATIBLE);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_INTERNAL);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_STATE);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_HANDLE);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_QUERY);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNIMPLEMENTED);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNAVAILABLE);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_FREE_HANDLES);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_MEMORY);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_NULL);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_TIMEOUT);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_WOULD_BLOCK);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_ORDER);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_OUT_OF_RANGE);
+        AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_SERVICE);
+    }
+    return "Unrecognized AAudio error.";
+}
+
+AAUDIO_API const char * AAudio_convertStreamStateToText(aaudio_stream_state_t state) {
+    switch (state) {
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_UNINITIALIZED);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_UNKNOWN);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_OPEN);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STARTING);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STARTED);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_PAUSING);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_PAUSED);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_FLUSHING);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_FLUSHED);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STOPPING);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STOPPED);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSING);
+        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSED);
+    }
+    return "Unrecognized AAudio state.";
+}
+
+#undef AAUDIO_CASE_ENUM
+
+static AudioStream *convertAAudioStreamToAudioStream(AAudioStream* stream)
+{
+    return (AudioStream*) stream;
+}
+
+static AudioStreamBuilder *convertAAudioBuilderToStreamBuilder(AAudioStreamBuilder* builder)
+{
+    return (AudioStreamBuilder*) builder;
+}
+
+AAUDIO_API aaudio_result_t AAudio_createStreamBuilder(AAudioStreamBuilder** builder)
+{
+    ALOGD("AAudio_createStreamBuilder(): check sHandleTracker.isInitialized ()");
+    AudioStreamBuilder *audioStreamBuilder =  new AudioStreamBuilder();
+    if (audioStreamBuilder == nullptr) {
+        return AAUDIO_ERROR_NO_MEMORY;
+    }
+    *builder = (AAudioStreamBuilder*) audioStreamBuilder;
+    return AAUDIO_OK;
+}
+
+AAUDIO_API void AAudioStreamBuilder_setDeviceId(AAudioStreamBuilder* builder,
+                                                     int32_t deviceId)
+{
+    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);;
+    streamBuilder->setDeviceId(deviceId);
+}
+
+AAUDIO_API void AAudioStreamBuilder_setSampleRate(AAudioStreamBuilder* builder,
+                                              int32_t sampleRate)
+{
+    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);;
+    streamBuilder->setSampleRate(sampleRate);
+}
+
+AAUDIO_API void AAudioStreamBuilder_setSamplesPerFrame(AAudioStreamBuilder* builder,
+                                                   int32_t samplesPerFrame)
+{
+    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);;
+    streamBuilder->setSamplesPerFrame(samplesPerFrame);
+}
+
+AAUDIO_API void AAudioStreamBuilder_setDirection(AAudioStreamBuilder* builder,
+                                             aaudio_direction_t direction)
+{
+    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);;
+    streamBuilder->setDirection(direction);
+}
+
+
+AAUDIO_API void AAudioStreamBuilder_setFormat(AAudioStreamBuilder* builder,
+                                                   aaudio_audio_format_t format)
+{
+    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);;
+    streamBuilder->setFormat(format);
+}
+
+AAUDIO_API void AAudioStreamBuilder_setSharingMode(AAudioStreamBuilder* builder,
+                                                        aaudio_sharing_mode_t sharingMode)
+{
+    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);;
+    streamBuilder->setSharingMode(sharingMode);
+}
+
+AAUDIO_API void AAudioStreamBuilder_setBufferCapacityInFrames(AAudioStreamBuilder* builder,
+                                                        int32_t frames)
+{
+    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);;
+    streamBuilder->setBufferCapacity(frames);
+}
+
+static aaudio_result_t  AAudioInternal_openStream(AudioStreamBuilder *streamBuilder,
+                                              AAudioStream** streamPtr)
+{
+    AudioStream *audioStream = nullptr;
+    aaudio_result_t result = streamBuilder->build(&audioStream);
+    if (result != AAUDIO_OK) {
+        return result;
+    } else {
+        *streamPtr = (AAudioStream*) audioStream;
+        return AAUDIO_OK;
+    }
+}
+
+AAUDIO_API aaudio_result_t  AAudioStreamBuilder_openStream(AAudioStreamBuilder* builder,
+                                                     AAudioStream** streamPtr)
+{
+    ALOGD("AAudioStreamBuilder_openStream(): builder = %p", builder);
+    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(streamPtr);
+    return AAudioInternal_openStream(streamBuilder, streamPtr);
+}
+
+AAUDIO_API aaudio_result_t  AAudioStreamBuilder_delete(AAudioStreamBuilder* builder)
+{
+    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+    if (streamBuilder != nullptr) {
+        delete streamBuilder;
+        return AAUDIO_OK;
+    }
+    return AAUDIO_ERROR_INVALID_HANDLE;
+}
+
+AAUDIO_API aaudio_result_t  AAudioStream_close(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    ALOGD("AAudioStream_close(%p)", stream);
+    if (audioStream != nullptr) {
+        audioStream->close();
+        delete audioStream;
+        return AAUDIO_OK;
+    }
+    return AAUDIO_ERROR_INVALID_HANDLE;
+}
+
+AAUDIO_API aaudio_result_t  AAudioStream_requestStart(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    ALOGD("AAudioStream_requestStart(%p)", stream);
+    return audioStream->requestStart();
+}
+
+AAUDIO_API aaudio_result_t  AAudioStream_requestPause(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    ALOGD("AAudioStream_requestPause(%p)", stream);
+    return audioStream->requestPause();
+}
+
+AAUDIO_API aaudio_result_t  AAudioStream_requestFlush(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    ALOGD("AAudioStream_requestFlush(%p)", stream);
+    return audioStream->requestFlush();
+}
+
+AAUDIO_API aaudio_result_t  AAudioStream_requestStop(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    ALOGD("AAudioStream_requestStop(%p)", stream);
+    return audioStream->requestStop();
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_waitForStateChange(AAudioStream* stream,
+                                            aaudio_stream_state_t inputState,
+                                            aaudio_stream_state_t *nextState,
+                                            int64_t timeoutNanoseconds)
+{
+
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->waitForStateChange(inputState, nextState, timeoutNanoseconds);
+}
+
+// ============================================================
+// Stream - non-blocking I/O
+// ============================================================
+
+AAUDIO_API aaudio_result_t AAudioStream_read(AAudioStream* stream,
+                               void *buffer,
+                               int32_t numFrames,
+                               int64_t timeoutNanoseconds)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    if (buffer == nullptr) {
+        return AAUDIO_ERROR_NULL;
+    }
+    if (numFrames < 0) {
+        return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+    } else if (numFrames == 0) {
+        return 0;
+    }
+
+    aaudio_result_t result = audioStream->read(buffer, numFrames, timeoutNanoseconds);
+    // ALOGD("AAudioStream_read(): read returns %d", result);
+
+    return result;
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_write(AAudioStream* stream,
+                               const void *buffer,
+                               int32_t numFrames,
+                               int64_t timeoutNanoseconds)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    if (buffer == nullptr) {
+        return AAUDIO_ERROR_NULL;
+    }
+    if (numFrames < 0) {
+        return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+    } else if (numFrames == 0) {
+        return 0;
+    }
+
+    aaudio_result_t result = audioStream->write(buffer, numFrames, timeoutNanoseconds);
+    // ALOGD("AAudioStream_write(): write returns %d", result);
+
+    return result;
+}
+
+// ============================================================
+// Miscellaneous
+// ============================================================
+
+AAUDIO_API aaudio_result_t AAudioStream_createThread(AAudioStream* stream,
+                                     int64_t periodNanoseconds,
+                                     aaudio_audio_thread_proc_t threadProc, void *arg)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->createThread(periodNanoseconds, threadProc, arg);
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_joinThread(AAudioStream* stream,
+                                   void **returnArg,
+                                   int64_t timeoutNanoseconds)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->joinThread(returnArg, timeoutNanoseconds);
+}
+
+// ============================================================
+// Stream - queries
+// ============================================================
+
+AAUDIO_API int32_t AAudioStream_getSampleRate(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getSampleRate();
+}
+
+AAUDIO_API int32_t AAudioStream_getSamplesPerFrame(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getSamplesPerFrame();
+}
+
+AAUDIO_API aaudio_stream_state_t AAudioStream_getState(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getState();
+}
+
+AAUDIO_API aaudio_audio_format_t AAudioStream_getFormat(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getFormat();
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_setBufferSizeInFrames(AAudioStream* stream,
+                                                int32_t requestedFrames)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->setBufferSize(requestedFrames);
+}
+
+AAUDIO_API int32_t AAudioStream_getBufferSizeInFrames(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getBufferSize();
+}
+
+AAUDIO_API aaudio_direction_t AAudioStream_getDirection(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getDirection();
+}
+
+AAUDIO_API int32_t AAudioStream_getFramesPerBurst(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getFramesPerBurst();
+}
+
+AAUDIO_API int32_t AAudioStream_getBufferCapacityInFrames(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getBufferCapacity();
+}
+
+AAUDIO_API int32_t AAudioStream_getXRunCount(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getXRunCount();
+}
+
+AAUDIO_API int32_t AAudioStream_getDeviceId(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getDeviceId();
+}
+
+AAUDIO_API aaudio_sharing_mode_t AAudioStream_getSharingMode(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getSharingMode();
+}
+
+AAUDIO_API int64_t AAudioStream_getFramesWritten(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getFramesWritten();
+}
+
+AAUDIO_API int64_t AAudioStream_getFramesRead(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getFramesRead();
+}
+
+AAUDIO_API aaudio_result_t AAudioStream_getTimestamp(AAudioStream* stream,
+                                      clockid_t clockid,
+                                      int64_t *framePosition,
+                                      int64_t *timeNanoseconds)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    if (framePosition == nullptr) {
+        return AAUDIO_ERROR_NULL;
+    } else if (timeNanoseconds == nullptr) {
+        return AAUDIO_ERROR_NULL;
+    } else if (clockid != CLOCK_MONOTONIC && clockid != CLOCK_BOOTTIME) {
+        return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+    }
+
+    return audioStream->getTimestamp(clockid, framePosition, timeNanoseconds);
+}
diff --git a/media/liboboe/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
similarity index 91%
rename from media/liboboe/src/core/AudioStream.cpp
rename to media/libaaudio/src/core/AudioStream.cpp
index 77d3cc0..b054d94 100644
--- a/media/liboboe/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -52,7 +52,7 @@
 
 aaudio_result_t AudioStream::waitForStateTransition(aaudio_stream_state_t startingState,
                                                aaudio_stream_state_t endingState,
-                                               aaudio_nanoseconds_t timeoutNanoseconds)
+                                               int64_t timeoutNanoseconds)
 {
     aaudio_stream_state_t state = getState();
     aaudio_stream_state_t nextState = state;
@@ -73,10 +73,10 @@
 
 aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState,
                                                 aaudio_stream_state_t *nextState,
-                                                aaudio_nanoseconds_t timeoutNanoseconds)
+                                                int64_t timeoutNanoseconds)
 {
     // TODO replace this when similar functionality added to AudioTrack.cpp
-    aaudio_nanoseconds_t durationNanos = 20 * AAUDIO_NANOS_PER_MILLISECOND;
+    int64_t durationNanos = 20 * AAUDIO_NANOS_PER_MILLISECOND;
     aaudio_stream_state_t state = getState();
     while (state == currentState && timeoutNanoseconds > 0) {
         if (durationNanos > timeoutNanoseconds) {
@@ -120,8 +120,8 @@
     return audioStream->wrapUserThread();
 }
 
-aaudio_result_t AudioStream::createThread(aaudio_nanoseconds_t periodNanoseconds,
-                                     aaudio_audio_thread_proc_t *threadProc,
+aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds,
+                                     aaudio_audio_thread_proc_t threadProc,
                                      void* threadArg)
 {
     if (mHasThread) {
@@ -144,7 +144,7 @@
     }
 }
 
-aaudio_result_t AudioStream::joinThread(void** returnArg, aaudio_nanoseconds_t timeoutNanoseconds)
+aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds)
 {
     if (!mHasThread) {
         return AAUDIO_ERROR_INVALID_STATE;
diff --git a/media/liboboe/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
similarity index 69%
rename from media/liboboe/src/core/AudioStream.h
rename to media/libaaudio/src/core/AudioStream.h
index 8e4aa05..af0593d 100644
--- a/media/liboboe/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -52,8 +52,8 @@
 
     // TODO use aaudio_clockid_t all the way down to AudioClock
     virtual aaudio_result_t getTimestamp(clockid_t clockId,
-                                       aaudio_position_frames_t *framePosition,
-                                       aaudio_nanoseconds_t *timeNanoseconds) = 0;
+                                       int64_t *framePosition,
+                                       int64_t *timeNanoseconds) = 0;
 
 
     virtual aaudio_result_t updateState() = 0;
@@ -63,7 +63,7 @@
 
     virtual aaudio_result_t waitForStateChange(aaudio_stream_state_t currentState,
                                           aaudio_stream_state_t *nextState,
-                                          aaudio_nanoseconds_t timeoutNanoseconds);
+                                          int64_t timeoutNanoseconds);
 
     /**
      * Open the stream using the parameters in the builder.
@@ -79,16 +79,15 @@
         return AAUDIO_OK;
     }
 
-    virtual aaudio_result_t setBufferSize(aaudio_size_frames_t requestedFrames,
-                                        aaudio_size_frames_t *actualFrames) {
+    virtual aaudio_result_t setBufferSize(int32_t requestedFrames) {
         return AAUDIO_ERROR_UNIMPLEMENTED;
     }
 
-    virtual aaudio_result_t createThread(aaudio_nanoseconds_t periodNanoseconds,
-                                       aaudio_audio_thread_proc_t *threadProc,
+    virtual aaudio_result_t createThread(int64_t periodNanoseconds,
+                                       aaudio_audio_thread_proc_t threadProc,
                                        void *threadArg);
 
-    virtual aaudio_result_t joinThread(void **returnArg, aaudio_nanoseconds_t timeoutNanoseconds);
+    virtual aaudio_result_t joinThread(void **returnArg, int64_t timeoutNanoseconds);
 
     virtual aaudio_result_t registerThread() {
         return AAUDIO_OK;
@@ -106,19 +105,19 @@
 
     // ============== Queries ===========================
 
-    virtual aaudio_stream_state_t getState() const {
+    aaudio_stream_state_t getState() const {
         return mState;
     }
 
-    virtual aaudio_size_frames_t getBufferSize() const {
+    virtual int32_t getBufferSize() const {
         return AAUDIO_ERROR_UNIMPLEMENTED;
     }
 
-    virtual aaudio_size_frames_t getBufferCapacity() const {
+    virtual int32_t getBufferCapacity() const {
         return AAUDIO_ERROR_UNIMPLEMENTED;
     }
 
-    virtual aaudio_size_frames_t getFramesPerBurst() const {
+    virtual int32_t getFramesPerBurst() const {
         return AAUDIO_ERROR_UNIMPLEMENTED;
     }
 
@@ -142,7 +141,7 @@
         return mSamplesPerFrame;
     }
 
-    aaudio_device_id_t getDeviceId() const {
+    int32_t getDeviceId() const {
         return mDeviceId;
     }
 
@@ -154,19 +153,19 @@
         return mDirection;
     }
 
-    aaudio_size_bytes_t getBytesPerFrame() const {
+    int32_t getBytesPerFrame() const {
         return mSamplesPerFrame * getBytesPerSample();
     }
 
-    aaudio_size_bytes_t getBytesPerSample() const {
+    int32_t getBytesPerSample() const {
         return AAudioConvert_formatToSizeInBytes(mFormat);
     }
 
-    virtual aaudio_position_frames_t getFramesWritten() {
+    virtual int64_t getFramesWritten() {
         return mFramesWritten.get();
     }
 
-    virtual aaudio_position_frames_t getFramesRead() {
+    virtual int64_t getFramesRead() {
         return mFramesRead.get();
     }
 
@@ -174,25 +173,25 @@
     // ============== I/O ===========================
     // A Stream will only implement read() or write() depending on its direction.
     virtual aaudio_result_t write(const void *buffer,
-                             aaudio_size_frames_t numFrames,
-                             aaudio_nanoseconds_t timeoutNanoseconds) {
+                             int32_t numFrames,
+                             int64_t timeoutNanoseconds) {
         return AAUDIO_ERROR_UNIMPLEMENTED;
     }
 
     virtual aaudio_result_t read(void *buffer,
-                            aaudio_size_frames_t numFrames,
-                            aaudio_nanoseconds_t timeoutNanoseconds) {
+                            int32_t numFrames,
+                            int64_t timeoutNanoseconds) {
         return AAUDIO_ERROR_UNIMPLEMENTED;
     }
 
 protected:
 
-    virtual aaudio_position_frames_t incrementFramesWritten(aaudio_size_frames_t frames) {
-        return static_cast<aaudio_position_frames_t>(mFramesWritten.increment(frames));
+    virtual int64_t incrementFramesWritten(int32_t frames) {
+        return static_cast<int64_t>(mFramesWritten.increment(frames));
     }
 
-    virtual aaudio_position_frames_t incrementFramesRead(aaudio_size_frames_t frames) {
-        return static_cast<aaudio_position_frames_t>(mFramesRead.increment(frames));
+    virtual int64_t incrementFramesRead(int32_t frames) {
+        return static_cast<int64_t>(mFramesRead.increment(frames));
     }
 
     /**
@@ -202,13 +201,13 @@
      *   or AAUDIO_ERROR_TIMEOUT
      */
     virtual aaudio_result_t waitForStateTransition(aaudio_stream_state_t startingState,
-                                              aaudio_stream_state_t endingState,
-                                              aaudio_nanoseconds_t timeoutNanoseconds);
+                                                   aaudio_stream_state_t endingState,
+                                                   int64_t timeoutNanoseconds);
 
     /**
      * This should not be called after the open() call.
      */
-    void setSampleRate(aaudio_sample_rate_t sampleRate) {
+    void setSampleRate(int32_t sampleRate) {
         mSampleRate = sampleRate;
     }
 
@@ -243,33 +242,33 @@
     MonotonicCounter     mFramesWritten;
     MonotonicCounter     mFramesRead;
 
-    void setPeriodNanoseconds(aaudio_nanoseconds_t periodNanoseconds) {
+    void setPeriodNanoseconds(int64_t periodNanoseconds) {
         mPeriodNanoseconds.store(periodNanoseconds, std::memory_order_release);
     }
 
-    aaudio_nanoseconds_t getPeriodNanoseconds() {
+    int64_t getPeriodNanoseconds() {
         return mPeriodNanoseconds.load(std::memory_order_acquire);
     }
 
 private:
     // These do not change after open().
-    int32_t              mSamplesPerFrame = AAUDIO_UNSPECIFIED;
-    aaudio_sample_rate_t   mSampleRate = AAUDIO_UNSPECIFIED;
-    aaudio_stream_state_t  mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
-    aaudio_device_id_t     mDeviceId = AAUDIO_UNSPECIFIED;
-    aaudio_sharing_mode_t  mSharingMode = AAUDIO_SHARING_MODE_LEGACY;
+    int32_t                mSamplesPerFrame = AAUDIO_UNSPECIFIED;
+    int32_t                mSampleRate = AAUDIO_UNSPECIFIED;
+    int32_t                mDeviceId = AAUDIO_UNSPECIFIED;
+    aaudio_sharing_mode_t  mSharingMode = AAUDIO_SHARING_MODE_SHARED;
     aaudio_audio_format_t  mFormat = AAUDIO_FORMAT_UNSPECIFIED;
     aaudio_direction_t     mDirection = AAUDIO_DIRECTION_OUTPUT;
+    aaudio_stream_state_t  mState = AAUDIO_STREAM_STATE_UNINITIALIZED;
 
     // background thread ----------------------------------
-    bool                 mHasThread = false;
-    pthread_t            mThread; // initialized in constructor
+    bool                   mHasThread = false;
+    pthread_t              mThread; // initialized in constructor
 
     // These are set by the application thread and then read by the audio pthread.
-    std::atomic<aaudio_nanoseconds_t>  mPeriodNanoseconds; // for tuning SCHED_FIFO threads
+    std::atomic<int64_t>   mPeriodNanoseconds; // for tuning SCHED_FIFO threads
     // TODO make atomic?
-    aaudio_audio_thread_proc_t* mThreadProc = nullptr;
-    void*                mThreadArg = nullptr;
+    aaudio_audio_thread_proc_t mThreadProc = nullptr;
+    void*                  mThreadArg = nullptr;
     aaudio_result_t        mThreadRegistrationResult = AAUDIO_OK;
 
 
diff --git a/media/liboboe/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
similarity index 93%
rename from media/liboboe/src/core/AudioStreamBuilder.cpp
rename to media/libaaudio/src/core/AudioStreamBuilder.cpp
index decd53c..5a54e62 100644
--- a/media/liboboe/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -42,13 +42,12 @@
 }
 
 aaudio_result_t AudioStreamBuilder::build(AudioStream** streamPtr) {
-    // TODO Is there a better place to put the code that decides which class to use?
     AudioStream* audioStream = nullptr;
     const aaudio_sharing_mode_t sharingMode = getSharingMode();
     switch (getDirection()) {
     case AAUDIO_DIRECTION_INPUT:
         switch (sharingMode) {
-            case AAUDIO_SHARING_MODE_LEGACY:
+            case AAUDIO_SHARING_MODE_SHARED:
                 audioStream = new(std::nothrow) AudioStreamRecord();
                 break;
             default:
@@ -59,7 +58,7 @@
         break;
     case AAUDIO_DIRECTION_OUTPUT:
         switch (sharingMode) {
-            case AAUDIO_SHARING_MODE_LEGACY:
+            case AAUDIO_SHARING_MODE_SHARED:
                 audioStream = new(std::nothrow) AudioStreamTrack();
                 break;
             case AAUDIO_SHARING_MODE_EXCLUSIVE:
diff --git a/media/liboboe/src/core/AudioStreamBuilder.h b/media/libaaudio/src/core/AudioStreamBuilder.h
similarity index 76%
rename from media/liboboe/src/core/AudioStreamBuilder.h
rename to media/libaaudio/src/core/AudioStreamBuilder.h
index 9e1a1a7..7b5f35c 100644
--- a/media/liboboe/src/core/AudioStreamBuilder.h
+++ b/media/libaaudio/src/core/AudioStreamBuilder.h
@@ -56,11 +56,11 @@
         return this;
     }
 
-    aaudio_sample_rate_t getSampleRate() const {
+    int32_t getSampleRate() const {
         return mSampleRate;
     }
 
-    AudioStreamBuilder* setSampleRate(aaudio_sample_rate_t sampleRate) {
+    AudioStreamBuilder* setSampleRate(int32_t sampleRate) {
         mSampleRate = sampleRate;
         return this;
     }
@@ -83,11 +83,20 @@
         return this;
     }
 
-    aaudio_device_id_t getDeviceId() const {
+    int32_t getBufferCapacity() const {
+        return mBufferCapacity;
+    }
+
+    AudioStreamBuilder* setBufferCapacity(int32_t frames) {
+        mBufferCapacity = frames;
+        return this;
+    }
+
+    int32_t getDeviceId() const {
         return mDeviceId;
     }
 
-    AudioStreamBuilder* setDeviceId(aaudio_device_id_t deviceId) {
+    AudioStreamBuilder* setDeviceId(int32_t deviceId) {
         mDeviceId = deviceId;
         return this;
     }
@@ -95,12 +104,13 @@
     aaudio_result_t build(AudioStream **streamPtr);
 
 private:
-    int32_t              mSamplesPerFrame = AAUDIO_UNSPECIFIED;
-    aaudio_sample_rate_t   mSampleRate = AAUDIO_UNSPECIFIED;
-    aaudio_device_id_t     mDeviceId = AAUDIO_DEVICE_UNSPECIFIED;
-    aaudio_sharing_mode_t  mSharingMode = AAUDIO_SHARING_MODE_LEGACY;
+    int32_t                mSamplesPerFrame = AAUDIO_UNSPECIFIED;
+    int32_t                mSampleRate = AAUDIO_UNSPECIFIED;
+    int32_t                mDeviceId = AAUDIO_DEVICE_UNSPECIFIED;
+    aaudio_sharing_mode_t  mSharingMode = AAUDIO_SHARING_MODE_SHARED;
     aaudio_audio_format_t  mFormat = AAUDIO_FORMAT_UNSPECIFIED;
     aaudio_direction_t     mDirection = AAUDIO_DIRECTION_OUTPUT;
+    int32_t                mBufferCapacity = AAUDIO_UNSPECIFIED;
 };
 
 } /* namespace aaudio */
diff --git a/media/liboboe/src/core/README.md b/media/libaaudio/src/core/README.md
similarity index 100%
rename from media/liboboe/src/core/README.md
rename to media/libaaudio/src/core/README.md
diff --git a/media/liboboe/src/core/VersionExperiment.txt b/media/libaaudio/src/core/VersionExperiment.txt
similarity index 100%
rename from media/liboboe/src/core/VersionExperiment.txt
rename to media/libaaudio/src/core/VersionExperiment.txt
diff --git a/media/liboboe/src/fifo/FifoBuffer.cpp b/media/libaaudio/src/fifo/FifoBuffer.cpp
similarity index 100%
rename from media/liboboe/src/fifo/FifoBuffer.cpp
rename to media/libaaudio/src/fifo/FifoBuffer.cpp
diff --git a/media/liboboe/src/fifo/FifoBuffer.h b/media/libaaudio/src/fifo/FifoBuffer.h
similarity index 100%
rename from media/liboboe/src/fifo/FifoBuffer.h
rename to media/libaaudio/src/fifo/FifoBuffer.h
diff --git a/media/liboboe/src/fifo/FifoController.h b/media/libaaudio/src/fifo/FifoController.h
similarity index 100%
rename from media/liboboe/src/fifo/FifoController.h
rename to media/libaaudio/src/fifo/FifoController.h
diff --git a/media/liboboe/src/fifo/FifoControllerBase.cpp b/media/libaaudio/src/fifo/FifoControllerBase.cpp
similarity index 100%
rename from media/liboboe/src/fifo/FifoControllerBase.cpp
rename to media/libaaudio/src/fifo/FifoControllerBase.cpp
diff --git a/media/liboboe/src/fifo/FifoControllerBase.h b/media/libaaudio/src/fifo/FifoControllerBase.h
similarity index 100%
rename from media/liboboe/src/fifo/FifoControllerBase.h
rename to media/libaaudio/src/fifo/FifoControllerBase.h
diff --git a/media/liboboe/src/fifo/FifoControllerIndirect.h b/media/libaaudio/src/fifo/FifoControllerIndirect.h
similarity index 100%
rename from media/liboboe/src/fifo/FifoControllerIndirect.h
rename to media/libaaudio/src/fifo/FifoControllerIndirect.h
diff --git a/media/liboboe/src/fifo/README.md b/media/libaaudio/src/fifo/README.md
similarity index 100%
rename from media/liboboe/src/fifo/README.md
rename to media/libaaudio/src/fifo/README.md
diff --git a/media/liboboe/src/legacy/AAudioLegacy.h b/media/libaaudio/src/legacy/AAudioLegacy.h
similarity index 100%
rename from media/liboboe/src/legacy/AAudioLegacy.h
rename to media/libaaudio/src/legacy/AAudioLegacy.h
diff --git a/media/liboboe/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
similarity index 85%
rename from media/liboboe/src/legacy/AudioStreamRecord.cpp
rename to media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 2d1785f..dd040a0 100644
--- a/media/liboboe/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -60,6 +60,8 @@
     AudioRecord::callback_t callback = nullptr;
     audio_input_flags_t flags = (audio_input_flags_t) AUDIO_INPUT_FLAG_NONE;
 
+    size_t frameCount = (builder.getBufferCapacity() == AAUDIO_UNSPECIFIED) ? 0
+                        : builder.getBufferCapacity();
     // TODO implement an unspecified Android format then use that.
     audio_format_t format = (getFormat() == AAUDIO_UNSPECIFIED)
             ? AUDIO_FORMAT_PCM_FLOAT
@@ -70,20 +72,18 @@
             getSampleRate(),
             format,
             channelMask,
-
             mOpPackageName, // const String16& opPackageName TODO does not compile
-
-            0,    //    size_t frameCount = 0,
+            frameCount,
             callback,
             nullptr, //    void* user = nullptr,
             0,    //    uint32_t notificationFrames = 0,
             AUDIO_SESSION_ALLOCATE,
             AudioRecord::TRANSFER_DEFAULT,
             flags
-             //   int uid = -1,
-             //   pid_t pid = -1,
-             //   const audio_attributes_t* pAttributes = nullptr
-             );
+            //   int uid = -1,
+            //   pid_t pid = -1,
+            //   const audio_attributes_t* pAttributes = nullptr
+            );
 
     // Did we get a valid track?
     status_t status = mAudioRecord->initCheck();
@@ -177,11 +177,11 @@
 }
 
 aaudio_result_t AudioStreamRecord::read(void *buffer,
-                                      aaudio_size_frames_t numFrames,
-                                      aaudio_nanoseconds_t timeoutNanoseconds)
+                                      int32_t numFrames,
+                                      int64_t timeoutNanoseconds)
 {
-    aaudio_size_frames_t bytesPerFrame = getBytesPerFrame();
-    aaudio_size_bytes_t numBytes;
+    int32_t bytesPerFrame = getBytesPerFrame();
+    int32_t numBytes;
     aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes);
     if (result != AAUDIO_OK) {
         return result;
@@ -195,25 +195,23 @@
     } else if (bytesRead < 0) {
         return AAudioConvert_androidToAAudioResult(bytesRead);
     }
-    aaudio_size_frames_t framesRead = (aaudio_size_frames_t)(bytesRead / bytesPerFrame);
+    int32_t framesRead = (int32_t)(bytesRead / bytesPerFrame);
     return (aaudio_result_t) framesRead;
 }
 
-aaudio_result_t AudioStreamRecord::setBufferSize(aaudio_size_frames_t requestedFrames,
-                                             aaudio_size_frames_t *actualFrames)
+aaudio_result_t AudioStreamRecord::setBufferSize(int32_t requestedFrames)
 {
-    *actualFrames = getBufferCapacity();
-    return AAUDIO_OK;
+    return getBufferSize();
 }
 
-aaudio_size_frames_t AudioStreamRecord::getBufferSize() const
+int32_t AudioStreamRecord::getBufferSize() const
 {
     return getBufferCapacity(); // TODO implement in AudioRecord?
 }
 
-aaudio_size_frames_t AudioStreamRecord::getBufferCapacity() const
+int32_t AudioStreamRecord::getBufferCapacity() const
 {
-    return static_cast<aaudio_size_frames_t>(mAudioRecord->frameCount());
+    return static_cast<int32_t>(mAudioRecord->frameCount());
 }
 
 int32_t AudioStreamRecord::getXRunCount() const
@@ -221,7 +219,7 @@
     return AAUDIO_ERROR_UNIMPLEMENTED; // TODO implement when AudioRecord supports it
 }
 
-aaudio_size_frames_t AudioStreamRecord::getFramesPerBurst() const
+int32_t AudioStreamRecord::getFramesPerBurst() const
 {
     return 192; // TODO add query to AudioRecord.cpp
 }
diff --git a/media/liboboe/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h
similarity index 72%
rename from media/liboboe/src/legacy/AudioStreamRecord.h
rename to media/libaaudio/src/legacy/AudioStreamRecord.h
index a2ac9f3..c8d389b 100644
--- a/media/liboboe/src/legacy/AudioStreamRecord.h
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.h
@@ -44,25 +44,24 @@
     virtual aaudio_result_t requestStop() override;
 
     virtual aaudio_result_t getTimestamp(clockid_t clockId,
-                                       aaudio_position_frames_t *framePosition,
-                                       aaudio_nanoseconds_t *timeNanoseconds) override {
+                                       int64_t *framePosition,
+                                       int64_t *timeNanoseconds) override {
         return AAUDIO_ERROR_UNIMPLEMENTED; // TODO
     }
 
     virtual aaudio_result_t read(void *buffer,
-                             aaudio_size_frames_t numFrames,
-                             aaudio_nanoseconds_t timeoutNanoseconds) override;
+                             int32_t numFrames,
+                             int64_t timeoutNanoseconds) override;
 
-    virtual aaudio_result_t setBufferSize(aaudio_size_frames_t requestedFrames,
-                                             aaudio_size_frames_t *actualFrames) override;
+    virtual aaudio_result_t setBufferSize(int32_t requestedFrames) override;
 
-    virtual aaudio_size_frames_t getBufferSize() const override;
+    virtual int32_t getBufferSize() const override;
 
-    virtual aaudio_size_frames_t getBufferCapacity() const override;
+    virtual int32_t getBufferCapacity() const override;
 
     virtual int32_t getXRunCount() const override;
 
-    virtual aaudio_size_frames_t getFramesPerBurst() const override;
+    virtual int32_t getFramesPerBurst() const override;
 
     virtual aaudio_result_t updateState() override;
 
@@ -70,7 +69,7 @@
     android::sp<android::AudioRecord> mAudioRecord;
     // TODO add 64-bit position reporting to AudioRecord and use it.
     aaudio_wrapping_frames_t   mPositionWhenStarting = 0;
-    android::String16        mOpPackageName;
+    android::String16          mOpPackageName;
 };
 
 } /* namespace aaudio */
diff --git a/media/liboboe/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
similarity index 89%
rename from media/liboboe/src/legacy/AudioStreamTrack.cpp
rename to media/libaaudio/src/legacy/AudioStreamTrack.cpp
index a60b5b4..e0a04c3 100644
--- a/media/liboboe/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -64,7 +64,8 @@
     AudioTrack::callback_t callback = nullptr;
     // TODO add more performance options
     audio_output_flags_t flags = (audio_output_flags_t) AUDIO_OUTPUT_FLAG_FAST;
-    size_t frameCount = 0;
+    size_t frameCount = (builder.getBufferCapacity() == AAUDIO_UNSPECIFIED) ? 0
+                        : builder.getBufferCapacity();
     // TODO implement an unspecified AudioTrack format then use that.
     audio_format_t format = (getFormat() == AAUDIO_UNSPECIFIED)
             ? AUDIO_FORMAT_PCM_FLOAT
@@ -220,11 +221,11 @@
 }
 
 aaudio_result_t AudioStreamTrack::write(const void *buffer,
-                                      aaudio_size_frames_t numFrames,
-                                      aaudio_nanoseconds_t timeoutNanoseconds)
+                                      int32_t numFrames,
+                                      int64_t timeoutNanoseconds)
 {
-    aaudio_size_frames_t bytesPerFrame = getBytesPerFrame();
-    aaudio_size_bytes_t numBytes;
+    int32_t bytesPerFrame = getBytesPerFrame();
+    int32_t numBytes;
     aaudio_result_t result = AAudioConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes);
     if (result != AAUDIO_OK) {
         return result;
@@ -239,31 +240,29 @@
         ALOGE("invalid write, returned %d", (int)bytesWritten);
         return AAudioConvert_androidToAAudioResult(bytesWritten);
     }
-    aaudio_size_frames_t framesWritten = (aaudio_size_frames_t)(bytesWritten / bytesPerFrame);
+    int32_t framesWritten = (int32_t)(bytesWritten / bytesPerFrame);
     incrementFramesWritten(framesWritten);
     return framesWritten;
 }
 
-aaudio_result_t AudioStreamTrack::setBufferSize(aaudio_size_frames_t requestedFrames,
-                                             aaudio_size_frames_t *actualFrames)
+aaudio_result_t AudioStreamTrack::setBufferSize(int32_t requestedFrames)
 {
     ssize_t result = mAudioTrack->setBufferSizeInFrames(requestedFrames);
-    if (result != OK) {
+    if (result < 0) {
         return AAudioConvert_androidToAAudioResult(result);
     } else {
-        *actualFrames = result;
-        return AAUDIO_OK;
+        return result;
     }
 }
 
-aaudio_size_frames_t AudioStreamTrack::getBufferSize() const
+int32_t AudioStreamTrack::getBufferSize() const
 {
-    return static_cast<aaudio_size_frames_t>(mAudioTrack->getBufferSizeInFrames());
+    return static_cast<int32_t>(mAudioTrack->getBufferSizeInFrames());
 }
 
-aaudio_size_frames_t AudioStreamTrack::getBufferCapacity() const
+int32_t AudioStreamTrack::getBufferCapacity() const
 {
-    return static_cast<aaudio_size_frames_t>(mAudioTrack->frameCount());
+    return static_cast<int32_t>(mAudioTrack->frameCount());
 }
 
 int32_t AudioStreamTrack::getXRunCount() const
@@ -276,7 +275,7 @@
     return 192; // TODO add query to AudioTrack.cpp
 }
 
-aaudio_position_frames_t AudioStreamTrack::getFramesRead() {
+int64_t AudioStreamTrack::getFramesRead() {
     aaudio_wrapping_frames_t position;
     status_t result;
     switch (getState()) {
diff --git a/media/liboboe/src/legacy/AudioStreamTrack.h b/media/libaaudio/src/legacy/AudioStreamTrack.h
similarity index 68%
rename from media/liboboe/src/legacy/AudioStreamTrack.h
rename to media/libaaudio/src/legacy/AudioStreamTrack.h
index 73d0cac..1de07ce 100644
--- a/media/liboboe/src/legacy/AudioStreamTrack.h
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.h
@@ -46,31 +46,30 @@
     virtual aaudio_result_t requestStop() override;
 
     virtual aaudio_result_t getTimestamp(clockid_t clockId,
-                                       aaudio_position_frames_t *framePosition,
-                                       aaudio_nanoseconds_t *timeNanoseconds) override {
+                                       int64_t *framePosition,
+                                       int64_t *timeNanoseconds) override {
         return AAUDIO_ERROR_UNIMPLEMENTED; // TODO call getTimestamp(ExtendedTimestamp *timestamp);
     }
 
     virtual aaudio_result_t write(const void *buffer,
-                             aaudio_size_frames_t numFrames,
-                             aaudio_nanoseconds_t timeoutNanoseconds) override;
+                             int32_t numFrames,
+                             int64_t timeoutNanoseconds) override;
 
-    virtual aaudio_result_t setBufferSize(aaudio_size_frames_t requestedFrames,
-                                             aaudio_size_frames_t *actualFrames) override;
-    virtual aaudio_size_frames_t getBufferSize() const override;
-    virtual aaudio_size_frames_t getBufferCapacity() const override;
-    virtual aaudio_size_frames_t getFramesPerBurst()const  override;
+    virtual aaudio_result_t setBufferSize(int32_t requestedFrames) override;
+    virtual int32_t getBufferSize() const override;
+    virtual int32_t getBufferCapacity() const override;
+    virtual int32_t getFramesPerBurst()const  override;
     virtual int32_t getXRunCount() const override;
 
-    virtual aaudio_position_frames_t getFramesRead() override;
+    virtual int64_t getFramesRead() override;
 
     virtual aaudio_result_t updateState() override;
 
 private:
     android::sp<android::AudioTrack> mAudioTrack;
     // TODO add 64-bit position reporting to AudioRecord and use it.
-    aaudio_wrapping_frames_t           mPositionWhenStarting = 0;
-    aaudio_wrapping_frames_t           mPositionWhenPausing = 0;
+    aaudio_wrapping_frames_t         mPositionWhenStarting = 0;
+    aaudio_wrapping_frames_t         mPositionWhenPausing = 0;
 };
 
 } /* namespace aaudio */
diff --git a/media/liboboe/src/legacy/README.md b/media/libaaudio/src/legacy/README.md
similarity index 100%
rename from media/liboboe/src/legacy/README.md
rename to media/libaaudio/src/legacy/README.md
diff --git a/media/liboboe/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
similarity index 92%
rename from media/liboboe/src/utility/AAudioUtilities.cpp
rename to media/libaaudio/src/utility/AAudioUtilities.cpp
index 34c1ae4..26fa75d 100644
--- a/media/liboboe/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -27,8 +27,8 @@
 
 using namespace android;
 
-aaudio_size_bytes_t AAudioConvert_formatToSizeInBytes(aaudio_audio_format_t format) {
-    aaudio_size_bytes_t size = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+int32_t AAudioConvert_formatToSizeInBytes(aaudio_audio_format_t format) {
+    int32_t size = AAUDIO_ERROR_ILLEGAL_ARGUMENT;
     switch (format) {
         case AAUDIO_FORMAT_PCM_I16:
             size = sizeof(int16_t);
@@ -172,12 +172,12 @@
     return aaudioFormat;
 }
 
-aaudio_size_bytes_t AAudioConvert_framesToBytes(aaudio_size_frames_t numFrames,
-                                            aaudio_size_bytes_t bytesPerFrame,
-                                            aaudio_size_bytes_t *sizeInBytes) {
+int32_t AAudioConvert_framesToBytes(int32_t numFrames,
+                                            int32_t bytesPerFrame,
+                                            int32_t *sizeInBytes) {
     // TODO implement more elegantly
     const int32_t maxChannels = 256; // ridiculously large
-    const aaudio_size_frames_t maxBytesPerFrame = maxChannels * sizeof(float);
+    const int32_t maxBytesPerFrame = maxChannels * sizeof(float);
     // Prevent overflow by limiting multiplicands.
     if (bytesPerFrame > maxBytesPerFrame || numFrames > (0x3FFFFFFF / maxBytesPerFrame)) {
         ALOGE("size overflow, numFrames = %d, frameSize = %zd", numFrames, bytesPerFrame);
diff --git a/media/liboboe/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
similarity index 85%
rename from media/liboboe/src/utility/AAudioUtilities.h
rename to media/libaaudio/src/utility/AAudioUtilities.h
index 38696df..d3b5ffe 100644
--- a/media/liboboe/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -46,9 +46,9 @@
  * @param sizeInBytes total size in bytes
  * @return AAUDIO_OK or negative error, eg. AAUDIO_ERROR_OUT_OF_RANGE
  */
-aaudio_size_bytes_t AAudioConvert_framesToBytes(aaudio_size_frames_t numFrames,
-                                            aaudio_size_bytes_t bytesPerFrame,
-                                            aaudio_size_bytes_t *sizeInBytes);
+int32_t AAudioConvert_framesToBytes(int32_t numFrames,
+                                            int32_t bytesPerFrame,
+                                            int32_t *sizeInBytes);
 
 audio_format_t AAudioConvert_aaudioToAndroidDataFormat(aaudio_audio_format_t aaudio_format);
 
@@ -57,6 +57,6 @@
 /**
  * @return the size of a sample of the given format in bytes or AAUDIO_ERROR_ILLEGAL_ARGUMENT
  */
-aaudio_size_bytes_t AAudioConvert_formatToSizeInBytes(aaudio_audio_format_t format);
+int32_t AAudioConvert_formatToSizeInBytes(aaudio_audio_format_t format);
 
 #endif //UTILITY_AAUDIO_UTILITIES_H
diff --git a/media/liboboe/src/utility/AudioClock.h b/media/libaaudio/src/utility/AudioClock.h
similarity index 86%
rename from media/liboboe/src/utility/AudioClock.h
rename to media/libaaudio/src/utility/AudioClock.h
index 9ac21d3..952c7b8 100644
--- a/media/liboboe/src/utility/AudioClock.h
+++ b/media/libaaudio/src/utility/AudioClock.h
@@ -22,9 +22,15 @@
 
 #include <aaudio/AAudioDefinitions.h>
 
+// Time conversion constants.
+#define AAUDIO_NANOS_PER_MICROSECOND ((int64_t)1000)
+#define AAUDIO_NANOS_PER_MILLISECOND (AAUDIO_NANOS_PER_MICROSECOND * 1000)
+#define AAUDIO_MILLIS_PER_SECOND     1000
+#define AAUDIO_NANOS_PER_SECOND      (AAUDIO_NANOS_PER_MILLISECOND * AAUDIO_MILLIS_PER_SECOND)
+
 class AudioClock {
 public:
-    static aaudio_nanoseconds_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
+    static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
         struct timespec time;
         int result = clock_gettime(clockId, &time);
         if (result < 0) {
@@ -42,7 +48,7 @@
      * @param clockId CLOCK_MONOTONIC is default
      * @return 0, a negative error, or 1 if the call is interrupted by a signal handler (EINTR)
      */
-    static int sleepUntilNanoTime(aaudio_nanoseconds_t nanoTime,
+    static int sleepUntilNanoTime(int64_t nanoTime,
                                   clockid_t clockId = CLOCK_MONOTONIC) {
         if (nanoTime > 0) {
             struct timespec time;
@@ -72,7 +78,7 @@
      * @param clockId CLOCK_MONOTONIC is default
      * @return 0, a negative error, or 1 if the call is interrupted by a signal handler (EINTR)
      */
-    static int sleepForNanos(aaudio_nanoseconds_t nanoseconds, clockid_t clockId = CLOCK_MONOTONIC) {
+    static int sleepForNanos(int64_t nanoseconds, clockid_t clockId = CLOCK_MONOTONIC) {
         if (nanoseconds > 0) {
             struct timespec time;
             time.tv_sec = nanoseconds / AAUDIO_NANOS_PER_SECOND;
diff --git a/media/liboboe/src/utility/HandleTracker.cpp b/media/libaaudio/src/utility/HandleTracker.cpp
similarity index 100%
rename from media/liboboe/src/utility/HandleTracker.cpp
rename to media/libaaudio/src/utility/HandleTracker.cpp
diff --git a/media/liboboe/src/utility/HandleTracker.h b/media/libaaudio/src/utility/HandleTracker.h
similarity index 99%
rename from media/liboboe/src/utility/HandleTracker.h
rename to media/libaaudio/src/utility/HandleTracker.h
index c80860c..23a73ed 100644
--- a/media/liboboe/src/utility/HandleTracker.h
+++ b/media/libaaudio/src/utility/HandleTracker.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <utils/Mutex.h>
 
+typedef int32_t  aaudio_handle_t;
 typedef int32_t  handle_tracker_type_t;       // what kind of handle
 typedef int32_t  handle_tracker_slot_t;       // index in allocation table
 typedef int32_t  handle_tracker_generation_t; // incremented when slot used
diff --git a/media/liboboe/src/utility/MonotonicCounter.h b/media/libaaudio/src/utility/MonotonicCounter.h
similarity index 100%
rename from media/liboboe/src/utility/MonotonicCounter.h
rename to media/libaaudio/src/utility/MonotonicCounter.h
diff --git a/media/liboboe/src/utility/README.md b/media/libaaudio/src/utility/README.md
similarity index 100%
rename from media/liboboe/src/utility/README.md
rename to media/libaaudio/src/utility/README.md
diff --git a/media/libaaudio/tests/Android.mk b/media/libaaudio/tests/Android.mk
new file mode 100644
index 0000000..7899cf5
--- /dev/null
+++ b/media/libaaudio/tests/Android.mk
@@ -0,0 +1,29 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/av/media/libaaudio/include \
+    frameworks/av/media/libaaudio/src/core \
+    frameworks/av/media/libaaudio/src/utility
+LOCAL_SRC_FILES:= test_handle_tracker.cpp
+LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \
+                          libcutils liblog libmedia libutils
+LOCAL_STATIC_LIBRARIES := libaaudio
+LOCAL_MODULE := test_handle_tracker
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils) \
+    frameworks/av/media/libaaudio/include \
+    frameworks/av/media/libaaudio/src \
+    frameworks/av/media/libaaudio/src/core \
+    frameworks/av/media/libaaudio/src/fifo \
+    frameworks/av/media/libaaudio/src/utility
+LOCAL_SRC_FILES:= test_marshalling.cpp
+LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \
+                          libcutils liblog libmedia libutils
+LOCAL_STATIC_LIBRARIES := libaaudio
+LOCAL_MODULE := test_marshalling
+include $(BUILD_NATIVE_TEST)
diff --git a/media/liboboe/tests/test_handle_tracker.cpp b/media/libaaudio/tests/test_handle_tracker.cpp
similarity index 100%
rename from media/liboboe/tests/test_handle_tracker.cpp
rename to media/libaaudio/tests/test_handle_tracker.cpp
diff --git a/media/liboboe/tests/test_marshalling.cpp b/media/libaaudio/tests/test_marshalling.cpp
similarity index 100%
rename from media/liboboe/tests/test_marshalling.cpp
rename to media/libaaudio/tests/test_marshalling.cpp
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 03dce0c..ad130e0 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -26,6 +26,8 @@
         "libaudioutils",
     ],
     export_shared_lib_headers: ["libbinder"],
+    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
     // for memory heap analysis
     static_libs: [
         "libc_malloc_debug_backtrace",
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 0de3559..f878be9 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -556,7 +556,7 @@
     mFramesWritten = 0;
     mFramesWrittenServerOffset = 0;
     mFramesWrittenAtRestore = -1; // -1 is a unique initializer.
-
+    mVolumeHandler = new VolumeHandler();
     return NO_ERROR;
 }
 
@@ -2250,6 +2250,20 @@
                 }
             }
         }
+        // restore volume handler
+        mVolumeHandler->forall([this](const sp<VolumeShaper::Configuration> &configuration,
+                const sp<VolumeShaper::Operation> &operation) -> VolumeShaper::Status {
+            sp<VolumeShaper::Operation> operationToEnd = new VolumeShaper::Operation(*operation);
+            // TODO: Ideally we would restore to the exact xOffset position
+            // as returned by getVolumeShaperState(), but we don't have that
+            // information when restoring at the client unless we periodically poll
+            // the server or create shared memory state.
+            //
+            // For now, we simply advance to the end of the VolumeShaper effect.
+            operationToEnd->setXOffset(1.f);
+            return mAudioTrack->applyVolumeShaper(configuration, operationToEnd);
+        });
+
         if (mState == STATE_ACTIVE) {
             result = mAudioTrack->start();
         }
@@ -2310,6 +2324,28 @@
     return mAudioTrack->setParameters(keyValuePairs);
 }
 
+VolumeShaper::Status AudioTrack::applyVolumeShaper(
+        const sp<VolumeShaper::Configuration>& configuration,
+        const sp<VolumeShaper::Operation>& operation)
+{
+    AutoMutex lock(mLock);
+    mVolumeHandler->setIdIfNecessary(configuration);
+    VolumeShaper::Status status = mAudioTrack->applyVolumeShaper(configuration, operation);
+    if (status >= 0) {
+        // save VolumeShaper for restore
+        mVolumeHandler->applyVolumeShaper(configuration, operation);
+    }
+    return status;
+}
+
+sp<VolumeShaper::State> AudioTrack::getVolumeShaperState(int id)
+{
+    // TODO: To properly restore the AudioTrack
+    // we will need to save the last state in AudioTrackShared.
+    AutoMutex lock(mLock);
+    return mAudioTrack->getVolumeShaperState(id);
+}
+
 status_t AudioTrack::getTimestamp(ExtendedTimestamp *timestamp)
 {
     if (timestamp == nullptr) {
diff --git a/media/libaudioclient/IAudioTrack.cpp b/media/libaudioclient/IAudioTrack.cpp
index 89e0fcc..79e864d 100644
--- a/media/libaudioclient/IAudioTrack.cpp
+++ b/media/libaudioclient/IAudioTrack.cpp
@@ -39,6 +39,8 @@
     SET_PARAMETERS,
     GET_TIMESTAMP,
     SIGNAL,
+    APPLY_VOLUME_SHAPER,
+    GET_VOLUME_SHAPER_STATE,
 };
 
 class BpAudioTrack : public BpInterface<IAudioTrack>
@@ -143,6 +145,52 @@
         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
         remote()->transact(SIGNAL, data, &reply);
     }
+
+    virtual VolumeShaper::Status applyVolumeShaper(
+            const sp<VolumeShaper::Configuration>& configuration,
+            const sp<VolumeShaper::Operation>& operation) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+
+        status_t status = configuration.get() == nullptr
+                ? data.writeInt32(0)
+                :  data.writeInt32(1)
+                    ?: configuration->writeToParcel(&data);
+        if (status != NO_ERROR) {
+            return VolumeShaper::Status(status);
+        }
+
+        status = operation.get() == nullptr
+                ? status = data.writeInt32(0)
+                : data.writeInt32(1)
+                    ?: operation->writeToParcel(&data);
+        if (status != NO_ERROR) {
+            return VolumeShaper::Status(status);
+        }
+
+        int32_t remoteVolumeShaperStatus;
+        status = remote()->transact(APPLY_VOLUME_SHAPER, data, &reply)
+                 ?: reply.readInt32(&remoteVolumeShaperStatus);
+
+        return VolumeShaper::Status(status ?: remoteVolumeShaperStatus);
+    }
+
+    virtual sp<VolumeShaper::State> getVolumeShaperState(int id) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+
+        data.writeInt32(id);
+        status_t status = remote()->transact(GET_VOLUME_SHAPER_STATE, data, &reply);
+        if (status != NO_ERROR) {
+            return nullptr;
+        }
+        sp<VolumeShaper::State> state = new VolumeShaper::State;
+        status = state->readFromParcel(reply);
+        if (status != NO_ERROR) {
+            return nullptr;
+        }
+        return state;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack");
@@ -206,6 +254,40 @@
             signal();
             return NO_ERROR;
         } break;
+        case APPLY_VOLUME_SHAPER: {
+            CHECK_INTERFACE(IAudioTrack, data, reply);
+            sp<VolumeShaper::Configuration> configuration;
+            sp<VolumeShaper::Operation> operation;
+
+            int32_t present;
+            status_t status = data.readInt32(&present);
+            if (status == NO_ERROR && present != 0) {
+                configuration = new VolumeShaper::Configuration();
+                status = configuration->readFromParcel(data);
+            }
+            status = status ?: data.readInt32(&present);
+            if (status == NO_ERROR && present != 0) {
+                operation = new VolumeShaper::Operation();
+                status = operation->readFromParcel(data);
+            }
+            if (status == NO_ERROR) {
+                status = (status_t)applyVolumeShaper(configuration, operation);
+            }
+            reply->writeInt32(status);
+            return NO_ERROR;
+        } break;
+        case GET_VOLUME_SHAPER_STATE: {
+            CHECK_INTERFACE(IAudioTrack, data, reply);
+            int id;
+            status_t status = data.readInt32(&id);
+            if (status == NO_ERROR) {
+                sp<VolumeShaper::State> state = getVolumeShaperState(id);
+                if (state.get() != nullptr) {
+                     status = state->writeToParcel(reply);
+                }
+            }
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/include/media/AudioBufferProvider.h b/media/libaudioclient/include/AudioBufferProvider.h
similarity index 100%
rename from include/media/AudioBufferProvider.h
rename to media/libaudioclient/include/AudioBufferProvider.h
diff --git a/include/media/AudioEffect.h b/media/libaudioclient/include/AudioEffect.h
similarity index 100%
rename from include/media/AudioEffect.h
rename to media/libaudioclient/include/AudioEffect.h
diff --git a/include/media/AudioIoDescriptor.h b/media/libaudioclient/include/AudioIoDescriptor.h
similarity index 100%
rename from include/media/AudioIoDescriptor.h
rename to media/libaudioclient/include/AudioIoDescriptor.h
diff --git a/include/media/AudioMixer.h b/media/libaudioclient/include/AudioMixer.h
similarity index 100%
rename from include/media/AudioMixer.h
rename to media/libaudioclient/include/AudioMixer.h
diff --git a/include/media/AudioParameter.h b/media/libaudioclient/include/AudioParameter.h
similarity index 100%
rename from include/media/AudioParameter.h
rename to media/libaudioclient/include/AudioParameter.h
diff --git a/include/media/AudioPolicy.h b/media/libaudioclient/include/AudioPolicy.h
similarity index 100%
rename from include/media/AudioPolicy.h
rename to media/libaudioclient/include/AudioPolicy.h
diff --git a/include/media/AudioPolicyHelper.h b/media/libaudioclient/include/AudioPolicyHelper.h
similarity index 100%
rename from include/media/AudioPolicyHelper.h
rename to media/libaudioclient/include/AudioPolicyHelper.h
diff --git a/include/media/AudioRecord.h b/media/libaudioclient/include/AudioRecord.h
similarity index 100%
rename from include/media/AudioRecord.h
rename to media/libaudioclient/include/AudioRecord.h
diff --git a/include/media/AudioSystem.h b/media/libaudioclient/include/AudioSystem.h
similarity index 99%
rename from include/media/AudioSystem.h
rename to media/libaudioclient/include/AudioSystem.h
index 4c64242..853d318 100644
--- a/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/AudioSystem.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_AUDIOSYSTEM_H_
 #define ANDROID_AUDIOSYSTEM_H_
 
+#include <sys/types.h>
+
 #include <media/AudioPolicy.h>
 #include <media/AudioIoDescriptor.h>
 #include <media/IAudioFlingerClient.h>
diff --git a/include/media/AudioTimestamp.h b/media/libaudioclient/include/AudioTimestamp.h
similarity index 100%
rename from include/media/AudioTimestamp.h
rename to media/libaudioclient/include/AudioTimestamp.h
diff --git a/include/media/AudioTrack.h b/media/libaudioclient/include/AudioTrack.h
similarity index 98%
rename from include/media/AudioTrack.h
rename to media/libaudioclient/include/AudioTrack.h
index cd33a44..0358363 100644
--- a/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/AudioTrack.h
@@ -732,6 +732,14 @@
     /* Set parameters - only possible when using direct output */
             status_t    setParameters(const String8& keyValuePairs);
 
+    /* Sets the volume shaper object */
+            VolumeShaper::Status applyVolumeShaper(
+                    const sp<VolumeShaper::Configuration>& configuration,
+                    const sp<VolumeShaper::Operation>& operation);
+
+    /* Gets the volume shaper state */
+            sp<VolumeShaper::State> getVolumeShaperState(int id);
+
     /* Get parameters */
             String8     getParameters(const String8& keys);
 
@@ -1118,6 +1126,8 @@
     //  a value of AUDIO_PORT_HANDLE_NONE indicated default (AudioPolicyManager) routing.
     audio_port_handle_t     mSelectedDeviceId;
 
+    sp<VolumeHandler>       mVolumeHandler;
+
 private:
     class DeathNotifier : public IBinder::DeathRecipient {
     public:
diff --git a/include/media/IAudioFlinger.h b/media/libaudioclient/include/IAudioFlinger.h
similarity index 100%
rename from include/media/IAudioFlinger.h
rename to media/libaudioclient/include/IAudioFlinger.h
diff --git a/include/media/IAudioFlingerClient.h b/media/libaudioclient/include/IAudioFlingerClient.h
similarity index 100%
rename from include/media/IAudioFlingerClient.h
rename to media/libaudioclient/include/IAudioFlingerClient.h
diff --git a/include/media/IAudioPolicyService.h b/media/libaudioclient/include/IAudioPolicyService.h
similarity index 100%
rename from include/media/IAudioPolicyService.h
rename to media/libaudioclient/include/IAudioPolicyService.h
diff --git a/include/media/IAudioPolicyServiceClient.h b/media/libaudioclient/include/IAudioPolicyServiceClient.h
similarity index 100%
rename from include/media/IAudioPolicyServiceClient.h
rename to media/libaudioclient/include/IAudioPolicyServiceClient.h
diff --git a/include/media/IAudioRecord.h b/media/libaudioclient/include/IAudioRecord.h
similarity index 100%
rename from include/media/IAudioRecord.h
rename to media/libaudioclient/include/IAudioRecord.h
diff --git a/include/media/IAudioTrack.h b/media/libaudioclient/include/IAudioTrack.h
similarity index 89%
rename from include/media/IAudioTrack.h
rename to media/libaudioclient/include/IAudioTrack.h
index a31cec6..27a62d6 100644
--- a/include/media/IAudioTrack.h
+++ b/media/libaudioclient/include/IAudioTrack.h
@@ -26,6 +26,7 @@
 #include <binder/IMemory.h>
 #include <utils/String8.h>
 #include <media/AudioTimestamp.h>
+#include <media/VolumeShaper.h>
 
 namespace android {
 
@@ -74,6 +75,14 @@
 
     /* Signal the playback thread for a change in control block */
     virtual void        signal() = 0;
+
+    /* Sets the volume shaper */
+    virtual VolumeShaper::Status applyVolumeShaper(
+            const sp<VolumeShaper::Configuration>& configuration,
+            const sp<VolumeShaper::Operation>& operation) = 0;
+
+    /* gets the volume shaper state */
+    virtual sp<VolumeShaper::State> getVolumeShaperState(int id) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/IEffect.h b/media/libaudioclient/include/IEffect.h
similarity index 100%
rename from include/media/IEffect.h
rename to media/libaudioclient/include/IEffect.h
diff --git a/include/media/IEffectClient.h b/media/libaudioclient/include/IEffectClient.h
similarity index 100%
rename from include/media/IEffectClient.h
rename to media/libaudioclient/include/IEffectClient.h
diff --git a/include/media/ToneGenerator.h b/media/libaudioclient/include/ToneGenerator.h
similarity index 100%
rename from include/media/ToneGenerator.h
rename to media/libaudioclient/include/ToneGenerator.h
diff --git a/media/libaudiohal/Android.mk b/media/libaudiohal/Android.mk
index 5e00b77..032b3e9 100644
--- a/media/libaudiohal/Android.mk
+++ b/media/libaudiohal/Android.mk
@@ -45,11 +45,17 @@
     android.hardware.audio.common@2.0      \
     android.hardware.audio.common@2.0-util \
     android.hardware.audio.effect@2.0      \
+    android.hidl.allocator@1.0             \
     android.hidl.memory@1.0                \
-    libmedia_helper
+    libmedia_helper  \
+    libmediautils
 
 endif  # USE_LEGACY_LOCAL_AUDIO_HAL
 
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
 LOCAL_MODULE := libaudiohal
 
 LOCAL_CFLAGS := -Wall -Werror
diff --git a/media/libaudiohal/ConversionHelperHidl.h b/media/libaudiohal/ConversionHelperHidl.h
index 23fb360..a991baf 100644
--- a/media/libaudiohal/ConversionHelperHidl.h
+++ b/media/libaudiohal/ConversionHelperHidl.h
@@ -56,17 +56,19 @@
     }
 
     status_t processReturn(const char* funcName, const Return<hardware::audio::V2_0::Result>& ret) {
-        return processReturn(funcName, ret, ret);
+        if (!ret.isOk()) {
+            emitError(funcName, ret.description().c_str());
+        }
+        return ret.isOk() ? analyzeResult(ret) : FAILED_TRANSACTION;
     }
 
     template<typename T>
     status_t processReturn(
             const char* funcName, const Return<T>& ret, hardware::audio::V2_0::Result retval) {
-        const status_t st = ret.isOk() ? analyzeResult(retval) : FAILED_TRANSACTION;
         if (!ret.isOk()) {
             emitError(funcName, ret.description().c_str());
         }
-        return st;
+        return ret.isOk() ? analyzeResult(retval) : FAILED_TRANSACTION;
     }
 
   private:
diff --git a/media/libaudiohal/DeviceHalHidl.cpp b/media/libaudiohal/DeviceHalHidl.cpp
index dcedfd3..71fbd98 100644
--- a/media/libaudiohal/DeviceHalHidl.cpp
+++ b/media/libaudiohal/DeviceHalHidl.cpp
@@ -21,6 +21,7 @@
 
 #include <android/hardware/audio/2.0/IPrimaryDevice.h>
 #include <cutils/native_handle.h>
+#include <hwbinder/IPCThreadState.h>
 #include <utils/Log.h>
 
 #include "DeviceHalHidl.h"
@@ -101,6 +102,10 @@
 }
 
 DeviceHalHidl::~DeviceHalHidl() {
+    if (mDevice != 0) {
+        mDevice.clear();
+        hardware::IPCThreadState::self()->flushCommands();
+    }
 }
 
 status_t DeviceHalHidl::getSupportedDevices(uint32_t*) {
diff --git a/media/libaudiohal/DevicesFactoryHalHidl.cpp b/media/libaudiohal/DevicesFactoryHalHidl.cpp
index b0f28b9..9cbe018 100644
--- a/media/libaudiohal/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/DevicesFactoryHalHidl.cpp
@@ -40,7 +40,7 @@
 }
 
 DevicesFactoryHalHidl::DevicesFactoryHalHidl() {
-    mDevicesFactory = IDevicesFactory::getService("audio_devices_factory");
+    mDevicesFactory = IDevicesFactory::getService();
     if (mDevicesFactory != 0) {
         // It is assumet that DevicesFactory is owned by AudioFlinger
         // and thus have the same lifespan.
diff --git a/media/libaudiohal/EffectBufferHalHidl.cpp b/media/libaudiohal/EffectBufferHalHidl.cpp
index 82b4a75..ce581f2 100644
--- a/media/libaudiohal/EffectBufferHalHidl.cpp
+++ b/media/libaudiohal/EffectBufferHalHidl.cpp
@@ -19,7 +19,7 @@
 #define LOG_TAG "EffectBufferHalHidl"
 //#define LOG_NDEBUG 0
 
-#include <android/hidl/memory/1.0/IAllocator.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
 #include <hidlmemory/mapping.h>
 #include <utils/Log.h>
 
@@ -28,7 +28,7 @@
 
 using ::android::hardware::Return;
 using ::android::hardware::Status;
-using ::android::hidl::memory::V1_0::IAllocator;
+using ::android::hidl::allocator::V1_0::IAllocator;
 
 namespace android {
 
diff --git a/media/libaudiohal/EffectHalHidl.cpp b/media/libaudiohal/EffectHalHidl.cpp
index d74ef8a..db115ef 100644
--- a/media/libaudiohal/EffectHalHidl.cpp
+++ b/media/libaudiohal/EffectHalHidl.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "EffectHalHidl"
 //#define LOG_NDEBUG 0
 
+#include <hwbinder/IPCThreadState.h>
 #include <media/EffectsFactoryApi.h>
 #include <utils/Log.h>
 
@@ -26,8 +27,12 @@
 #include "HidlUtils.h"
 
 using ::android::hardware::audio::effect::V2_0::AudioBuffer;
+using ::android::hardware::audio::effect::V2_0::EffectBufferAccess;
+using ::android::hardware::audio::effect::V2_0::EffectConfigParameters;
 using ::android::hardware::audio::effect::V2_0::MessageQueueFlagBits;
 using ::android::hardware::audio::effect::V2_0::Result;
+using ::android::hardware::audio::common::V2_0::AudioChannelMask;
+using ::android::hardware::audio::common::V2_0::AudioFormat;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::MQDescriptorSync;
 using ::android::hardware::Return;
@@ -40,7 +45,11 @@
 }
 
 EffectHalHidl::~EffectHalHidl() {
-    close();
+    if (mEffect != 0) {
+        close();
+        mEffect.clear();
+        hardware::IPCThreadState::self()->flushCommands();
+    }
 }
 
 // static
@@ -56,6 +65,46 @@
             descriptor.implementor.data(), descriptor.implementor.size());
 }
 
+// TODO(mnaganov): These buffer conversion functions should be shared with Effect wrapper
+// via HidlUtils. Move them there when hardware/interfaces will get un-frozen again.
+
+// static
+void EffectHalHidl::effectBufferConfigFromHal(
+        const buffer_config_t& halConfig, EffectBufferConfig* config) {
+    config->samplingRateHz = halConfig.samplingRate;
+    config->channels = AudioChannelMask(halConfig.channels);
+    config->format = AudioFormat(halConfig.format);
+    config->accessMode = EffectBufferAccess(halConfig.accessMode);
+    config->mask = EffectConfigParameters(halConfig.mask);
+}
+
+// static
+void EffectHalHidl::effectBufferConfigToHal(
+        const EffectBufferConfig& config, buffer_config_t* halConfig) {
+    halConfig->buffer.frameCount = 0;
+    halConfig->buffer.raw = NULL;
+    halConfig->samplingRate = config.samplingRateHz;
+    halConfig->channels = static_cast<uint32_t>(config.channels);
+    halConfig->bufferProvider.cookie = NULL;
+    halConfig->bufferProvider.getBuffer = NULL;
+    halConfig->bufferProvider.releaseBuffer = NULL;
+    halConfig->format = static_cast<uint8_t>(config.format);
+    halConfig->accessMode = static_cast<uint8_t>(config.accessMode);
+    halConfig->mask = static_cast<uint8_t>(config.mask);
+}
+
+// static
+void EffectHalHidl::effectConfigFromHal(const effect_config_t& halConfig, EffectConfig* config) {
+    effectBufferConfigFromHal(halConfig.inputCfg, &config->inputCfg);
+    effectBufferConfigFromHal(halConfig.outputCfg, &config->outputCfg);
+}
+
+// static
+void EffectHalHidl::effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig) {
+    effectBufferConfigToHal(config.inputCfg, &halConfig->inputCfg);
+    effectBufferConfigToHal(config.outputCfg, &halConfig->outputCfg);
+}
+
 // static
 status_t EffectHalHidl::analyzeResult(const Result& result) {
     switch (result) {
@@ -135,7 +184,7 @@
     uint32_t efState = 0;
 retry:
     status_t ret = mEfGroup->wait(
-            static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING), &efState, NS_PER_SEC);
+            static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING), &efState);
     if (efState & static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING)) {
         Result retval = Result::NOT_INITIALIZED;
         mStatusMQ->read(&retval);
@@ -166,6 +215,15 @@
 status_t EffectHalHidl::command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
         uint32_t *replySize, void *pReplyData) {
     if (mEffect == 0) return NO_INIT;
+
+    // Special cases.
+    if (cmdCode == EFFECT_CMD_SET_CONFIG || cmdCode == EFFECT_CMD_SET_CONFIG_REVERSE) {
+        return setConfigImpl(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
+    } else if (cmdCode == EFFECT_CMD_GET_CONFIG || cmdCode == EFFECT_CMD_GET_CONFIG_REVERSE) {
+        return getConfigImpl(cmdCode, replySize, pReplyData);
+    }
+
+    // Common case.
     hidl_vec<uint8_t> hidlData;
     if (pCmdData != nullptr && cmdSize > 0) {
         hidlData.setToExternal(reinterpret_cast<uint8_t*>(pCmdData), cmdSize);
@@ -205,4 +263,58 @@
     return ret.isOk() ? analyzeResult(ret) : FAILED_TRANSACTION;
 }
 
+status_t EffectHalHidl::getConfigImpl(
+        uint32_t cmdCode, uint32_t *replySize, void *pReplyData) {
+    if (replySize == NULL || *replySize != sizeof(effect_config_t) || pReplyData == NULL) {
+        return BAD_VALUE;
+    }
+    status_t result = FAILED_TRANSACTION;
+    Return<void> ret;
+    if (cmdCode == EFFECT_CMD_GET_CONFIG) {
+        ret = mEffect->getConfig([&] (Result r, const EffectConfig &hidlConfig) {
+            result = analyzeResult(r);
+            if (r == Result::OK) {
+                effectConfigToHal(hidlConfig, static_cast<effect_config_t*>(pReplyData));
+            }
+        });
+    } else {
+        ret = mEffect->getConfigReverse([&] (Result r, const EffectConfig &hidlConfig) {
+            result = analyzeResult(r);
+            if (r == Result::OK) {
+                effectConfigToHal(hidlConfig, static_cast<effect_config_t*>(pReplyData));
+            }
+        });
+    }
+    if (!ret.isOk()) {
+        result = FAILED_TRANSACTION;
+    }
+    return result;
+}
+
+status_t EffectHalHidl::setConfigImpl(
+        uint32_t cmdCode, uint32_t cmdSize, void *pCmdData, uint32_t *replySize, void *pReplyData) {
+    if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) ||
+            replySize == NULL || *replySize != sizeof(int32_t) || pReplyData == NULL) {
+        return BAD_VALUE;
+    }
+    const effect_config_t *halConfig = static_cast<effect_config_t*>(pCmdData);
+    if (halConfig->inputCfg.bufferProvider.getBuffer != NULL ||
+            halConfig->inputCfg.bufferProvider.releaseBuffer != NULL ||
+            halConfig->outputCfg.bufferProvider.getBuffer != NULL ||
+            halConfig->outputCfg.bufferProvider.releaseBuffer != NULL) {
+        ALOGE("Buffer provider callbacks are not supported");
+    }
+    EffectConfig hidlConfig;
+    effectConfigFromHal(*halConfig, &hidlConfig);
+    Return<Result> ret = cmdCode == EFFECT_CMD_SET_CONFIG ?
+            mEffect->setConfig(hidlConfig, nullptr, nullptr) :
+            mEffect->setConfigReverse(hidlConfig, nullptr, nullptr);
+    status_t result = FAILED_TRANSACTION;
+    if (ret.isOk()) {
+        result = analyzeResult(ret);
+        *static_cast<int32_t*>(pReplyData) = result;
+    }
+    return result;
+}
+
 } // namespace android
diff --git a/media/libaudiohal/EffectHalHidl.h b/media/libaudiohal/EffectHalHidl.h
index 1ed1153..c8db36f 100644
--- a/media/libaudiohal/EffectHalHidl.h
+++ b/media/libaudiohal/EffectHalHidl.h
@@ -23,6 +23,8 @@
 #include <fmq/MessageQueue.h>
 #include <system/audio_effect.h>
 
+using ::android::hardware::audio::effect::V2_0::EffectBufferConfig;
+using ::android::hardware::audio::effect::V2_0::EffectConfig;
 using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
 using ::android::hardware::audio::effect::V2_0::IEffect;
 using ::android::hardware::EventFlag;
@@ -75,6 +77,12 @@
     EventFlag* mEfGroup;
 
     static status_t analyzeResult(const hardware::audio::effect::V2_0::Result& result);
+    static void effectBufferConfigFromHal(
+            const buffer_config_t& halConfig, EffectBufferConfig* config);
+    static void effectBufferConfigToHal(
+            const EffectBufferConfig& config, buffer_config_t* halConfig);
+    static void effectConfigFromHal(const effect_config_t& halConfig, EffectConfig* config);
+    static void effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig);
 
     // Can not be constructed directly by clients.
     EffectHalHidl(const sp<IEffect>& effect, uint64_t effectId);
@@ -82,8 +90,12 @@
     // The destructor automatically releases the effect.
     virtual ~EffectHalHidl();
 
+    status_t getConfigImpl(uint32_t cmdCode, uint32_t *replySize, void *pReplyData);
     status_t prepareForProcessing();
     status_t processImpl(uint32_t mqFlag);
+    status_t setConfigImpl(
+            uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
+            uint32_t *replySize, void *pReplyData);
     status_t setProcessBuffers();
 };
 
diff --git a/media/libaudiohal/EffectsFactoryHalHidl.cpp b/media/libaudiohal/EffectsFactoryHalHidl.cpp
index ad12654..950f9dc 100644
--- a/media/libaudiohal/EffectsFactoryHalHidl.cpp
+++ b/media/libaudiohal/EffectsFactoryHalHidl.cpp
@@ -17,9 +17,7 @@
 #define LOG_TAG "EffectsFactoryHalHidl"
 //#define LOG_NDEBUG 0
 
-#include <android/hidl/memory/1.0/IAllocator.h>
 #include <cutils/native_handle.h>
-#include <hidl/ServiceManagement.h>
 #include <media/EffectsFactoryApi.h>
 
 #include "ConversionHelperHidl.h"
@@ -45,12 +43,8 @@
     return EffectIsNullUuid(pEffectUuid);
 }
 
-EffectsFactoryHalHidl::EffectsFactoryHalHidl() : ConversionHelperHidl("EffectsFactory"){
-    mEffectsFactory = IEffectsFactory::getService("audio_effects_factory");
-    // TODO: Waiting should not be needed (b/34772726).
-    // Also remove include of IAllocator.h and ServiceManagement.h
-    android::hardware::details::waitForHwService(
-            hidl::memory::V1_0::IAllocator::descriptor, "ashmem");
+EffectsFactoryHalHidl::EffectsFactoryHalHidl() : ConversionHelperHidl("EffectsFactory") {
+    mEffectsFactory = IEffectsFactory::getService();
 }
 
 EffectsFactoryHalHidl::~EffectsFactoryHalHidl() {
diff --git a/media/libaudiohal/StreamHalHidl.cpp b/media/libaudiohal/StreamHalHidl.cpp
index 9ee8fa8..77ba716 100644
--- a/media/libaudiohal/StreamHalHidl.cpp
+++ b/media/libaudiohal/StreamHalHidl.cpp
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-#include <time.h>
-
 #define LOG_TAG "StreamHalHidl"
 //#define LOG_NDEBUG 0
 
 #include <android/hardware/audio/2.0/IStreamOutCallback.h>
+#include <hwbinder/IPCThreadState.h>
+#include <mediautils/SchedulingPolicyService.h>
 #include <utils/Log.h>
 
 #include "DeviceHalHidl.h"
@@ -28,6 +28,7 @@
 
 using ::android::hardware::audio::common::V2_0::AudioChannelMask;
 using ::android::hardware::audio::common::V2_0::AudioFormat;
+using ::android::hardware::audio::common::V2_0::ThreadInfo;
 using ::android::hardware::audio::V2_0::AudioDrain;
 using ::android::hardware::audio::V2_0::IStreamOutCallback;
 using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
@@ -35,18 +36,18 @@
 using ::android::hardware::audio::V2_0::MmapPosition;
 using ::android::hardware::audio::V2_0::ParameterValue;
 using ::android::hardware::audio::V2_0::Result;
-using ::android::hardware::audio::V2_0::ThreadPriority;
 using ::android::hardware::audio::V2_0::TimeSpec;
 using ::android::hardware::MQDescriptorSync;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
+using ReadCommand = ::android::hardware::audio::V2_0::IStreamIn::ReadCommand;
 
 namespace android {
 
 StreamHalHidl::StreamHalHidl(IStream *stream)
         : ConversionHelperHidl("Stream"),
-          mHalThreadPriority(static_cast<int>(ThreadPriority::NORMAL)),
-          mStream(stream) {
+          mStream(stream),
+          mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT) {
 }
 
 StreamHalHidl::~StreamHalHidl() {
@@ -188,6 +189,19 @@
     return OK;
 }
 
+bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
+    if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
+        return true;
+    }
+    int err = requestPriority(
+            threadPid, threadId,
+            mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
+    ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
+            mHalThreadPriority, threadPid, threadId, err);
+    // Audio will still work, but latency will be higher and sometimes unacceptable.
+    return err == 0;
+}
+
 namespace {
 
 /* Notes on callback ownership.
@@ -241,8 +255,7 @@
 }  // namespace
 
 StreamOutHalHidl::StreamOutHalHidl(const sp<IStreamOut>& stream)
-        : StreamHalHidl(stream.get()), mStream(stream), mEfGroup(nullptr),
-          mGetPresentationPositionNotSupported(false), mPPosFromWrite{ 0, OK, 0, { 0, 0 } } {
+        : StreamHalHidl(stream.get()), mStream(stream), mWriterClient(0), mEfGroup(nullptr) {
 }
 
 StreamOutHalHidl::~StreamOutHalHidl() {
@@ -251,8 +264,10 @@
             processReturn("clearCallback", mStream->clearCallback());
         }
         processReturn("close", mStream->close());
+        mStream.clear();
     }
     mCallback.clear();
+    hardware::IPCThreadState::self()->flushCommands();
     if (mEfGroup) {
         EventFlag::deleteEventFlag(&mEfGroup);
     }
@@ -265,7 +280,15 @@
 
 status_t StreamOutHalHidl::getLatency(uint32_t *latency) {
     if (mStream == 0) return NO_INIT;
-    return processReturn("getLatency", mStream->getLatency(), latency);
+    if (mWriterClient == gettid() && mCommandMQ) {
+        return callWriterThread(
+                WriteCommand::GET_LATENCY, "getLatency", nullptr, 0,
+                [&](const WriteStatus& writeStatus) {
+                    *latency = writeStatus.reply.latencyMs;
+                });
+    } else {
+        return processReturn("getLatency", mStream->getLatency(), latency);
+    }
 }
 
 status_t StreamOutHalHidl::setVolume(float left, float right) {
@@ -288,37 +311,54 @@
         return status;
     }
 
-    const size_t availBytes = mDataMQ->availableToWrite();
-    if (bytes > availBytes) { bytes = availBytes; }
-    if (!mDataMQ->write(static_cast<const uint8_t*>(buffer), bytes)) {
-        ALOGW("data message queue write failed");
+    return callWriterThread(
+            WriteCommand::WRITE, "write", static_cast<const uint8_t*>(buffer), bytes,
+            [&] (const WriteStatus& writeStatus) {
+                *written = writeStatus.reply.written;
+                // Diagnostics of the cause of b/35813113.
+                ALOGE_IF(*written > bytes,
+                        "hal reports more bytes written than asked for: %lld > %lld",
+                        (long long)*written, (long long)bytes);
+            });
+}
+
+status_t StreamOutHalHidl::callWriterThread(
+        WriteCommand cmd, const char* cmdName,
+        const uint8_t* data, size_t dataSize, StreamOutHalHidl::WriterCallback callback) {
+    if (!mCommandMQ->write(&cmd)) {
+        ALOGE("command message queue write failed for \"%s\"", cmdName);
+        return -EAGAIN;
+    }
+    if (data != nullptr) {
+        size_t availableToWrite = mDataMQ->availableToWrite();
+        if (dataSize > availableToWrite) {
+            ALOGW("truncating write data from %lld to %lld due to insufficient data queue space",
+                    (long long)dataSize, (long long)availableToWrite);
+            dataSize = availableToWrite;
+        }
+        if (!mDataMQ->write(data, dataSize)) {
+            ALOGE("data message queue write failed for \"%s\"", cmdName);
+        }
     }
     mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
 
     // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
     uint32_t efState = 0;
 retry:
-    status_t ret = mEfGroup->wait(
-            static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState, NS_PER_SEC);
+    status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
     if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL)) {
-        WriteStatus writeStatus =
-                { Result::NOT_INITIALIZED, 0, Result::NOT_INITIALIZED, 0, { 0, 0 } };
-        mStatusMQ->read(&writeStatus);
-        if (writeStatus.writeRetval == Result::OK) {
-            status = OK;
-            *written = writeStatus.written;
-            mPPosFromWrite.status = processReturn(
-                    "get_presentation_position", writeStatus.presentationPositionRetval);
-            if (mPPosFromWrite.status == OK) {
-                mPPosFromWrite.frames = writeStatus.frames;
-                mPPosFromWrite.ts.tv_sec = writeStatus.timeStamp.tvSec;
-                mPPosFromWrite.ts.tv_nsec = writeStatus.timeStamp.tvNSec;
-            }
-            mPPosFromWrite.obtained = getCurrentTimeMs();
-        } else {
-            status = processReturn("write", writeStatus.writeRetval);
+        WriteStatus writeStatus;
+        writeStatus.retval = Result::NOT_INITIALIZED;
+        if (!mStatusMQ->read(&writeStatus)) {
+            ALOGE("status message read failed for \"%s\"", cmdName);
         }
-        return status;
+        if (writeStatus.retval == Result::OK) {
+            ret = OK;
+            callback(writeStatus);
+        } else {
+            ret = processReturn(cmdName, writeStatus.retval);
+        }
+        return ret;
     }
     if (ret == -EAGAIN) {
         // This normally retries no more than once.
@@ -327,35 +367,41 @@
     return ret;
 }
 
-uint64_t StreamOutHalHidl::getCurrentTimeMs() {
-    struct timespec timeNow;
-    clock_gettime(CLOCK_MONOTONIC, &timeNow);
-    return timeNow.tv_sec * 1000000 + timeNow.tv_nsec / 1000;
-}
-
 status_t StreamOutHalHidl::prepareForWriting(size_t bufferSize) {
+    std::unique_ptr<CommandMQ> tempCommandMQ;
     std::unique_ptr<DataMQ> tempDataMQ;
     std::unique_ptr<StatusMQ> tempStatusMQ;
     Result retval;
+    pid_t halThreadPid, halThreadTid;
     Return<void> ret = mStream->prepareForWriting(
-            1, bufferSize, ThreadPriority(mHalThreadPriority),
+            1, bufferSize,
             [&](Result r,
+                    const CommandMQ::Descriptor& commandMQ,
                     const DataMQ::Descriptor& dataMQ,
-                    const StatusMQ::Descriptor& statusMQ) {
+                    const StatusMQ::Descriptor& statusMQ,
+                    const ThreadInfo& halThreadInfo) {
                 retval = r;
                 if (retval == Result::OK) {
+                    tempCommandMQ.reset(new CommandMQ(commandMQ));
                     tempDataMQ.reset(new DataMQ(dataMQ));
                     tempStatusMQ.reset(new StatusMQ(statusMQ));
                     if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
                         EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
                     }
+                    halThreadPid = halThreadInfo.pid;
+                    halThreadTid = halThreadInfo.tid;
                 }
             });
     if (!ret.isOk() || retval != Result::OK) {
         return processReturn("prepareForWriting", ret, retval);
     }
-    if (!tempDataMQ || !tempDataMQ->isValid() || !tempStatusMQ || !tempStatusMQ->isValid()
-        || !mEfGroup) {
+    if (!tempCommandMQ || !tempCommandMQ->isValid() ||
+            !tempDataMQ || !tempDataMQ->isValid() ||
+            !tempStatusMQ || !tempStatusMQ->isValid() ||
+            !mEfGroup) {
+        ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
+        ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
+                "Command message queue for writing is invalid");
         ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for writing");
         ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for writing is invalid");
         ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for writing");
@@ -364,8 +410,12 @@
         ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
         return NO_INIT;
     }
+    requestHalThreadPriority(halThreadPid, halThreadTid);
+
+    mCommandMQ = std::move(tempCommandMQ);
     mDataMQ = std::move(tempDataMQ);
     mStatusMQ = std::move(tempStatusMQ);
+    mWriterClient = gettid();
     return OK;
 }
 
@@ -443,31 +493,27 @@
 
 status_t StreamOutHalHidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
     if (mStream == 0) return NO_INIT;
-    if (mGetPresentationPositionNotSupported) return INVALID_OPERATION;
-    if (getCurrentTimeMs() - mPPosFromWrite.obtained <= 1000) {
-        // No more than 1 ms passed since the last write, use cached result to avoid binder calls.
-        if (mPPosFromWrite.status == OK) {
-            *frames = mPPosFromWrite.frames;
-            timestamp->tv_sec = mPPosFromWrite.ts.tv_sec;
-            timestamp->tv_nsec = mPPosFromWrite.ts.tv_nsec;
-        }
-        return mPPosFromWrite.status;
+    if (mWriterClient == gettid() && mCommandMQ) {
+        return callWriterThread(
+                WriteCommand::GET_PRESENTATION_POSITION, "getPresentationPosition", nullptr, 0,
+                [&](const WriteStatus& writeStatus) {
+                    *frames = writeStatus.reply.presentationPosition.frames;
+                    timestamp->tv_sec = writeStatus.reply.presentationPosition.timeStamp.tvSec;
+                    timestamp->tv_nsec = writeStatus.reply.presentationPosition.timeStamp.tvNSec;
+                });
+    } else {
+        Result retval;
+        Return<void> ret = mStream->getPresentationPosition(
+                [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
+                    retval = r;
+                    if (retval == Result::OK) {
+                        *frames = hidlFrames;
+                        timestamp->tv_sec = hidlTimeStamp.tvSec;
+                        timestamp->tv_nsec = hidlTimeStamp.tvNSec;
+                    }
+                });
+        return processReturn("getPresentationPosition", ret, retval);
     }
-
-    Result retval;
-    Return<void> ret = mStream->getPresentationPosition(
-            [&](Result r, uint64_t hidlFrames, const TimeSpec& hidlTimeStamp) {
-                retval = r;
-                if (retval == Result::OK) {
-                    *frames = hidlFrames;
-                    timestamp->tv_sec = hidlTimeStamp.tvSec;
-                    timestamp->tv_nsec = hidlTimeStamp.tvNSec;
-                }
-            });
-    if (ret.isOk() && retval == Result::NOT_SUPPORTED) {
-        mGetPresentationPositionNotSupported = true;
-    }
-    return processReturn("getPresentationPosition", ret, retval);
 }
 
 void StreamOutHalHidl::onWriteReady() {
@@ -493,12 +539,14 @@
 
 
 StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
-        : StreamHalHidl(stream.get()), mStream(stream), mEfGroup(nullptr) {
+        : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
 }
 
 StreamInHalHidl::~StreamInHalHidl() {
     if (mStream != 0) {
         processReturn("close", mStream->close());
+        mStream.clear();
+        hardware::IPCThreadState::self()->flushCommands();
     }
     if (mEfGroup) {
         EventFlag::deleteEventFlag(&mEfGroup);
@@ -525,33 +573,52 @@
     }
 
     status_t status;
-    if (!mDataMQ) {
-        if ((status = prepareForReading(bytes)) != OK) return status;
-        // Trigger the first read.
-        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
+    if (!mDataMQ && (status = prepareForReading(bytes)) != OK) {
+        return status;
     }
 
+    ReadParameters params;
+    params.command = ReadCommand::READ;
+    params.params.read = bytes;
+    return callReaderThread(params, "read",
+            [&](const ReadStatus& readStatus) {
+                const size_t availToRead = mDataMQ->availableToRead();
+                if (!mDataMQ->read(static_cast<uint8_t*>(buffer), std::min(bytes, availToRead))) {
+                    ALOGE("data message queue read failed for \"read\"");
+                }
+                ALOGW_IF(availToRead != readStatus.reply.read,
+                        "HAL read report inconsistent: mq = %d, status = %d",
+                        (int32_t)availToRead, (int32_t)readStatus.reply.read);
+                *read = readStatus.reply.read;
+            });
+}
+
+status_t StreamInHalHidl::callReaderThread(
+        const ReadParameters& params, const char* cmdName,
+        StreamInHalHidl::ReaderCallback callback) {
+    if (!mCommandMQ->write(&params)) {
+        ALOGW("command message queue write failed");
+        return -EAGAIN;
+    }
+    mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
+
     // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
     uint32_t efState = 0;
 retry:
-    status_t ret = mEfGroup->wait(
-            static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState, NS_PER_SEC);
+    status_t ret = mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
     if (efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY)) {
-        ReadStatus readStatus = { Result::NOT_INITIALIZED, 0 };
-        const size_t availToRead = mDataMQ->availableToRead();
-        if (bytes > availToRead) { bytes = availToRead; }
-        mDataMQ->read(static_cast<uint8_t*>(buffer), bytes);
-        mStatusMQ->read(&readStatus);
-        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
-        if (readStatus.retval == Result::OK) {
-            ALOGW_IF(availToRead != readStatus.read,
-                    "HAL read report inconsistent: mq = %d, status = %d",
-                    (int32_t)availToRead, (int32_t)readStatus.read);
-            *read = readStatus.read;
-        } else {
-            status = processReturn("read", readStatus.retval);
+        ReadStatus readStatus;
+        readStatus.retval = Result::NOT_INITIALIZED;
+        if (!mStatusMQ->read(&readStatus)) {
+            ALOGE("status message read failed for \"%s\"", cmdName);
         }
-        return status;
+         if (readStatus.retval == Result::OK) {
+            ret = OK;
+            callback(readStatus);
+        } else {
+            ret = processReturn(cmdName, readStatus.retval);
+        }
+        return ret;
     }
     if (ret == -EAGAIN) {
         // This normally retries no more than once.
@@ -561,28 +628,40 @@
 }
 
 status_t StreamInHalHidl::prepareForReading(size_t bufferSize) {
+    std::unique_ptr<CommandMQ> tempCommandMQ;
     std::unique_ptr<DataMQ> tempDataMQ;
     std::unique_ptr<StatusMQ> tempStatusMQ;
     Result retval;
+    pid_t halThreadPid, halThreadTid;
     Return<void> ret = mStream->prepareForReading(
-            1, bufferSize, ThreadPriority(mHalThreadPriority),
+            1, bufferSize,
             [&](Result r,
+                    const CommandMQ::Descriptor& commandMQ,
                     const DataMQ::Descriptor& dataMQ,
-                    const StatusMQ::Descriptor& statusMQ) {
+                    const StatusMQ::Descriptor& statusMQ,
+                    const ThreadInfo& halThreadInfo) {
                 retval = r;
                 if (retval == Result::OK) {
+                    tempCommandMQ.reset(new CommandMQ(commandMQ));
                     tempDataMQ.reset(new DataMQ(dataMQ));
                     tempStatusMQ.reset(new StatusMQ(statusMQ));
                     if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
                         EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
                     }
+                    halThreadPid = halThreadInfo.pid;
+                    halThreadTid = halThreadInfo.tid;
                 }
             });
     if (!ret.isOk() || retval != Result::OK) {
         return processReturn("prepareForReading", ret, retval);
     }
-    if (!tempDataMQ || !tempDataMQ->isValid() || !tempStatusMQ || !tempStatusMQ->isValid()
-        || !mEfGroup) {
+    if (!tempCommandMQ || !tempCommandMQ->isValid() ||
+            !tempDataMQ || !tempDataMQ->isValid() ||
+            !tempStatusMQ || !tempStatusMQ->isValid() ||
+            !mEfGroup) {
+        ALOGE_IF(!tempCommandMQ, "Failed to obtain command message queue for writing");
+        ALOGE_IF(tempCommandMQ && !tempCommandMQ->isValid(),
+                "Command message queue for writing is invalid");
         ALOGE_IF(!tempDataMQ, "Failed to obtain data message queue for reading");
         ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "Data message queue for reading is invalid");
         ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for reading");
@@ -591,8 +670,12 @@
         ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
         return NO_INIT;
     }
+    requestHalThreadPriority(halThreadPid, halThreadTid);
+
+    mCommandMQ = std::move(tempCommandMQ);
     mDataMQ = std::move(tempDataMQ);
     mStatusMQ = std::move(tempStatusMQ);
+    mReaderClient = gettid();
     return OK;
 }
 
@@ -603,16 +686,26 @@
 
 status_t StreamInHalHidl::getCapturePosition(int64_t *frames, int64_t *time) {
     if (mStream == 0) return NO_INIT;
-    Result retval;
-    Return<void> ret = mStream->getCapturePosition(
-            [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
-                retval = r;
-                if (retval == Result::OK) {
-                    *frames = hidlFrames;
-                    *time = hidlTime;
-                }
-            });
-    return processReturn("getCapturePosition", ret, retval);
+    if (mReaderClient == gettid() && mCommandMQ) {
+        ReadParameters params;
+        params.command = ReadCommand::GET_CAPTURE_POSITION;
+        return callReaderThread(params, "getCapturePosition",
+                [&](const ReadStatus& readStatus) {
+                    *frames = readStatus.reply.capturePosition.frames;
+                    *time = readStatus.reply.capturePosition.time;
+                });
+    } else {
+        Result retval;
+        Return<void> ret = mStream->getCapturePosition(
+                [&](Result r, uint64_t hidlFrames, uint64_t hidlTime) {
+                    retval = r;
+                    if (retval == Result::OK) {
+                        *frames = hidlFrames;
+                        *time = hidlTime;
+                    }
+                });
+        return processReturn("getCapturePosition", ret, retval);
+    }
 }
 
 } // namespace android
diff --git a/media/libaudiohal/StreamHalHidl.h b/media/libaudiohal/StreamHalHidl.h
index 8b5867e..a7df276 100644
--- a/media/libaudiohal/StreamHalHidl.h
+++ b/media/libaudiohal/StreamHalHidl.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_HARDWARE_STREAM_HAL_HIDL_H
 #define ANDROID_HARDWARE_STREAM_HAL_HIDL_H
 
+#include <atomic>
+
 #include <android/hardware/audio/2.0/IStream.h>
 #include <android/hardware/audio/2.0/IStreamIn.h>
 #include <android/hardware/audio/2.0/IStreamOut.h>
@@ -32,7 +34,9 @@
 using ::android::hardware::EventFlag;
 using ::android::hardware::MessageQueue;
 using ::android::hardware::Return;
+using ReadParameters = ::android::hardware::audio::V2_0::IStreamIn::ReadParameters;
 using ReadStatus = ::android::hardware::audio::V2_0::IStreamIn::ReadStatus;
+using WriteCommand = ::android::hardware::audio::V2_0::IStreamOut::WriteCommand;
 using WriteStatus = ::android::hardware::audio::V2_0::IStreamOut::WriteStatus;
 
 namespace android {
@@ -97,10 +101,12 @@
     // The destructor automatically closes the stream.
     virtual ~StreamHalHidl();
 
-    int mHalThreadPriority;
+    bool requestHalThreadPriority(pid_t threadPid, pid_t threadId);
 
   private:
+    const int HAL_THREAD_PRIORITY_DEFAULT = -1;
     IStream *mStream;
+    int mHalThreadPriority;
 };
 
 class StreamOutHalHidl : public StreamOutHalInterface, public StreamHalHidl {
@@ -155,28 +161,27 @@
 
   private:
     friend class DeviceHalHidl;
+    typedef MessageQueue<WriteCommand, hardware::kSynchronizedReadWrite> CommandMQ;
     typedef MessageQueue<uint8_t, hardware::kSynchronizedReadWrite> DataMQ;
     typedef MessageQueue<WriteStatus, hardware::kSynchronizedReadWrite> StatusMQ;
 
     wp<StreamOutHalInterfaceCallback> mCallback;
     sp<IStreamOut> mStream;
+    std::unique_ptr<CommandMQ> mCommandMQ;
     std::unique_ptr<DataMQ> mDataMQ;
     std::unique_ptr<StatusMQ> mStatusMQ;
+    std::atomic<pid_t> mWriterClient;
     EventFlag* mEfGroup;
-    bool mGetPresentationPositionNotSupported;
-    struct {
-        uint64_t obtained;
-        status_t status;
-        uint64_t frames;
-        struct timespec ts;
-    } mPPosFromWrite;
 
     // Can not be constructed directly by clients.
     StreamOutHalHidl(const sp<IStreamOut>& stream);
 
     virtual ~StreamOutHalHidl();
 
-    uint64_t getCurrentTimeMs();
+    using WriterCallback = std::function<void(const WriteStatus& writeStatus)>;
+    status_t callWriterThread(
+            WriteCommand cmd, const char* cmdName,
+            const uint8_t* data, size_t dataSize, WriterCallback callback);
     status_t prepareForWriting(size_t bufferSize);
 };
 
@@ -200,12 +205,15 @@
 
   private:
     friend class DeviceHalHidl;
+    typedef MessageQueue<ReadParameters, hardware::kSynchronizedReadWrite> CommandMQ;
     typedef MessageQueue<uint8_t, hardware::kSynchronizedReadWrite> DataMQ;
     typedef MessageQueue<ReadStatus, hardware::kSynchronizedReadWrite> StatusMQ;
 
     sp<IStreamIn> mStream;
+    std::unique_ptr<CommandMQ> mCommandMQ;
     std::unique_ptr<DataMQ> mDataMQ;
     std::unique_ptr<StatusMQ> mStatusMQ;
+    std::atomic<pid_t> mReaderClient;
     EventFlag* mEfGroup;
 
     // Can not be constructed directly by clients.
@@ -213,6 +221,9 @@
 
     virtual ~StreamInHalHidl();
 
+    using ReaderCallback = std::function<void(const ReadStatus& readStatus)>;
+    status_t callReaderThread(
+            const ReadParameters& params, const char* cmdName, ReaderCallback callback);
     status_t prepareForReading(size_t bufferSize);
 };
 
diff --git a/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/DeviceHalInterface.h
similarity index 100%
rename from include/media/audiohal/DeviceHalInterface.h
rename to media/libaudiohal/include/DeviceHalInterface.h
diff --git a/include/media/audiohal/DevicesFactoryHalInterface.h b/media/libaudiohal/include/DevicesFactoryHalInterface.h
similarity index 100%
rename from include/media/audiohal/DevicesFactoryHalInterface.h
rename to media/libaudiohal/include/DevicesFactoryHalInterface.h
diff --git a/include/media/audiohal/EffectBufferHalInterface.h b/media/libaudiohal/include/EffectBufferHalInterface.h
similarity index 100%
rename from include/media/audiohal/EffectBufferHalInterface.h
rename to media/libaudiohal/include/EffectBufferHalInterface.h
diff --git a/include/media/audiohal/EffectHalInterface.h b/media/libaudiohal/include/EffectHalInterface.h
similarity index 100%
rename from include/media/audiohal/EffectHalInterface.h
rename to media/libaudiohal/include/EffectHalInterface.h
diff --git a/include/media/audiohal/EffectsFactoryHalInterface.h b/media/libaudiohal/include/EffectsFactoryHalInterface.h
similarity index 100%
rename from include/media/audiohal/EffectsFactoryHalInterface.h
rename to media/libaudiohal/include/EffectsFactoryHalInterface.h
diff --git a/include/media/audiohal/StreamHalInterface.h b/media/libaudiohal/include/StreamHalInterface.h
similarity index 100%
rename from include/media/audiohal/StreamHalInterface.h
rename to media/libaudiohal/include/StreamHalInterface.h
diff --git a/include/media/audiohal/hidl/HalDeathHandler.h b/media/libaudiohal/include/hidl/HalDeathHandler.h
similarity index 100%
rename from include/media/audiohal/hidl/HalDeathHandler.h
rename to media/libaudiohal/include/hidl/HalDeathHandler.h
diff --git a/media/libaudioprocessing/Android.mk b/media/libaudioprocessing/Android.mk
index b7ea99e..c850984 100644
--- a/media/libaudioprocessing/Android.mk
+++ b/media/libaudioprocessing/Android.mk
@@ -14,6 +14,9 @@
 LOCAL_C_INCLUDES := \
     $(TOP) \
     $(call include-path-for, audio-utils) \
+    $(LOCAL_PATH)/include \
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
 
 LOCAL_SHARED_LIBRARIES := \
     libaudiohal \
diff --git a/include/media/AudioResampler.h b/media/libaudioprocessing/include/AudioResampler.h
similarity index 100%
rename from include/media/AudioResampler.h
rename to media/libaudioprocessing/include/AudioResampler.h
diff --git a/include/media/AudioResamplerPublic.h b/media/libaudioprocessing/include/AudioResamplerPublic.h
similarity index 100%
rename from include/media/AudioResamplerPublic.h
rename to media/libaudioprocessing/include/AudioResamplerPublic.h
diff --git a/include/cpustats/CentralTendencyStatistics.h b/media/libcpustats/include/cpustats/CentralTendencyStatistics.h
similarity index 100%
rename from include/cpustats/CentralTendencyStatistics.h
rename to media/libcpustats/include/cpustats/CentralTendencyStatistics.h
diff --git a/include/cpustats/README.txt b/media/libcpustats/include/cpustats/README.txt
similarity index 100%
rename from include/cpustats/README.txt
rename to media/libcpustats/include/cpustats/README.txt
diff --git a/include/cpustats/ThreadCpuUsage.h b/media/libcpustats/include/cpustats/ThreadCpuUsage.h
similarity index 100%
rename from include/cpustats/ThreadCpuUsage.h
rename to media/libcpustats/include/cpustats/ThreadCpuUsage.h
diff --git a/media/libeffects/factory/Android.bp b/media/libeffects/factory/Android.bp
index 0d8b6eb..e0e0d13 100644
--- a/media/libeffects/factory/Android.bp
+++ b/media/libeffects/factory/Android.bp
@@ -10,4 +10,8 @@
     ],
 
     include_dirs: ["system/media/audio_effects/include"],
+
+    local_include_dirs:["include"],
+
+    export_include_dirs: ["include"],
 }
diff --git a/include/media/EffectsFactoryApi.h b/media/libeffects/factory/include/EffectsFactoryApi.h
similarity index 100%
rename from include/media/EffectsFactoryApi.h
rename to media/libeffects/factory/include/EffectsFactoryApi.h
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 616fb9c..0d8142d 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -1463,17 +1463,25 @@
 //                            horizontal plane, +90 is directly above the user, -90 below
 //
 //----------------------------------------------------------------------------
-void VirtualizerGetSpeakerAngles(audio_channel_mask_t channelMask __unused,
+void VirtualizerGetSpeakerAngles(audio_channel_mask_t channelMask,
         audio_devices_t deviceType __unused, int32_t *pSpeakerAngles) {
     // the channel count is guaranteed to be 1 or 2
     // the device is guaranteed to be of type headphone
-    // this virtualizer is always 2in with speakers at -90 and 90deg of azimuth, 0deg of elevation
-    *pSpeakerAngles++ = (int32_t) AUDIO_CHANNEL_OUT_FRONT_LEFT;
-    *pSpeakerAngles++ = -90; // azimuth
-    *pSpeakerAngles++ = 0;   // elevation
-    *pSpeakerAngles++ = (int32_t) AUDIO_CHANNEL_OUT_FRONT_RIGHT;
-    *pSpeakerAngles++ = 90;  // azimuth
-    *pSpeakerAngles   = 0;   // elevation
+    // this virtualizer is always using 2 virtual speakers at -90 and 90deg of azimuth, 0deg of
+    // elevation but the return information is sized for nbChannels * 3, so we have to consider
+    // the (false here) case of a single channel, and return only 3 fields.
+    if (audio_channel_count_from_out_mask(channelMask) == 1) {
+        *pSpeakerAngles++ = (int32_t) AUDIO_CHANNEL_OUT_MONO; // same as FRONT_LEFT
+        *pSpeakerAngles++ = 0; // azimuth
+        *pSpeakerAngles = 0; // elevation
+    } else {
+        *pSpeakerAngles++ = (int32_t) AUDIO_CHANNEL_OUT_FRONT_LEFT;
+        *pSpeakerAngles++ = -90; // azimuth
+        *pSpeakerAngles++ = 0;   // elevation
+        *pSpeakerAngles++ = (int32_t) AUDIO_CHANNEL_OUT_FRONT_RIGHT;
+        *pSpeakerAngles++ = 90;  // azimuth
+        *pSpeakerAngles   = 0;   // elevation
+    }
 }
 
 //----------------------------------------------------------------------------
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 6c6c369..eac532b 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -60,10 +60,10 @@
         libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \
         libcamera_client libstagefright_foundation \
         libgui libdl libaudioutils libaudioclient \
-        libmedia_helper \
+        libmedia_helper libmediadrm \
         libhidlbase \
 
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libsonivox
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libsonivox libmediadrm
 
 # for memory heap analysis
 LOCAL_STATIC_LIBRARIES := libc_malloc_debug_backtrace libc_logging
diff --git a/media/libmedia/IHDCP.cpp b/media/libmedia/IHDCP.cpp
index 21e35f6..15ed579 100644
--- a/media/libmedia/IHDCP.cpp
+++ b/media/libmedia/IHDCP.cpp
@@ -241,14 +241,11 @@
         case HDCP_ENCRYPT:
         {
             size_t size = data.readInt32();
-            size_t bufSize = 2 * size;
-
-            // watch out for overflow
             void *inData = NULL;
-            if (bufSize > size) {
-                inData = malloc(bufSize);
+            // watch out for overflow
+            if (size <= SIZE_MAX / 2) {
+                inData = malloc(2 * size);
             }
-
             if (inData == NULL) {
                 reply->writeInt32(ERROR_OUT_OF_RANGE);
                 return OK;
@@ -256,11 +253,16 @@
 
             void *outData = (uint8_t *)inData + size;
 
-            data.read(inData, size);
+            status_t err = data.read(inData, size);
+            if (err != OK) {
+                free(inData);
+                reply->writeInt32(err);
+                return OK;
+            }
 
             uint32_t streamCTR = data.readInt32();
             uint64_t inputCTR;
-            status_t err = encrypt(inData, size, streamCTR, &inputCTR, outData);
+            err = encrypt(inData, size, streamCTR, &inputCTR, outData);
 
             reply->writeInt32(err);
 
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index 0f4f092..f08fabb 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <android/media/ICas.h>
 #include <binder/IPCThreadState.h>
 #include <binder/Parcel.h>
 #include <media/IMediaExtractor.h>
@@ -35,8 +36,10 @@
     GETMETADATA,
     FLAGS,
     GETDRMTRACKINFO,
+    SETMEDIACAS,
     SETUID,
-    NAME
+    NAME,
+    GETMETRICS
 };
 
 class BpMediaExtractor : public BpInterface<IMediaExtractor> {
@@ -94,6 +97,16 @@
         return NULL;
     }
 
+    virtual status_t getMetrics(Parcel * reply) {
+        Parcel data;
+        data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+        status_t ret = remote()->transact(GETMETRICS, data, reply);
+        if (ret == NO_ERROR) {
+            return OK;
+        }
+        return UNKNOWN_ERROR;
+    }
+
     virtual uint32_t flags() const {
         ALOGV("flags NOT IMPLEMENTED");
         return 0;
@@ -103,6 +116,21 @@
         ALOGV("getDrmTrackInfo NOT IMPLEMENTED");
         return NULL;
     }
+
+    virtual status_t setMediaCas(const sp<ICas> & cas) {
+        ALOGV("setMediaCas");
+
+        Parcel data, reply;
+        data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+        data.writeStrongBinder(IInterface::asBinder(cas));
+
+        status_t err = remote()->transact(SETMEDIACAS, data, &reply);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        return reply.readInt32();
+    }
+
     virtual void setUID(uid_t uid __unused) {
         ALOGV("setUID NOT IMPLEMENTED");
     }
@@ -169,6 +197,26 @@
             }
             return UNKNOWN_ERROR;
         }
+        case GETMETRICS: {
+            CHECK_INTERFACE(IMediaExtractor, data, reply);
+            status_t ret = getMetrics(reply);
+            return ret;
+        }
+        case SETMEDIACAS: {
+            ALOGV("setMediaCas");
+            CHECK_INTERFACE(IMediaExtractor, data, reply);
+
+            sp<IBinder> casBinder;
+            status_t err = data.readNullableStrongBinder(&casBinder);
+            if (err != NO_ERROR) {
+                ALOGE("Error reading cas from parcel");
+                return err;
+            }
+            sp<ICas> cas = interface_cast<ICas>(casBinder);
+
+            reply->writeInt32(setMediaCas(cas));
+            return OK;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IMediaHTTPConnection.cpp b/media/libmedia/IMediaHTTPConnection.cpp
index e4b717b..1bb8d67 100644
--- a/media/libmedia/IMediaHTTPConnection.cpp
+++ b/media/libmedia/IMediaHTTPConnection.cpp
@@ -124,6 +124,14 @@
             ALOGE("got %zu, but memory has %zu", len, mMemory->size());
             return ERROR_OUT_OF_RANGE;
         }
+        if(buffer == NULL) {
+           ALOGE("readAt got a NULL buffer");
+           return UNKNOWN_ERROR;
+        }
+        if (mMemory->pointer() == NULL) {
+           ALOGE("readAt got a NULL mMemory->pointer()");
+           return UNKNOWN_ERROR;
+        }
 
         memcpy(buffer, mMemory->pointer(), len);
 
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 966267a..3996227 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -70,14 +70,11 @@
     SET_RETRANSMIT_ENDPOINT,
     GET_RETRANSMIT_ENDPOINT,
     SET_NEXT_PLAYER,
-    // ModDrm
+    APPLY_VOLUME_SHAPER,
+    GET_VOLUME_SHAPER_STATE,
+    // Modular DRM
     PREPARE_DRM,
     RELEASE_DRM,
-    GET_KEY_REQUEST,
-    PROVIDE_KEY_RESPONSE,
-    RESTORE_KEYS,
-    GET_DRM_PROPERTY_STRING,
-    SET_DRM_PROPERTY_STRING,
 };
 
 // ModDrm helpers
@@ -468,14 +465,65 @@
         return err;
     }
 
-    // ModDrm
-    status_t prepareDrm(const uint8_t uuid[16], const int mode)
+    virtual VolumeShaper::Status applyVolumeShaper(
+            const sp<VolumeShaper::Configuration>& configuration,
+            const sp<VolumeShaper::Operation>& operation) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        status_t tmp;
+        status_t status = configuration.get() == nullptr
+                ? data.writeInt32(0)
+                : (tmp = data.writeInt32(1)) != NO_ERROR
+                    ? tmp : configuration->writeToParcel(&data);
+        if (status != NO_ERROR) {
+            return VolumeShaper::Status(status);
+        }
+
+        status = operation.get() == nullptr
+                ? status = data.writeInt32(0)
+                : (tmp = data.writeInt32(1)) != NO_ERROR
+                    ? tmp : operation->writeToParcel(&data);
+        if (status != NO_ERROR) {
+            return VolumeShaper::Status(status);
+        }
+
+        int32_t remoteVolumeShaperStatus;
+        status = remote()->transact(APPLY_VOLUME_SHAPER, data, &reply);
+        if (status == NO_ERROR) {
+            status = reply.readInt32(&remoteVolumeShaperStatus);
+        }
+        if (status != NO_ERROR) {
+            return VolumeShaper::Status(status);
+        }
+        return VolumeShaper::Status(remoteVolumeShaperStatus);
+    }
+
+    virtual sp<VolumeShaper::State> getVolumeShaperState(int id) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        data.writeInt32(id);
+        status_t status = remote()->transact(GET_VOLUME_SHAPER_STATE, data, &reply);
+        if (status != NO_ERROR) {
+            return nullptr;
+        }
+        sp<VolumeShaper::State> state = new VolumeShaper::State();
+        status = state->readFromParcel(reply);
+        if (status != NO_ERROR) {
+            return nullptr;
+        }
+        return state;
+    }
+
+    // Modular DRM
+    status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
 
         data.write(uuid, 16);
-        data.writeInt32(mode);
+        writeVector(data, drmSessionId);
 
         status_t status = remote()->transact(PREPARE_DRM, data, &reply);
         if (status != OK) {
@@ -499,105 +547,6 @@
 
         return reply.readInt32();
     }
-
-    status_t getKeyRequest(Vector<uint8_t> const& scope, String8 const& mimeType,
-            DrmPlugin::KeyType keyType, KeyedVector<String8, String8>& optionalParameters,
-            Vector<uint8_t>& request, String8& defaultUrl,
-            DrmPlugin::KeyRequestType& keyRequestType)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
-
-        writeVector(data, scope);
-        data.writeString8(mimeType);
-        data.writeInt32((int32_t)keyType);
-
-        data.writeUint32(optionalParameters.size());
-        for (size_t i = 0; i < optionalParameters.size(); ++i) {
-            data.writeString8(optionalParameters.keyAt(i));
-            data.writeString8(optionalParameters.valueAt(i));
-        }
-
-        status_t status = remote()->transact(GET_KEY_REQUEST, data, &reply);
-        if (status != OK) {
-            ALOGE("getKeyRequest: binder call failed: %d", status);
-            return status;
-        }
-
-        readVector(reply, request);
-        defaultUrl = reply.readString8();
-        keyRequestType = (DrmPlugin::KeyRequestType)reply.readInt32();
-
-        return reply.readInt32();
-    }
-
-    status_t provideKeyResponse(Vector<uint8_t>& releaseKeySetId, Vector<uint8_t>& response,
-            Vector<uint8_t> &keySetId)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
-
-        writeVector(data, releaseKeySetId);
-        writeVector(data, response);
-
-        status_t status = remote()->transact(PROVIDE_KEY_RESPONSE, data, &reply);
-        if (status != OK) {
-            ALOGE("provideKeyResponse: binder call failed: %d", status);
-            return status;
-        }
-
-        readVector(reply, keySetId);
-
-        return reply.readInt32();
-    }
-
-    status_t restoreKeys(Vector<uint8_t> const& keySetId)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
-
-        writeVector(data, keySetId);
-
-        status_t status = remote()->transact(RESTORE_KEYS, data, &reply);
-        if (status != OK) {
-            ALOGE("restoreKeys: binder call failed: %d", status);
-            return status;
-        }
-
-        return reply.readInt32();
-    }
-
-    status_t getDrmPropertyString(String8 const& name, String8& value)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
-
-        data.writeString8(name);
-        status_t status = remote()->transact(GET_DRM_PROPERTY_STRING, data, &reply);
-        if (status != OK) {
-            ALOGE("getDrmPropertyString: binder call failed: %d", status);
-            return status;
-        }
-
-        value = reply.readString8();
-        return reply.readInt32();
-    }
-
-    status_t setDrmPropertyString(String8 const& name, String8 const& value)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
-
-        data.writeString8(name);
-        data.writeString8(value);
-        status_t status = remote()->transact(SET_DRM_PROPERTY_STRING, data, &reply);
-        if (status != OK) {
-            ALOGE("setDrmPropertyString: binder call failed: %d", status);
-            return status;
-        }
-
-        return reply.readInt32();
-    }
 };
 
 IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
@@ -893,15 +842,53 @@
             return NO_ERROR;
         } break;
 
-        // ModDrm
+        case APPLY_VOLUME_SHAPER: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            sp<VolumeShaper::Configuration> configuration;
+            sp<VolumeShaper::Operation> operation;
+
+            int32_t present;
+            status_t status = data.readInt32(&present);
+            if (status == NO_ERROR && present != 0) {
+                configuration = new VolumeShaper::Configuration();
+                status = configuration->readFromParcel(data);
+            }
+            if (status == NO_ERROR) {
+                status = data.readInt32(&present);
+            }
+            if (status == NO_ERROR && present != 0) {
+                operation = new VolumeShaper::Operation();
+                status = operation->readFromParcel(data);
+            }
+            if (status == NO_ERROR) {
+                status = (status_t)applyVolumeShaper(configuration, operation);
+            }
+            reply->writeInt32(status);
+            return NO_ERROR;
+        } break;
+        case GET_VOLUME_SHAPER_STATE: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            int id;
+            status_t status = data.readInt32(&id);
+            if (status == NO_ERROR) {
+                sp<VolumeShaper::State> state = getVolumeShaperState(id);
+                if (state.get() != nullptr) {
+                     status = state->writeToParcel(reply);
+                }
+            }
+            return NO_ERROR;
+        } break;
+
+        // Modular DRM
         case PREPARE_DRM: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
+
             uint8_t uuid[16];
             data.read(uuid, sizeof(uuid));
+            Vector<uint8_t> drmSessionId;
+            readVector(data, drmSessionId);
 
-            int mode = data.readInt32();
-
-            uint32_t result = prepareDrm(uuid, mode);
+            uint32_t result = prepareDrm(uuid, drmSessionId);
             reply->writeInt32(result);
             return OK;
         }
@@ -912,73 +899,6 @@
             reply->writeInt32(result);
             return OK;
         }
-        case GET_KEY_REQUEST: {
-            CHECK_INTERFACE(IMediaPlayer, data, reply);
-
-            Vector<uint8_t> scope;
-            readVector(data, scope);
-            String8 mimeType = data.readString8();
-            DrmPlugin::KeyType keyType = (DrmPlugin::KeyType)data.readInt32();
-
-            KeyedVector<String8, String8> optionalParameters;
-            uint32_t count = data.readUint32();
-            for (size_t i = 0; i < count; ++i) {
-                String8 key, value;
-                key = data.readString8();
-                value = data.readString8();
-                optionalParameters.add(key, value);
-            }
-
-            Vector<uint8_t> request;
-            String8 defaultUrl;
-            DrmPlugin::KeyRequestType keyRequestType = DrmPlugin::kKeyRequestType_Unknown;
-
-            status_t result = getKeyRequest(scope, mimeType, keyType, optionalParameters,
-                                      request, defaultUrl, keyRequestType);
-
-            writeVector(*reply, request);
-            reply->writeString8(defaultUrl);
-            reply->writeInt32(keyRequestType);
-            reply->writeInt32(result);
-            return OK;
-        }
-        case PROVIDE_KEY_RESPONSE: {
-            CHECK_INTERFACE(IMediaPlayer, data, reply);
-            Vector<uint8_t> releaseKeySetId, response, keySetId;
-            readVector(data, releaseKeySetId);
-            readVector(data, response);
-            uint32_t result = provideKeyResponse(releaseKeySetId, response, keySetId);
-            writeVector(*reply, keySetId);
-            reply->writeInt32(result);
-            return OK;
-        }
-        case RESTORE_KEYS: {
-            CHECK_INTERFACE(IMediaPlayer, data, reply);
-
-            Vector<uint8_t> keySetId;
-            readVector(data, keySetId);
-            uint32_t result = restoreKeys(keySetId);
-            reply->writeInt32(result);
-            return OK;
-        }
-        case GET_DRM_PROPERTY_STRING: {
-            CHECK_INTERFACE(IMediaPlayer, data, reply);
-            String8 name, value;
-            name = data.readString8();
-            uint32_t result = getDrmPropertyString(name, value);
-            reply->writeString8(value);
-            reply->writeInt32(result);
-            return OK;
-        }
-        case SET_DRM_PROPERTY_STRING: {
-            CHECK_INTERFACE(IMediaPlayer, data, reply);
-            String8 name, value;
-            name = data.readString8();
-            value = data.readString8();
-            uint32_t result = setDrmPropertyString(name, value);
-            reply->writeInt32(result);
-            return OK;
-        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 5730c76..5282352 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -59,7 +59,9 @@
     SET_LISTENER,
     SET_CLIENT_NAME,
     PAUSE,
-    RESUME
+    RESUME,
+    GET_METRICS,
+
 };
 
 class BpMediaRecorder: public BpInterface<IMediaRecorder>
@@ -261,6 +263,18 @@
         return reply.readInt32();
     }
 
+    status_t getMetrics(Parcel* reply)
+    {
+        ALOGV("getMetrics");
+        Parcel data;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        status_t ret = remote()->transact(GET_METRICS, data, reply);
+        if (ret == NO_ERROR) {
+            return OK;
+        }
+        return UNKNOWN_ERROR;
+    }
+
     status_t start()
     {
         ALOGV("start");
@@ -397,6 +411,11 @@
             reply->writeInt32(ret);
             return NO_ERROR;
         } break;
+        case GET_METRICS: {
+            ALOGV("GET_METRICS");
+            status_t ret = getMetrics(reply);
+            return ret;
+        } break;
         case SET_VIDEO_SOURCE: {
             ALOGV("SET_VIDEO_SOURCE");
             CHECK_INTERFACE(IMediaRecorder, data, reply);
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 3d466b1..67939b2 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -25,8 +25,9 @@
 #include <media/IOMX.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/openmax/OMX_IndexExt.h>
-#include <utils/NativeHandle.h>
 #include <media/OMXBuffer.h>
+#include <utils/NativeHandle.h>
+#include <gui/IGraphicBufferProducer.h>
 
 #include <android/IGraphicBufferSource.h>
 #include <android/IOMXBufferSource.h>
diff --git a/media/libmedia/MediaDefs.cpp b/media/libmedia/MediaDefs.cpp
index 2ae71f7..544a6ae 100644
--- a/media/libmedia/MediaDefs.cpp
+++ b/media/libmedia/MediaDefs.cpp
@@ -29,6 +29,7 @@
 const char *MEDIA_MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
 const char *MEDIA_MIMETYPE_VIDEO_RAW = "video/raw";
 const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
+const char *MEDIA_MIMETYPE_VIDEO_SCRAMBLED = "video/scrambled";
 
 const char *MEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
 const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
@@ -48,6 +49,7 @@
 const char *MEDIA_MIMETYPE_AUDIO_MSGSM = "audio/gsm";
 const char *MEDIA_MIMETYPE_AUDIO_AC3 = "audio/ac3";
 const char *MEDIA_MIMETYPE_AUDIO_EAC3 = "audio/eac3";
+const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
 
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mp4";
 const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/x-wav";
diff --git a/media/libmedia/OMXBuffer.cpp b/media/libmedia/OMXBuffer.cpp
index 71d2908..6d54a13 100644
--- a/media/libmedia/OMXBuffer.cpp
+++ b/media/libmedia/OMXBuffer.cpp
@@ -90,6 +90,13 @@
 
         case kBufferTypeANWBuffer:
         {
+            if (mGraphicBuffer == NULL) {
+                return parcel->writeBool(false);
+            }
+            status_t err = parcel->writeBool(true);
+            if (err != OK) {
+                return err;
+            }
             return parcel->write(*mGraphicBuffer);
         }
 
@@ -130,15 +137,21 @@
 
         case kBufferTypeANWBuffer:
         {
-            sp<GraphicBuffer> buffer = new GraphicBuffer();
-
-            status_t err = parcel->read(*buffer);
-
+            bool notNull;
+            status_t err = parcel->readBool(&notNull);
             if (err != OK) {
                 return err;
             }
-
-            mGraphicBuffer = buffer;
+            if (notNull) {
+                sp<GraphicBuffer> buffer = new GraphicBuffer();
+                status_t err = parcel->read(*buffer);
+                if (err != OK) {
+                    return err;
+                }
+                mGraphicBuffer = buffer;
+            } else {
+                mGraphicBuffer = nullptr;
+            }
             break;
         }
 
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmedia/TypeConverter.cpp
index 8ce2b9f..bead69a 100644
--- a/media/libmedia/TypeConverter.cpp
+++ b/media/libmedia/TypeConverter.cpp
@@ -111,6 +111,7 @@
     MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_SYNC),
     MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO),
     MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_DIRECT_PCM),
+    MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ),
     TERMINATOR
 };
 
@@ -122,6 +123,7 @@
     MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_HW_HOTWORD),
     MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_RAW),
     MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_SYNC),
+    MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_MMAP_NOIRQ),
     TERMINATOR
 };
 
diff --git a/media/libmedia/aidl/android/IGraphicBufferSource.aidl b/media/libmedia/aidl/android/IGraphicBufferSource.aidl
index a8dd309..325c631 100644
--- a/media/libmedia/aidl/android/IGraphicBufferSource.aidl
+++ b/media/libmedia/aidl/android/IGraphicBufferSource.aidl
@@ -25,11 +25,12 @@
  */
 interface IGraphicBufferSource {
     void configure(IOMXNode omxNode, int dataSpace);
-    void setSuspend(boolean suspend);
+    void setSuspend(boolean suspend, long suspendTimeUs);
     void setRepeatPreviousFrameDelayUs(long repeatAfterUs);
     void setMaxFps(float maxFps);
     void setTimeLapseConfig(long timePerFrameUs, long timePerCaptureUs);
     void setStartTimeUs(long startTimeUs);
+    void setStopTimeUs(long stopTimeUs);
     void setColorAspects(int aspects);
     void setTimeOffsetUs(long timeOffsetsUs);
     void signalEndOfInputStream();
diff --git a/include/media/AVSyncSettings.h b/media/libmedia/include/AVSyncSettings.h
similarity index 100%
rename from include/media/AVSyncSettings.h
rename to media/libmedia/include/AVSyncSettings.h
diff --git a/include/media/BufferProviders.h b/media/libmedia/include/BufferProviders.h
similarity index 100%
rename from include/media/BufferProviders.h
rename to media/libmedia/include/BufferProviders.h
diff --git a/include/media/BufferingSettings.h b/media/libmedia/include/BufferingSettings.h
similarity index 100%
rename from include/media/BufferingSettings.h
rename to media/libmedia/include/BufferingSettings.h
diff --git a/include/media/CharacterEncodingDetector.h b/media/libmedia/include/CharacterEncodingDetector.h
similarity index 100%
rename from include/media/CharacterEncodingDetector.h
rename to media/libmedia/include/CharacterEncodingDetector.h
diff --git a/include/media/Crypto.h b/media/libmedia/include/Crypto.h
similarity index 100%
rename from include/media/Crypto.h
rename to media/libmedia/include/Crypto.h
diff --git a/include/media/CryptoHal.h b/media/libmedia/include/CryptoHal.h
similarity index 90%
rename from include/media/CryptoHal.h
rename to media/libmedia/include/CryptoHal.h
index 1ace957..9d0c3e4 100644
--- a/include/media/CryptoHal.h
+++ b/media/libmedia/include/CryptoHal.h
@@ -26,6 +26,8 @@
 
 #include "SharedLibrary.h"
 
+class IMemoryHeap;
+
 namespace android {
 
 struct CryptoHal : public BnCrypto {
@@ -70,7 +72,8 @@
      */
     status_t mInitCheck;
 
-    void *mHeapBase;
+    KeyedVector<void *, uint32_t> mHeapBases;
+    uint32_t mNextBufferId;
 
     sp<::android::hardware::drm::V1_0::ICryptoFactory>
             makeCryptoFactory();
@@ -78,7 +81,10 @@
             makeCryptoPlugin(const uint8_t uuid[16], const void *initData,
                 size_t size);
 
-    status_t setHeapBase(const sp<IMemory> &sharedBuffer);
+    void setHeapBase(const sp<IMemoryHeap>& heap);
+
+    status_t toSharedBuffer(const sp<IMemory>& memory,
+            ::android::hardware::drm::V1_0::SharedBuffer* buffer);
 
     DISALLOW_EVIL_CONSTRUCTORS(CryptoHal);
 };
diff --git a/include/media/Drm.h b/media/libmedia/include/Drm.h
similarity index 100%
rename from include/media/Drm.h
rename to media/libmedia/include/Drm.h
diff --git a/include/media/DrmHal.h b/media/libmedia/include/DrmHal.h
similarity index 100%
rename from include/media/DrmHal.h
rename to media/libmedia/include/DrmHal.h
diff --git a/include/media/DrmSessionClientInterface.h b/media/libmedia/include/DrmSessionClientInterface.h
similarity index 100%
rename from include/media/DrmSessionClientInterface.h
rename to media/libmedia/include/DrmSessionClientInterface.h
diff --git a/include/media/DrmSessionManager.h b/media/libmedia/include/DrmSessionManager.h
similarity index 100%
rename from include/media/DrmSessionManager.h
rename to media/libmedia/include/DrmSessionManager.h
diff --git a/include/media/ExtendedAudioBufferProvider.h b/media/libmedia/include/ExtendedAudioBufferProvider.h
similarity index 100%
rename from include/media/ExtendedAudioBufferProvider.h
rename to media/libmedia/include/ExtendedAudioBufferProvider.h
diff --git a/include/media/ICrypto.h b/media/libmedia/include/ICrypto.h
similarity index 100%
rename from include/media/ICrypto.h
rename to media/libmedia/include/ICrypto.h
diff --git a/include/media/IDataSource.h b/media/libmedia/include/IDataSource.h
similarity index 100%
rename from include/media/IDataSource.h
rename to media/libmedia/include/IDataSource.h
diff --git a/include/media/IDrm.h b/media/libmedia/include/IDrm.h
similarity index 100%
rename from include/media/IDrm.h
rename to media/libmedia/include/IDrm.h
diff --git a/include/media/IDrmClient.h b/media/libmedia/include/IDrmClient.h
similarity index 100%
rename from include/media/IDrmClient.h
rename to media/libmedia/include/IDrmClient.h
diff --git a/include/media/IHDCP.h b/media/libmedia/include/IHDCP.h
similarity index 100%
rename from include/media/IHDCP.h
rename to media/libmedia/include/IHDCP.h
diff --git a/include/media/IMediaAnalyticsService.h b/media/libmedia/include/IMediaAnalyticsService.h
similarity index 100%
rename from include/media/IMediaAnalyticsService.h
rename to media/libmedia/include/IMediaAnalyticsService.h
diff --git a/include/media/IMediaCodecList.h b/media/libmedia/include/IMediaCodecList.h
similarity index 100%
rename from include/media/IMediaCodecList.h
rename to media/libmedia/include/IMediaCodecList.h
diff --git a/include/media/IMediaCodecService.h b/media/libmedia/include/IMediaCodecService.h
similarity index 100%
rename from include/media/IMediaCodecService.h
rename to media/libmedia/include/IMediaCodecService.h
diff --git a/include/media/IMediaDeathNotifier.h b/media/libmedia/include/IMediaDeathNotifier.h
similarity index 100%
rename from include/media/IMediaDeathNotifier.h
rename to media/libmedia/include/IMediaDeathNotifier.h
diff --git a/include/media/IMediaDrmService.h b/media/libmedia/include/IMediaDrmService.h
similarity index 100%
rename from include/media/IMediaDrmService.h
rename to media/libmedia/include/IMediaDrmService.h
diff --git a/include/media/IMediaExtractor.h b/media/libmedia/include/IMediaExtractor.h
similarity index 93%
rename from include/media/IMediaExtractor.h
rename to media/libmedia/include/IMediaExtractor.h
index e0a81f1..cf1b9fb 100644
--- a/include/media/IMediaExtractor.h
+++ b/media/libmedia/include/IMediaExtractor.h
@@ -24,6 +24,10 @@
 namespace android {
 
 class MetaData;
+namespace media {
+class ICas;
+};
+using namespace media;
 
 class IMediaExtractor : public IInterface {
 public:
@@ -42,6 +46,8 @@
     // returns an empty metadata object.
     virtual sp<MetaData> getMetaData() = 0;
 
+    virtual status_t getMetrics(Parcel *reply) = 0;
+
     enum Flags {
         CAN_SEEK_BACKWARD  = 1,  // the "seek 10secs back button"
         CAN_SEEK_FORWARD   = 2,  // the "seek 10secs forward button"
@@ -55,6 +61,9 @@
 
     // for DRM
     virtual char* getDrmTrackInfo(size_t trackID, int *len)  = 0;
+
+    virtual status_t setMediaCas(const sp<ICas> &cas) = 0;
+
     virtual void setUID(uid_t uid)  = 0;
 
     virtual const char * name() = 0;
diff --git a/include/media/IMediaExtractorService.h b/media/libmedia/include/IMediaExtractorService.h
similarity index 100%
rename from include/media/IMediaExtractorService.h
rename to media/libmedia/include/IMediaExtractorService.h
diff --git a/include/media/IMediaHTTPConnection.h b/media/libmedia/include/IMediaHTTPConnection.h
similarity index 100%
rename from include/media/IMediaHTTPConnection.h
rename to media/libmedia/include/IMediaHTTPConnection.h
diff --git a/include/media/IMediaHTTPService.h b/media/libmedia/include/IMediaHTTPService.h
similarity index 100%
rename from include/media/IMediaHTTPService.h
rename to media/libmedia/include/IMediaHTTPService.h
diff --git a/include/media/IMediaLogService.h b/media/libmedia/include/IMediaLogService.h
similarity index 100%
rename from include/media/IMediaLogService.h
rename to media/libmedia/include/IMediaLogService.h
diff --git a/include/media/IMediaMetadataRetriever.h b/media/libmedia/include/IMediaMetadataRetriever.h
similarity index 100%
rename from include/media/IMediaMetadataRetriever.h
rename to media/libmedia/include/IMediaMetadataRetriever.h
diff --git a/include/media/IMediaPlayer.h b/media/libmedia/include/IMediaPlayer.h
similarity index 84%
rename from include/media/IMediaPlayer.h
rename to media/libmedia/include/IMediaPlayer.h
index ca865a8..e5a98dd 100644
--- a/include/media/IMediaPlayer.h
+++ b/media/libmedia/include/IMediaPlayer.h
@@ -24,7 +24,7 @@
 #include <system/audio.h>
 
 #include <media/IMediaSource.h>
-#include <media/drm/DrmAPI.h>   // for DrmPlugin::* enum
+#include <media/VolumeShaper.h>
 
 // Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
 // global, and not in android::
@@ -90,22 +90,16 @@
     virtual status_t        setRetransmitEndpoint(const struct sockaddr_in* endpoint) = 0;
     virtual status_t        getRetransmitEndpoint(struct sockaddr_in* endpoint) = 0;
     virtual status_t        setNextPlayer(const sp<IMediaPlayer>& next) = 0;
-    // ModDrm
-    virtual status_t        prepareDrm(const uint8_t uuid[16], const int mode) = 0;
+
+    virtual VolumeShaper::Status applyVolumeShaper(
+                                    const sp<VolumeShaper::Configuration>& configuration,
+                                    const sp<VolumeShaper::Operation>& operation) = 0;
+    virtual sp<VolumeShaper::State> getVolumeShaperState(int id) = 0;
+
+    // Modular DRM
+    virtual status_t        prepareDrm(const uint8_t uuid[16],
+                                    const Vector<uint8_t>& drmSessionId) = 0;
     virtual status_t        releaseDrm() = 0;
-    virtual status_t        getKeyRequest(Vector<uint8_t> const& scope,
-                                    String8 const &mimeType,
-                                    DrmPlugin::KeyType keyType,
-                                    KeyedVector<String8, String8>& optionalParameters,
-                                    Vector<uint8_t>& request,
-                                    String8& defaultUrl,
-                                    DrmPlugin::KeyRequestType& keyRequestType) = 0;
-    virtual status_t        provideKeyResponse(Vector<uint8_t>& releaseKeySetId,
-                                    Vector<uint8_t>& response,
-                                    Vector<uint8_t>& keySetId) = 0;
-    virtual status_t        restoreKeys(Vector<uint8_t> const& keySetId) = 0;
-    virtual status_t        getDrmPropertyString(String8 const& name, String8& value) = 0;
-    virtual status_t        setDrmPropertyString(String8 const& name, String8 const& value) = 0;
 
     // Invoke a generic method on the player by using opaque parcels
     // for the request and reply.
diff --git a/include/media/IMediaPlayerClient.h b/media/libmedia/include/IMediaPlayerClient.h
similarity index 100%
rename from include/media/IMediaPlayerClient.h
rename to media/libmedia/include/IMediaPlayerClient.h
diff --git a/include/media/IMediaPlayerService.h b/media/libmedia/include/IMediaPlayerService.h
similarity index 100%
rename from include/media/IMediaPlayerService.h
rename to media/libmedia/include/IMediaPlayerService.h
diff --git a/include/media/IMediaRecorder.h b/media/libmedia/include/IMediaRecorder.h
similarity index 97%
rename from include/media/IMediaRecorder.h
rename to media/libmedia/include/IMediaRecorder.h
index d5aec3f..9d0341a 100644
--- a/include/media/IMediaRecorder.h
+++ b/media/libmedia/include/IMediaRecorder.h
@@ -53,6 +53,7 @@
     virtual status_t setClientName(const String16& clientName) = 0;
     virtual status_t prepare() = 0;
     virtual status_t getMaxAmplitude(int* max) = 0;
+    virtual status_t getMetrics(Parcel *reply) = 0;
     virtual status_t start() = 0;
     virtual status_t stop() = 0;
     virtual status_t reset() = 0;
diff --git a/include/media/IMediaRecorderClient.h b/media/libmedia/include/IMediaRecorderClient.h
similarity index 100%
rename from include/media/IMediaRecorderClient.h
rename to media/libmedia/include/IMediaRecorderClient.h
diff --git a/include/media/IMediaSource.h b/media/libmedia/include/IMediaSource.h
similarity index 100%
rename from include/media/IMediaSource.h
rename to media/libmedia/include/IMediaSource.h
diff --git a/include/media/IOMX.h b/media/libmedia/include/IOMX.h
similarity index 99%
rename from include/media/IOMX.h
rename to media/libmedia/include/IOMX.h
index ec1d4b6..39b9ad4 100644
--- a/include/media/IOMX.h
+++ b/media/libmedia/include/IOMX.h
@@ -19,9 +19,9 @@
 #define ANDROID_IOMX_H_
 
 #include <binder/IInterface.h>
-#include <gui/IGraphicBufferProducer.h>
 #include <utils/List.h>
 #include <utils/String8.h>
+#include <cutils/native_handle.h>
 
 #include <list>
 
diff --git a/include/media/IRemoteDisplay.h b/media/libmedia/include/IRemoteDisplay.h
similarity index 100%
rename from include/media/IRemoteDisplay.h
rename to media/libmedia/include/IRemoteDisplay.h
diff --git a/include/media/IRemoteDisplayClient.h b/media/libmedia/include/IRemoteDisplayClient.h
similarity index 100%
rename from include/media/IRemoteDisplayClient.h
rename to media/libmedia/include/IRemoteDisplayClient.h
diff --git a/include/media/IResourceManagerClient.h b/media/libmedia/include/IResourceManagerClient.h
similarity index 100%
rename from include/media/IResourceManagerClient.h
rename to media/libmedia/include/IResourceManagerClient.h
diff --git a/include/media/IResourceManagerService.h b/media/libmedia/include/IResourceManagerService.h
similarity index 100%
rename from include/media/IResourceManagerService.h
rename to media/libmedia/include/IResourceManagerService.h
diff --git a/include/media/IStreamSource.h b/media/libmedia/include/IStreamSource.h
similarity index 100%
rename from include/media/IStreamSource.h
rename to media/libmedia/include/IStreamSource.h
diff --git a/include/media/JetPlayer.h b/media/libmedia/include/JetPlayer.h
similarity index 100%
rename from include/media/JetPlayer.h
rename to media/libmedia/include/JetPlayer.h
diff --git a/include/media/LinearMap.h b/media/libmedia/include/LinearMap.h
similarity index 100%
rename from include/media/LinearMap.h
rename to media/libmedia/include/LinearMap.h
diff --git a/include/media/MediaAnalyticsItem.h b/media/libmedia/include/MediaAnalyticsItem.h
similarity index 100%
rename from include/media/MediaAnalyticsItem.h
rename to media/libmedia/include/MediaAnalyticsItem.h
diff --git a/include/media/MediaCodecBuffer.h b/media/libmedia/include/MediaCodecBuffer.h
similarity index 100%
rename from include/media/MediaCodecBuffer.h
rename to media/libmedia/include/MediaCodecBuffer.h
diff --git a/include/media/MediaCodecInfo.h b/media/libmedia/include/MediaCodecInfo.h
similarity index 100%
rename from include/media/MediaCodecInfo.h
rename to media/libmedia/include/MediaCodecInfo.h
diff --git a/include/media/MediaDefs.h b/media/libmedia/include/MediaDefs.h
similarity index 96%
rename from include/media/MediaDefs.h
rename to media/libmedia/include/MediaDefs.h
index 0682413..7f17013 100644
--- a/include/media/MediaDefs.h
+++ b/media/libmedia/include/MediaDefs.h
@@ -31,6 +31,7 @@
 extern const char *MEDIA_MIMETYPE_VIDEO_MPEG2;
 extern const char *MEDIA_MIMETYPE_VIDEO_RAW;
 extern const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION;
+extern const char *MEDIA_MIMETYPE_VIDEO_SCRAMBLED;
 
 extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB;
 extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
@@ -50,6 +51,7 @@
 extern const char *MEDIA_MIMETYPE_AUDIO_MSGSM;
 extern const char *MEDIA_MIMETYPE_AUDIO_AC3;
 extern const char *MEDIA_MIMETYPE_AUDIO_EAC3;
+extern const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED;
 
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
 extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;
diff --git a/include/media/MediaMetadataRetrieverInterface.h b/media/libmedia/include/MediaMetadataRetrieverInterface.h
similarity index 100%
rename from include/media/MediaMetadataRetrieverInterface.h
rename to media/libmedia/include/MediaMetadataRetrieverInterface.h
diff --git a/include/media/MediaProfiles.h b/media/libmedia/include/MediaProfiles.h
similarity index 100%
rename from include/media/MediaProfiles.h
rename to media/libmedia/include/MediaProfiles.h
diff --git a/include/media/MediaRecorderBase.h b/media/libmedia/include/MediaRecorderBase.h
similarity index 97%
rename from include/media/MediaRecorderBase.h
rename to media/libmedia/include/MediaRecorderBase.h
index c273da7..0b0f916 100644
--- a/include/media/MediaRecorderBase.h
+++ b/media/libmedia/include/MediaRecorderBase.h
@@ -58,6 +58,7 @@
     virtual status_t close() = 0;
     virtual status_t reset() = 0;
     virtual status_t getMaxAmplitude(int *max) = 0;
+    virtual status_t getMetrics(Parcel *reply) = 0;
     virtual status_t dump(int fd, const Vector<String16>& args) const = 0;
     virtual status_t setInputSurface(const sp<PersistentSurface>& surface) = 0;
     virtual sp<IGraphicBufferProducer> querySurfaceMediaSource() const = 0;
diff --git a/include/media/MediaResource.h b/media/libmedia/include/MediaResource.h
similarity index 100%
rename from include/media/MediaResource.h
rename to media/libmedia/include/MediaResource.h
diff --git a/include/media/MediaResourcePolicy.h b/media/libmedia/include/MediaResourcePolicy.h
similarity index 100%
rename from include/media/MediaResourcePolicy.h
rename to media/libmedia/include/MediaResourcePolicy.h
diff --git a/include/media/MemoryLeakTrackUtil.h b/media/libmedia/include/MemoryLeakTrackUtil.h
similarity index 100%
rename from include/media/MemoryLeakTrackUtil.h
rename to media/libmedia/include/MemoryLeakTrackUtil.h
diff --git a/include/media/Metadata.h b/media/libmedia/include/Metadata.h
similarity index 100%
rename from include/media/Metadata.h
rename to media/libmedia/include/Metadata.h
diff --git a/include/media/MidiDeviceInfo.h b/media/libmedia/include/MidiDeviceInfo.h
similarity index 100%
rename from include/media/MidiDeviceInfo.h
rename to media/libmedia/include/MidiDeviceInfo.h
diff --git a/include/media/MidiIoWrapper.h b/media/libmedia/include/MidiIoWrapper.h
similarity index 100%
rename from include/media/MidiIoWrapper.h
rename to media/libmedia/include/MidiIoWrapper.h
diff --git a/include/media/Modulo.h b/media/libmedia/include/Modulo.h
similarity index 100%
rename from include/media/Modulo.h
rename to media/libmedia/include/Modulo.h
diff --git a/include/media/OMXBuffer.h b/media/libmedia/include/OMXBuffer.h
similarity index 100%
rename from include/media/OMXBuffer.h
rename to media/libmedia/include/OMXBuffer.h
diff --git a/include/media/OMXFenceParcelable.h b/media/libmedia/include/OMXFenceParcelable.h
similarity index 100%
rename from include/media/OMXFenceParcelable.h
rename to media/libmedia/include/OMXFenceParcelable.h
diff --git a/include/media/PluginLoader.h b/media/libmedia/include/PluginLoader.h
similarity index 100%
rename from include/media/PluginLoader.h
rename to media/libmedia/include/PluginLoader.h
diff --git a/include/media/RecordBufferConverter.h b/media/libmedia/include/RecordBufferConverter.h
similarity index 100%
rename from include/media/RecordBufferConverter.h
rename to media/libmedia/include/RecordBufferConverter.h
diff --git a/include/media/RingBuffer.h b/media/libmedia/include/RingBuffer.h
similarity index 100%
rename from include/media/RingBuffer.h
rename to media/libmedia/include/RingBuffer.h
diff --git a/include/media/SharedLibrary.h b/media/libmedia/include/SharedLibrary.h
similarity index 100%
rename from include/media/SharedLibrary.h
rename to media/libmedia/include/SharedLibrary.h
diff --git a/include/media/SingleStateQueue.h b/media/libmedia/include/SingleStateQueue.h
similarity index 100%
rename from include/media/SingleStateQueue.h
rename to media/libmedia/include/SingleStateQueue.h
diff --git a/include/media/StringArray.h b/media/libmedia/include/StringArray.h
similarity index 100%
rename from include/media/StringArray.h
rename to media/libmedia/include/StringArray.h
diff --git a/include/media/TypeConverter.h b/media/libmedia/include/TypeConverter.h
similarity index 100%
rename from include/media/TypeConverter.h
rename to media/libmedia/include/TypeConverter.h
diff --git a/include/media/Visualizer.h b/media/libmedia/include/Visualizer.h
similarity index 100%
rename from include/media/Visualizer.h
rename to media/libmedia/include/Visualizer.h
diff --git a/include/media/convert.h b/media/libmedia/include/convert.h
similarity index 100%
rename from include/media/convert.h
rename to media/libmedia/include/convert.h
diff --git a/include/media/mediametadataretriever.h b/media/libmedia/include/mediametadataretriever.h
similarity index 100%
rename from include/media/mediametadataretriever.h
rename to media/libmedia/include/mediametadataretriever.h
diff --git a/include/media/mediaplayer.h b/media/libmedia/include/mediaplayer.h
similarity index 93%
rename from include/media/mediaplayer.h
rename to media/libmedia/include/mediaplayer.h
index 2c5ff1f..18d69a7 100644
--- a/include/media/mediaplayer.h
+++ b/media/libmedia/include/mediaplayer.h
@@ -261,19 +261,14 @@
             status_t        getParameter(int key, Parcel* reply);
             status_t        setRetransmitEndpoint(const char* addrString, uint16_t port);
             status_t        setNextMediaPlayer(const sp<MediaPlayer>& player);
-            // ModDrm
-            status_t        prepareDrm(const uint8_t uuid[16], const int mode);
+
+            VolumeShaper::Status applyVolumeShaper(
+                                    const sp<VolumeShaper::Configuration>& configuration,
+                                    const sp<VolumeShaper::Operation>& operation);
+            sp<VolumeShaper::State> getVolumeShaperState(int id);
+            // Modular DRM
+            status_t        prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId);
             status_t        releaseDrm();
-            status_t        getKeyRequest(Vector<uint8_t> const& scope, String8 const& mimeType,
-                                    DrmPlugin::KeyType keyType,
-                                    KeyedVector<String8, String8>& optionalParameters,
-                                    Vector<uint8_t>& request, String8& defaultUrl,
-                                    DrmPlugin::KeyRequestType& keyRequestType);
-            status_t        provideKeyResponse(Vector<uint8_t>& releaseKeySetId,
-                                    Vector<uint8_t>& response, Vector<uint8_t>& keySetId);
-            status_t        restoreKeys(Vector<uint8_t> const& keySetId);
-            status_t        getDrmPropertyString(String8 const& name, String8& value);
-            status_t        setDrmPropertyString(String8 const& name, String8 const& value);
 
 private:
             void            clear_l();
diff --git a/include/media/mediarecorder.h b/media/libmedia/include/mediarecorder.h
similarity index 99%
rename from include/media/mediarecorder.h
rename to media/libmedia/include/mediarecorder.h
index c2916be..071e7a1 100644
--- a/include/media/mediarecorder.h
+++ b/media/libmedia/include/mediarecorder.h
@@ -249,6 +249,7 @@
     void        notify(int msg, int ext1, int ext2);
     status_t    setInputSurface(const sp<PersistentSurface>& surface);
     sp<IGraphicBufferProducer>     querySurfaceMediaSourceFromMediaServer();
+    status_t    getMetrics(Parcel *reply);
 
 private:
     void                    doCleanUp();
diff --git a/include/media/mediascanner.h b/media/libmedia/include/mediascanner.h
similarity index 100%
rename from include/media/mediascanner.h
rename to media/libmedia/include/mediascanner.h
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 2feb035..685065a 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -16,7 +16,7 @@
 */
 
 //#define LOG_NDEBUG 0
-#define LOG_TAG "MediaPlayer"
+#define LOG_TAG "MediaPlayerNative"
 
 #include <fcntl.h>
 #include <inttypes.h>
@@ -991,10 +991,34 @@
     return mPlayer->setNextPlayer(next == NULL ? NULL : next->mPlayer);
 }
 
-// ModDrm
-status_t MediaPlayer::prepareDrm(const uint8_t uuid[16], const int mode)
+VolumeShaper::Status MediaPlayer::applyVolumeShaper(
+        const sp<VolumeShaper::Configuration>& configuration,
+        const sp<VolumeShaper::Operation>& operation)
 {
     Mutex::Autolock _l(mLock);
+    if (mPlayer == nullptr) {
+        return VolumeShaper::Status(NO_INIT);
+    }
+    VolumeShaper::Status status = mPlayer->applyVolumeShaper(configuration, operation);
+    return status;
+}
+
+sp<VolumeShaper::State> MediaPlayer::getVolumeShaperState(int id)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == nullptr) {
+        return nullptr;
+    }
+    return mPlayer->getVolumeShaperState(id);
+}
+
+// Modular DRM
+status_t MediaPlayer::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId)
+{
+    // TODO change to ALOGV
+    ALOGD("prepareDrm: uuid: %p  drmSessionId: %p(%zu)", uuid,
+            drmSessionId.array(), drmSessionId.size());
+    Mutex::Autolock _l(mLock);
     if (mPlayer == NULL) {
         return NO_INIT;
     }
@@ -1005,10 +1029,19 @@
         return INVALID_OPERATION;
     }
 
-    status_t ret = mPlayer->prepareDrm(uuid, mode);
-    ALOGV("prepareDrm: ret=%d", ret);
+    if (drmSessionId.isEmpty()) {
+        ALOGE("prepareDrm: Unexpected. Can't proceed with crypto. Empty drmSessionId.");
+        return INVALID_OPERATION;
+    }
 
-    return ret;
+    // Passing down to mediaserver mainly for creating the crypto
+    status_t status = mPlayer->prepareDrm(uuid, drmSessionId);
+    ALOGE_IF(status != OK, "prepareDrm: Failed at mediaserver with ret: %d", status);
+
+    // TODO change to ALOGV
+    ALOGD("prepareDrm: mediaserver::prepareDrm ret=%d", status);
+
+    return status;
 }
 
 status_t MediaPlayer::releaseDrm()
@@ -1018,96 +1051,26 @@
         return NO_INIT;
     }
 
-    // Not allowing releaseDrm in an active state
-    if (mCurrentState & (MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED)) {
-        ALOGE("releaseDrm can not be called in the started/paused state.");
+    // Not allowing releaseDrm in an active/resumable state
+    if (mCurrentState & (MEDIA_PLAYER_STARTED |
+                         MEDIA_PLAYER_PAUSED |
+                         MEDIA_PLAYER_PLAYBACK_COMPLETE |
+                         MEDIA_PLAYER_STATE_ERROR)) {
+        ALOGE("releaseDrm Unexpected state %d. Can only be called in stopped/idle.", mCurrentState);
         return INVALID_OPERATION;
     }
 
-    status_t ret = mPlayer->releaseDrm();
-    ALOGV("releaseDrm: ret=%d", ret);
-
-    return ret;
-}
-
-status_t MediaPlayer::getKeyRequest(Vector<uint8_t> const& scope, String8 const& mimeType,
-                              DrmPlugin::KeyType keyType,
-                              KeyedVector<String8, String8>& optionalParameters,
-                              Vector<uint8_t>& request, String8& defaultUrl,
-                              DrmPlugin::KeyRequestType& keyRequestType)
-{
-    Mutex::Autolock _l(mLock);
-    if (mPlayer == NULL) {
-        return NO_INIT;
+    status_t status = mPlayer->releaseDrm();
+    // TODO change to ALOGV
+    ALOGD("releaseDrm: mediaserver::releaseDrm ret: %d", status);
+    if (status != OK) {
+        ALOGE("releaseDrm: Failed at mediaserver with ret: %d", status);
+        // Overriding to OK so the client proceed with its own cleanup
+        // Client can't do more cleanup. mediaserver release its crypto at end of session anyway.
+        status = OK;
     }
 
-    // Not enforcing a particular state beyond the checks enforced by the Java layer
-    // Key exchange can happen after the start.
-    status_t ret = mPlayer->getKeyRequest(scope, mimeType, keyType, optionalParameters,
-                                     request, defaultUrl, keyRequestType);
-    ALOGV("getKeyRequest ret=%d  %d %s %d ", ret,
-          (int)request.size(), defaultUrl.string(), (int)keyRequestType);
-
-    return ret;
-}
-
-status_t MediaPlayer::provideKeyResponse(Vector<uint8_t>& releaseKeySetId,
-                              Vector<uint8_t>& response, Vector<uint8_t>& keySetId)
-{
-    Mutex::Autolock _l(mLock);
-    if (mPlayer == NULL) {
-        return NO_INIT;
-    }
-
-    // Not enforcing a particular state beyond the checks enforced by the Java layer
-    // Key exchange can happen after the start.
-    status_t ret = mPlayer->provideKeyResponse(releaseKeySetId, response, keySetId);
-    ALOGV("provideKeyResponse: ret=%d", ret);
-
-    return ret;
-}
-
-status_t MediaPlayer::restoreKeys(Vector<uint8_t> const& keySetId)
-{
-    Mutex::Autolock _l(mLock);
-    if (mPlayer == NULL) {
-        return NO_INIT;
-    }
-
-    // Not enforcing a particular state beyond the checks enforced by the Java layer
-    // Key exchange can happen after the start.
-    status_t ret = mPlayer->restoreKeys(keySetId);
-    ALOGV("restoreKeys: ret=%d", ret);
-
-    return ret;
-}
-
-status_t MediaPlayer::getDrmPropertyString(String8 const& name, String8& value)
-{
-    Mutex::Autolock _l(mLock);
-    if (mPlayer == NULL) {
-        return NO_INIT;
-    }
-
-    // Not enforcing a particular state beyond the checks enforced by the Java layer
-    status_t ret = mPlayer->getDrmPropertyString(name, value);
-    ALOGV("getDrmPropertyString: ret=%d", ret);
-
-    return ret;
-}
-
-status_t MediaPlayer::setDrmPropertyString(String8 const& name, String8 const& value)
-{
-    Mutex::Autolock _l(mLock);
-    if (mPlayer == NULL) {
-        return NO_INIT;
-    }
-
-    // Not enforcing a particular state beyond the checks enforced by the Java layer
-    status_t ret = mPlayer->setDrmPropertyString(name, value);
-    ALOGV("setDrmPropertyString: ret=%d", ret);
-
-    return ret;
+    return status;
 }
 
 } // namespace android
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index dbe4b3b..4405930 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -513,6 +513,17 @@
     return ret;
 }
 
+status_t MediaRecorder::getMetrics(Parcel *reply) {
+
+    ALOGV("getMetrics");
+
+    status_t ret = mMediaRecorder->getMetrics(reply);
+    if (OK != ret) {
+        ALOGE("getMetrics failed: %d", ret);
+    }
+    return ret;
+}
+
 status_t MediaRecorder::start()
 {
     ALOGV("start");
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 1786e6b..f7e1ff5 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -25,8 +25,9 @@
     liblog                      \
     libdl                       \
     libgui                      \
-    libmedia                    \
     libaudioclient              \
+    libmedia                    \
+    libmediadrm                 \
     libmediautils               \
     libmemunreachable           \
     libstagefright              \
@@ -35,6 +36,9 @@
     libstagefright_omx          \
     libstagefright_wfd          \
     libutils                    \
+    libnativewindow             \
+    libhidlbase                 \
+    android.hardware.media.omx@1.0 \
 
 LOCAL_STATIC_LIBRARIES :=       \
     libstagefright_nuplayer     \
@@ -48,7 +52,7 @@
     $(TOP)/frameworks/av/media/libstagefright/rtsp                  \
     $(TOP)/frameworks/av/media/libstagefright/wifi-display          \
     $(TOP)/frameworks/av/media/libstagefright/webm                  \
-    $(TOP)/frameworks/av/include/media                              \
+    $(LOCAL_PATH)/include/media                              \
     $(TOP)/frameworks/av/include/camera                             \
     $(TOP)/frameworks/native/include/media/openmax                  \
     $(TOP)/frameworks/native/include/media/hardware                 \
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 2d4c475..f3fc924 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -60,6 +60,7 @@
 #include <media/stagefright/Utils.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooperRoster.h>
+#include <media/stagefright/SurfaceUtils.h>
 #include <mediautils/BatteryNotifier.h>
 
 #include <memunreachable/memunreachable.h>
@@ -597,6 +598,7 @@
     if (mAudioAttributes != NULL) {
         free(mAudioAttributes);
     }
+    clearDeathNotifiers();
 }
 
 void MediaPlayerService::Client::disconnect()
@@ -654,12 +656,22 @@
         const sp<MediaPlayerBase>& listener,
         int which) {
     mService = service;
+    mOmx = nullptr;
+    mListener = listener;
+    mWhich = which;
+}
+
+MediaPlayerService::Client::ServiceDeathNotifier::ServiceDeathNotifier(
+        const sp<IOmx>& omx,
+        const sp<MediaPlayerBase>& listener,
+        int which) {
+    mService = nullptr;
+    mOmx = omx;
     mListener = listener;
     mWhich = which;
 }
 
 MediaPlayerService::Client::ServiceDeathNotifier::~ServiceDeathNotifier() {
-    mService->unlinkToDeath(this);
 }
 
 void MediaPlayerService::Client::ServiceDeathNotifier::binderDied(const wp<IBinder>& /*who*/) {
@@ -671,10 +683,43 @@
     }
 }
 
+void MediaPlayerService::Client::ServiceDeathNotifier::serviceDied(
+        uint64_t /* cookie */,
+        const wp<::android::hidl::base::V1_0::IBase>& /* who */) {
+    sp<MediaPlayerBase> listener = mListener.promote();
+    if (listener != NULL) {
+        listener->sendEvent(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, mWhich);
+    } else {
+        ALOGW("listener for process %d death is gone", mWhich);
+    }
+}
+
+void MediaPlayerService::Client::ServiceDeathNotifier::unlinkToDeath() {
+    if (mService != nullptr) {
+        mService->unlinkToDeath(this);
+        mService = nullptr;
+    } else if (mOmx != nullptr) {
+        mOmx->unlinkToDeath(this);
+        mOmx = nullptr;
+    }
+}
+
+void MediaPlayerService::Client::clearDeathNotifiers() {
+    if (mExtractorDeathListener != nullptr) {
+        mExtractorDeathListener->unlinkToDeath();
+        mExtractorDeathListener = nullptr;
+    }
+    if (mCodecDeathListener != nullptr) {
+        mCodecDeathListener->unlinkToDeath();
+        mCodecDeathListener = nullptr;
+    }
+}
+
 sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
         player_type playerType)
 {
     ALOGV("player type = %d", playerType);
+    clearDeathNotifiers();
 
     // create the right type of player
     sp<MediaPlayerBase> p = createPlayer(playerType);
@@ -691,13 +736,27 @@
     mExtractorDeathListener = new ServiceDeathNotifier(binder, p, MEDIAEXTRACTOR_PROCESS_DEATH);
     binder->linkToDeath(mExtractorDeathListener);
 
-    binder = sm->getService(String16("media.codec"));
-    if (binder == NULL) {
-        ALOGE("codec service not available");
-        return NULL;
+    int32_t trebleOmx = property_get_int32("persist.media.treble_omx", -1);
+    if ((trebleOmx == 1) || ((trebleOmx == -1) &&
+            property_get_bool("persist.hal.binderization", 0))) {
+        // Treble IOmx
+        sp<IOmx> omx = IOmx::getService();
+        if (omx == nullptr) {
+            ALOGE("Treble IOmx not available");
+            return NULL;
+        }
+        mCodecDeathListener = new ServiceDeathNotifier(omx, p, MEDIACODEC_PROCESS_DEATH);
+        omx->linkToDeath(mCodecDeathListener, 0);
+    } else {
+        // Legacy IOMX
+        binder = sm->getService(String16("media.codec"));
+        if (binder == NULL) {
+            ALOGE("codec service not available");
+            return NULL;
+        }
+        mCodecDeathListener = new ServiceDeathNotifier(binder, p, MEDIACODEC_PROCESS_DEATH);
+        binder->linkToDeath(mCodecDeathListener);
     }
-    mCodecDeathListener = new ServiceDeathNotifier(binder, p, MEDIACODEC_PROCESS_DEATH);
-    binder->linkToDeath(mCodecDeathListener);
 
     if (!p->hardwareOutput()) {
         Mutex::Autolock l(mLock);
@@ -845,11 +904,11 @@
 
 void MediaPlayerService::Client::disconnectNativeWindow() {
     if (mConnectedWindow != NULL) {
-        status_t err = native_window_api_disconnect(mConnectedWindow.get(),
-                NATIVE_WINDOW_API_MEDIA);
+        status_t err = nativeWindowDisconnect(
+                mConnectedWindow.get(), "disconnectNativeWindow");
 
         if (err != OK) {
-            ALOGW("native_window_api_disconnect returned an error: %s (%d)",
+            ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
                     strerror(-err), err);
         }
     }
@@ -871,8 +930,7 @@
     sp<ANativeWindow> anw;
     if (bufferProducer != NULL) {
         anw = new Surface(bufferProducer, true /* controlledByApp */);
-        status_t err = native_window_api_connect(anw.get(),
-                NATIVE_WINDOW_API_MEDIA);
+        status_t err = nativeWindowConnect(anw.get(), "setVideoSurfaceTexture");
 
         if (err != OK) {
             ALOGE("setVideoSurfaceTexture failed: %d", err);
@@ -1147,6 +1205,42 @@
     return OK;
 }
 
+VolumeShaper::Status MediaPlayerService::Client::applyVolumeShaper(
+        const sp<VolumeShaper::Configuration>& configuration,
+        const sp<VolumeShaper::Operation>& operation) {
+    // for hardware output, call player instead
+    ALOGV("Client::applyVolumeShaper(%p)", this);
+    sp<MediaPlayerBase> p = getPlayer();
+    {
+        Mutex::Autolock l(mLock);
+        if (p != 0 && p->hardwareOutput()) {
+            // TODO: investigate internal implementation
+            return VolumeShaper::Status(INVALID_OPERATION);
+        }
+        if (mAudioOutput.get() != nullptr) {
+            return mAudioOutput->applyVolumeShaper(configuration, operation);
+        }
+    }
+    return VolumeShaper::Status(INVALID_OPERATION);
+}
+
+sp<VolumeShaper::State> MediaPlayerService::Client::getVolumeShaperState(int id) {
+    // for hardware output, call player instead
+    ALOGV("Client::getVolumeShaperState(%p)", this);
+    sp<MediaPlayerBase> p = getPlayer();
+    {
+        Mutex::Autolock l(mLock);
+        if (p != 0 && p->hardwareOutput()) {
+            // TODO: investigate internal implementation.
+            return nullptr;
+        }
+        if (mAudioOutput.get() != nullptr) {
+            return mAudioOutput->getVolumeShaperState(id);
+        }
+    }
+    return nullptr;
+}
+
 status_t MediaPlayerService::Client::seekTo(int msec, MediaPlayerSeekMode mode)
 {
     ALOGV("[%d] seekTo(%d, %d)", mConnId, msec, mode);
@@ -1392,6 +1486,32 @@
     }
 }
 
+// Modular DRM
+status_t MediaPlayerService::Client::prepareDrm(const uint8_t uuid[16],
+        const Vector<uint8_t>& drmSessionId)
+{
+    ALOGV("[%d] prepareDrm", mConnId);
+    sp<MediaPlayerBase> p = getPlayer();
+    if (p == 0) return UNKNOWN_ERROR;
+
+    status_t ret = p->prepareDrm(uuid, drmSessionId);
+    ALOGV("prepareDrm ret: %d", ret);
+
+    return ret;
+}
+
+status_t MediaPlayerService::Client::releaseDrm()
+{
+    ALOGV("[%d] releaseDrm", mConnId);
+    sp<MediaPlayerBase> p = getPlayer();
+    if (p == 0) return UNKNOWN_ERROR;
+
+    status_t ret = p->releaseDrm();
+    ALOGV("releaseDrm ret: %d", ret);
+
+    return ret;
+}
+
 #if CALLBACK_ANTAGONIZER
 const int Antagonizer::interval = 10000; // 10 msecs
 
@@ -1446,7 +1566,8 @@
       mPid(pid),
       mSendLevel(0.0),
       mAuxEffectId(0),
-      mFlags(AUDIO_OUTPUT_FLAG_NONE)
+      mFlags(AUDIO_OUTPUT_FLAG_NONE),
+      mVolumeHandler(new VolumeHandler())
 {
     ALOGV("AudioOutput(%d)", sessionId);
     if (attr != NULL) {
@@ -1910,6 +2031,13 @@
     ALOGV("setVolume");
     t->setVolume(mLeftVolume, mRightVolume);
 
+    // Dispatch any queued VolumeShapers when the track was not open.
+    mVolumeHandler->forall([&t](const sp<VolumeShaper::Configuration> &configuration,
+            const sp<VolumeShaper::Operation> &operation) -> VolumeShaper::Status {
+        return t->applyVolumeShaper(configuration, operation);
+    });
+    mVolumeHandler->reset(); // After dispatching, clear VolumeShaper queue.
+
     mSampleRateHz = sampleRate;
     mFlags = flags;
     mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate);
@@ -2146,6 +2274,32 @@
     return NO_ERROR;
 }
 
+VolumeShaper::Status MediaPlayerService::AudioOutput::applyVolumeShaper(
+                const sp<VolumeShaper::Configuration>& configuration,
+                const sp<VolumeShaper::Operation>& operation)
+{
+    Mutex::Autolock lock(mLock);
+    ALOGV("AudioOutput::applyVolumeShaper");
+
+    // We take ownership of the VolumeShaper if set before the track is created.
+    mVolumeHandler->setIdIfNecessary(configuration);
+    if (mTrack != 0) {
+        return mTrack->applyVolumeShaper(configuration, operation);
+    } else {
+        return mVolumeHandler->applyVolumeShaper(configuration, operation);
+    }
+}
+
+sp<VolumeShaper::State> MediaPlayerService::AudioOutput::getVolumeShaperState(int id)
+{
+    Mutex::Autolock lock(mLock);
+    if (mTrack != 0) {
+        return mTrack->getVolumeShaperState(id);
+    } else {
+        return mVolumeHandler->getVolumeShaperState(id);
+    }
+}
+
 // static
 void MediaPlayerService::AudioOutput::CallbackWrapper(
         int event, void *cookie, void *info) {
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 819973e..009fe73 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -30,6 +30,8 @@
 #include <media/Metadata.h>
 #include <media/stagefright/foundation/ABase.h>
 
+#include <android/hardware/media/omx/1.0/IOmx.h>
+
 #include <system/audio.h>
 
 namespace android {
@@ -69,6 +71,7 @@
 class MediaPlayerService : public BnMediaPlayerService
 {
     class Client;
+    typedef ::android::hardware::media::omx::V1_0::IOmx IOmx;
 
     class AudioOutput : public MediaPlayerBase::AudioSink
     {
@@ -129,6 +132,11 @@
         virtual status_t        setParameters(const String8& keyValuePairs);
         virtual String8         getParameters(const String8& keys);
 
+        virtual VolumeShaper::Status applyVolumeShaper(
+                                        const sp<VolumeShaper::Configuration>& configuration,
+                                        const sp<VolumeShaper::Operation>& operation) override;
+        virtual sp<VolumeShaper::State> getVolumeShaperState(int id) override;
+
     private:
         static void             setMinBufferCount();
         static void             CallbackWrapper(
@@ -157,6 +165,7 @@
         float                   mSendLevel;
         int                     mAuxEffectId;
         audio_output_flags_t    mFlags;
+        sp<VolumeHandler>       mVolumeHandler;
         mutable Mutex           mLock;
 
         // static variables below not protected by mutex
@@ -323,6 +332,11 @@
         virtual status_t        getRetransmitEndpoint(struct sockaddr_in* endpoint);
         virtual status_t        setNextPlayer(const sp<IMediaPlayer>& player);
 
+        virtual VolumeShaper::Status applyVolumeShaper(
+                                        const sp<VolumeShaper::Configuration>& configuration,
+                                        const sp<VolumeShaper::Operation>& operation) override;
+        virtual sp<VolumeShaper::State> getVolumeShaperState(int id) override;
+
         sp<MediaPlayerBase>     createPlayer(player_type playerType);
 
         virtual status_t        setDataSource(
@@ -347,50 +361,40 @@
         virtual status_t        dump(int fd, const Vector<String16>& args);
 
                 audio_session_t getAudioSessionId() { return mAudioSessionId; }
-        // ModDrm
-        virtual status_t prepareDrm(const uint8_t /*uuid*/[16], const int /*mode*/)
-                            { return INVALID_OPERATION; }
-        virtual status_t releaseDrm()
-                            { return INVALID_OPERATION; }
-        virtual status_t getKeyRequest(Vector<uint8_t> const& /*scope*/,
-                                 String8 const& /*mimeType*/,
-                                 DrmPlugin::KeyType /*keyType*/,
-                                 KeyedVector<String8, String8>& /*optionalParameters*/,
-                                 Vector<uint8_t>& /*request*/,
-                                 String8& /*defaultUrl*/,
-                                 DrmPlugin::KeyRequestType& /*keyRequestType*/)
-                            { return INVALID_OPERATION; }
-        virtual status_t provideKeyResponse(Vector<uint8_t>& /*releaseKeySetId*/,
-                                 Vector<uint8_t>& /*response*/,
-                                 Vector<uint8_t>& /*keySetId*/)
-                            { return INVALID_OPERATION; }
-        virtual status_t restoreKeys(Vector<uint8_t> const& /*keySetId*/)
-                            { return INVALID_OPERATION; }
-        virtual status_t getDrmPropertyString(String8 const& /*name*/,
-                                              String8& /*value*/)
-                            { return INVALID_OPERATION; }
-        virtual status_t setDrmPropertyString(String8 const& /*name*/,
-                                              String8 const& /*value*/)
-                            { return INVALID_OPERATION; }
-
+        // Modular DRM
+        virtual status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId);
+        virtual status_t releaseDrm();
 
     private:
-        class ServiceDeathNotifier: public IBinder::DeathRecipient
+        class ServiceDeathNotifier:
+                public IBinder::DeathRecipient,
+                public ::android::hardware::hidl_death_recipient
         {
         public:
             ServiceDeathNotifier(
                     const sp<IBinder>& service,
                     const sp<MediaPlayerBase>& listener,
                     int which);
+            ServiceDeathNotifier(
+                    const sp<IOmx>& omx,
+                    const sp<MediaPlayerBase>& listener,
+                    int which);
             virtual ~ServiceDeathNotifier();
             virtual void binderDied(const wp<IBinder>& who);
+            virtual void serviceDied(
+                    uint64_t cookie,
+                    const wp<::android::hidl::base::V1_0::IBase>& who);
+            void unlinkToDeath();
 
         private:
             int mWhich;
             sp<IBinder> mService;
+            sp<IOmx> mOmx;
             wp<MediaPlayerBase> mListener;
         };
 
+        void clearDeathNotifiers();
+
         friend class MediaPlayerService;
                                 Client( const sp<MediaPlayerService>& service,
                                         pid_t pid,
@@ -450,8 +454,8 @@
         // getMetadata clears this set.
         media::Metadata::Filter mMetadataUpdated;  // protected by mLock
 
-        sp<IBinder::DeathRecipient> mExtractorDeathListener;
-        sp<IBinder::DeathRecipient> mCodecDeathListener;
+        sp<ServiceDeathNotifier> mExtractorDeathListener;
+        sp<ServiceDeathNotifier> mCodecDeathListener;
 #if CALLBACK_ANTAGONIZER
                     Antagonizer*                mAntagonizer;
 #endif
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index bb2d28b..c00a951 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -238,6 +238,17 @@
     return mRecorder->getMaxAmplitude(max);
 }
 
+status_t MediaRecorderClient::getMetrics(Parcel* reply)
+{
+    ALOGV("MediaRecorderClient::getMetrics");
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        ALOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->getMetrics(reply);
+}
+
 status_t MediaRecorderClient::start()
 {
     ALOGV("start");
@@ -328,6 +339,7 @@
         wp<MediaRecorderClient> client(this);
         mMediaPlayerService->removeMediaRecorderClient(client);
     }
+    clearDeathNotifiers();
     return NO_ERROR;
 }
 
@@ -351,15 +363,25 @@
         const sp<IMediaRecorderClient>& listener,
         int which) {
     mService = service;
+    mOmx = nullptr;
+    mListener = listener;
+    mWhich = which;
+}
+
+MediaRecorderClient::ServiceDeathNotifier::ServiceDeathNotifier(
+        const sp<IOmx>& omx,
+        const sp<IMediaRecorderClient>& listener,
+        int which) {
+    mService = nullptr;
+    mOmx = omx;
     mListener = listener;
     mWhich = which;
 }
 
 MediaRecorderClient::ServiceDeathNotifier::~ServiceDeathNotifier() {
-    mService->unlinkToDeath(this);
 }
 
-void  MediaRecorderClient::ServiceDeathNotifier::binderDied(const wp<IBinder>& /*who*/) {
+void MediaRecorderClient::ServiceDeathNotifier::binderDied(const wp<IBinder>& /*who*/) {
     sp<IMediaRecorderClient> listener = mListener.promote();
     if (listener != NULL) {
         listener->notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, mWhich);
@@ -368,9 +390,42 @@
     }
 }
 
+void MediaRecorderClient::ServiceDeathNotifier::serviceDied(
+        uint64_t /* cookie */,
+        const wp<::android::hidl::base::V1_0::IBase>& /* who */) {
+    sp<IMediaRecorderClient> listener = mListener.promote();
+    if (listener != NULL) {
+        listener->notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, mWhich);
+    } else {
+        ALOGW("listener for process %d death is gone", mWhich);
+    }
+}
+
+void MediaRecorderClient::ServiceDeathNotifier::unlinkToDeath() {
+    if (mService != nullptr) {
+        mService->unlinkToDeath(this);
+        mService = nullptr;
+    } else if (mOmx != nullptr) {
+        mOmx->unlinkToDeath(this);
+        mOmx = nullptr;
+    }
+}
+
+void MediaRecorderClient::clearDeathNotifiers() {
+    if (mCameraDeathListener != nullptr) {
+        mCameraDeathListener->unlinkToDeath();
+        mCameraDeathListener = nullptr;
+    }
+    if (mCodecDeathListener != nullptr) {
+        mCodecDeathListener->unlinkToDeath();
+        mCodecDeathListener = nullptr;
+    }
+}
+
 status_t MediaRecorderClient::setListener(const sp<IMediaRecorderClient>& listener)
 {
     ALOGV("setListener");
+    clearDeathNotifiers();
     Mutex::Autolock lock(mLock);
     if (mRecorder == NULL) {
         ALOGE("recorder is not initialized");
@@ -395,10 +450,25 @@
     }
     sCameraChecked = true;
 
-    binder = sm->getService(String16("media.codec"));
-    mCodecDeathListener = new ServiceDeathNotifier(binder, listener,
-            MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
-    binder->linkToDeath(mCodecDeathListener);
+    int32_t trebleOmx = property_get_int32("persist.media.treble_omx", -1);
+    if ((trebleOmx == 1) || ((trebleOmx == -1) &&
+            property_get_bool("persist.hal.binderization", 0))) {
+        // Treble IOmx
+        sp<IOmx> omx = IOmx::getService();
+        if (omx == nullptr) {
+            ALOGE("Treble IOmx not available");
+            return NO_INIT;
+        }
+        mCodecDeathListener = new ServiceDeathNotifier(omx, listener,
+                MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
+        omx->linkToDeath(mCodecDeathListener, 0);
+    } else {
+        // Legacy IOMX
+        binder = sm->getService(String16("media.codec"));
+        mCodecDeathListener = new ServiceDeathNotifier(binder, listener,
+                MediaPlayerService::MEDIACODEC_PROCESS_DEATH);
+        binder->linkToDeath(mCodecDeathListener);
+    }
 
     return OK;
 }
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 8ddd680..7868a91 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -20,6 +20,8 @@
 
 #include <media/IMediaRecorder.h>
 
+#include <android/hardware/media/omx/1.0/IOmx.h>
+
 namespace android {
 
 struct MediaRecorderBase;
@@ -28,22 +30,36 @@
 
 class MediaRecorderClient : public BnMediaRecorder
 {
-    class ServiceDeathNotifier: public IBinder::DeathRecipient
+    typedef ::android::hardware::media::omx::V1_0::IOmx IOmx;
+
+    class ServiceDeathNotifier :
+            public IBinder::DeathRecipient,
+            public ::android::hardware::hidl_death_recipient
     {
     public:
         ServiceDeathNotifier(
                 const sp<IBinder>& service,
                 const sp<IMediaRecorderClient>& listener,
                 int which);
+        ServiceDeathNotifier(
+                const sp<IOmx>& omx,
+                const sp<IMediaRecorderClient>& listener,
+                int which);
         virtual ~ServiceDeathNotifier();
         virtual void binderDied(const wp<IBinder>& who);
-
+        virtual void serviceDied(
+                uint64_t cookie,
+                const wp<::android::hidl::base::V1_0::IBase>& who);
+        void unlinkToDeath();
     private:
         int mWhich;
         sp<IBinder> mService;
+        sp<IOmx> mOmx;
         wp<IMediaRecorderClient> mListener;
     };
 
+    void clearDeathNotifiers();
+
 public:
     virtual     status_t   setCamera(const sp<hardware::ICamera>& camera,
                                     const sp<ICameraRecordingProxy>& proxy);
@@ -63,6 +79,7 @@
     virtual     status_t   setClientName(const String16& clientName);
     virtual     status_t   prepare();
     virtual     status_t   getMaxAmplitude(int* max);
+    virtual     status_t   getMetrics(Parcel* reply);
     virtual     status_t   start();
     virtual     status_t   stop();
     virtual     status_t   reset();
@@ -84,8 +101,8 @@
                                                                const String16& opPackageName);
     virtual                ~MediaRecorderClient();
 
-    sp<IBinder::DeathRecipient> mCameraDeathListener;
-    sp<IBinder::DeathRecipient> mCodecDeathListener;
+    sp<ServiceDeathNotifier> mCameraDeathListener;
+    sp<ServiceDeathNotifier> mCodecDeathListener;
 
     pid_t                  mPid;
     Mutex                  mLock;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 9ce65c4..73570c8 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -30,6 +30,7 @@
 #include <binder/IServiceManager.h>
 
 #include <media/IMediaPlayerService.h>
+#include <media/MediaAnalyticsItem.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -65,6 +66,10 @@
 static const float kMinTypicalDisplayRefreshingRate = kTypicalDisplayRefreshingRate / 2;
 static const int kMaxNumVideoTemporalLayers = 8;
 
+// key for media statistics
+static const char *kKeyRecorder = "recorder";
+// attrs for media statistics
+//
 // To collect the encoder usage for the battery app
 static void addBatteryData(uint32_t params) {
     sp<IBinder> binder =
@@ -85,6 +90,8 @@
       mStarted(false) {
 
     ALOGV("Constructor");
+
+    mAnalyticsDirty = false;
     reset();
 }
 
@@ -95,6 +102,80 @@
     if (mLooper != NULL) {
         mLooper->stop();
     }
+
+    // log the current record, provided it has some information worth recording
+    if (mAnalyticsDirty && mAnalyticsItem != NULL) {
+        updateMetrics();
+        if (mAnalyticsItem->count() > 0) {
+            mAnalyticsItem->setFinalized(true);
+            mAnalyticsItem->selfrecord();
+        }
+        delete mAnalyticsItem;
+        mAnalyticsItem = NULL;
+    }
+}
+
+void StagefrightRecorder::updateMetrics() {
+    ALOGV("updateMetrics");
+
+    // we'll populate the values from the raw fields.
+    // (NOT going to populate as we go through the various set* ops)
+
+    // TBD mOutputFormat  = OUTPUT_FORMAT_THREE_GPP;
+    // TBD mAudioEncoder  = AUDIO_ENCODER_AMR_NB;
+    // TBD mVideoEncoder  = VIDEO_ENCODER_DEFAULT;
+    mAnalyticsItem->setInt32("ht", mVideoHeight);
+    mAnalyticsItem->setInt32("wid", mVideoWidth);
+    mAnalyticsItem->setInt32("frame-rate", mFrameRate);
+    mAnalyticsItem->setInt32("video-bitrate", mVideoBitRate);
+    mAnalyticsItem->setInt32("audio-samplerate", mSampleRate);
+    mAnalyticsItem->setInt32("audio-channels", mAudioChannels);
+    mAnalyticsItem->setInt32("audio-bitrate", mAudioBitRate);
+    // TBD mInterleaveDurationUs = 0;
+    mAnalyticsItem->setInt32("video-iframe-interval", mIFramesIntervalSec);
+    // TBD mAudioSourceNode = 0;
+    // TBD mUse64BitFileOffset = false;
+    mAnalyticsItem->setInt32("movie-timescale", mMovieTimeScale);
+    mAnalyticsItem->setInt32("audio-timescale", mAudioTimeScale);
+    mAnalyticsItem->setInt32("video-timescale", mVideoTimeScale);
+    // TBD mCameraId        = 0;
+    // TBD mStartTimeOffsetMs = -1;
+    mAnalyticsItem->setInt32("video-encoder-profile", mVideoEncoderProfile);
+    mAnalyticsItem->setInt32("video-encoder-level", mVideoEncoderLevel);
+    // TBD mMaxFileDurationUs = 0;
+    // TBD mMaxFileSizeBytes = 0;
+    // TBD mTrackEveryTimeDurationUs = 0;
+    mAnalyticsItem->setInt32("capture-fpsenable", mCaptureFpsEnable);
+    mAnalyticsItem->setInt32("capture-fps", mCaptureFps);
+    // TBD mTimeBetweenCaptureUs = -1;
+    // TBD mCameraSourceTimeLapse = NULL;
+    // TBD mMetaDataStoredInVideoBuffers = kMetadataBufferTypeInvalid;
+    // TBD mEncoderProfiles = MediaProfiles::getInstance();
+    mAnalyticsItem->setInt32("rotation", mRotationDegrees);
+    // PII mLatitudex10000 = -3600000;
+    // PII mLongitudex10000 = -3600000;
+    // TBD mTotalBitRate = 0;
+
+    // TBD: some duration information (capture, paused)
+    //
+
+}
+
+void StagefrightRecorder::resetMetrics() {
+    ALOGV("resetMetrics");
+    // flush anything we have, restart the record
+    if (mAnalyticsDirty && mAnalyticsItem != NULL) {
+        updateMetrics();
+        if (mAnalyticsItem->count() > 0) {
+            mAnalyticsItem->setFinalized(true);
+            mAnalyticsItem->selfrecord();
+        }
+        delete mAnalyticsItem;
+        mAnalyticsItem = NULL;
+    }
+    mAnalyticsItem = new MediaAnalyticsItem(kKeyRecorder);
+    (void) mAnalyticsItem->generateSessionID();
+    mAnalyticsDirty = false;
 }
 
 status_t StagefrightRecorder::init() {
@@ -275,6 +356,7 @@
 }
 
 status_t StagefrightRecorder::setNextOutputFile(int fd) {
+    Mutex::Autolock autolock(mLock);
     // Only support MPEG4
     if (mOutputFormat != OUTPUT_FORMAT_MPEG_4) {
         ALOGE("Only MP4 file format supports setting next output file");
@@ -290,6 +372,10 @@
     // start with a clean, empty file
     ftruncate(fd, 0);
     int nextFd = dup(fd);
+    if (mWriter == NULL) {
+        ALOGE("setNextOutputFile failed. Writer has been freed");
+        return INVALID_OPERATION;
+    }
     return mWriter->setNextFd(nextFd);
 }
 
@@ -382,6 +468,7 @@
 
     // Additional check on the sample rate will be performed later.
     mSampleRate = sampleRate;
+
     return OK;
 }
 
@@ -394,6 +481,7 @@
 
     // Additional check on the number of channels will be performed later.
     mAudioChannels = channels;
+
     return OK;
 }
 
@@ -851,6 +939,8 @@
 }
 
 status_t StagefrightRecorder::prepare() {
+    ALOGV("prepare");
+    Mutex::Autolock autolock(mLock);
     if (mVideoSource == VIDEO_SOURCE_SURFACE) {
         return prepareInternal();
     }
@@ -859,6 +949,7 @@
 
 status_t StagefrightRecorder::start() {
     ALOGV("start");
+    Mutex::Autolock autolock(mLock);
     if (mOutputFd < 0) {
         ALOGE("Output file descriptor is invalid");
         return INVALID_OPERATION;
@@ -922,6 +1013,7 @@
     }
 
     if ((status == OK) && (!mStarted)) {
+        mAnalyticsDirty = true;
         mStarted = true;
 
         uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted;
@@ -1804,15 +1896,17 @@
         return OK;
     }
 
+    mPauseStartTimeUs = systemTime() / 1000;
+    sp<MetaData> meta = new MetaData;
+    meta->setInt64(kKeyTime, mPauseStartTimeUs);
+
     if (mAudioEncoderSource != NULL) {
         mAudioEncoderSource->pause();
     }
     if (mVideoEncoderSource != NULL) {
-        mVideoEncoderSource->pause();
+        mVideoEncoderSource->pause(meta.get());
     }
 
-    mPauseStartTimeUs = systemTime() / 1000;
-
     return OK;
 }
 
@@ -1827,6 +1921,8 @@
         return OK;
     }
 
+    int64_t resumeStartTimeUs = systemTime() / 1000;
+
     int64_t bufferStartTimeUs = 0;
     bool allSourcesStarted = true;
     for (const auto &source : { mAudioEncoderSource, mVideoEncoderSource }) {
@@ -1847,18 +1943,20 @@
             mPauseStartTimeUs = bufferStartTimeUs;
         }
         // 30 ms buffer to avoid timestamp overlap
-        mTotalPausedDurationUs += (systemTime() / 1000) - mPauseStartTimeUs - 30000;
+        mTotalPausedDurationUs += resumeStartTimeUs - mPauseStartTimeUs - 30000;
     }
     double timeOffset = -mTotalPausedDurationUs;
     if (mCaptureFpsEnable) {
         timeOffset *= mCaptureFps / mFrameRate;
     }
+    sp<MetaData> meta = new MetaData;
+    meta->setInt64(kKeyTime, resumeStartTimeUs);
     for (const auto &source : { mAudioEncoderSource, mVideoEncoderSource }) {
         if (source == nullptr) {
             continue;
         }
         source->setInputBufferTimeOffset((int64_t)timeOffset);
-        source->start();
+        source->start(meta.get());
     }
     mPauseStartTimeUs = 0;
 
@@ -1867,6 +1965,7 @@
 
 status_t StagefrightRecorder::stop() {
     ALOGV("stop");
+    Mutex::Autolock autolock(mLock);
     status_t err = OK;
 
     if (mCaptureFpsEnable && mCameraSourceTimeLapse != NULL) {
@@ -1874,10 +1973,19 @@
         mCameraSourceTimeLapse = NULL;
     }
 
+    if (mVideoEncoderSource != NULL) {
+        int64_t stopTimeUs = systemTime() / 1000;
+        sp<MetaData> meta = new MetaData;
+        err = mVideoEncoderSource->setStopStimeUs(stopTimeUs);
+    }
+
     if (mWriter != NULL) {
         err = mWriter->stop();
         mWriter.clear();
     }
+
+    resetMetrics();
+
     mTotalPausedDurationUs = 0;
     mPauseStartTimeUs = 0;
 
@@ -1981,9 +2089,27 @@
     return OK;
 }
 
+status_t StagefrightRecorder::getMetrics(Parcel *reply) {
+    ALOGD("StagefrightRecorder::getMetrics");
+
+    if (reply == NULL) {
+        ALOGE("Null pointer argument");
+        return BAD_VALUE;
+    }
+
+    if (mAnalyticsItem == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    updateMetrics();
+    mAnalyticsItem->writeToParcel(reply);
+    return OK;
+}
+
 status_t StagefrightRecorder::dump(
         int fd, const Vector<String16>& args) const {
     ALOGV("dump");
+    Mutex::Autolock autolock(mLock);
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 870c5d0..38377d2 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -18,6 +18,7 @@
 
 #define STAGEFRIGHT_RECORDER_H_
 
+#include <media/MediaAnalyticsItem.h>
 #include <media/MediaRecorderBase.h>
 #include <camera/CameraParameters.h>
 #include <utils/String8.h>
@@ -43,7 +44,6 @@
 struct StagefrightRecorder : public MediaRecorderBase {
     explicit StagefrightRecorder(const String16 &opPackageName);
     virtual ~StagefrightRecorder();
-
     virtual status_t init();
     virtual status_t setAudioSource(audio_source_t as);
     virtual status_t setVideoSource(video_source vs);
@@ -68,11 +68,13 @@
     virtual status_t close();
     virtual status_t reset();
     virtual status_t getMaxAmplitude(int *max);
+    virtual status_t getMetrics(Parcel *reply);
     virtual status_t dump(int fd, const Vector<String16> &args) const;
     // Querying a SurfaceMediaSourcer
     virtual sp<IGraphicBufferProducer> querySurfaceMediaSource() const;
 
 private:
+    mutable Mutex mLock;
     sp<hardware::ICamera> mCamera;
     sp<ICameraRecordingProxy> mCameraProxy;
     sp<IGraphicBufferProducer> mPreviewSurface;
@@ -85,6 +87,11 @@
     int mOutputFd;
     sp<AudioSource> mAudioSourceNode;
 
+    MediaAnalyticsItem *mAnalyticsItem;
+    bool mAnalyticsDirty;
+    void resetMetrics();
+    void updateMetrics();
+
     audio_source_t mAudioSource;
     video_source mVideoSource;
     output_format mOutputFormat;
diff --git a/include/media/MediaPlayerInterface.h b/media/libmediaplayerservice/include/MediaPlayerInterface.h
similarity index 91%
rename from include/media/MediaPlayerInterface.h
rename to media/libmediaplayerservice/include/MediaPlayerInterface.h
index 4e18f1f..a01f7f2 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/media/libmediaplayerservice/include/MediaPlayerInterface.h
@@ -145,6 +145,11 @@
 
         virtual status_t    setParameters(const String8& /* keyValuePairs */) { return NO_ERROR; }
         virtual String8     getParameters(const String8& /* keys */) { return String8::empty(); }
+
+        virtual VolumeShaper::Status applyVolumeShaper(
+                                    const sp<VolumeShaper::Configuration>& configuration,
+                                    const sp<VolumeShaper::Operation>& operation);
+        virtual sp<VolumeShaper::State> getVolumeShaperState(int id);
     };
 
                         MediaPlayerBase() : mCookie(0), mNotify(0) {}
@@ -280,33 +285,13 @@
         return INVALID_OPERATION;
     }
 
-    // ModDrm
-    virtual status_t prepareDrm(const uint8_t uuid[16], const int mode) {
+    // Modular DRM
+    virtual status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId) {
         return INVALID_OPERATION;
     }
     virtual status_t releaseDrm() {
         return INVALID_OPERATION;
     }
-    virtual status_t getKeyRequest(Vector<uint8_t> const& scope, String8 const& mimeType,
-                             DrmPlugin::KeyType keyType,
-                             KeyedVector<String8, String8>& optionalParameters,
-                             Vector<uint8_t>& request, String8& defaultUrl,
-                             DrmPlugin::KeyRequestType& keyRequestType) {
-        return INVALID_OPERATION;
-    }
-    virtual status_t provideKeyResponse(Vector<uint8_t>& releaseKeySetId,
-                             Vector<uint8_t>& response, Vector<uint8_t>& keySetId) {
-        return INVALID_OPERATION;
-    }
-    virtual status_t restoreKeys(Vector<uint8_t> const& keySetId) {
-        return INVALID_OPERATION;
-    }
-    virtual status_t getDrmPropertyString(String8 const& name, String8& value) {
-        return INVALID_OPERATION;
-    }
-    virtual status_t setDrmPropertyString(String8 const& name, String8 const& value) {
-        return INVALID_OPERATION;
-    }
 
 private:
     friend class MediaPlayerService;
diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk
index a0e633c..56c558d 100644
--- a/media/libmediaplayerservice/nuplayer/Android.mk
+++ b/media/libmediaplayerservice/nuplayer/Android.mk
@@ -10,6 +10,7 @@
         NuPlayerDecoderBase.cpp         \
         NuPlayerDecoderPassThrough.cpp  \
         NuPlayerDriver.cpp              \
+        NuPlayerDrm.cpp                 \
         NuPlayerRenderer.cpp            \
         NuPlayerStreamListener.cpp      \
         RTSPSource.cpp                  \
@@ -32,7 +33,11 @@
 LOCAL_CFLAGS += -DENABLE_STAGEFRIGHT_EXPERIMENTS
 endif
 
-LOCAL_SHARED_LIBRARIES := libmedia
+LOCAL_SHARED_LIBRARIES :=       \
+    libbinder                   \
+    libui                       \
+    libmedia                    \
+    libmediadrm                 \
 
 LOCAL_MODULE:= libstagefright_nuplayer
 
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 91a2b7b..c949080 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "GenericSource"
 
 #include "GenericSource.h"
+#include "NuPlayerDrm.h"
 
 #include "AnotherPacketSource.h"
 
@@ -63,14 +64,17 @@
       mUIDValid(uidValid),
       mUID(uid),
       mFd(-1),
-      mDrmManagerClient(NULL),
       mBitrate(-1ll),
       mPendingReadBufferTypes(0) {
+    ALOGV("GenericSource");
+
     mBufferingMonitor = new BufferingMonitor(notify);
     resetDataSource();
 }
 
 void NuPlayer::GenericSource::resetDataSource() {
+    ALOGV("resetDataSource");
+
     mHTTPService.clear();
     mHttpSource.clear();
     mUri.clear();
@@ -81,9 +85,6 @@
     }
     mOffset = 0;
     mLength = 0;
-    setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
-    mDecryptHandle = NULL;
-    mDrmManagerClient = NULL;
     mStarted = false;
     mStopRead = true;
 
@@ -93,12 +94,18 @@
         mBufferingMonitorLooper = NULL;
     }
     mBufferingMonitor->stop();
+
+    mIsDrmProtected = false;
+    mIsSecure = false;
+    mMimes.clear();
 }
 
 status_t NuPlayer::GenericSource::setDataSource(
         const sp<IMediaHTTPService> &httpService,
         const char *url,
         const KeyedVector<String8, String8> *headers) {
+    ALOGV("setDataSource url: %s", url);
+
     resetDataSource();
 
     mHTTPService = httpService;
@@ -115,6 +122,8 @@
 
 status_t NuPlayer::GenericSource::setDataSource(
         int fd, int64_t offset, int64_t length) {
+    ALOGV("setDataSource %d/%lld/%lld", fd, (long long)offset, (long long)length);
+
     resetDataSource();
 
     mFd = dup(fd);
@@ -127,6 +136,8 @@
 }
 
 status_t NuPlayer::GenericSource::setDataSource(const sp<DataSource>& source) {
+    ALOGV("setDataSource (source: %p)", source.get());
+
     resetDataSource();
     mDataSource = source;
     return OK;
@@ -161,6 +172,8 @@
         return UNKNOWN_ERROR;
     }
 
+    mMimes.clear();
+
     for (size_t i = 0; i < numtracks; ++i) {
         sp<IMediaSource> track = extractor->getTrack(i);
         if (track == NULL) {
@@ -176,6 +189,8 @@
         const char *mime;
         CHECK(meta->findCString(kKeyMIMEType, &mime));
 
+        ALOGV("initFromDataSource track[%zu]: %s", i, mime);
+
         // Do the string compare immediately with "mime",
         // we can't assume "mime" would stay valid after another
         // extractor operation, some extractors might modify meta
@@ -192,6 +207,8 @@
                 } else {
                     mAudioIsVorbis = false;
                 }
+
+                mMimes.add(String8(mime));
             }
         } else if (!strncasecmp(mime, "video/", 6)) {
             if (mVideoTrack.mSource == NULL) {
@@ -200,15 +217,8 @@
                 mVideoTrack.mPackets =
                     new AnotherPacketSource(mVideoTrack.mSource->getFormat());
 
-                // check if the source requires secure buffers
-                int32_t secure;
-                if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
-                        && secure) {
-                    mIsSecure = true;
-                    if (mUIDValid) {
-                        extractor->setUID(mUID);
-                    }
-                }
+                // video always at the beginning
+                mMimes.insertAt(String8(mime), 0);
             }
         }
 
@@ -228,11 +238,17 @@
         }
     }
 
+    ALOGV("initFromDataSource mSources.size(): %zu  mIsSecure: %d  mime[0]: %s", mSources.size(),
+            mIsSecure, (mMimes.isEmpty() ? "NONE" : mMimes[0].string()));
+
     if (mSources.size() == 0) {
         ALOGE("b/23705695");
         return UNKNOWN_ERROR;
     }
 
+    // Modular DRM: The return value doesn't affect source initialization.
+    (void)checkDrmInfo();
+
     mBitrate = totalBitrate;
 
     return OK;
@@ -296,6 +312,7 @@
 }
 
 NuPlayer::GenericSource::~GenericSource() {
+    ALOGV("~GenericSource");
     if (mLooper != NULL) {
         mLooper->unregisterHandler(id());
         mLooper->stop();
@@ -304,6 +321,8 @@
 }
 
 void NuPlayer::GenericSource::prepareAsync() {
+    ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL));
+
     if (mLooper == NULL) {
         mLooper = new ALooper;
         mLooper->setName("generic");
@@ -317,6 +336,8 @@
 }
 
 void NuPlayer::GenericSource::onPrepareAsync() {
+    ALOGV("onPrepareAsync: mDataSource: %d", (mDataSource != NULL));
+
     // delayed data source creation
     if (mDataSource == NULL) {
         // set to false first, if the extractor
@@ -380,35 +401,21 @@
     }
 
     notifyFlagsChanged(
-            (mIsSecure ? FLAG_SECURE : 0)
-            | (mDecryptHandle != NULL ? FLAG_PROTECTED : 0)
-            | FLAG_CAN_PAUSE
-            | FLAG_CAN_SEEK_BACKWARD
-            | FLAG_CAN_SEEK_FORWARD
-            | FLAG_CAN_SEEK);
+            // FLAG_SECURE will be known if/when prepareDrm is called by the app
+            // FLAG_PROTECTED will be known if/when prepareDrm is called by the app
+            FLAG_CAN_PAUSE |
+            FLAG_CAN_SEEK_BACKWARD |
+            FLAG_CAN_SEEK_FORWARD |
+            FLAG_CAN_SEEK);
 
-    if (mIsSecure) {
-        // secure decoders must be instantiated before starting widevine source
-        //
-        // TODO: mIsSecure and FLAG_SECURE may be obsolete, revisit after
-        // removing widevine
-        sp<AMessage> reply = new AMessage(kWhatSecureDecodersInstantiated, this);
-        notifyInstantiateSecureDecoders(reply);
-    } else {
-        finishPrepareAsync();
-    }
-}
-
-void NuPlayer::GenericSource::onSecureDecodersInstantiated(status_t err) {
-    if (err != OK) {
-        ALOGE("Failed to instantiate secure decoders!");
-        notifyPreparedAndCleanup(err);
-        return;
-    }
     finishPrepareAsync();
+
+    ALOGV("onPrepareAsync: Done");
 }
 
 void NuPlayer::GenericSource::finishPrepareAsync() {
+    ALOGV("finishPrepareAsync");
+
     status_t err = startSources();
     if (err != OK) {
         ALOGE("Failed to init start data source!");
@@ -443,8 +450,6 @@
             {
                 Mutex::Autolock _l(mDisconnectLock);
                 mDataSource.clear();
-                mDecryptHandle = NULL;
-                mDrmManagerClient = NULL;
                 mCachedSource.clear();
                 mHttpSource.clear();
             }
@@ -468,27 +473,20 @@
         postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
     }
 
-    setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
     mStarted = true;
 
     (new AMessage(kWhatStart, this))->post();
 }
 
 void NuPlayer::GenericSource::stop() {
-    // nothing to do, just account for DRM playback status
-    setDrmPlaybackStatusIfNeeded(Playback::STOP, 0);
     mStarted = false;
 }
 
 void NuPlayer::GenericSource::pause() {
-    // nothing to do, just account for DRM playback status
-    setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
     mStarted = false;
 }
 
 void NuPlayer::GenericSource::resume() {
-    // nothing to do, just account for DRM playback status
-    setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
     mStarted = true;
 
     (new AMessage(kWhatResume, this))->post();
@@ -512,14 +510,6 @@
     }
 }
 
-void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) {
-    if (mDecryptHandle != NULL) {
-        mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position);
-    }
-    mSubtitleTrack.mPackets = new AnotherPacketSource(NULL);
-    mTimedTextTrack.mPackets = new AnotherPacketSource(NULL);
-}
-
 status_t NuPlayer::GenericSource::feedMoreTSData() {
     return OK;
 }
@@ -653,11 +643,14 @@
           break;
       }
 
-      case kWhatSecureDecodersInstantiated:
+      case kWhatPrepareDrm:
       {
-          int32_t err;
-          CHECK(msg->findInt32("err", &err));
-          onSecureDecodersInstantiated(err);
+          status_t status = onPrepareDrm(msg);
+          sp<AMessage> response = new AMessage;
+          response->setInt32("status", status);
+          sp<AReplyToken> replyID;
+          CHECK(msg->senderAwaitsResponse(&replyID));
+          response->postReply(replyID);
           break;
       }
 
@@ -1194,11 +1187,6 @@
         mAudioLastDequeueTimeUs = seekTimeUs;
     }
 
-    setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000);
-    if (!mStarted) {
-        setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0);
-    }
-
     // If currently buffering, post kWhatBufferingEnd first, so that
     // NuPlayer resumes. Otherwise, if cache hits high watermark
     // before new polling happens, no one will resume the playback.
@@ -1219,11 +1207,26 @@
     }
 
     sp<ABuffer> ab;
-    if (mIsSecure && !audio) {
+
+    if (mIsDrmProtected)   {
+        // Modular DRM
+        // Enabled for both video/audio so 1) media buffer is reused without extra copying
+        // 2) meta data can be retrieved in onInputBufferFetched for calling queueSecureInputBuffer.
+
         // data is already provided in the buffer
         ab = new ABuffer(NULL, mb->range_length());
         mb->add_ref();
         ab->setMediaBufferBase(mb);
+
+        // Modular DRM: Required b/c of the above add_ref.
+        // If ref>0, there must be an observer, or it'll crash at release().
+        // TODO: MediaBuffer might need to be revised to ease such need.
+        mb->setObserver(this);
+        // setMediaBufferBase() interestingly doesn't increment the ref count on its own.
+        // Extra increment (since we want to keep mb alive and attached to ab beyond this function
+        // call. This is to counter the effect of mb->release() towards the end.
+        mb->add_ref();
+
     } else {
         ab = new ABuffer(outLength);
         memcpy(ab->data(),
@@ -1828,4 +1831,128 @@
     }
 }
 
+// Modular DRM
+status_t NuPlayer::GenericSource::prepareDrm(
+        const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *crypto)
+{
+    ALOGV("prepareDrm");
+
+    sp<AMessage> msg = new AMessage(kWhatPrepareDrm, this);
+    // synchronous call so just passing the address but with local copies of "const" args
+    uint8_t UUID[16];
+    memcpy(UUID, uuid, sizeof(UUID));
+    Vector<uint8_t> sessionId = drmSessionId;
+    msg->setPointer("uuid", (void*)UUID);
+    msg->setPointer("drmSessionId", (void*)&sessionId);
+    msg->setPointer("crypto", (void*)crypto);
+
+    sp<AMessage> response;
+    status_t status = msg->postAndAwaitResponse(&response);
+
+    if (status == OK && response != NULL) {
+        CHECK(response->findInt32("status", &status));
+        ALOGV_IF(status == OK, "prepareDrm: mCrypto: %p (%d)", crypto->get(),
+                (*crypto != NULL ? (*crypto)->getStrongCount() : 0));
+        ALOGD("prepareDrm ret: %d ", status);
+    } else {
+        ALOGE("prepareDrm err: %d", status);
+    }
+
+    return status;
+}
+
+status_t NuPlayer::GenericSource::onPrepareDrm(const sp<AMessage> &msg)
+{
+    ALOGV("onPrepareDrm ");
+
+    mIsDrmProtected = false;
+    mIsSecure = false;
+
+    uint8_t *uuid;
+    Vector<uint8_t> *drmSessionId;
+    sp<ICrypto> *outCrypto;
+    CHECK(msg->findPointer("uuid", (void**)&uuid));
+    CHECK(msg->findPointer("drmSessionId", (void**)&drmSessionId));
+    CHECK(msg->findPointer("crypto", (void**)&outCrypto));
+
+    status_t status = OK;
+    sp<ICrypto> crypto = NuPlayerDrm::createCryptoAndPlugin(uuid, *drmSessionId, status);
+    if (crypto == NULL) {
+        ALOGE("onPrepareDrm: createCrypto failed. status: %d", status);
+        return status;
+    }
+    ALOGV("onPrepareDrm: createCryptoAndPlugin succeeded for uuid: %s",
+            DrmUUID::toHexString(uuid).string());
+
+    *outCrypto = crypto;
+    // as long a there is an active crypto
+    mIsDrmProtected = true;
+
+    if (mMimes.size() == 0) {
+        status = UNKNOWN_ERROR;
+        ALOGE("onPrepareDrm: Unexpected. Must have at least one track. status: %d", status);
+        return status;
+    }
+
+    // first mime in this list is either the video track, or the first audio track
+    const char *mime = mMimes[0].string();
+    mIsSecure = crypto->requiresSecureDecoderComponent(mime);
+    ALOGV("onPrepareDrm: requiresSecureDecoderComponent mime: %s  isSecure: %d",
+            mime, mIsSecure);
+
+    // Checking the member flags while in the looper to send out the notification.
+    // The legacy mDecryptHandle!=NULL check (for FLAG_PROTECTED) is equivalent to mIsDrmProtected.
+    notifyFlagsChanged(
+            (mIsSecure ? FLAG_SECURE : 0) |
+            (mIsDrmProtected ? FLAG_PROTECTED : 0) |
+            FLAG_CAN_PAUSE |
+            FLAG_CAN_SEEK_BACKWARD |
+            FLAG_CAN_SEEK_FORWARD |
+            FLAG_CAN_SEEK);
+
+    return status;
+}
+
+status_t NuPlayer::GenericSource::checkDrmInfo()
+{
+    if (mFileMeta == NULL) {
+        ALOGE("checkDrmInfo: No metadata");
+        return OK; // letting the caller responds accordingly
+    }
+
+    uint32_t type;
+    const void *pssh;
+    size_t psshsize;
+
+    if (!mFileMeta->findData(kKeyPssh, &type, &pssh, &psshsize)) {
+        ALOGE("checkDrmInfo: No PSSH");
+        return OK; // source without DRM info
+    }
+
+    Parcel parcel;
+    NuPlayerDrm::retrieveDrmInfo(pssh, psshsize, mMimes, &parcel);
+    ALOGV("checkDrmInfo: MEDIA_DRM_INFO PSSH size: %d  Parcel size: %d  objects#: %d",
+          (int)psshsize, (int)parcel.dataSize(), (int)parcel.objectsCount());
+
+    if (parcel.dataSize() == 0) {
+        ALOGE("checkDrmInfo: Unexpected parcel size: 0");
+        return UNKNOWN_ERROR;
+    }
+
+    // Can't pass parcel as a message to the player. Converting Parcel->ABuffer to pass it
+    // to the Player's onSourceNotify then back to Parcel for calling driver's notifyListener.
+    sp<ABuffer> drmInfoBuffer = ABuffer::CreateAsCopy(parcel.data(), parcel.dataSize());
+    notifyDrmInfo(drmInfoBuffer);
+
+    return OK;
+}
+
+void NuPlayer::GenericSource::signalBufferReturned(MediaBuffer *buffer)
+{
+    //ALOGV("signalBufferReturned %p  refCount: %d", buffer, buffer->localRefcount());
+
+    buffer->setObserver(NULL);
+    buffer->release(); // this leads to delete since that there is no observor
+}
+
 }  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index e1949f3..64f21a6 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -28,7 +28,6 @@
 namespace android {
 
 class DecryptHandle;
-class DrmManagerClient;
 struct AnotherPacketSource;
 struct ARTSPController;
 class DataSource;
@@ -38,7 +37,9 @@
 class MediaBuffer;
 struct NuCachedSource2;
 
-struct NuPlayer::GenericSource : public NuPlayer::Source {
+struct NuPlayer::GenericSource : public NuPlayer::Source,
+                                 public MediaBufferObserver // Modular DRM
+{
     GenericSource(const sp<AMessage> &notify, bool uidValid, uid_t uid);
 
     status_t setDataSource(
@@ -84,6 +85,13 @@
 
     virtual void setOffloadAudio(bool offload);
 
+    // Modular DRM
+    virtual void signalBufferReturned(MediaBuffer *buffer);
+
+    virtual status_t prepareDrm(
+            const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *crypto);
+
+
 protected:
     virtual ~GenericSource();
 
@@ -109,6 +117,8 @@
         kWhatStart,
         kWhatResume,
         kWhatSecureDecodersInstantiated,
+        // Modular DRM
+        kWhatPrepareDrm,
     };
 
     struct Track {
@@ -224,8 +234,6 @@
     sp<NuCachedSource2> mCachedSource;
     sp<DataSource> mHttpSource;
     sp<MetaData> mFileMeta;
-    DrmManagerClient *mDrmManagerClient;
-    sp<DecryptHandle> mDecryptHandle;
     bool mStarted;
     bool mStopRead;
     int64_t mBitrate;
@@ -243,7 +251,6 @@
 
     status_t initFromDataSource();
     int64_t getLastReadPosition();
-    void setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position);
 
     void notifyPreparedAndCleanup(status_t err);
     void onSecureDecodersInstantiated(status_t err);
@@ -299,6 +306,13 @@
     void queueDiscontinuityIfNeeded(
             bool seeking, bool formatChange, media_track_type trackType, Track *track);
 
+    // Modular DRM
+    bool mIsDrmProtected;
+    Vector<String8> mMimes;
+
+    status_t checkDrmInfo();
+    status_t onPrepareDrm(const sp<AMessage> &msg);
+
     DISALLOW_EVIL_CONSTRUCTORS(GenericSource);
 };
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 6593fcd..50d5343 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -199,7 +199,8 @@
       mSourceStarted(false),
       mPaused(false),
       mPausedByClient(true),
-      mPausedForBuffering(false) {
+      mPausedForBuffering(false),
+      mIsDrmProtected(false) {
     clearFlushComplete();
 }
 
@@ -254,16 +255,21 @@
     sp<Source> source;
     if (IsHTTPLiveURL(url)) {
         source = new HTTPLiveSource(notify, httpService, url, headers);
+        ALOGV("setDataSourceAsync HTTPLiveSource %s", url);
     } else if (!strncasecmp(url, "rtsp://", 7)) {
         source = new RTSPSource(
                 notify, httpService, url, headers, mUIDValid, mUID);
+        ALOGV("setDataSourceAsync RTSPSource %s", url);
     } else if ((!strncasecmp(url, "http://", 7)
                 || !strncasecmp(url, "https://", 8))
                     && ((len >= 4 && !strcasecmp(".sdp", &url[len - 4]))
                     || strstr(url, ".sdp?"))) {
         source = new RTSPSource(
                 notify, httpService, url, headers, mUIDValid, mUID, true);
+        ALOGV("setDataSourceAsync RTSPSource http/https/.sdp %s", url);
     } else {
+        ALOGV("setDataSourceAsync GenericSource %s", url);
+
         sp<GenericSource> genericSource =
                 new GenericSource(notify, mUIDValid, mUID);
 
@@ -287,6 +293,9 @@
     sp<GenericSource> source =
             new GenericSource(notify, mUIDValid, mUID);
 
+    ALOGV("setDataSourceAsync fd %d/%lld/%lld source: %p",
+            fd, (long long)offset, (long long)length, source.get());
+
     status_t err = source->setDataSource(fd, offset, length);
 
     if (err != OK) {
@@ -340,6 +349,8 @@
 }
 
 void NuPlayer::prepareAsync() {
+    ALOGV("prepareAsync");
+
     (new AMessage(kWhatPrepare, this))->post();
 }
 
@@ -577,6 +588,8 @@
 
         case kWhatPrepare:
         {
+            ALOGV("onMessageReceived kWhatPrepare");
+
             mSource->prepareAsync();
             break;
         }
@@ -1133,11 +1146,6 @@
                     case SHUTTING_DOWN_DECODER:
                         break; // Wait for shutdown to complete.
                     case FLUSHED:
-                        // Widevine source reads must stop before releasing the video decoder.
-                        if (!audio && mSource != NULL && mSourceFlags & Source::FLAG_SECURE) {
-                            mSource->stop();
-                            mSourceStarted = false;
-                        }
                         getDecoder(audio)->initiateShutdown(); // In the middle of a seek.
                         *flushing = SHUTTING_DOWN_DECODER;     // Shut down.
                         break;
@@ -1330,6 +1338,30 @@
             break;
         }
 
+        case kWhatPrepareDrm:
+        {
+            status_t status = onPrepareDrm(msg);
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("status", status);
+            sp<AReplyToken> replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+            response->postReply(replyID);
+            break;
+        }
+
+        case kWhatReleaseDrm:
+        {
+            status_t status = onReleaseDrm();
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("status", status);
+            sp<AReplyToken> replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+            response->postReply(replyID);
+            break;
+        }
+
         default:
             TRESPASS();
             break;
@@ -1391,6 +1423,9 @@
 }
 
 void NuPlayer::onStart(int64_t startPositionUs, MediaPlayerSeekMode mode) {
+    ALOGV("onStart: mCrypto: %p (%d)", mCrypto.get(),
+            (mCrypto != NULL ? mCrypto->getStrongCount() : 0));
+
     if (!mSourceStarted) {
         mSourceStarted = true;
         mSource->start();
@@ -1435,6 +1470,13 @@
     mOffloadAudio =
         canOffloadStream(audioMeta, hasVideo, mSource->isStreaming(), streamType)
                 && (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
+
+    // Modular DRM: Disabling audio offload if the source is protected
+    if (mOffloadAudio && mIsDrmProtected) {
+        mOffloadAudio = false;
+        ALOGV("onStart: Disabling mOffloadAudio now that the source is protected.");
+    }
+
     if (mOffloadAudio) {
         flags |= Renderer::FLAG_OFFLOAD_AUDIO;
     }
@@ -1527,13 +1569,6 @@
             *state = SHUTTING_DOWN_DECODER;
 
             ALOGV("initiating %s decoder shutdown", audio ? "audio" : "video");
-            if (!audio) {
-                // Widevine source reads must stop before releasing the video decoder.
-                if (mSource != NULL && mSourceFlags & Source::FLAG_SECURE) {
-                    mSource->stop();
-                    mSourceStarted = false;
-                }
-            }
             getDecoder(audio)->initiateShutdown();
             break;
         }
@@ -1650,9 +1685,16 @@
     sp<AMessage> videoFormat = mSource->getFormat(false /* audio */);
     audio_stream_type_t streamType = mAudioSink->getAudioStreamType();
     const bool hasVideo = (videoFormat != NULL);
-    const bool canOffload = canOffloadStream(
+    bool canOffload = canOffloadStream(
             audioMeta, hasVideo, mSource->isStreaming(), streamType)
                     && (mPlaybackSettings.mSpeed == 1.f && mPlaybackSettings.mPitch == 1.f);
+
+    // Modular DRM: Disabling audio offload if the source is protected
+    if (canOffload && mIsDrmProtected) {
+        canOffload = false;
+        ALOGV("determineAudioModeChange: Disabling mOffloadAudio b/c the source is protected.");
+    }
+
     if (canOffload) {
         if (!mOffloadAudio) {
             mRenderer->signalEnableOffloadAudio();
@@ -1725,10 +1767,12 @@
             const bool hasVideo = (mSource->getFormat(false /*audio */) != NULL);
             format->setInt32("has-video", hasVideo);
             *decoder = new DecoderPassThrough(notify, mSource, mRenderer);
+            ALOGV("instantiateDecoder audio DecoderPassThrough  hasVideo: %d", hasVideo);
         } else {
             mSource->setOffloadAudio(false /* offload */);
 
             *decoder = new Decoder(notify, mSource, mPID, mUID, mRenderer);
+            ALOGV("instantiateDecoder audio Decoder");
         }
     } else {
         sp<AMessage> notify = new AMessage(kWhatVideoNotify, this);
@@ -1748,6 +1792,15 @@
         }
     }
     (*decoder)->init();
+
+    // Modular DRM
+    if (mIsDrmProtected) {
+        format->setPointer("crypto", mCrypto.get());
+        ALOGV("instantiateDecoder: mCrypto: %p (%d) isSecure: %d", mCrypto.get(),
+                (mCrypto != NULL ? mCrypto->getStrongCount() : 0),
+                (mSourceFlags & Source::FLAG_SECURE) != 0);
+    }
+
     (*decoder)->configure(format);
 
     if (!audio) {
@@ -2142,6 +2195,16 @@
     mPrepared = false;
     mResetting = false;
     mSourceStarted = false;
+
+    // Modular DRM
+    if (mCrypto != NULL) {
+        // decoders will be flushed before this so their mCrypto would go away on their own
+        // TODO change to ALOGV
+        ALOGD("performReset mCrypto: %p (%d)", mCrypto.get(),
+                (mCrypto != NULL ? mCrypto->getStrongCount() : 0));
+        mCrypto.clear();
+    }
+    mIsDrmProtected = false;
 }
 
 void NuPlayer::performScanSources() {
@@ -2236,6 +2299,7 @@
 
         case Source::kWhatPrepared:
         {
+            ALOGV("NuPlayer::onSourceNotify Source::kWhatPrepared source: %p", mSource.get());
             if (mSource == NULL) {
                 // This is a stale notification from a source that was
                 // asynchronously preparing when the client called reset().
@@ -2270,6 +2334,22 @@
             break;
         }
 
+        // Modular DRM
+        case Source::kWhatDrmInfo:
+        {
+            Parcel parcel;
+            sp<ABuffer> drmInfo;
+            CHECK(msg->findBuffer("drmInfo", &drmInfo));
+            parcel.setData(drmInfo->data(), drmInfo->size());
+
+            ALOGV("onSourceNotify() kWhatDrmInfo MEDIA_DRM_INFO drmInfo: %p  parcel size: %zu",
+                    drmInfo.get(), parcel.dataSize());
+
+            notifyListener(MEDIA_DRM_INFO, 0 /* ext1 */, 0 /* ext2 */, &parcel);
+
+            break;
+        }
+
         case Source::kWhatFlagsChanged:
         {
             uint32_t flags;
@@ -2277,6 +2357,19 @@
 
             sp<NuPlayerDriver> driver = mDriver.promote();
             if (driver != NULL) {
+
+                ALOGV("onSourceNotify() kWhatFlagsChanged  FLAG_CAN_PAUSE: %d  "
+                        "FLAG_CAN_SEEK_BACKWARD: %d \n\t\t\t\t FLAG_CAN_SEEK_FORWARD: %d  "
+                        "FLAG_CAN_SEEK: %d  FLAG_DYNAMIC_DURATION: %d \n"
+                        "\t\t\t\t FLAG_SECURE: %d  FLAG_PROTECTED: %d",
+                        (flags & Source::FLAG_CAN_PAUSE) != 0,
+                        (flags & Source::FLAG_CAN_SEEK_BACKWARD) != 0,
+                        (flags & Source::FLAG_CAN_SEEK_FORWARD) != 0,
+                        (flags & Source::FLAG_CAN_SEEK) != 0,
+                        (flags & Source::FLAG_DYNAMIC_DURATION) != 0,
+                        (flags & Source::FLAG_SECURE) != 0,
+                        (flags & Source::FLAG_PROTECTED) != 0);
+
                 if ((flags & NuPlayer::Source::FLAG_CAN_SEEK) == 0) {
                     driver->notifyListener(
                             MEDIA_INFO, MEDIA_INFO_NOT_SEEKABLE, 0);
@@ -2527,6 +2620,136 @@
         notifyListener(MEDIA_TIMED_TEXT, 0, 0);
     }
 }
+
+// Modular DRM begin
+status_t NuPlayer::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId)
+{
+    ALOGV("prepareDrm ");
+
+    // Passing to the looper anyway; called in a pre-config prepared state so no race on mCrypto
+    sp<AMessage> msg = new AMessage(kWhatPrepareDrm, this);
+    // synchronous call so just passing the address but with local copies of "const" args
+    uint8_t UUID[16];
+    memcpy(UUID, uuid, sizeof(UUID));
+    Vector<uint8_t> sessionId = drmSessionId;
+    msg->setPointer("uuid", (void*)UUID);
+    msg->setPointer("drmSessionId", (void*)&sessionId);
+
+    sp<AMessage> response;
+    status_t status = msg->postAndAwaitResponse(&response);
+
+    if (status == OK && response != NULL) {
+        CHECK(response->findInt32("status", &status));
+        ALOGV("prepareDrm ret: %d ", status);
+    } else {
+        ALOGE("prepareDrm err: %d", status);
+    }
+
+    return status;
+}
+
+status_t NuPlayer::releaseDrm()
+{
+    ALOGV("releaseDrm ");
+
+    sp<AMessage> msg = new AMessage(kWhatReleaseDrm, this);
+
+    sp<AMessage> response;
+    status_t status = msg->postAndAwaitResponse(&response);
+
+    if (status == OK && response != NULL) {
+        CHECK(response->findInt32("status", &status));
+        ALOGV("releaseDrm ret: %d ", status);
+    } else {
+        ALOGE("releaseDrm err: %d", status);
+    }
+
+    return status;
+}
+
+status_t NuPlayer::onPrepareDrm(const sp<AMessage> &msg)
+{
+    // TODO change to ALOGV
+    ALOGD("onPrepareDrm ");
+
+    status_t status = INVALID_OPERATION;
+    if (mSource == NULL) {
+        ALOGE("onPrepareDrm: No source. onPrepareDrm failed with %d.", status);
+        return status;
+    }
+
+    uint8_t *uuid;
+    Vector<uint8_t> *drmSessionId;
+    CHECK(msg->findPointer("uuid", (void**)&uuid));
+    CHECK(msg->findPointer("drmSessionId", (void**)&drmSessionId));
+
+    status = OK;
+    sp<ICrypto> crypto = NULL;
+
+    status = mSource->prepareDrm(uuid, *drmSessionId, &crypto);
+    if (crypto == NULL) {
+        ALOGE("onPrepareDrm: mSource->prepareDrm failed. status: %d", status);
+        return status;
+    }
+    ALOGV("onPrepareDrm: mSource->prepareDrm succeeded");
+
+    if (mCrypto != NULL) {
+        ALOGE("onPrepareDrm: Unexpected. Already having mCrypto: %p (%d)",
+                mCrypto.get(), mCrypto->getStrongCount());
+        mCrypto.clear();
+    }
+
+    mCrypto = crypto;
+    mIsDrmProtected = true;
+    // TODO change to ALOGV
+    ALOGD("onPrepareDrm: mCrypto: %p (%d)", mCrypto.get(),
+            (mCrypto != NULL ? mCrypto->getStrongCount() : 0));
+
+    return status;
+}
+
+status_t NuPlayer::onReleaseDrm()
+{
+    // TODO change to ALOGV
+    ALOGD("onReleaseDrm ");
+
+    if (!mIsDrmProtected) {
+        ALOGW("onReleaseDrm: Unexpected. mIsDrmProtected is already false.");
+    }
+
+    mIsDrmProtected = false;
+
+    status_t status;
+    if (mCrypto != NULL) {
+        status=OK;
+        // first making sure the codecs have released their crypto reference
+        const sp<DecoderBase> &videoDecoder = getDecoder(false/*audio*/);
+        if (videoDecoder != NULL) {
+            status = videoDecoder->releaseCrypto();
+            ALOGV("onReleaseDrm: video decoder ret: %d", status);
+        }
+
+        const sp<DecoderBase> &audioDecoder = getDecoder(true/*audio*/);
+        if (audioDecoder != NULL) {
+            status_t status_audio = audioDecoder->releaseCrypto();
+            if (status == OK) {   // otherwise, returning the first error
+                status = status_audio;
+            }
+            ALOGV("onReleaseDrm: audio decoder ret: %d", status_audio);
+        }
+
+        // TODO change to ALOGV
+        ALOGD("onReleaseDrm: mCrypto: %p (%d)", mCrypto.get(),
+                (mCrypto != NULL ? mCrypto->getStrongCount() : 0));
+        mCrypto.clear();
+    } else {   // mCrypto == NULL
+        ALOGE("onReleaseDrm: Unexpected. There is no crypto.");
+        status = INVALID_OPERATION;
+    }
+
+    return status;
+}
+// Modular DRM end
 ////////////////////////////////////////////////////////////////////////////////
 
 sp<AMessage> NuPlayer::Source::getFormat(bool audio) {
@@ -2559,12 +2782,24 @@
 }
 
 void NuPlayer::Source::notifyPrepared(status_t err) {
+    ALOGV("Source::notifyPrepared %d", err);
     sp<AMessage> notify = dupNotify();
     notify->setInt32("what", kWhatPrepared);
     notify->setInt32("err", err);
     notify->post();
 }
 
+void NuPlayer::Source::notifyDrmInfo(const sp<ABuffer> &drmInfoBuffer)
+{
+    ALOGV("Source::notifyDrmInfo");
+
+    sp<AMessage> notify = dupNotify();
+    notify->setInt32("what", kWhatDrmInfo);
+    notify->setBuffer("drmInfo", drmInfoBuffer);
+
+    notify->post();
+}
+
 void NuPlayer::Source::notifyInstantiateSecureDecoders(const sp<AMessage> &reply) {
     sp<AMessage> notify = dupNotify();
     notify->setInt32("what", kWhatInstantiateSecureDecoders);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index cc8c97a..d3cb7c1 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -19,6 +19,7 @@
 #define NU_PLAYER_H_
 
 #include <media/AudioResamplerPublic.h>
+#include <media/ICrypto.h>
 #include <media/MediaPlayerInterface.h>
 #include <media/stagefright/foundation/AHandler.h>
 
@@ -88,6 +89,10 @@
     sp<MetaData> getFileMeta();
     float getFrameRate();
 
+    // Modular DRM
+    status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId);
+    status_t releaseDrm();
+
 protected:
     virtual ~NuPlayer();
 
@@ -142,6 +147,8 @@
         kWhatSelectTrack                = 'selT',
         kWhatGetDefaultBufferingSettings = 'gDBS',
         kWhatSetBufferingSettings       = 'sBuS',
+        kWhatPrepareDrm                 = 'pDrm',
+        kWhatReleaseDrm                 = 'rDrm',
     };
 
     wp<NuPlayerDriver> mDriver;
@@ -223,6 +230,10 @@
     // Pause state as requested by source (internally) due to buffering
     bool mPausedForBuffering;
 
+    // Modular DRM
+    sp<ICrypto> mCrypto;
+    bool mIsDrmProtected;
+
     inline const sp<DecoderBase> &getDecoder(bool audio) {
         return audio ? mAudioDecoder : mVideoDecoder;
     }
@@ -294,6 +305,9 @@
 
     void writeTrackInfo(Parcel* reply, const sp<AMessage>& format) const;
 
+    status_t onPrepareDrm(const sp<AMessage> &msg);
+    status_t onReleaseDrm();
+
     DISALLOW_EVIL_CONSTRUCTORS(NuPlayer);
 };
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 1d62498..9a2224e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -23,6 +23,7 @@
 
 #include "NuPlayerCCDecoder.h"
 #include "NuPlayerDecoder.h"
+#include "NuPlayerDrm.h"
 #include "NuPlayerRenderer.h"
 #include "NuPlayerSource.h"
 
@@ -36,7 +37,7 @@
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
-
+#include <media/stagefright/SurfaceUtils.h>
 #include <gui/Surface.h>
 
 #include "avc_utils.h"
@@ -231,21 +232,21 @@
                 //
                 // at this point MediaPlayerService::client has already connected to the
                 // surface, which MediaCodec does not expect
-                err = native_window_api_disconnect(surface.get(), NATIVE_WINDOW_API_MEDIA);
+                err = nativeWindowDisconnect(surface.get(), "kWhatSetVideoSurface(surface)");
                 if (err == OK) {
                     err = mCodec->setSurface(surface);
                     ALOGI_IF(err, "codec setSurface returned: %d", err);
                     if (err == OK) {
                         // reconnect to the old surface as MPS::Client will expect to
                         // be able to disconnect from it.
-                        (void)native_window_api_connect(mSurface.get(), NATIVE_WINDOW_API_MEDIA);
+                        (void)nativeWindowConnect(mSurface.get(), "kWhatSetVideoSurface(mSurface)");
                         mSurface = surface;
                     }
                 }
                 if (err != OK) {
                     // reconnect to the new surface on error as MPS::Client will expect to
                     // be able to disconnect from it.
-                    (void)native_window_api_connect(surface.get(), NATIVE_WINDOW_API_MEDIA);
+                    (void)nativeWindowConnect(surface.get(), "kWhatSetVideoSurface(err)");
                 }
             }
 
@@ -255,6 +256,13 @@
             break;
         }
 
+        case kWhatDrmReleaseCrypto:
+        {
+            ALOGV("kWhatDrmReleaseCrypto");
+            onReleaseCrypto(msg);
+            break;
+        }
+
         default:
             DecoderBase::onMessageReceived(msg);
             break;
@@ -305,15 +313,25 @@
     status_t err;
     if (mSurface != NULL) {
         // disconnect from surface as MediaCodec will reconnect
-        err = native_window_api_disconnect(
-                mSurface.get(), NATIVE_WINDOW_API_MEDIA);
+        err = nativeWindowDisconnect(mSurface.get(), "onConfigure");
         // We treat this as a warning, as this is a preparatory step.
         // Codec will try to connect to the surface, which is where
         // any error signaling will occur.
         ALOGW_IF(err != OK, "failed to disconnect from surface: %d", err);
     }
+
+    // Modular DRM
+    void *pCrypto;
+    if (!format->findPointer("crypto", &pCrypto)) {
+        pCrypto = NULL;
+    }
+    sp<ICrypto> crypto = (ICrypto*)pCrypto;
+    ALOGV("onConfigure mCrypto: %p (%d)  mIsSecure: %d",
+            crypto.get(), (crypto != NULL ? crypto->getStrongCount() : 0), mIsSecure);
+
     err = mCodec->configure(
-            format, mSurface, NULL /* crypto */, 0 /* flags */);
+            format, mSurface, crypto, 0 /* flags */);
+
     if (err != OK) {
         ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err);
         mCodec->release();
@@ -491,8 +509,7 @@
 
         if (mSurface != NULL) {
             // reconnect to surface as MediaCodec disconnected from it
-            status_t error =
-                    native_window_api_connect(mSurface.get(), NATIVE_WINDOW_API_MEDIA);
+            status_t error = nativeWindowConnect(mSurface.get(), "onShutdown");
             ALOGW_IF(error != NO_ERROR,
                     "[%s] failed to connect to native window, error=%d",
                     mComponentName.c_str(), error);
@@ -559,6 +576,43 @@
     notify->post();
 }
 
+status_t NuPlayer::Decoder::releaseCrypto()
+{
+    ALOGV("releaseCrypto");
+
+    sp<AMessage> msg = new AMessage(kWhatDrmReleaseCrypto, this);
+
+    sp<AMessage> response;
+    status_t status = msg->postAndAwaitResponse(&response);
+    if (status == OK && response != NULL) {
+        CHECK(response->findInt32("status", &status));
+        ALOGV("releaseCrypto ret: %d ", status);
+    } else {
+        ALOGE("releaseCrypto err: %d", status);
+    }
+
+    return status;
+}
+
+void NuPlayer::Decoder::onReleaseCrypto(const sp<AMessage>& msg)
+{
+    status_t status = INVALID_OPERATION;
+    if (mCodec != NULL) {
+        status = mCodec->releaseCrypto();
+    } else {
+        // returning OK if the codec has been already released
+        status = OK;
+        ALOGE("onReleaseCrypto No mCodec. err: %d", status);
+    }
+
+    sp<AMessage> response = new AMessage;
+    response->setInt32("status", status);
+
+    sp<AReplyToken> replyID;
+    CHECK(msg->senderAwaitsResponse(&replyID));
+    response->postReply(replyID);
+}
+
 bool NuPlayer::Decoder::handleAnInputBuffer(size_t index) {
     if (isDiscontinuityPending()) {
         return false;
@@ -634,6 +688,11 @@
     sp<MediaCodecBuffer> buffer;
     mCodec->getOutputBuffer(index, &buffer);
 
+    if (buffer == NULL) {
+        handleError(UNKNOWN_ERROR);
+        return false;
+    }
+
     if (index >= mOutputBuffers.size()) {
         for (size_t i = mOutputBuffers.size(); i <= index; ++i) {
             mOutputBuffers.add();
@@ -924,6 +983,10 @@
             flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
         }
 
+        // Modular DRM
+        MediaBuffer *mediaBuf = NULL;
+        NuPlayerDrm::CryptoInfo *cryptInfo = NULL;
+
         // copy into codec buffer
         if (needsCopy) {
             if (buffer->size() > codecBuffer->capacity()) {
@@ -931,24 +994,68 @@
                 mDequeuedInputBuffers.push_back(bufferIx);
                 return false;
             }
-            codecBuffer->setRange(0, buffer->size());
-            memcpy(codecBuffer->data(), buffer->data(), buffer->size());
-        }
 
-        status_t err = mCodec->queueInputBuffer(
-                        bufferIx,
-                        codecBuffer->offset(),
-                        codecBuffer->size(),
-                        timeUs,
-                        flags);
+            if (buffer->data() != NULL) {
+                codecBuffer->setRange(0, buffer->size());
+                memcpy(codecBuffer->data(), buffer->data(), buffer->size());
+            } else { // No buffer->data()
+                //Modular DRM
+                mediaBuf = (MediaBuffer*)buffer->getMediaBufferBase();
+                if (mediaBuf != NULL) {
+                    codecBuffer->setRange(0, mediaBuf->size());
+                    memcpy(codecBuffer->data(), mediaBuf->data(), mediaBuf->size());
+
+                    sp<MetaData> meta_data = mediaBuf->meta_data();
+                    cryptInfo = NuPlayerDrm::getSampleCryptoInfo(meta_data);
+
+                    // since getMediaBuffer() has incremented the refCount
+                    mediaBuf->release();
+                } else { // No mediaBuf
+                    ALOGE("onInputBufferFetched: buffer->data()/mediaBuf are NULL for %p",
+                            buffer.get());
+                    handleError(UNKNOWN_ERROR);
+                    return false;
+                }
+            } // buffer->data()
+        } // needsCopy
+
+        status_t err;
+        AString errorDetailMsg;
+        if (cryptInfo != NULL) {
+            err = mCodec->queueSecureInputBuffer(
+                    bufferIx,
+                    codecBuffer->offset(),
+                    cryptInfo->subSamples,
+                    cryptInfo->numSubSamples,
+                    cryptInfo->key,
+                    cryptInfo->iv,
+                    cryptInfo->mode,
+                    cryptInfo->pattern,
+                    timeUs,
+                    flags,
+                    &errorDetailMsg);
+            // synchronous call so done with cryptInfo here
+            free(cryptInfo);
+        } else {
+            err = mCodec->queueInputBuffer(
+                    bufferIx,
+                    codecBuffer->offset(),
+                    codecBuffer->size(),
+                    timeUs,
+                    flags,
+                    &errorDetailMsg);
+        } // no cryptInfo
+
         if (err != OK) {
-            ALOGE("Failed to queue input buffer for %s (err=%d)",
-                    mComponentName.c_str(), err);
+            ALOGE("onInputBufferFetched: queue%sInputBuffer failed for %s (err=%d, %s)",
+                    (cryptInfo != NULL ? "Secure" : ""),
+                    mComponentName.c_str(), err, errorDetailMsg.c_str());
             handleError(err);
         } else {
             mInputBufferIsDequeued.editItemAt(bufferIx) = false;
         }
-    }
+
+    }   // buffer != NULL
     return true;
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 82db59c..de21379 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -39,6 +39,8 @@
     // sets the output surface of video decoders.
     virtual status_t setVideoSurface(const sp<Surface> &surface);
 
+    virtual status_t releaseCrypto();
+
 protected:
     virtual ~Decoder();
 
@@ -57,7 +59,8 @@
         kWhatCodecNotify         = 'cdcN',
         kWhatRenderBuffer        = 'rndr',
         kWhatSetVideoSurface     = 'sSur',
-        kWhatAudioOutputFormatChanged = 'aofc'
+        kWhatAudioOutputFormatChanged = 'aofc',
+        kWhatDrmReleaseCrypto    = 'rDrm',
     };
 
     enum {
@@ -135,6 +138,8 @@
 
     void notifyResumeCompleteIfNecessary();
 
+    void onReleaseCrypto(const sp<AMessage>& msg);
+
     DISALLOW_EVIL_CONSTRUCTORS(Decoder);
 };
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
index 6811903..dcdfcaf 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
@@ -51,6 +51,10 @@
         return mStats;
     }
 
+    virtual status_t releaseCrypto() {
+        return INVALID_OPERATION;
+    }
+
     enum {
         kWhatInputDiscontinuity  = 'inDi',
         kWhatVideoSizeChanged    = 'viSC',
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 0ddbd63..3b2a8a1 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -206,9 +206,11 @@
 
 status_t NuPlayerDriver::getDefaultBufferingSettings(BufferingSettings* buffering) {
     ALOGV("getDefaultBufferingSettings(%p)", this);
-    Mutex::Autolock autoLock(mLock);
-    if (mState == STATE_IDLE) {
-        return INVALID_OPERATION;
+    {
+        Mutex::Autolock autoLock(mLock);
+        if (mState == STATE_IDLE) {
+            return INVALID_OPERATION;
+        }
     }
 
     return mPlayer->getDefaultBufferingSettings(buffering);
@@ -216,9 +218,11 @@
 
 status_t NuPlayerDriver::setBufferingSettings(const BufferingSettings& buffering) {
     ALOGV("setBufferingSettings(%p)", this);
-    Mutex::Autolock autoLock(mLock);
-    if (mState == STATE_IDLE) {
-        return INVALID_OPERATION;
+    {
+        Mutex::Autolock autoLock(mLock);
+        if (mState == STATE_IDLE) {
+            return INVALID_OPERATION;
+        }
     }
 
     return mPlayer->setBufferingSettings(buffering);
@@ -884,8 +888,8 @@
 
 void NuPlayerDriver::notifyListener_l(
         int msg, int ext1, int ext2, const Parcel *in) {
-    ALOGD("notifyListener_l(%p), (%d, %d, %d), loop setting(%d, %d)",
-            this, msg, ext1, ext2, mAutoLoop, mLooping);
+    ALOGD("notifyListener_l(%p), (%d, %d, %d, %d), loop setting(%d, %d)",
+            this, msg, ext1, ext2, (in == NULL ? -1 : (int)in->dataSize()), mAutoLoop, mLooping);
     switch (msg) {
         case MEDIA_PLAYBACK_COMPLETE:
         {
@@ -943,6 +947,8 @@
 }
 
 void NuPlayerDriver::notifyPrepareCompleted(status_t err) {
+    ALOGV("notifyPrepareCompleted %d", err);
+
     Mutex::Autolock autoLock(mLock);
 
     if (mState != STATE_PREPARING) {
@@ -987,4 +993,33 @@
     mPlayerFlags = flags;
 }
 
+// Modular DRM
+status_t NuPlayerDriver::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId)
+{
+    ALOGV("prepareDrm(%p) state: %d", this, mState);
+
+    Mutex::Autolock autoLock(mLock);
+
+    // leaving the state verification for mediaplayer.cpp
+    status_t ret = mPlayer->prepareDrm(uuid, drmSessionId);
+
+    ALOGV("prepareDrm ret: %d", ret);
+
+    return ret;
+}
+
+status_t NuPlayerDriver::releaseDrm()
+{
+    ALOGV("releaseDrm(%p) state: %d", this, mState);
+
+    Mutex::Autolock autoLock(mLock);
+
+    // leaving the state verification for mediaplayer.cpp
+    status_t ret = mPlayer->releaseDrm();
+
+    ALOGV("releaseDrm ret: %d", ret);
+
+    return ret;
+}
+
 }  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 5bfc539..972a348 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -87,6 +87,10 @@
     void notifyListener(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL);
     void notifyFlagsChanged(uint32_t flags);
 
+    // Modular DRM
+    virtual status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId);
+    virtual status_t releaseDrm();
+
 protected:
     virtual ~NuPlayerDriver();
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
new file mode 100644
index 0000000..ce6cedc
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
@@ -0,0 +1,366 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "NuPlayerDrm"
+
+#include "NuPlayerDrm.h"
+
+#include <binder/IServiceManager.h>
+#include <media/IMediaDrmService.h>
+#include <utils/Log.h>
+
+
+namespace android {
+
+// static helpers - internal
+
+sp<IDrm> NuPlayerDrm::CreateDrm(status_t *pstatus)
+{
+    status_t &status = *pstatus;
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16("media.drm"));
+    ALOGV("CreateDrm binder %p", (binder != NULL ? binder.get() : 0));
+
+    sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
+    if (service == NULL) {
+        ALOGE("CreateDrm failed at IMediaDrmService");
+        return NULL;
+    }
+
+    sp<IDrm> drm = service->makeDrm();
+    if (drm == NULL) {
+        ALOGE("CreateDrm failed at makeDrm");
+        return NULL;
+    }
+
+    // this is before plugin creation so NO_INIT is fine
+    status = drm->initCheck();
+    if (status != OK && status != NO_INIT) {
+        ALOGE("CreateDrm failed drm->initCheck(): %d", status);
+        return NULL;
+    }
+    return drm;
+}
+
+sp<ICrypto> NuPlayerDrm::createCrypto(status_t *pstatus)
+{
+    status_t &status = *pstatus;
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> binder = sm->getService(String16("media.drm"));
+
+    sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
+    if (service == NULL) {
+        status = UNKNOWN_ERROR;
+        ALOGE("CreateCrypto failed at IMediaDrmService");
+        return NULL;
+    }
+
+    sp<ICrypto> crypto = service->makeCrypto();
+    if (crypto == NULL) {
+        status = UNKNOWN_ERROR;
+        ALOGE("createCrypto failed");
+        return NULL;
+    }
+
+    // this is before plugin creation so NO_INIT is fine
+    status = crypto->initCheck();
+    if (status != OK && status != NO_INIT) {
+        ALOGE("createCrypto failed crypto->initCheck(): %d", status);
+        return NULL;
+    }
+
+    return crypto;
+}
+
+Vector<DrmUUID> NuPlayerDrm::parsePSSH(const void *pssh, size_t psshsize)
+{
+    Vector<DrmUUID> drmSchemes, empty;
+    const int DATALEN_SIZE = 4;
+
+    // the format of the buffer is 1 or more of:
+    //    {
+    //        16 byte uuid
+    //        4 byte data length N
+    //        N bytes of data
+    //    }
+    // Determine the number of entries in the source data.
+    // Since we got the data from stagefright, we trust it is valid and properly formatted.
+
+    const uint8_t *data = (const uint8_t*)pssh;
+    size_t len = psshsize;
+    size_t numentries = 0;
+    while (len > 0) {
+        if (len < DrmUUID::UUID_SIZE) {
+            ALOGE("ParsePSSH: invalid PSSH data");
+            return empty;
+        }
+
+        const uint8_t *uuidPtr = data;
+
+        // skip uuid
+        data += DrmUUID::UUID_SIZE;
+        len -= DrmUUID::UUID_SIZE;
+
+        // get data length
+        if (len < DATALEN_SIZE) {
+            ALOGE("ParsePSSH: invalid PSSH data");
+            return empty;
+        }
+
+        uint32_t datalen = *((uint32_t*)data);
+        data += DATALEN_SIZE;
+        len -= DATALEN_SIZE;
+
+        if (len < datalen) {
+            ALOGE("ParsePSSH: invalid PSSH data");
+            return empty;
+        }
+
+        // skip the data
+        data += datalen;
+        len -= datalen;
+
+        DrmUUID _uuid(uuidPtr);
+        drmSchemes.add(_uuid);
+
+        ALOGV("ParsePSSH[%zu]: %s: %s", numentries,
+                _uuid.toHexString().string(),
+                DrmUUID::arrayToHex(data, datalen).string()
+             );
+
+        numentries++;
+    }
+
+    return drmSchemes;
+}
+
+Vector<DrmUUID> NuPlayerDrm::getSupportedDrmSchemes(const void *pssh, size_t psshsize)
+{
+    Vector<DrmUUID> psshDRMs = parsePSSH(pssh, psshsize);
+
+    Vector<DrmUUID> supportedDRMs;
+     // temporary DRM object for crypto Scheme enquiry (without creating a plugin)
+    status_t status = OK;
+    sp<IDrm> drm = CreateDrm(&status);
+    if (drm != NULL) {
+        for (size_t i = 0; i < psshDRMs.size(); i++) {
+            DrmUUID uuid = psshDRMs[i];
+            if (drm->isCryptoSchemeSupported(uuid.ptr(), String8()))
+                supportedDRMs.add(uuid);
+        }
+
+        drm.clear();
+    } else {
+        ALOGE("getSupportedDrmSchemes: Can't create Drm obj: %d", status);
+    }
+
+    ALOGV("getSupportedDrmSchemes: psshDRMs: %zu supportedDRMs: %zu",
+            psshDRMs.size(), supportedDRMs.size());
+
+    return supportedDRMs;
+}
+
+// static helpers - public
+
+sp<ICrypto> NuPlayerDrm::createCryptoAndPlugin(const uint8_t uuid[16],
+        const Vector<uint8_t> &drmSessionId, status_t &status)
+{
+    // Extra check
+    if (drmSessionId.isEmpty()) {
+        status = INVALID_OPERATION;
+        ALOGE("createCryptoAndPlugin: Failed. Empty drmSessionId. status: %d", status);
+        return NULL;
+    }
+
+    status = OK;
+    sp<ICrypto> crypto = createCrypto(&status);
+    if (crypto == NULL) {
+        ALOGE("createCryptoAndPlugin: createCrypto failed. status: %d", status);
+        return NULL;
+    }
+    ALOGV("createCryptoAndPlugin: createCrypto succeeded");
+
+    status = crypto->createPlugin(uuid, drmSessionId.array(), drmSessionId.size());
+    if (status != OK) {
+        ALOGE("createCryptoAndPlugin: createCryptoPlugin failed. status: %d", status);
+        // crypto will clean itself when leaving the current scope
+        return NULL;
+    }
+
+    return crypto;
+}
+
+// Parcel has only private copy constructor so passing it in rather than returning
+void NuPlayerDrm::retrieveDrmInfo(const void *pssh, size_t psshsize,
+        const Vector<String8> &mimes_in, Parcel *parcel)
+{
+    // 0) Make mimes a vector of unique items while keeping the original order; video first
+    Vector<String8> mimes;
+    for (size_t j = 0; j < mimes_in.size(); j++) {
+        String8 mime = mimes_in[j];
+        bool exists = false;
+        for (size_t i = 0; i < mimes.size() && !exists; i++) {
+            if (mimes[i] == mime) {
+                exists = true;
+            }
+        } // for i
+
+        if (!exists) {
+            mimes.add(mime);
+        }
+    } // for j
+
+
+    // 1) PSSH bytes
+    parcel->writeUint32(psshsize);
+    parcel->writeByteArray(psshsize, (const uint8_t*)pssh);
+
+    ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO  PSSH: size: %zu %s", psshsize,
+            DrmUUID::arrayToHex((uint8_t*)pssh, psshsize).string());
+
+    // 2) supportedDRMs
+    Vector<DrmUUID> supportedDRMs = getSupportedDrmSchemes(pssh, psshsize);
+    parcel->writeUint32(supportedDRMs.size());
+    for (size_t i = 0; i < supportedDRMs.size(); i++) {
+        DrmUUID uuid = supportedDRMs[i];
+        parcel->writeByteArray(DrmUUID::UUID_SIZE, uuid.ptr());
+
+        ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO  supportedScheme[%zu] %s", i,
+                uuid.toHexString().string());
+    }
+
+    // TODO: remove mimes after it's removed from Java DrmInfo
+    // 3) mimes
+    parcel->writeUint32(mimes.size());
+    for (size_t i = 0; i < mimes.size(); i++) {
+        // writing as String16 so the Java framework side can unpack it to Java String
+        String16 mime(mimes[i]);
+        parcel->writeString16(mime);
+
+        ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO  MIME[%zu] %s",
+                i, mimes[i].string());
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+/// Helpers for NuPlayerDecoder
+////////////////////////////////////////////////////////////////////////////////////////////
+
+NuPlayerDrm::CryptoInfo *NuPlayerDrm::makeCryptoInfo(
+        int numSubSamples,
+        uint8_t key[kBlockSize],
+        uint8_t iv[kBlockSize],
+        CryptoPlugin::Mode mode,
+        size_t *clearbytes,
+        size_t *encryptedbytes)
+{
+    // size needed to store all the crypto data
+    size_t cryptosize = sizeof(CryptoInfo) +
+                        sizeof(CryptoPlugin::SubSample) * numSubSamples;
+    CryptoInfo *ret = (CryptoInfo*) malloc(cryptosize);
+    if (ret == NULL) {
+        ALOGE("couldn't allocate %zu bytes", cryptosize);
+        return NULL;
+    }
+    ret->numSubSamples = numSubSamples;
+    memcpy(ret->key, key, kBlockSize);
+    memcpy(ret->iv, iv, kBlockSize);
+    ret->mode = mode;
+    ret->pattern.mEncryptBlocks = 0;
+    ret->pattern.mSkipBlocks = 0;
+    ret->subSamples = (CryptoPlugin::SubSample*)(ret + 1);
+    CryptoPlugin::SubSample *subSamples = ret->subSamples;
+
+    for (int i = 0; i < numSubSamples; i++) {
+        subSamples[i].mNumBytesOfClearData = (clearbytes == NULL) ? 0 : clearbytes[i];
+        subSamples[i].mNumBytesOfEncryptedData = (encryptedbytes == NULL) ?
+                                                  0 :
+                                                  encryptedbytes[i];
+    }
+
+    return ret;
+}
+
+NuPlayerDrm::CryptoInfo *NuPlayerDrm::getSampleCryptoInfo(sp<MetaData> meta)
+{
+    uint32_t type;
+    const void *crypteddata;
+    size_t cryptedsize;
+
+    if (meta == NULL) {
+        ALOGE("getSampleCryptoInfo: Unexpected. No meta data for sample.");
+        return NULL;
+    }
+
+    if (!meta->findData(kKeyEncryptedSizes, &type, &crypteddata, &cryptedsize)) {
+        return NULL;
+    }
+    size_t numSubSamples = cryptedsize / sizeof(size_t);
+
+    if (numSubSamples <= 0) {
+        ALOGE("getSampleCryptoInfo INVALID numSubSamples: %zu", numSubSamples);
+        return NULL;
+    }
+
+    const void *cleardata;
+    size_t clearsize;
+    if (meta->findData(kKeyPlainSizes, &type, &cleardata, &clearsize)) {
+        if (clearsize != cryptedsize) {
+            // The two must be of the same length.
+            ALOGE("getSampleCryptoInfo mismatch cryptedsize: %zu != clearsize: %zu",
+                    cryptedsize, clearsize);
+            return NULL;
+        }
+    }
+
+    const void *key;
+    size_t keysize;
+    if (meta->findData(kKeyCryptoKey, &type, &key, &keysize)) {
+        if (keysize != kBlockSize) {
+            ALOGE("getSampleCryptoInfo Keys must be %d bytes in length: %zu",
+                    kBlockSize, keysize);
+            // Keys must be 16 bytes in length.
+            return NULL;
+        }
+    }
+
+    const void *iv;
+    size_t ivsize;
+    if (meta->findData(kKeyCryptoIV, &type, &iv, &ivsize)) {
+        if (ivsize != kBlockSize) {
+            ALOGE("getSampleCryptoInfo IV must be %d bytes in length: %zu",
+                    kBlockSize, ivsize);
+            // IVs must be 16 bytes in length.
+            return NULL;
+        }
+    }
+
+    int32_t mode;
+    if (!meta->findInt32(kKeyCryptoMode, &mode)) {
+        mode = CryptoPlugin::kMode_AES_CTR;
+    }
+
+    return makeCryptoInfo(numSubSamples,
+            (uint8_t*) key,
+            (uint8_t*) iv,
+            (CryptoPlugin::Mode)mode,
+            (size_t*) cleardata,
+            (size_t*) crypteddata);
+}
+
+}   // namespace android
+
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h
new file mode 100644
index 0000000..6704bd1
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h
@@ -0,0 +1,119 @@
+/*
+ * 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 NUPLAYER_DRM_H_
+#define NUPLAYER_DRM_H_
+
+#include <binder/Parcel.h>
+#include <media/ICrypto.h>
+#include <media/IDrm.h>
+#include <media/stagefright/MetaData.h> // for CryptInfo
+
+
+namespace android {
+
+    struct DrmUUID {
+        static const int UUID_SIZE = 16;
+
+        DrmUUID() {
+            memset(this->uuid, 0, sizeof(uuid));
+        }
+
+        // to allow defining Vector/KeyedVector of UUID type
+        DrmUUID(const DrmUUID &a) {
+            memcpy(this->uuid, a.uuid, sizeof(uuid));
+        }
+
+        // to allow defining Vector/KeyedVector of UUID type
+        DrmUUID(const uint8_t uuid_in[UUID_SIZE]) {
+            memcpy(this->uuid, uuid_in, sizeof(uuid));
+        }
+
+        const uint8_t *ptr() const {
+            return uuid;
+        }
+
+        String8 toHexString() const {
+            return arrayToHex(uuid, UUID_SIZE);
+        }
+
+        static String8 toHexString(const uint8_t uuid_in[UUID_SIZE]) {
+            return arrayToHex(uuid_in, UUID_SIZE);
+        }
+
+        static String8 arrayToHex(const uint8_t *array, int bytes) {
+            String8 result;
+            for (int i = 0; i < bytes; i++) {
+                result.appendFormat("%02x", array[i]);
+            }
+
+            return result;
+        }
+
+    protected:
+        uint8_t uuid[UUID_SIZE];
+    };
+
+
+    struct NuPlayerDrm {
+
+        // static helpers - internal
+
+    protected:
+        static sp<IDrm> CreateDrm(status_t *pstatus);
+        static sp<ICrypto> createCrypto(status_t *pstatus);
+        static Vector<DrmUUID> parsePSSH(const void *pssh, size_t psshsize);
+        static Vector<DrmUUID> getSupportedDrmSchemes(const void *pssh, size_t psshsize);
+
+        // static helpers - public
+
+    public:
+        static sp<ICrypto> createCryptoAndPlugin(const uint8_t uuid[16],
+                const Vector<uint8_t> &drmSessionId, status_t &status);
+        // Parcel has only private copy constructor so passing it in rather than returning
+        static void retrieveDrmInfo(const void *pssh, size_t psshsize,
+                const Vector<String8> &mimes_in, Parcel *parcel);
+
+        ////////////////////////////////////////////////////////////////////////////////////////////
+        /// Helpers for NuPlayerDecoder
+        ////////////////////////////////////////////////////////////////////////////////////////////
+
+        static const uint8_t kBlockSize = 16; // AES_BLOCK_SIZE
+
+        struct CryptoInfo {
+            int numSubSamples;
+            uint8_t key[kBlockSize];
+            uint8_t iv[kBlockSize];
+            CryptoPlugin::Mode mode;
+            CryptoPlugin::Pattern pattern;
+            CryptoPlugin::SubSample *subSamples;
+        };
+
+        static CryptoInfo *makeCryptoInfo(
+                int numSubSamples,
+                uint8_t key[kBlockSize],
+                uint8_t iv[kBlockSize],
+                CryptoPlugin::Mode mode,
+                size_t *clearbytes,
+                size_t *encryptedbytes);
+
+        static CryptoInfo *getSampleCryptoInfo(sp<MetaData> meta);
+
+    };  // NuPlayerDrm
+
+}   // android
+
+#endif     //NUPLAYER_DRM_H_
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 42e95da..9350440 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -405,10 +405,10 @@
     msg->setInt32("flags", flags);
 
     sp<AMessage> response;
-    msg->postAndAwaitResponse(&response);
+    status_t postStatus = msg->postAndAwaitResponse(&response);
 
     int32_t err;
-    if (!response->findInt32("err", &err)) {
+    if (postStatus != OK || response.get() == nullptr || !response->findInt32("err", &err)) {
         err = INVALID_OPERATION;
     } else if (err == OK && isOffloaded != NULL) {
         int32_t offload;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 0429ef1..e7cca27 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -20,9 +20,10 @@
 
 #include "NuPlayer.h"
 
+#include <media/ICrypto.h>
+#include <media/mediaplayer.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MetaData.h>
-#include <media/mediaplayer.h>
 #include <utils/Vector.h>
 
 namespace android {
@@ -55,6 +56,8 @@
         kWhatQueueDecoderShutdown,
         kWhatDrmNoLicense,
         kWhatInstantiateSecureDecoders,
+        // Modular DRM
+        kWhatDrmInfo,
     };
 
     // The provides message is used to notify the player about various
@@ -132,6 +135,17 @@
 
     virtual void setOffloadAudio(bool /* offload */) {}
 
+    // Modular DRM
+    virtual status_t prepareDrm(
+            const uint8_t /*uuid*/[16], const Vector<uint8_t> &/*drmSessionId*/,
+            sp<ICrypto> */*crypto*/) {
+        return INVALID_OPERATION;
+    }
+
+    virtual status_t releaseDrm() {
+        return INVALID_OPERATION;
+    }
+
 protected:
     virtual ~Source() {}
 
@@ -143,6 +157,8 @@
     void notifyVideoSizeChanged(const sp<AMessage> &format = NULL);
     void notifyInstantiateSecureDecoders(const sp<AMessage> &reply);
     void notifyPrepared(status_t err = OK);
+    // Modular DRM
+    void notifyDrmInfo(const sp<ABuffer> &buffer);
 
 private:
     sp<AMessage> mNotify;
diff --git a/media/libnbaio/Android.bp b/media/libnbaio/Android.bp
index fd7af4f..f511876 100644
--- a/media/libnbaio/Android.bp
+++ b/media/libnbaio/Android.bp
@@ -34,4 +34,8 @@
     ],
 
     include_dirs: ["system/media/audio_utils/include"],
+
+    local_include_dirs: ["include"],
+
+    export_include_dirs: ["include"],
 }
diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp
index 7c2523d..f480c16 100644
--- a/media/libnbaio/NBLog.cpp
+++ b/media/libnbaio/NBLog.cpp
@@ -21,6 +21,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/prctl.h>
 #include <time.h>
 #include <new>
 #include <audio_utils/roundup.h>
@@ -28,6 +29,8 @@
 #include <utils/Log.h>
 #include <utils/String8.h>
 
+#include <queue>
+
 namespace android {
 
 int NBLog::Entry::readAt(size_t offset) const
@@ -47,6 +50,120 @@
 
 // ---------------------------------------------------------------------------
 
+NBLog::FormatEntry::FormatEntry(const uint8_t *entry) : mEntry(entry) {
+    ALOGW_IF(entry[offsetof(struct entry, type)] != EVENT_START_FMT,
+        "Created format entry with invalid event type %d", entry[offsetof(struct entry, type)]);
+}
+
+NBLog::FormatEntry::FormatEntry(const NBLog::FormatEntry::iterator &it) : FormatEntry(it.ptr) {}
+
+const char *NBLog::FormatEntry::formatString() const {
+    return (const char*) mEntry + offsetof(entry, data);
+}
+
+size_t NBLog::FormatEntry::formatStringLength() const {
+    return mEntry[offsetof(entry, length)];
+}
+
+NBLog::FormatEntry::iterator NBLog::FormatEntry::args() const {
+    auto it = begin();
+    // Second entry can be author or timestamp. Skip author if present
+    if ((++it)->type == EVENT_AUTHOR) {
+        ++it;
+    }
+    return ++it;
+}
+
+timespec NBLog::FormatEntry::timestamp() const {
+    auto it = begin();
+    if ((++it)->type != EVENT_TIMESTAMP) {
+        ++it;
+    }
+    return it.payload<timespec>();
+}
+
+pid_t NBLog::FormatEntry::author() const {
+    auto it = begin();
+    if ((++it)->type == EVENT_AUTHOR) {
+        return it.payload<int>();
+    }
+    return -1;
+}
+
+size_t NBLog::FormatEntry::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
+    auto it = this->begin();
+    // copy fmt start entry
+    it.copyTo(dst);
+    // insert author entry
+    size_t authorEntrySize = NBLog::Entry::kOverhead + sizeof(author);
+    uint8_t authorEntry[authorEntrySize];
+    authorEntry[offsetof(entry, type)] = EVENT_AUTHOR;
+    authorEntry[offsetof(entry, length)] =
+        authorEntry[authorEntrySize + NBLog::Entry::kPreviousLengthOffset] =
+        sizeof(author);
+    *(int*) (&authorEntry[offsetof(entry, data)]) = author;
+    dst->write(authorEntry, authorEntrySize);
+    // copy rest of entries
+    while ((++it)->type != EVENT_END_FMT) {
+        it.copyTo(dst);
+    }
+    it.copyTo(dst);
+    ++it;
+    return it - this->begin();
+}
+
+void NBLog::FormatEntry::iterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const {
+    size_t length = ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
+    dst->write(ptr, length);
+}
+
+void NBLog::FormatEntry::iterator::copyData(uint8_t *dst) const {
+    memcpy((void*) dst, ptr + offsetof(entry, data), ptr[offsetof(entry, length)]);
+}
+
+NBLog::FormatEntry::iterator NBLog::FormatEntry::begin() const {
+    return iterator(mEntry);
+}
+
+NBLog::FormatEntry::iterator::iterator(const uint8_t *entry)
+    : ptr(entry) {}
+
+NBLog::FormatEntry::iterator::iterator(const NBLog::FormatEntry::iterator &other)
+    : ptr(other.ptr) {}
+
+const NBLog::FormatEntry::entry& NBLog::FormatEntry::iterator::operator*() const {
+    return *(entry*) ptr;
+}
+
+const NBLog::FormatEntry::entry* NBLog::FormatEntry::iterator::operator->() const {
+    return (entry*) ptr;
+}
+
+NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator++() {
+    ptr += ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
+    return *this;
+}
+
+NBLog::FormatEntry::iterator& NBLog::FormatEntry::iterator::operator--() {
+    ptr -= ptr[NBLog::Entry::kPreviousLengthOffset] + NBLog::Entry::kOverhead;
+    return *this;
+}
+
+int NBLog::FormatEntry::iterator::operator-(const NBLog::FormatEntry::iterator &other) const {
+    return ptr - other.ptr;
+}
+
+bool NBLog::FormatEntry::iterator::operator!=(const iterator &other) const {
+    return ptr != other.ptr;
+}
+
+bool NBLog::FormatEntry::iterator::hasConsistentLength() const {
+    return ptr[offsetof(entry, length)] == ptr[ptr[offsetof(entry, length)] +
+        NBLog::Entry::kOverhead + NBLog::Entry::kPreviousLengthOffset];
+}
+
+// ---------------------------------------------------------------------------
+
 #if 0   // FIXME see note in NBLog.h
 NBLog::Timeline::Timeline(size_t size, void *shared)
     : mSize(roundup(size)), mOwn(shared == NULL),
@@ -74,7 +191,7 @@
 // ---------------------------------------------------------------------------
 
 NBLog::Writer::Writer()
-    : mShared(NULL), mFifo(NULL), mFifoWriter(NULL), mEnabled(false)
+    : mShared(NULL), mFifo(NULL), mFifoWriter(NULL), mEnabled(false), mPidTag(NULL), mPidTagSize(0)
 {
 }
 
@@ -86,6 +203,18 @@
       mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL),
       mEnabled(mFifoWriter != NULL)
 {
+    // caching pid and process name
+    pid_t id = ::getpid();
+    char procName[16];
+    int status = prctl(PR_GET_NAME, procName);
+    if (status) {  // error getting process name
+        procName[0] = '\0';
+    }
+    size_t length = strlen(procName);
+    mPidTagSize = length + sizeof(pid_t);
+    mPidTag = new char[mPidTagSize];
+    memcpy(mPidTag, &id, sizeof(pid_t));
+    memcpy(mPidTag + sizeof(pid_t), procName, length);
 }
 
 NBLog::Writer::Writer(const sp<IMemory>& iMemory, size_t size)
@@ -98,6 +227,7 @@
 {
     delete mFifoWriter;
     delete mFifo;
+    delete[] mPidTag;
 }
 
 void NBLog::Writer::log(const char *string)
@@ -181,15 +311,7 @@
     if (!mEnabled) {
         return;
     }
-    pid_t id = ::getpid();
-    // TODO: append process name to pid
-    // const char* path = sprintf("/proc/%d/status", id);
-    // FILE* f = fopen(path);
-    // size_t length = 30
-    // char buffer[length];
-    // getline(&buffer, &length, f);
-    // char* pidTag = sprintf("")
-    log(EVENT_PID, &id, sizeof(pid_t));
+    log(EVENT_PID, mPidTag, mPidTagSize);
 }
 
 void NBLog::Writer::logStart(const char *fmt)
@@ -271,10 +393,12 @@
             --p;
             break;
 
+        case '%':
+            break;
+
         default:
             ALOGW("NBLog Writer parsed invalid format specifier: %c", *p);
             break;
-        // the '%' case is handled using the formatted string in the reader
         }
     }
     Writer::logEnd();
@@ -455,53 +579,53 @@
     delete mFifo;
 }
 
-void NBLog::Reader::dump(int fd, size_t indent)
+std::unique_ptr<NBLog::Reader::Snapshot> NBLog::Reader::getSnapshot()
 {
     if (mFifoReader == NULL) {
-        return;
+        return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
     }
     // make a copy to avoid race condition with writer
     size_t capacity = mFifo->capacity();
 
-    // TODO Stack-based allocation of large objects may fail.
-    //      Currently the log buffers are a page or two, which should be safe.
-    //      But if the log buffers ever get a lot larger,
-    //      then change this to allocate from heap when necessary.
-    static size_t kReasonableStackObjectSize = 32768;
-    ALOGW_IF(capacity > kReasonableStackObjectSize, "Stack-based allocation of object may fail");
-    uint8_t copy[capacity];
+    std::unique_ptr<Snapshot> snapshot(new Snapshot(capacity));
 
-    size_t lost;
-    ssize_t actual = mFifoReader->read(copy, capacity, NULL /*timeout*/, &lost);
+    ssize_t actual = mFifoReader->read((void*) snapshot->mData, capacity, NULL /*timeout*/,
+                                       &(snapshot->mLost));
     ALOG_ASSERT(actual <= capacity);
-    size_t avail = actual > 0 ? (size_t) actual : 0;
-    size_t i = avail;
-    Event event;
-    size_t length;
+    snapshot->mAvail = actual > 0 ? (size_t) actual : 0;
+    return snapshot;
+}
+
+void NBLog::Reader::dump(int fd, size_t indent, NBLog::Reader::Snapshot &snapshot)
+{
+    NBLog::FormatEntry::iterator entry(snapshot.data() + snapshot.available());
+    NBLog::FormatEntry::iterator prevEntry = entry;
+    --prevEntry;
+    NBLog::FormatEntry::iterator start(snapshot.data());
+
     struct timespec ts;
     time_t maxSec = -1;
-    while (i >= Entry::kOverhead) {
-        length = copy[i - 1];
-        if (length + Entry::kOverhead > i || copy[i - length - 2] != length) {
+    while (entry - start >= (int) Entry::kOverhead) {
+        if (prevEntry - start < 0 || !prevEntry.hasConsistentLength()) {
             break;
         }
-        event = (Event) copy[i - length - Entry::kOverhead];
-        if (event == EVENT_TIMESTAMP) {
-            if (length != sizeof(struct timespec)) {
+        if (prevEntry->type == EVENT_TIMESTAMP) {
+            if (prevEntry->length != sizeof(struct timespec)) {
                 // corrupt
                 break;
             }
-            memcpy(&ts, &copy[i - length - 1], sizeof(struct timespec));
+            prevEntry.copyData((uint8_t*) &ts);
             if (ts.tv_sec > maxSec) {
                 maxSec = ts.tv_sec;
             }
         }
-        i -= length + Entry::kOverhead;
+        --entry;
+        --prevEntry;
     }
     mFd = fd;
     mIndent = indent;
     String8 timestamp, body;
-    lost += i;
+    size_t lost = snapshot.lost() + (entry - start);
     if (lost > 0) {
         body.appendFormat("warning: lost %zu bytes worth of events", lost);
         // TODO timestamp empty here, only other choice to wait for the first timestamp event in the
@@ -517,30 +641,29 @@
         timestamp.appendFormat("[%*s]", (int) width + 4, "");
     }
     bool deferredTimestamp = false;
-    while (i < avail) {
-        event = (Event) copy[i];
-        length = copy[i + 1];
-        const void *data = &copy[i + 2];
-        size_t advance = length + Entry::kOverhead;
-        switch (event) {
+    NBLog::FormatEntry::iterator end(snapshot.data() + snapshot.available());
+
+    while (entry != end) {
+        switch (entry->type) {
+#if 0
         case EVENT_STRING:
-            body.appendFormat("%.*s", (int) length, (const char *) data);
+            body.appendFormat("%.*s", (int) entry.length(), entry.data());
             break;
         case EVENT_TIMESTAMP: {
             // already checked that length == sizeof(struct timespec);
-            memcpy(&ts, data, sizeof(struct timespec));
+            entry.copyData((const uint8_t*) &ts);
             long prevNsec = ts.tv_nsec;
             long deltaMin = LONG_MAX;
             long deltaMax = -1;
             long deltaTotal = 0;
-            size_t j = i;
+            auto aux(entry);
             for (;;) {
-                j += sizeof(struct timespec) + 3 /*Entry::kOverhead?*/;
-                if (j >= avail || (Event) copy[j] != EVENT_TIMESTAMP) {
+                ++aux;
+                if (end - aux >= 0 || aux.type() != EVENT_TIMESTAMP) {
                     break;
                 }
                 struct timespec tsNext;
-                memcpy(&tsNext, &copy[j + 2], sizeof(struct timespec));
+                aux.copyData((const uint8_t*) &tsNext);
                 if (tsNext.tv_sec != ts.tv_sec) {
                     break;
                 }
@@ -557,7 +680,7 @@
                 deltaTotal += delta;
                 prevNsec = tsNext.tv_nsec;
             }
-            size_t n = (j - i) / (sizeof(struct timespec) + 3 /*Entry::kOverhead?*/);
+            size_t n = (aux - entry) / (sizeof(struct timespec) + 3 /*Entry::kOverhead?*/);
             if (deferredTimestamp) {
                 dumpLine(timestamp, body);
                 deferredTimestamp = false;
@@ -568,36 +691,37 @@
                         (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000),
                         (int) ((ts.tv_nsec + deltaTotal) / 1000000),
                         (int) (deltaMin / 1000000), (int) (deltaMax / 1000000));
-                i = j;
-                advance = 0;
+                entry = aux;
+                // advance = 0;
                 break;
             }
             timestamp.appendFormat("[%d.%03d]", (int) ts.tv_sec,
                     (int) (ts.tv_nsec / 1000000));
             deferredTimestamp = true;
-            } break;
+            }
+            break;
         case EVENT_INTEGER:
-            appendInt(&body, data);
+            appendInt(&body, entry.data());
             break;
         case EVENT_FLOAT:
-            appendFloat(&body, data);
+            appendFloat(&body, entry.data());
             break;
         case EVENT_PID:
-            appendPID(&body, data);
+            appendPID(&body, entry.data(), entry.length());
             break;
+#endif
         case EVENT_START_FMT:
-            advance += handleFormat((const char*) &copy[i + 2], length,
-                                    &copy[i + Entry::kOverhead + length], &timestamp, &body);
+            // right now, this is the only supported case
+            entry = handleFormat(FormatEntry(entry), &timestamp, &body);
             break;
         case EVENT_END_FMT:
             body.appendFormat("warning: got to end format event");
             break;
         case EVENT_RESERVED:
         default:
-            body.appendFormat("warning: unknown event %d", event);
+            body.appendFormat("warning: unknown event %d", entry->type);
             break;
         }
-        i += advance;
 
         if (!body.isEmpty()) {
             dumpLine(timestamp, body);
@@ -609,6 +733,13 @@
     }
 }
 
+void NBLog::Reader::dump(int fd, size_t indent)
+{
+    // get a snapshot, dump it
+    std::unique_ptr<Snapshot> snap = getSnapshot();
+    dump(fd, indent, *snap);
+}
+
 void NBLog::Reader::dumpLine(const String8 &timestamp, String8 &body)
 {
     if (mFd >= 0) {
@@ -642,86 +773,189 @@
     body->appendFormat("<%f>", f);
 }
 
-void NBLog::appendPID(String8 *body, const void* data) {
+void NBLog::appendPID(String8 *body, const void* data, size_t length) {
     pid_t id = *((pid_t*) data);
-    body->appendFormat("<PID: %d>", id);
+    char * name = &((char*) data)[sizeof(pid_t)];
+    body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
 }
 
-int NBLog::handleFormat(const char *fmt, size_t fmt_length, const uint8_t *data,
-                        String8 *timestamp, String8 *body) {
-    if (data[0] != EVENT_TIMESTAMP) {
-        ALOGW("NBLog Reader Expected timestamp event %d, got %d", EVENT_TIMESTAMP, data[0]);
-    }
-    struct timespec ts;
-    memcpy(&ts, &data[2], sizeof(ts));
+NBLog::FormatEntry::iterator NBLog::Reader::handleFormat(const FormatEntry &fmtEntry,
+                                                         String8 *timestamp,
+                                                         String8 *body) {
+    // log timestamp
+    struct timespec ts = fmtEntry.timestamp();
     timestamp->clear();
     timestamp->appendFormat("[%d.%03d]", (int) ts.tv_sec,
                     (int) (ts.tv_nsec / 1000000));
-    size_t data_offset = Entry::kOverhead + sizeof ts;
+
+    // log author (if present)
+    handleAuthor(fmtEntry, body);
+
+    // log string
+    NBLog::FormatEntry::iterator arg = fmtEntry.args();
+
+    const char* fmt = fmtEntry.formatString();
+    size_t fmt_length = fmtEntry.formatStringLength();
 
     for (size_t fmt_offset = 0; fmt_offset < fmt_length; ++fmt_offset) {
         if (fmt[fmt_offset] != '%') {
             body->append(&fmt[fmt_offset], 1); // TODO optimize to write consecutive strings at once
             continue;
         }
+        // case "%%""
         if (fmt[++fmt_offset] == '%') {
             body->append("%");
             continue;
         }
+        // case "%\0"
         if (fmt_offset == fmt_length) {
             continue;
         }
 
-        NBLog::Event event = (NBLog::Event) data[data_offset];
-        size_t length = data[data_offset + 1];
+        NBLog::Event event = (NBLog::Event) arg->type;
+        size_t length = arg->length;
 
         // TODO check length for event type is correct
-        if(length != data[data_offset + length + 2]) {
-            ALOGW("NBLog Reader recieved different lengths %zu and %d for event %d", length,
-                  data[data_offset + length + 2], event);
+        if (!arg.hasConsistentLength()) {
+            // TODO: corrupt, resync buffer
             body->append("<invalid entry>");
             ++fmt_offset;
             continue;
         }
 
+        if (event == EVENT_END_FMT) {
+            break;
+        }
+
         // TODO: implement more complex formatting such as %.3f
-        void * datum = (void*) &data[data_offset + 2]; // pointer to the current event data
+        const uint8_t *datum = arg->data; // pointer to the current event args
         switch(fmt[fmt_offset])
         {
         case 's': // string
-            ALOGW_IF(event != EVENT_STRING, "NBLog Reader incompatible event for string specifier: %d", event);
+            ALOGW_IF(event != EVENT_STRING,
+                "NBLog Reader incompatible event for string specifier: %d", event);
             body->append((const char*) datum, length);
             break;
 
         case 't': // timestamp
-            ALOGW_IF(event != EVENT_TIMESTAMP, "NBLog Reader incompatible event for timestamp specifier: %d", event);
+            ALOGW_IF(event != EVENT_TIMESTAMP,
+                "NBLog Reader incompatible event for timestamp specifier: %d", event);
             appendTimestamp(body, datum);
             break;
 
         case 'd': // integer
-            ALOGW_IF(event != EVENT_INTEGER, "NBLog Reader incompatible event for integer specifier: %d", event);
+            ALOGW_IF(event != EVENT_INTEGER,
+                "NBLog Reader incompatible event for integer specifier: %d", event);
             appendInt(body, datum);
-
             break;
 
         case 'f': // float
-            ALOGW_IF(event != EVENT_FLOAT, "NBLog Reader incompatible event for float specifier: %d", event);
+            ALOGW_IF(event != EVENT_FLOAT,
+                "NBLog Reader incompatible event for float specifier: %d", event);
             appendFloat(body, datum);
             break;
 
         case 'p': // pid
-            ALOGW_IF(event != EVENT_PID, "NBLog Reader incompatible event for pid specifier: %d", event);
-            appendPID(body, datum);
+            ALOGW_IF(event != EVENT_PID,
+                "NBLog Reader incompatible event for pid specifier: %d", event);
+            appendPID(body, datum, length);
             break;
 
         default:
             ALOGW("NBLog Reader encountered unknown character %c", fmt[fmt_offset]);
         }
-
-        data_offset += length + Entry::kOverhead;
-
+        ++arg;
     }
-    return data_offset + Entry::kOverhead; // data offset + size of END_FMT event
+    ALOGW_IF(arg->type != EVENT_END_FMT, "Expected end of format, got %d", arg->type);
+    ++arg;
+    return arg;
+}
+
+// ---------------------------------------------------------------------------
+
+NBLog::Merger::Merger(const void *shared, size_t size):
+      mBuffer(NULL),
+      mShared((Shared *) shared),
+      mFifo(mShared != NULL ?
+        new audio_utils_fifo(size, sizeof(uint8_t),
+            mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
+      mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL)
+      {}
+
+void NBLog::Merger::addReader(const NBLog::NamedReader &reader) {
+    mNamedReaders.push_back(reader);
+}
+
+// items placed in priority queue during merge
+// composed by a timestamp and the index of the snapshot where the timestamp came from
+struct MergeItem
+{
+    struct timespec ts;
+    int index;
+    MergeItem(struct timespec ts, int index): ts(ts), index(index) {}
+};
+
+// operators needed for priority queue in merge
+bool operator>(const struct timespec &t1, const struct timespec &t2) {
+    return t1.tv_sec > t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec);
+}
+
+bool operator>(const struct MergeItem &i1, const struct MergeItem &i2) {
+    return i1.ts > i2.ts ||
+        (i1.ts.tv_sec == i2.ts.tv_sec && i1.ts.tv_nsec == i2.ts.tv_nsec && i1.index > i2.index);
+}
+
+// Merge registered readers, sorted by timestamp
+void NBLog::Merger::merge() {
+    int nLogs = mNamedReaders.size();
+    std::vector<std::unique_ptr<NBLog::Reader::Snapshot>> snapshots(nLogs);
+    for (int i = 0; i < nLogs; ++i) {
+        snapshots[i] = mNamedReaders[i].reader()->getSnapshot();
+    }
+    // initialize offsets
+    std::vector<size_t> offsets(nLogs, 0);
+    // TODO custom heap implementation could allow to update top, improving performance
+    // for bursty buffers
+    std::priority_queue<MergeItem, std::vector<MergeItem>, std::greater<MergeItem>> timestamps;
+    for (int i = 0; i < nLogs; ++i)
+    {
+        if (snapshots[i]->available() > 0) {
+            timespec ts = FormatEntry(snapshots[i]->data()).timestamp();
+            MergeItem item(ts, i);
+            timestamps.push(item);
+        }
+    }
+
+    while (!timestamps.empty()) {
+        // find minimum timestamp
+        int index = timestamps.top().index;
+        // copy it to the log
+        size_t length = FormatEntry(snapshots[index]->data() + offsets[index]).copyTo(
+            mFifoWriter, index);
+        // update data structures
+        offsets[index] += length;
+        ALOGW_IF(offsets[index] > snapshots[index]->available(), "Overflown snapshot capacity");
+        timestamps.pop();
+        if (offsets[index] != snapshots[index]->available()) {
+            timespec ts = FormatEntry(snapshots[index]->data() + offsets[index]).timestamp();
+            MergeItem item(ts, index);
+            timestamps.emplace(item);
+        }
+    }
+}
+
+const std::vector<NBLog::NamedReader> *NBLog::Merger::getNamedReaders() const {
+    return &mNamedReaders;
+}
+
+NBLog::MergeReader::MergeReader(const void *shared, size_t size, Merger &merger)
+    : Reader(shared, size), mNamedReaders(merger.getNamedReaders()) {}
+
+size_t NBLog::MergeReader::handleAuthor(const NBLog::FormatEntry &fmtEntry, String8 *body) {
+    int author = fmtEntry.author();
+    const char* name = (*mNamedReaders)[author].name();
+    body->appendFormat("%s: ", name);
+    return NBLog::Entry::kOverhead + sizeof(author);
 }
 
 }   // namespace android
diff --git a/include/media/nbaio/AudioBufferProviderSource.h b/media/libnbaio/include/AudioBufferProviderSource.h
similarity index 100%
rename from include/media/nbaio/AudioBufferProviderSource.h
rename to media/libnbaio/include/AudioBufferProviderSource.h
diff --git a/include/media/nbaio/AudioStreamInSource.h b/media/libnbaio/include/AudioStreamInSource.h
similarity index 100%
rename from include/media/nbaio/AudioStreamInSource.h
rename to media/libnbaio/include/AudioStreamInSource.h
diff --git a/include/media/nbaio/AudioStreamOutSink.h b/media/libnbaio/include/AudioStreamOutSink.h
similarity index 100%
rename from include/media/nbaio/AudioStreamOutSink.h
rename to media/libnbaio/include/AudioStreamOutSink.h
diff --git a/include/media/nbaio/LibsndfileSink.h b/media/libnbaio/include/LibsndfileSink.h
similarity index 100%
rename from include/media/nbaio/LibsndfileSink.h
rename to media/libnbaio/include/LibsndfileSink.h
diff --git a/include/media/nbaio/LibsndfileSource.h b/media/libnbaio/include/LibsndfileSource.h
similarity index 100%
rename from include/media/nbaio/LibsndfileSource.h
rename to media/libnbaio/include/LibsndfileSource.h
diff --git a/include/media/nbaio/MonoPipe.h b/media/libnbaio/include/MonoPipe.h
similarity index 100%
rename from include/media/nbaio/MonoPipe.h
rename to media/libnbaio/include/MonoPipe.h
diff --git a/include/media/nbaio/MonoPipeReader.h b/media/libnbaio/include/MonoPipeReader.h
similarity index 100%
rename from include/media/nbaio/MonoPipeReader.h
rename to media/libnbaio/include/MonoPipeReader.h
diff --git a/include/media/nbaio/NBAIO.h b/media/libnbaio/include/NBAIO.h
similarity index 100%
rename from include/media/nbaio/NBAIO.h
rename to media/libnbaio/include/NBAIO.h
diff --git a/media/libnbaio/include/NBLog.h b/media/libnbaio/include/NBLog.h
new file mode 100644
index 0000000..043f15e
--- /dev/null
+++ b/media/libnbaio/include/NBLog.h
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Non-blocking event logger intended for safe communication between processes via shared memory
+
+#ifndef ANDROID_MEDIA_NBLOG_H
+#define ANDROID_MEDIA_NBLOG_H
+
+#include <binder/IMemory.h>
+#include <utils/Mutex.h>
+#include <audio_utils/fifo.h>
+
+#include <vector>
+
+namespace android {
+
+class String8;
+
+class NBLog {
+
+public:
+
+class Writer;
+class Reader;
+
+private:
+
+enum Event {
+    EVENT_RESERVED,
+    EVENT_STRING,               // ASCII string, not NUL-terminated
+    EVENT_TIMESTAMP,            // clock_gettime(CLOCK_MONOTONIC)
+    EVENT_INTEGER,              // integer value entry
+    EVENT_FLOAT,                // floating point value entry
+    EVENT_PID,                  // process ID and process name
+    EVENT_AUTHOR,               // author index (present in merged logs) tracks entry's original log
+    EVENT_START_FMT,            // logFormat start event: entry includes format string, following
+                                // entries contain format arguments
+    EVENT_END_FMT,              // end of logFormat argument list
+};
+
+
+// ---------------------------------------------------------------------------
+// API for handling format entry operations
+
+// a formatted entry has the following structure:
+//    * START_FMT entry, containing the format string
+//    * author entry of the thread that generated it (optional, present in merged log)
+//    * TIMESTAMP entry
+//    * format arg1
+//    * format arg2
+//    * ...
+//    * END_FMT entry
+
+class FormatEntry {
+public:
+    // build a Format Entry starting in the given pointer
+    class iterator;
+    explicit FormatEntry(const uint8_t *entry);
+    explicit FormatEntry(const iterator &it);
+
+    // entry representation in memory
+    struct entry {
+        const uint8_t type;
+        const uint8_t length;
+        const uint8_t data[0];
+    };
+
+    // entry tail representation (after data)
+    struct ending {
+        uint8_t length;
+        uint8_t next[0];
+    };
+
+    // entry iterator
+    class iterator {
+    public:
+        iterator(const uint8_t *entry);
+        iterator(const iterator &other);
+
+        // dereference underlying entry
+        const entry&    operator*() const;
+        const entry*    operator->() const;
+        // advance to next entry
+        iterator&       operator++(); // ++i
+        // back to previous entry
+        iterator&       operator--(); // --i
+        bool            operator!=(const iterator &other) const;
+        int             operator-(const iterator &other) const;
+
+        bool            hasConsistentLength() const;
+        void            copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
+        void            copyData(uint8_t *dst) const;
+
+        template<typename T>
+        inline const T& payload() {
+            return *reinterpret_cast<const T *>(ptr + 2);
+        }
+
+    private:
+        friend class FormatEntry;
+        const uint8_t  *ptr;
+    };
+
+    // Entry's format string
+    const char* formatString() const;
+
+    // Enrty's format string length
+    size_t      formatStringLength() const;
+
+    // Format arguments (excluding format string, timestamp and author)
+    iterator    args() const;
+
+    // get format entry timestamp
+    timespec    timestamp() const;
+
+    // entry's author index (-1 if none present)
+    // a Merger has a vector of Readers, author simply points to the index of the
+    // Reader that originated the entry
+    int         author() const;
+
+    // copy entry, adding author before timestamp, returns size of original entry
+    size_t      copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const;
+
+    iterator    begin() const;
+
+private:
+    // copies ordinary entry from src to dst, and returns length of entry
+    // size_t      copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
+    const uint8_t  *mEntry;
+};
+
+// ---------------------------------------------------------------------------
+
+// representation of a single log entry in private memory
+struct Entry {
+    Entry(Event event, const void *data, size_t length)
+        : mEvent(event), mLength(length), mData(data) { }
+    /*virtual*/ ~Entry() { }
+
+    int     readAt(size_t offset) const;
+
+private:
+    friend class Writer;
+    Event       mEvent;     // event type
+    uint8_t     mLength;    // length of additional data, 0 <= mLength <= kMaxLength
+    const void *mData;      // event type-specific data
+    static const size_t kMaxLength = 255;
+public:
+    // mEvent, mLength, mData[...], duplicate mLength
+    static const size_t kOverhead = sizeof(FormatEntry::entry) + sizeof(FormatEntry::ending);
+    // endind length of previous entry
+    static const size_t kPreviousLengthOffset = - sizeof(FormatEntry::ending) +
+                                                offsetof(FormatEntry::ending, length);
+};
+
+// representation of a single log entry in shared memory
+//  byte[0]             mEvent
+//  byte[1]             mLength
+//  byte[2]             mData[0]
+//  ...
+//  byte[2+i]           mData[i]
+//  ...
+//  byte[2+mLength-1]   mData[mLength-1]
+//  byte[2+mLength]     duplicate copy of mLength to permit reverse scan
+//  byte[3+mLength]     start of next log entry
+
+    static void    appendInt(String8 *body, const void *data);
+    static void    appendFloat(String8 *body, const void *data);
+    static void    appendPID(String8 *body, const void *data, size_t length);
+    static void    appendTimestamp(String8 *body, const void *data);
+    static size_t  fmtEntryLength(const uint8_t *data);
+
+public:
+
+// Located in shared memory, must be POD.
+// Exactly one process must explicitly call the constructor or use placement new.
+// Since this is a POD, the destructor is empty and unnecessary to call it explicitly.
+struct Shared {
+    Shared() /* mRear initialized via default constructor */ { }
+    /*virtual*/ ~Shared() { }
+
+    audio_utils_fifo_index  mRear;  // index one byte past the end of most recent Entry
+    char    mBuffer[0];             // circular buffer for entries
+};
+
+public:
+
+// ---------------------------------------------------------------------------
+
+// FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
+// For now it is just a namespace for sharedSize().
+class Timeline : public RefBase {
+public:
+#if 0
+    Timeline(size_t size, void *shared = NULL);
+    virtual ~Timeline();
+#endif
+
+    // Input parameter 'size' is the desired size of the timeline in byte units.
+    // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
+    static size_t sharedSize(size_t size);
+
+#if 0
+private:
+    friend class    Writer;
+    friend class    Reader;
+
+    const size_t    mSize;      // circular buffer size in bytes, must be a power of 2
+    bool            mOwn;       // whether I own the memory at mShared
+    Shared* const   mShared;    // pointer to shared memory
+#endif
+};
+
+// ---------------------------------------------------------------------------
+
+// Writer is thread-safe with respect to Reader, but not with respect to multiple threads
+// calling Writer methods.  If you need multi-thread safety for writing, use LockedWriter.
+class Writer : public RefBase {
+public:
+    Writer();                   // dummy nop implementation without shared memory
+
+    // Input parameter 'size' is the desired size of the timeline in byte units.
+    // The size of the shared memory must be at least Timeline::sharedSize(size).
+    Writer(void *shared, size_t size);
+    Writer(const sp<IMemory>& iMemory, size_t size);
+
+    virtual ~Writer();
+
+    virtual void    log(const char *string);
+    virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+    virtual void    logvf(const char *fmt, va_list ap);
+    virtual void    logTimestamp();
+    virtual void    logTimestamp(const struct timespec &ts);
+    virtual void    logInteger(const int x);
+    virtual void    logFloat(const float x);
+    virtual void    logPID();
+    virtual void    logFormat(const char *fmt, ...);
+    virtual void    logVFormat(const char *fmt, va_list ap);
+    virtual void    logStart(const char *fmt);
+    virtual void    logEnd();
+
+
+    virtual bool    isEnabled() const;
+
+    // return value for all of these is the previous isEnabled()
+    virtual bool    setEnabled(bool enabled);   // but won't enable if no shared memory
+            bool    enable()    { return setEnabled(true); }
+            bool    disable()   { return setEnabled(false); }
+
+    sp<IMemory>     getIMemory() const  { return mIMemory; }
+
+private:
+    // 0 <= length <= kMaxLength
+    void    log(Event event, const void *data, size_t length);
+    void    log(const Entry *entry, bool trusted = false);
+
+    Shared* const   mShared;    // raw pointer to shared memory
+    sp<IMemory>     mIMemory;   // ref-counted version, initialized in constructor and then const
+    audio_utils_fifo * const mFifo;                 // FIFO itself,
+                                                    // non-NULL unless constructor fails
+    audio_utils_fifo_writer * const mFifoWriter;    // used to write to FIFO,
+                                                    // non-NULL unless dummy constructor used
+    bool            mEnabled;   // whether to actually log
+
+    // cached pid and process name to use in %p format specifier
+    // total tag length is mPidTagSize and process name is not zero terminated
+    char   *mPidTag;
+    size_t  mPidTagSize;
+};
+
+// ---------------------------------------------------------------------------
+
+// Similar to Writer, but safe for multiple threads to call concurrently
+class LockedWriter : public Writer {
+public:
+    LockedWriter();
+    LockedWriter(void *shared, size_t size);
+
+    virtual void    log(const char *string);
+    virtual void    logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+    virtual void    logvf(const char *fmt, va_list ap);
+    virtual void    logTimestamp();
+    virtual void    logTimestamp(const struct timespec &ts);
+    virtual void    logInteger(const int x);
+    virtual void    logFloat(const float x);
+    virtual void    logPID();
+    virtual void    logStart(const char *fmt);
+    virtual void    logEnd();
+
+    virtual bool    isEnabled() const;
+    virtual bool    setEnabled(bool enabled);
+
+private:
+    mutable Mutex   mLock;
+};
+
+// ---------------------------------------------------------------------------
+
+class Reader : public RefBase {
+public:
+
+    // A snapshot of a readers buffer
+    class Snapshot {
+    public:
+        Snapshot() : mData(NULL), mAvail(0), mLost(0) {}
+
+        Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
+
+        ~Snapshot() { delete[] mData; }
+
+        // copy of the buffer
+        const uint8_t *data() const { return mData; }
+
+        // amount of data available (given by audio_utils_fifo_reader)
+        size_t   available() const { return mAvail; }
+
+        // amount of data lost (given by audio_utils_fifo_reader)
+        size_t   lost() const { return mLost; }
+
+    private:
+        friend class Reader;
+        const uint8_t *mData;
+        size_t         mAvail;
+        size_t         mLost;
+    };
+
+    // Input parameter 'size' is the desired size of the timeline in byte units.
+    // The size of the shared memory must be at least Timeline::sharedSize(size).
+    Reader(const void *shared, size_t size);
+    Reader(const sp<IMemory>& iMemory, size_t size);
+
+    virtual ~Reader();
+
+    // get snapshot of readers fifo buffer, effectively consuming the buffer
+    std::unique_ptr<Snapshot> getSnapshot();
+    // dump a particular snapshot of the reader
+    void     dump(int fd, size_t indent, Snapshot & snap);
+    // dump the current content of the reader's buffer
+    void     dump(int fd, size_t indent = 0);
+    bool     isIMemory(const sp<IMemory>& iMemory) const;
+
+private:
+    /*const*/ Shared* const mShared;    // raw pointer to shared memory, actually const but not
+                                        // declared as const because audio_utils_fifo() constructor
+    sp<IMemory> mIMemory;       // ref-counted version, assigned only in constructor
+    int     mFd;                // file descriptor
+    int     mIndent;            // indentation level
+    audio_utils_fifo * const mFifo;                 // FIFO itself,
+                                                    // non-NULL unless constructor fails
+    audio_utils_fifo_reader * const mFifoReader;    // used to read from FIFO,
+                                                    // non-NULL unless constructor fails
+
+    void    dumpLine(const String8& timestamp, String8& body);
+
+    FormatEntry::iterator   handleFormat(const FormatEntry &fmtEntry,
+                                         String8 *timestamp,
+                                         String8 *body);
+    // dummy method for handling absent author entry
+    virtual size_t handleAuthor(const FormatEntry &fmtEntry, String8 *body) { return 0; }
+
+    static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
+};
+
+// Wrapper for a reader with a name. Contains a pointer to the reader and a pointer to the name
+class NamedReader {
+public:
+    NamedReader() { mName[0] = '\0'; } // for Vector
+    NamedReader(const sp<NBLog::Reader>& reader, const char *name) :
+        mReader(reader)
+        { strlcpy(mName, name, sizeof(mName)); }
+    ~NamedReader() { }
+    const sp<NBLog::Reader>&  reader() const { return mReader; }
+    const char*               name() const { return mName; }
+
+private:
+    sp<NBLog::Reader>   mReader;
+    static const size_t kMaxName = 32;
+    char                mName[kMaxName];
+};
+
+// ---------------------------------------------------------------------------
+
+class Merger : public RefBase {
+public:
+    Merger(const void *shared, size_t size);
+
+    virtual ~Merger() {}
+
+    void addReader(const NamedReader &reader);
+    // TODO add removeReader
+    void merge();
+    const std::vector<NamedReader> *getNamedReaders() const;
+private:
+    // vector of the readers the merger is supposed to merge from.
+    // every reader reads from a writer's buffer
+    std::vector<NamedReader> mNamedReaders;
+    uint8_t *mBuffer;
+    Shared * const mShared;
+    std::unique_ptr<audio_utils_fifo> mFifo;
+    std::unique_ptr<audio_utils_fifo_writer> mFifoWriter;
+
+    static struct timespec getTimestamp(const uint8_t *data);
+};
+
+class MergeReader : public Reader {
+public:
+    MergeReader(const void *shared, size_t size, Merger &merger);
+private:
+    const std::vector<NamedReader> *mNamedReaders;
+    // handle author entry by looking up the author's name and appending it to the body
+    // returns number of bytes read from fmtEntry
+    size_t handleAuthor(const FormatEntry &fmtEntry, String8 *body);
+};
+
+};  // class NBLog
+
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_NBLOG_H
diff --git a/include/media/nbaio/Pipe.h b/media/libnbaio/include/Pipe.h
similarity index 100%
rename from include/media/nbaio/Pipe.h
rename to media/libnbaio/include/Pipe.h
diff --git a/include/media/nbaio/PipeReader.h b/media/libnbaio/include/PipeReader.h
similarity index 100%
rename from include/media/nbaio/PipeReader.h
rename to media/libnbaio/include/PipeReader.h
diff --git a/include/media/nbaio/SourceAudioBufferProvider.h b/media/libnbaio/include/SourceAudioBufferProvider.h
similarity index 100%
rename from include/media/nbaio/SourceAudioBufferProvider.h
rename to media/libnbaio/include/SourceAudioBufferProvider.h
diff --git a/media/liboboe/README.md b/media/liboboe/README.md
deleted file mode 100644
index 9f2c249..0000000
--- a/media/liboboe/README.md
+++ /dev/null
@@ -1 +0,0 @@
-AAudio Audio input/output API
diff --git a/media/liboboe/include/aaudio/AAudio.h b/media/liboboe/include/aaudio/AAudio.h
deleted file mode 100644
index 7324137..0000000
--- a/media/liboboe/include/aaudio/AAudio.h
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-/**
- * This is the 'C' ABI for AAudio.
- */
-#ifndef AAUDIO_AAUDIO_H
-#define AAUDIO_AAUDIO_H
-
-#include "AAudioDefinitions.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef aaudio_handle_t AAudioStream;
-typedef aaudio_handle_t AAudioStreamBuilder;
-
-#define AAUDIO_STREAM_NONE         ((AAudioStream)AAUDIO_HANDLE_INVALID)
-#define AAUDIO_STREAM_BUILDER_NONE ((AAudioStreamBuilder)AAUDIO_HANDLE_INVALID)
-
-/* AAUDIO_API will probably get defined in a Makefile for a specific platform. */
-#ifndef AAUDIO_API
-#define AAUDIO_API /* for exporting symbols */
-#endif
-
-// ============================================================
-// Audio System
-// ============================================================
-
-/**
- * @return time in the same clock domain as the timestamps
- */
-AAUDIO_API aaudio_nanoseconds_t AAudio_getNanoseconds(aaudio_clockid_t clockid);
-
-/**
- * The text is the ASCII symbol corresponding to the returnCode,
- * or an English message saying the returnCode is unrecognized.
- * This is intended for developers to use when debugging.
- * It is not for display to users.
- *
- * @return pointer to a text representation of an AAudio result code.
- */
-AAUDIO_API const char * AAudio_convertResultToText(aaudio_result_t returnCode);
-
-/**
- * The text is the ASCII symbol corresponding to the stream state,
- * or an English message saying the state is unrecognized.
- * This is intended for developers to use when debugging.
- * It is not for display to users.
- *
- * @return pointer to a text representation of an AAudio state.
- */
-AAUDIO_API const char * AAudio_convertStreamStateToText(aaudio_stream_state_t state);
-
-// ============================================================
-// StreamBuilder
-// ============================================================
-
-/**
- * Create a StreamBuilder that can be used to open a Stream.
- *
- * The deviceId is initially unspecified, meaning that the current default device will be used.
- *
- * The default direction is AAUDIO_DIRECTION_OUTPUT.
- * The default sharing mode is AAUDIO_SHARING_MODE_LEGACY.
- * The data format, samplesPerFrames and sampleRate are unspecified and will be
- * chosen by the device when it is opened.
- *
- * AAudioStreamBuilder_delete() must be called when you are done using the builder.
- */
-AAUDIO_API aaudio_result_t AAudio_createStreamBuilder(AAudioStreamBuilder *builder);
-
-/**
- * Request an audio device identified device using an ID.
- * The ID is platform specific.
- * On Android, for example, the ID could be obtained from the Java AudioManager.
- *
- * By default, the primary device will be used.
- *
- * @param builder handle provided by AAudio_createStreamBuilder()
- * @param deviceId platform specific identifier or AAUDIO_DEVICE_UNSPECIFIED
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_setDeviceId(AAudioStreamBuilder builder,
-                                                     aaudio_device_id_t deviceId);
-/**
- * Passes back requested device ID.
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_getDeviceId(AAudioStreamBuilder builder,
-                                                     aaudio_device_id_t *deviceId);
-
-/**
- * Request a sample rate in Hz.
- * The stream may be opened with a different sample rate.
- * So the application should query for the actual rate after the stream is opened.
- *
- * Technically, this should be called the "frame rate" or "frames per second",
- * because it refers to the number of complete frames transferred per second.
- * But it is traditionally called "sample rate". Se we use that term.
- *
- * Default is AAUDIO_UNSPECIFIED.
- *
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_setSampleRate(AAudioStreamBuilder builder,
-                                                       aaudio_sample_rate_t sampleRate);
-
-/**
- * Returns sample rate in Hertz (samples per second).
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_getSampleRate(AAudioStreamBuilder builder,
-                                                       aaudio_sample_rate_t *sampleRate);
-
-
-/**
- * Request a number of samples per frame.
- * The stream may be opened with a different value.
- * So the application should query for the actual value after the stream is opened.
- *
- * Default is AAUDIO_UNSPECIFIED.
- *
- * Note, this quantity is sometimes referred to as "channel count".
- *
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_setSamplesPerFrame(AAudioStreamBuilder builder,
-                                                   int32_t samplesPerFrame);
-
-/**
- * Note, this quantity is sometimes referred to as "channel count".
- *
- * @param builder handle provided by AAudio_createStreamBuilder()
- * @param samplesPerFrame pointer to a variable to be set to samplesPerFrame.
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_getSamplesPerFrame(AAudioStreamBuilder builder,
-                                                   int32_t *samplesPerFrame);
-
-
-/**
- * Request a sample data format, for example AAUDIO_FORMAT_PCM_I16.
- * The application should query for the actual format after the stream is opened.
- *
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_setFormat(AAudioStreamBuilder builder,
-                                                   aaudio_audio_format_t format);
-
-/**
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_getFormat(AAudioStreamBuilder builder,
-                                                   aaudio_audio_format_t *format);
-
-/**
- * Request a mode for sharing the device.
- * The requested sharing mode may not be available.
- * So the application should query for the actual mode after the stream is opened.
- *
- * @param builder handle provided by AAudio_createStreamBuilder()
- * @param sharingMode AAUDIO_SHARING_MODE_LEGACY or AAUDIO_SHARING_MODE_EXCLUSIVE
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_setSharingMode(AAudioStreamBuilder builder,
-                                                        aaudio_sharing_mode_t sharingMode);
-
-/**
- * Return requested sharing mode.
- * @return AAUDIO_OK or a negative error
- */
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_getSharingMode(AAudioStreamBuilder builder,
-                                                        aaudio_sharing_mode_t *sharingMode);
-
-/**
- * Request the direction for a stream. The default is AAUDIO_DIRECTION_OUTPUT.
- *
- * @param builder handle provided by AAudio_createStreamBuilder()
- * @param direction AAUDIO_DIRECTION_OUTPUT or AAUDIO_DIRECTION_INPUT
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_setDirection(AAudioStreamBuilder builder,
-                                                      aaudio_direction_t direction);
-
-/**
- * @param builder handle provided by AAudio_createStreamBuilder()
- * @param direction pointer to a variable to be set to the currently requested direction.
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_getDirection(AAudioStreamBuilder builder,
-                                                      aaudio_direction_t *direction);
-
-/**
- * Open a stream based on the options in the StreamBuilder.
- *
- * AAudioStream_close must be called when finished with the stream to recover
- * the memory and to free the associated resources.
- *
- * @param builder handle provided by AAudio_createStreamBuilder()
- * @param stream pointer to a variable to receive the new stream handle
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t  AAudioStreamBuilder_openStream(AAudioStreamBuilder builder,
-                                                     AAudioStream *stream);
-
-/**
- * Delete the resources associated with the StreamBuilder.
- *
- * @param builder handle provided by AAudio_createStreamBuilder()
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t  AAudioStreamBuilder_delete(AAudioStreamBuilder builder);
-
-// ============================================================
-// Stream Control
-// ============================================================
-
-/**
- * Free the resources associated with a stream created by AAudioStreamBuilder_openStream()
- *
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t  AAudioStream_close(AAudioStream stream);
-
-/**
- * Asynchronously request to start playing the stream. For output streams, one should
- * write to the stream to fill the buffer before starting.
- * Otherwise it will underflow.
- * After this call the state will be in AAUDIO_STREAM_STATE_STARTING or AAUDIO_STREAM_STATE_STARTED.
- *
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t  AAudioStream_requestStart(AAudioStream stream);
-
-/**
- * Asynchronous request for the stream to pause.
- * Pausing a stream will freeze the data flow but not flush any buffers.
- * Use AAudioStream_Start() to resume playback after a pause.
- * After this call the state will be in AAUDIO_STREAM_STATE_PAUSING or AAUDIO_STREAM_STATE_PAUSED.
- *
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t  AAudioStream_requestPause(AAudioStream stream);
-
-/**
- * Asynchronous request for the stream to flush.
- * Flushing will discard any pending data.
- * This call only works if the stream is pausing or paused. TODO review
- * Frame counters are not reset by a flush. They may be advanced.
- * After this call the state will be in AAUDIO_STREAM_STATE_FLUSHING or AAUDIO_STREAM_STATE_FLUSHED.
- *
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t  AAudioStream_requestFlush(AAudioStream stream);
-
-/**
- * Asynchronous request for the stream to stop.
- * The stream will stop after all of the data currently buffered has been played.
- * After this call the state will be in AAUDIO_STREAM_STATE_STOPPING or AAUDIO_STREAM_STATE_STOPPED.
- *
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t  AAudioStream_requestStop(AAudioStream stream);
-
-/**
- * Query the current state, eg. AAUDIO_STREAM_STATE_PAUSING
- *
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @param state pointer to a variable that will be set to the current state
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_getState(AAudioStream stream, aaudio_stream_state_t *state);
-
-/**
- * Wait until the current state no longer matches the input state.
- *
- * <pre><code>
- * aaudio_stream_state_t currentState;
- * aaudio_result_t result = AAudioStream_getState(stream, &currentState);
- * while (result == AAUDIO_OK && currentState != AAUDIO_STREAM_STATE_PAUSING) {
- *     result = AAudioStream_waitForStateChange(
- *                                   stream, currentState, &currentState, MY_TIMEOUT_NANOS);
- * }
- * </code></pre>
- *
- * @param stream A handle provided by AAudioStreamBuilder_openStream()
- * @param inputState The state we want to avoid.
- * @param nextState Pointer to a variable that will be set to the new state.
- * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_waitForStateChange(AAudioStream stream,
-                                            aaudio_stream_state_t inputState,
-                                            aaudio_stream_state_t *nextState,
-                                            aaudio_nanoseconds_t timeoutNanoseconds);
-
-// ============================================================
-// Stream I/O
-// ============================================================
-
-/**
- * Read data from the stream.
- *
- * The call will wait until the read is complete or until it runs out of time.
- * If timeoutNanos is zero then this call will not wait.
- *
- * Note that timeoutNanoseconds is a relative duration in wall clock time.
- * Time will not stop if the thread is asleep.
- * So it will be implemented using CLOCK_BOOTTIME.
- *
- * This call is "strong non-blocking" unless it has to wait for data.
- *
- * @param stream A stream created using AAudioStreamBuilder_openStream().
- * @param buffer The address of the first sample.
- * @param numFrames Number of frames to read. Only complete frames will be written.
- * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
- * @return The number of frames actually written or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_read(AAudioStream stream,
-                               void *buffer,
-                               aaudio_size_frames_t numFrames,
-                               aaudio_nanoseconds_t timeoutNanoseconds);
-
-/**
- * Write data to the stream.
- *
- * The call will wait until the write is complete or until it runs out of time.
- * If timeoutNanos is zero then this call will not wait.
- *
- * Note that timeoutNanoseconds is a relative duration in wall clock time.
- * Time will not stop if the thread is asleep.
- * So it will be implemented using CLOCK_BOOTTIME.
- *
- * This call is "strong non-blocking" unless it has to wait for room in the buffer.
- *
- * @param stream A stream created using AAudioStreamBuilder_openStream().
- * @param buffer The address of the first sample.
- * @param numFrames Number of frames to write. Only complete frames will be written.
- * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
- * @return The number of frames actually written or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_write(AAudioStream stream,
-                               const void *buffer,
-                               aaudio_size_frames_t numFrames,
-                               aaudio_nanoseconds_t timeoutNanoseconds);
-
-
-// ============================================================
-// High priority audio threads
-// ============================================================
-
-typedef void *(aaudio_audio_thread_proc_t)(void *);
-
-/**
- * Create a thread associated with a stream. The thread has special properties for
- * low latency audio performance. This thread can be used to implement a callback API.
- *
- * Only one thread may be associated with a stream.
- *
- * Note that this API is in flux.
- *
- * @param stream A stream created using AAudioStreamBuilder_openStream().
- * @param periodNanoseconds the estimated period at which the audio thread will need to wake up
- * @param startRoutine your thread entry point
- * @param arg an argument that will be passed to your thread entry point
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_createThread(AAudioStream stream,
-                                     aaudio_nanoseconds_t periodNanoseconds,
-                                     aaudio_audio_thread_proc_t *threadProc,
-                                     void *arg);
-
-/**
- * Wait until the thread exits or an error occurs.
- * The thread handle will be deleted.
- *
- * @param stream A stream created using AAudioStreamBuilder_openStream().
- * @param returnArg a pointer to a variable to receive the return value
- * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_joinThread(AAudioStream stream,
-                                   void **returnArg,
-                                   aaudio_nanoseconds_t timeoutNanoseconds);
-
-// ============================================================
-// Stream - queries
-// ============================================================
-
-
-/**
- * This can be used to adjust the latency of the buffer by changing
- * the threshold where blocking will occur.
- * By combining this with AAudioStream_getUnderrunCount(), the latency can be tuned
- * at run-time for each device.
- *
- * This cannot be set higher than AAudioStream_getBufferCapacity().
- *
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @param requestedFrames requested number of frames that can be filled without blocking
- * @param actualFrames receives final number of frames
- * @return AAUDIO_OK or a negative error
- */
-AAUDIO_API aaudio_result_t AAudioStream_setBufferSize(AAudioStream stream,
-                                                aaudio_size_frames_t requestedFrames,
-                                                aaudio_size_frames_t *actualFrames);
-
-/**
- * Query the maximum number of frames that can be filled without blocking.
- *
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @param frames pointer to variable to receive the buffer size
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_getBufferSize(AAudioStream stream, aaudio_size_frames_t *frames);
-
-/**
- * Query the number of frames that are read or written by the endpoint at one time.
- *
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @param frames pointer to variable to receive the burst size
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_getFramesPerBurst(AAudioStream stream, aaudio_size_frames_t *frames);
-
-/**
- * Query maximum buffer capacity in frames.
- *
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @param frames pointer to variable to receive the buffer capacity
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_getBufferCapacity(AAudioStream stream, aaudio_size_frames_t *frames);
-
-/**
- * An XRun is an Underrun or an Overrun.
- * During playing, an underrun will occur if the stream is not written in time
- * and the system runs out of valid data.
- * During recording, an overrun will occur if the stream is not read in time
- * and there is no place to put the incoming data so it is discarded.
- *
- * An underrun or overrun can cause an audible "pop" or "glitch".
- *
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @param xRunCount pointer to variable to receive the underrun or overrun count
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_getXRunCount(AAudioStream stream, int32_t *xRunCount);
-
-/**
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @param sampleRate pointer to variable to receive the actual sample rate
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_getSampleRate(AAudioStream stream, aaudio_sample_rate_t *sampleRate);
-
-/**
- * The samplesPerFrame is also known as channelCount.
- *
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @param samplesPerFrame pointer to variable to receive the actual samples per frame
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_getSamplesPerFrame(AAudioStream stream, int32_t *samplesPerFrame);
-
-/**
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @param deviceId pointer to variable to receive the actual device ID
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_getDeviceId(AAudioStream stream, aaudio_device_id_t *deviceId);
-
-/**
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @param format pointer to variable to receive the actual data format
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_getFormat(AAudioStream stream, aaudio_audio_format_t *format);
-
-/**
- * Provide actual sharing mode.
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @param sharingMode pointer to variable to receive the actual sharing mode
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_getSharingMode(AAudioStream stream,
-                                        aaudio_sharing_mode_t *sharingMode);
-
-/**
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @param direction pointer to a variable to be set to the current direction.
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_getDirection(AAudioStream stream, aaudio_direction_t *direction);
-
-/**
- * Passes back the number of frames that have been written since the stream was created.
- * For an output stream, this will be advanced by the application calling write().
- * For an input stream, this will be advanced by the device or service.
- *
- * The frame position is monotonically increasing.
- *
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @param frames pointer to variable to receive the frames written
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_getFramesWritten(AAudioStream stream,
-                                                   aaudio_position_frames_t *frames);
-
-/**
- * Passes back the number of frames that have been read since the stream was created.
- * For an output stream, this will be advanced by the device or service.
- * For an input stream, this will be advanced by the application calling read().
- *
- * The frame position is monotonically increasing.
- *
- * @param stream handle provided by AAudioStreamBuilder_openStream()
- * @param frames pointer to variable to receive the frames written
- * @return AAUDIO_OK or a negative error.
- */
-AAUDIO_API aaudio_result_t AAudioStream_getFramesRead(AAudioStream stream, aaudio_position_frames_t *frames);
-
-/**
- * Passes back the time at which a particular frame was presented.
- * This can be used to synchronize audio with video or MIDI.
- * It can also be used to align a recorded stream with a playback stream.
- *
- * Timestamps are only valid when the stream is in AAUDIO_STREAM_STATE_STARTED.
- * AAUDIO_ERROR_INVALID_STATE will be returned if the stream is not started.
- * Note that because requestStart() is asynchronous, timestamps will not be valid until
- * a short time after calling requestStart().
- * So AAUDIO_ERROR_INVALID_STATE should not be considered a fatal error.
- * Just try calling again later.
- *
- * If an error occurs, then the position and time will not be modified.
- *
- * The position and time passed back are monotonically increasing.
- *
- * @param stream A handle provided by AAudioStreamBuilder_openStream()
- * @param clockid AAUDIO_CLOCK_MONOTONIC or AAUDIO_CLOCK_BOOTTIME
- * @param framePosition pointer to a variable to receive the position
- * @param timeNanoseconds pointer to a variable to receive the time
- * @return AAUDIO_OK or a negative error
- */
-AAUDIO_API aaudio_result_t AAudioStream_getTimestamp(AAudioStream stream,
-                                      aaudio_clockid_t clockid,
-                                      aaudio_position_frames_t *framePosition,
-                                      aaudio_nanoseconds_t *timeNanoseconds);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif //AAUDIO_AAUDIO_H
diff --git a/media/liboboe/include/aaudio/AAudioDefinitions.h b/media/liboboe/include/aaudio/AAudioDefinitions.h
deleted file mode 100644
index 979b8c9..0000000
--- a/media/liboboe/include/aaudio/AAudioDefinitions.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 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 AAUDIO_AAUDIODEFINITIONS_H
-#define AAUDIO_AAUDIODEFINITIONS_H
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef int32_t  aaudio_handle_t; // negative handles are error codes
-typedef int32_t  aaudio_result_t;
-/**
- * A platform specific identifier for a device.
- */
-typedef int32_t  aaudio_device_id_t;
-typedef int32_t  aaudio_sample_rate_t;
-/** This is used for small quantities such as the number of frames in a buffer. */
-typedef int32_t  aaudio_size_frames_t;
-/** This is used for small quantities such as the number of bytes in a frame. */
-typedef int32_t  aaudio_size_bytes_t;
-/**
- * This is used for large quantities, such as the number of frames that have
- * been played since a stream was started.
- * At 48000 Hz, a 32-bit integer would wrap around in just over 12 hours.
- */
-typedef int64_t  aaudio_position_frames_t;
-
-typedef int64_t  aaudio_nanoseconds_t;
-
-/**
- * This is used to represent a value that has not been specified.
- * For example, an application could use AAUDIO_UNSPECIFIED to indicate
- * that is did not not care what the specific value of a parameter was
- * and would accept whatever it was given.
- */
-#define AAUDIO_UNSPECIFIED           0
-#define AAUDIO_DEVICE_UNSPECIFIED    ((aaudio_device_id_t) -1)
-#define AAUDIO_NANOS_PER_MICROSECOND ((int64_t)1000)
-#define AAUDIO_NANOS_PER_MILLISECOND (AAUDIO_NANOS_PER_MICROSECOND * 1000)
-#define AAUDIO_MILLIS_PER_SECOND     1000
-#define AAUDIO_NANOS_PER_SECOND      (AAUDIO_NANOS_PER_MILLISECOND * AAUDIO_MILLIS_PER_SECOND)
-
-#define AAUDIO_HANDLE_INVALID     ((aaudio_handle_t)-1)
-
-enum aaudio_direction_t {
-    AAUDIO_DIRECTION_OUTPUT,
-    AAUDIO_DIRECTION_INPUT,
-    AAUDIO_DIRECTION_COUNT // This should always be last.
-};
-
-enum aaudio_audio_format_t {
-    AAUDIO_FORMAT_INVALID = -1,
-    AAUDIO_FORMAT_UNSPECIFIED = 0,
-    AAUDIO_FORMAT_PCM_I16,
-    AAUDIO_FORMAT_PCM_FLOAT,
-    AAUDIO_FORMAT_PCM_I8_24,
-    AAUDIO_FORMAT_PCM_I32
-};
-
-// TODO These are deprecated. Remove these aliases once all references are replaced.
-#define AAUDIO_FORMAT_PCM16    AAUDIO_FORMAT_PCM_I16
-#define AAUDIO_FORMAT_PCM824   AAUDIO_FORMAT_PCM_I8_24
-#define AAUDIO_FORMAT_PCM32    AAUDIO_FORMAT_PCM_I32
-
-enum {
-    AAUDIO_OK,
-    AAUDIO_ERROR_BASE = -900, // TODO review
-    AAUDIO_ERROR_DISCONNECTED,
-    AAUDIO_ERROR_ILLEGAL_ARGUMENT,
-    AAUDIO_ERROR_INCOMPATIBLE,
-    AAUDIO_ERROR_INTERNAL, // an underlying API returned an error code
-    AAUDIO_ERROR_INVALID_STATE,
-    AAUDIO_ERROR_UNEXPECTED_STATE,
-    AAUDIO_ERROR_UNEXPECTED_VALUE,
-    AAUDIO_ERROR_INVALID_HANDLE,
-    AAUDIO_ERROR_INVALID_QUERY,
-    AAUDIO_ERROR_UNIMPLEMENTED,
-    AAUDIO_ERROR_UNAVAILABLE,
-    AAUDIO_ERROR_NO_FREE_HANDLES,
-    AAUDIO_ERROR_NO_MEMORY,
-    AAUDIO_ERROR_NULL,
-    AAUDIO_ERROR_TIMEOUT,
-    AAUDIO_ERROR_WOULD_BLOCK,
-    AAUDIO_ERROR_INVALID_ORDER,
-    AAUDIO_ERROR_OUT_OF_RANGE,
-    AAUDIO_ERROR_NO_SERVICE
-};
-
-typedef enum {
-    AAUDIO_CLOCK_MONOTONIC, // Clock since booted, pauses when CPU is sleeping.
-    AAUDIO_CLOCK_BOOTTIME,  // Clock since booted, runs all the time.
-    AAUDIO_CLOCK_COUNT // This should always be last.
-} aaudio_clockid_t;
-
-typedef enum
-{
-    AAUDIO_STREAM_STATE_UNINITIALIZED = 0,
-    AAUDIO_STREAM_STATE_OPEN,
-    AAUDIO_STREAM_STATE_STARTING,
-    AAUDIO_STREAM_STATE_STARTED,
-    AAUDIO_STREAM_STATE_PAUSING,
-    AAUDIO_STREAM_STATE_PAUSED,
-    AAUDIO_STREAM_STATE_FLUSHING,
-    AAUDIO_STREAM_STATE_FLUSHED,
-    AAUDIO_STREAM_STATE_STOPPING,
-    AAUDIO_STREAM_STATE_STOPPED,
-    AAUDIO_STREAM_STATE_CLOSING,
-    AAUDIO_STREAM_STATE_CLOSED,
-} aaudio_stream_state_t;
-
-// TODO review API
-typedef enum {
-    /**
-     * This will use an AudioTrack object for playing audio
-     * and an AudioRecord for recording data.
-     */
-    AAUDIO_SHARING_MODE_LEGACY,
-    /**
-     * This will be the only stream using a particular source or sink.
-     * This mode will provide the lowest possible latency.
-     * You should close EXCLUSIVE streams immediately when you are not using them.
-     */
-    AAUDIO_SHARING_MODE_EXCLUSIVE,
-    /**
-     * Multiple applications will be mixed by the AAudio Server.
-     * This will have higher latency than the EXCLUSIVE mode.
-     */
-    AAUDIO_SHARING_MODE_SHARED,
-    /**
-     * Multiple applications will do their own mixing into a memory mapped buffer.
-     * It may be possible for malicious applications to read the data produced by
-     * other apps. So do not use this for private data such as telephony or messaging.
-     */
-    AAUDIO_SHARING_MODE_PUBLIC_MIX,
-    AAUDIO_SHARING_MODE_COUNT // This should always be last.
-} aaudio_sharing_mode_t;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // AAUDIO_AAUDIODEFINITIONS_H
diff --git a/media/liboboe/scripts/revert_all_aaudio.sh b/media/liboboe/scripts/revert_all_aaudio.sh
deleted file mode 100755
index de3fa7a..0000000
--- a/media/liboboe/scripts/revert_all_aaudio.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/bash
-
-echo "Revert Oboe names to AAudio names"
-
-echo "Top is ${ANDROID_BUILD_TOP}"
-LIBOBOE_DIR=${ANDROID_BUILD_TOP}/frameworks/av/media/liboboe
-echo "LIBOBOE_DIR is ${LIBOBOE_DIR}"
-OBOESERVICE_DIR=${ANDROID_BUILD_TOP}/frameworks/av/services/oboeservice
-echo "OBOESERVICE_DIR is ${OBOESERVICE_DIR}"
-OBOETEST_DIR=${ANDROID_BUILD_TOP}/cts/tests/tests/nativemedia/aaudio/src/
-echo "OBOETEST_DIR is ${OBOETEST_DIR}"
-
-git checkout -- ${LIBOBOE_DIR}/examples
-git checkout -- ${LIBOBOE_DIR}/include
-git checkout -- ${LIBOBOE_DIR}/src
-git checkout -- ${LIBOBOE_DIR}/tests
-git checkout -- ${LIBOBOE_DIR}/Android.bp
-git checkout -- ${LIBOBOE_DIR}/README.md
-git checkout -- ${LIBOBOE_DIR}/liboboe.map.txt
-git checkout -- ${OBOESERVICE_DIR}
-git checkout -- ${OBOETEST_DIR}
-
-rm -rf ${LIBOBOE_DIR}/include/aaudio
-
-find . -name "*aaudio*.cpp" -print -delete
-find . -name "*AAudio*.cpp" -print -delete
-find . -name "*AAudio*.h"   -print -delete
diff --git a/media/liboboe/src/core/AAudioAudio.cpp b/media/liboboe/src/core/AAudioAudio.cpp
deleted file mode 100644
index c1fa7cf..0000000
--- a/media/liboboe/src/core/AAudioAudio.cpp
+++ /dev/null
@@ -1,562 +0,0 @@
-/*
- * Copyright (C) 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_TAG "AAudio"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include <time.h>
-#include <pthread.h>
-
-#include <aaudio/AAudioDefinitions.h>
-#include <aaudio/AAudio.h>
-
-#include "AudioStreamBuilder.h"
-#include "AudioStream.h"
-#include "AudioClock.h"
-#include "client/AudioStreamInternal.h"
-#include "HandleTracker.h"
-
-using namespace aaudio;
-
-// This is not the maximum theoretic possible number of handles that the HandlerTracker
-// class could support; instead it is the maximum number of handles that we are configuring
-// for our HandleTracker instance (sHandleTracker).
-#define AAUDIO_MAX_HANDLES  64
-
-// Macros for common code that includes a return.
-// TODO Consider using do{}while(0) construct. I tried but it hung AndroidStudio
-#define CONVERT_BUILDER_HANDLE_OR_RETURN() \
-    convertAAudioBuilderToStreamBuilder(builder); \
-    if (streamBuilder == nullptr) { \
-        return AAUDIO_ERROR_INVALID_HANDLE; \
-    }
-
-#define COMMON_GET_FROM_BUILDER_OR_RETURN(resultPtr) \
-    CONVERT_BUILDER_HANDLE_OR_RETURN() \
-    if ((resultPtr) == nullptr) { \
-        return AAUDIO_ERROR_NULL; \
-    }
-
-#define CONVERT_STREAM_HANDLE_OR_RETURN() \
-    convertAAudioStreamToAudioStream(stream); \
-    if (audioStream == nullptr) { \
-        return AAUDIO_ERROR_INVALID_HANDLE; \
-    }
-
-#define COMMON_GET_FROM_STREAM_OR_RETURN(resultPtr) \
-    CONVERT_STREAM_HANDLE_OR_RETURN(); \
-    if ((resultPtr) == nullptr) { \
-        return AAUDIO_ERROR_NULL; \
-    }
-
-// Static data.
-// TODO static constructors are discouraged, alternatives?
-static HandleTracker sHandleTracker(AAUDIO_MAX_HANDLES);
-
-typedef enum
-{
-    AAUDIO_HANDLE_TYPE_STREAM,
-    AAUDIO_HANDLE_TYPE_STREAM_BUILDER,
-    AAUDIO_HANDLE_TYPE_COUNT
-} aaudio_handle_type_t;
-static_assert(AAUDIO_HANDLE_TYPE_COUNT <= HANDLE_TRACKER_MAX_TYPES, "Too many handle types.");
-
-
-#define AAUDIO_CASE_ENUM(name) case name: return #name
-
-AAUDIO_API const char * AAudio_convertResultToText(aaudio_result_t returnCode) {
-    switch (returnCode) {
-        AAUDIO_CASE_ENUM(AAUDIO_OK);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_ILLEGAL_ARGUMENT);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_INCOMPATIBLE);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_INTERNAL);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_STATE);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_HANDLE);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_QUERY);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNIMPLEMENTED);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_UNAVAILABLE);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_FREE_HANDLES);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_MEMORY);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_NULL);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_TIMEOUT);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_WOULD_BLOCK);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_ORDER);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_OUT_OF_RANGE);
-        AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_SERVICE);
-    }
-    return "Unrecognized AAudio error.";
-}
-
-AAUDIO_API const char * AAudio_convertStreamStateToText(aaudio_stream_state_t state) {
-    switch (state) {
-        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_UNINITIALIZED);
-        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_OPEN);
-        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STARTING);
-        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STARTED);
-        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_PAUSING);
-        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_PAUSED);
-        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_FLUSHING);
-        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_FLUSHED);
-        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STOPPING);
-        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_STOPPED);
-        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSING);
-        AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSED);
-    }
-    return "Unrecognized AAudio state.";
-}
-
-#undef AAUDIO_CASE_ENUM
-
-static AudioStream *convertAAudioStreamToAudioStream(AAudioStream stream)
-{
-    return (AudioStream *) sHandleTracker.get(AAUDIO_HANDLE_TYPE_STREAM,
-                                              (aaudio_handle_t) stream);
-}
-
-static AudioStreamBuilder *convertAAudioBuilderToStreamBuilder(AAudioStreamBuilder builder)
-{
-    return (AudioStreamBuilder *) sHandleTracker.get(AAUDIO_HANDLE_TYPE_STREAM_BUILDER,
-                                                     (aaudio_handle_t) builder);
-}
-
-AAUDIO_API aaudio_result_t AAudio_createStreamBuilder(AAudioStreamBuilder *builder)
-{
-    ALOGD("AAudio_createStreamBuilder(): check sHandleTracker.isInitialized ()");
-    if (!sHandleTracker.isInitialized()) {
-        return AAUDIO_ERROR_NO_MEMORY;
-    }
-    AudioStreamBuilder *audioStreamBuilder =  new AudioStreamBuilder();
-    if (audioStreamBuilder == nullptr) {
-        return AAUDIO_ERROR_NO_MEMORY;
-    }
-    ALOGD("AAudio_createStreamBuilder(): created AudioStreamBuilder = %p", audioStreamBuilder);
-    // TODO protect the put() with a Mutex
-    AAudioStreamBuilder handle = sHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM_BUILDER,
-            audioStreamBuilder);
-    if (handle < 0) {
-        delete audioStreamBuilder;
-        return static_cast<aaudio_result_t>(handle);
-    } else {
-        *builder = handle;
-    }
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_setDeviceId(AAudioStreamBuilder builder,
-                                                     aaudio_device_id_t deviceId)
-{
-    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
-    streamBuilder->setDeviceId(deviceId);
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_getDeviceId(AAudioStreamBuilder builder,
-                                              aaudio_device_id_t *deviceId)
-{
-    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(deviceId);
-    *deviceId = streamBuilder->getDeviceId();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_setSampleRate(AAudioStreamBuilder builder,
-                                              aaudio_sample_rate_t sampleRate)
-{
-    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
-    streamBuilder->setSampleRate(sampleRate);
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_getSampleRate(AAudioStreamBuilder builder,
-                                              aaudio_sample_rate_t *sampleRate)
-{
-    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(sampleRate);
-    *sampleRate = streamBuilder->getSampleRate();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_setSamplesPerFrame(AAudioStreamBuilder builder,
-                                                   int32_t samplesPerFrame)
-{
-    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
-    streamBuilder->setSamplesPerFrame(samplesPerFrame);
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_getSamplesPerFrame(AAudioStreamBuilder builder,
-                                                   int32_t *samplesPerFrame)
-{
-    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(samplesPerFrame);
-    *samplesPerFrame = streamBuilder->getSamplesPerFrame();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_setDirection(AAudioStreamBuilder builder,
-                                             aaudio_direction_t direction)
-{
-    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
-    streamBuilder->setDirection(direction);
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_getDirection(AAudioStreamBuilder builder,
-                                             aaudio_direction_t *direction)
-{
-    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(direction);
-    *direction = streamBuilder->getDirection();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_setFormat(AAudioStreamBuilder builder,
-                                                   aaudio_audio_format_t format)
-{
-    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
-    streamBuilder->setFormat(format);
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_getFormat(AAudioStreamBuilder builder,
-                                                   aaudio_audio_format_t *format)
-{
-    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(format);
-    *format = streamBuilder->getFormat();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_setSharingMode(AAudioStreamBuilder builder,
-                                                        aaudio_sharing_mode_t sharingMode)
-{
-    AudioStreamBuilder *streamBuilder = CONVERT_BUILDER_HANDLE_OR_RETURN();
-    if ((sharingMode < 0) || (sharingMode >= AAUDIO_SHARING_MODE_COUNT)) {
-        return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
-    } else {
-        streamBuilder->setSharingMode(sharingMode);
-        return AAUDIO_OK;
-    }
-}
-
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_getSharingMode(AAudioStreamBuilder builder,
-                                                        aaudio_sharing_mode_t *sharingMode)
-{
-    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(sharingMode);
-    *sharingMode = streamBuilder->getSharingMode();
-    return AAUDIO_OK;
-}
-
-static aaudio_result_t  AAudioInternal_openStream(AudioStreamBuilder *streamBuilder,
-                                              AAudioStream *streamPtr)
-{
-    AudioStream *audioStream = nullptr;
-    aaudio_result_t result = streamBuilder->build(&audioStream);
-    if (result != AAUDIO_OK) {
-        return result;
-    } else {
-        // Create a handle for referencing the object.
-        // TODO protect the put() with a Mutex
-        AAudioStream handle = sHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, audioStream);
-        if (handle < 0) {
-            delete audioStream;
-            return static_cast<aaudio_result_t>(handle);
-        }
-        *streamPtr = handle;
-        return AAUDIO_OK;
-    }
-}
-
-AAUDIO_API aaudio_result_t  AAudioStreamBuilder_openStream(AAudioStreamBuilder builder,
-                                                     AAudioStream *streamPtr)
-{
-    ALOGD("AAudioStreamBuilder_openStream(): builder = 0x%08X", builder);
-    AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(streamPtr);
-    return AAudioInternal_openStream(streamBuilder, streamPtr);
-}
-
-AAUDIO_API aaudio_result_t  AAudioStreamBuilder_delete(AAudioStreamBuilder builder)
-{
-    AudioStreamBuilder *streamBuilder = (AudioStreamBuilder *)
-            sHandleTracker.remove(AAUDIO_HANDLE_TYPE_STREAM_BUILDER, builder);
-    if (streamBuilder != nullptr) {
-        delete streamBuilder;
-        return AAUDIO_OK;
-    }
-    return AAUDIO_ERROR_INVALID_HANDLE;
-}
-
-AAUDIO_API aaudio_result_t  AAudioStream_close(AAudioStream stream)
-{
-    AudioStream *audioStream = (AudioStream *)
-            sHandleTracker.remove(AAUDIO_HANDLE_TYPE_STREAM, (aaudio_handle_t)stream);
-    ALOGD("AAudioStream_close(0x%08X), audioStream = %p", stream, audioStream);
-    if (audioStream != nullptr) {
-        audioStream->close();
-        delete audioStream;
-        return AAUDIO_OK;
-    }
-    return AAUDIO_ERROR_INVALID_HANDLE;
-}
-
-AAUDIO_API aaudio_result_t  AAudioStream_requestStart(AAudioStream stream)
-{
-    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
-    ALOGD("AAudioStream_requestStart(0x%08X), audioStream = %p", stream, audioStream);
-    return audioStream->requestStart();
-}
-
-AAUDIO_API aaudio_result_t  AAudioStream_requestPause(AAudioStream stream)
-{
-    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
-    ALOGD("AAudioStream_requestPause(0x%08X), audioStream = %p", stream, audioStream);
-    return audioStream->requestPause();
-}
-
-AAUDIO_API aaudio_result_t  AAudioStream_requestFlush(AAudioStream stream)
-{
-    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
-    ALOGD("AAudioStream_requestFlush(0x%08X), audioStream = %p", stream, audioStream);
-    return audioStream->requestFlush();
-}
-
-AAUDIO_API aaudio_result_t  AAudioStream_requestStop(AAudioStream stream)
-{
-    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
-    ALOGD("AAudioStream_requestStop(0x%08X), audioStream = %p", stream, audioStream);
-    return audioStream->requestStop();
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_waitForStateChange(AAudioStream stream,
-                                            aaudio_stream_state_t inputState,
-                                            aaudio_stream_state_t *nextState,
-                                            aaudio_nanoseconds_t timeoutNanoseconds)
-{
-
-    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
-    return audioStream->waitForStateChange(inputState, nextState, timeoutNanoseconds);
-}
-
-// ============================================================
-// Stream - non-blocking I/O
-// ============================================================
-
-AAUDIO_API aaudio_result_t AAudioStream_read(AAudioStream stream,
-                               void *buffer,
-                               aaudio_size_frames_t numFrames,
-                               aaudio_nanoseconds_t timeoutNanoseconds)
-{
-    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
-    if (buffer == nullptr) {
-        return AAUDIO_ERROR_NULL;
-    }
-    if (numFrames < 0) {
-        return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
-    } else if (numFrames == 0) {
-        return 0;
-    }
-
-    aaudio_result_t result = audioStream->read(buffer, numFrames, timeoutNanoseconds);
-    // ALOGD("AAudioStream_read(): read returns %d", result);
-
-    return result;
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_write(AAudioStream stream,
-                               const void *buffer,
-                               aaudio_size_frames_t numFrames,
-                               aaudio_nanoseconds_t timeoutNanoseconds)
-{
-    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
-    if (buffer == nullptr) {
-        return AAUDIO_ERROR_NULL;
-    }
-    if (numFrames < 0) {
-        return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
-    } else if (numFrames == 0) {
-        return 0;
-    }
-
-    aaudio_result_t result = audioStream->write(buffer, numFrames, timeoutNanoseconds);
-    // ALOGD("AAudioStream_write(): write returns %d", result);
-
-    return result;
-}
-
-// ============================================================
-// Miscellaneous
-// ============================================================
-
-AAUDIO_API aaudio_result_t AAudioStream_createThread(AAudioStream stream,
-                                     aaudio_nanoseconds_t periodNanoseconds,
-                                     aaudio_audio_thread_proc_t *threadProc, void *arg)
-{
-    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
-    return audioStream->createThread(periodNanoseconds, threadProc, arg);
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_joinThread(AAudioStream stream,
-                                   void **returnArg,
-                                   aaudio_nanoseconds_t timeoutNanoseconds)
-{
-    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
-    return audioStream->joinThread(returnArg, timeoutNanoseconds);
-}
-
-// ============================================================
-// Stream - queries
-// ============================================================
-
-// TODO Use aaudio_clockid_t all the way down through the C++ streams.
-static clockid_t AAudioConvert_fromAAudioClockId(aaudio_clockid_t clockid)
-{
-    clockid_t hostClockId;
-    switch (clockid) {
-        case AAUDIO_CLOCK_MONOTONIC:
-            hostClockId = CLOCK_MONOTONIC;
-            break;
-        case AAUDIO_CLOCK_BOOTTIME:
-            hostClockId = CLOCK_BOOTTIME;
-            break;
-        default:
-            hostClockId = 0; // TODO review
-    }
-    return hostClockId;
-}
-
-aaudio_nanoseconds_t AAudio_getNanoseconds(aaudio_clockid_t clockid)
-{
-    clockid_t hostClockId = AAudioConvert_fromAAudioClockId(clockid);
-   return AudioClock::getNanoseconds(hostClockId);
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_getSampleRate(AAudioStream stream, aaudio_sample_rate_t *sampleRate)
-{
-    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(sampleRate);
-    *sampleRate = audioStream->getSampleRate();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_getSamplesPerFrame(AAudioStream stream, int32_t *samplesPerFrame)
-{
-    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(samplesPerFrame);
-    *samplesPerFrame = audioStream->getSamplesPerFrame();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_getState(AAudioStream stream, aaudio_stream_state_t *state)
-{
-    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(state);
-    *state = audioStream->getState();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_getFormat(AAudioStream stream, aaudio_audio_format_t *format)
-{
-    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(format);
-    *format = audioStream->getFormat();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_setBufferSize(AAudioStream stream,
-                                                aaudio_size_frames_t requestedFrames,
-                                                aaudio_size_frames_t *actualFrames)
-{
-    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
-    return audioStream->setBufferSize(requestedFrames, actualFrames);
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_getBufferSize(AAudioStream stream, aaudio_size_frames_t *frames)
-{
-    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(frames);
-    *frames = audioStream->getBufferSize();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_getDirection(AAudioStream stream, int32_t *direction)
-{
-    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(direction);
-    *direction = audioStream->getDirection();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_getFramesPerBurst(AAudioStream stream,
-                                                    aaudio_size_frames_t *framesPerBurst)
-{
-    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(framesPerBurst);
-    *framesPerBurst = audioStream->getFramesPerBurst();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_getBufferCapacity(AAudioStream stream,
-                                           aaudio_size_frames_t *capacity)
-{
-    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(capacity);
-    *capacity = audioStream->getBufferCapacity();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_getXRunCount(AAudioStream stream, int32_t *xRunCount)
-{
-    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(xRunCount);
-    *xRunCount = audioStream->getXRunCount();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_getDeviceId(AAudioStream stream,
-                                                 aaudio_device_id_t *deviceId)
-{
-    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(deviceId);
-    *deviceId = audioStream->getDeviceId();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_getSharingMode(AAudioStream stream,
-                                                 aaudio_sharing_mode_t *sharingMode)
-{
-    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(sharingMode);
-    *sharingMode = audioStream->getSharingMode();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_getFramesWritten(AAudioStream stream,
-                                                   aaudio_position_frames_t *frames)
-{
-    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(frames);
-    *frames = audioStream->getFramesWritten();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_getFramesRead(AAudioStream stream, aaudio_position_frames_t *frames)
-{
-    AudioStream *audioStream = COMMON_GET_FROM_STREAM_OR_RETURN(frames);
-    *frames = audioStream->getFramesRead();
-    return AAUDIO_OK;
-}
-
-AAUDIO_API aaudio_result_t AAudioStream_getTimestamp(AAudioStream stream,
-                                      aaudio_clockid_t clockid,
-                                      aaudio_position_frames_t *framePosition,
-                                      aaudio_nanoseconds_t *timeNanoseconds)
-{
-    AudioStream *audioStream = CONVERT_STREAM_HANDLE_OR_RETURN();
-    if (framePosition == nullptr) {
-        return AAUDIO_ERROR_NULL;
-    } else if (timeNanoseconds == nullptr) {
-        return AAUDIO_ERROR_NULL;
-    } else if (clockid != AAUDIO_CLOCK_MONOTONIC && clockid != AAUDIO_CLOCK_BOOTTIME) {
-        return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
-    }
-
-    clockid_t hostClockId = AAudioConvert_fromAAudioClockId(clockid);
-    return audioStream->getTimestamp(hostClockId, framePosition, timeNanoseconds);
-}
diff --git a/media/liboboe/tests/Android.mk b/media/liboboe/tests/Android.mk
deleted file mode 100644
index 16279ec..0000000
--- a/media/liboboe/tests/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/liboboe/include \
-    frameworks/av/media/liboboe/src/core \
-    frameworks/av/media/liboboe/src/utility
-LOCAL_SRC_FILES := test_aaudio_api.cpp
-LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \
-                          libcutils liblog libmedia libutils
-LOCAL_STATIC_LIBRARIES := liboboe
-LOCAL_MODULE := test_aaudio_api
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/liboboe/include \
-    frameworks/av/media/liboboe/src/core \
-    frameworks/av/media/liboboe/src/utility
-LOCAL_SRC_FILES:= test_handle_tracker.cpp
-LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \
-                          libcutils liblog libmedia libutils
-LOCAL_STATIC_LIBRARIES := liboboe
-LOCAL_MODULE := test_handle_tracker
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/media/liboboe/include \
-    frameworks/av/media/liboboe/src \
-    frameworks/av/media/liboboe/src/core \
-    frameworks/av/media/liboboe/src/fifo \
-    frameworks/av/media/liboboe/src/utility
-LOCAL_SRC_FILES:= test_marshalling.cpp
-LOCAL_SHARED_LIBRARIES := libaudioclient libaudioutils libbinder \
-                          libcutils liblog libmedia libutils
-LOCAL_STATIC_LIBRARIES := liboboe
-LOCAL_MODULE := test_marshalling
-include $(BUILD_NATIVE_TEST)
diff --git a/media/liboboe/tests/test_aaudio_api.cpp b/media/liboboe/tests/test_aaudio_api.cpp
deleted file mode 100644
index 7db3688..0000000
--- a/media/liboboe/tests/test_aaudio_api.cpp
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-// Unit tests for AAudio 'C' API.
-
-#include <stdlib.h>
-#include <math.h>
-
-#include <gtest/gtest.h>
-
-#include <aaudio/AAudioDefinitions.h>
-#include <aaudio/AAudio.h>
-#include "AAudioUtilities.h"
-
-#define DEFAULT_STATE_TIMEOUT  (500 * AAUDIO_NANOS_PER_MILLISECOND)
-
-// Test AAudioStreamBuilder
-TEST(test_aaudio_api, aaudio_stream_builder) {
-    const aaudio_sample_rate_t requestedSampleRate1 = 48000;
-    const aaudio_sample_rate_t requestedSampleRate2 = 44100;
-    const int32_t requestedSamplesPerFrame = 2;
-    const aaudio_audio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM16;
-
-    aaudio_sample_rate_t sampleRate = 0;
-    int32_t samplesPerFrame = 0;
-    aaudio_audio_format_t actualDataFormat;
-    AAudioStreamBuilder aaudioBuilder1;
-    AAudioStreamBuilder aaudioBuilder2;
-
-    aaudio_result_t result = AAUDIO_OK;
-
-    // Use an AAudioStreamBuilder to define the stream.
-    result = AAudio_createStreamBuilder(&aaudioBuilder1);
-    ASSERT_EQ(AAUDIO_OK, result);
-
-    // Request stream properties.
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_setSampleRate(aaudioBuilder1, requestedSampleRate1));
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_setSamplesPerFrame(aaudioBuilder1, requestedSamplesPerFrame));
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_setFormat(aaudioBuilder1, requestedDataFormat));
-
-    // Check to make sure builder saved the properties.
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_getSampleRate(aaudioBuilder1, &sampleRate));
-    EXPECT_EQ(requestedSampleRate1, sampleRate);
-
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_getSamplesPerFrame(aaudioBuilder1, &samplesPerFrame));
-    EXPECT_EQ(requestedSamplesPerFrame, samplesPerFrame);
-
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_getFormat(aaudioBuilder1, &actualDataFormat));
-    EXPECT_EQ(requestedDataFormat, actualDataFormat);
-
-    result = AAudioStreamBuilder_getSampleRate(0x0BADCAFE, &sampleRate); // ridiculous token
-    EXPECT_EQ(AAUDIO_ERROR_INVALID_HANDLE, result);
-
-    // Create a second builder and make sure they do not collide.
-    ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder2));
-    ASSERT_NE(aaudioBuilder1, aaudioBuilder2);
-
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_setSampleRate(aaudioBuilder2, requestedSampleRate2));
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_getSampleRate(aaudioBuilder1, &sampleRate));
-    EXPECT_EQ(requestedSampleRate1, sampleRate);
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_getSampleRate(aaudioBuilder2, &sampleRate));
-    EXPECT_EQ(requestedSampleRate2, sampleRate);
-
-    // Delete the builder.
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder1));
-
-    // Now it should no longer be valid.
-    // Note that test assumes we are using the HandleTracker. If we use plain pointers
-    // then it will be difficult to detect this kind of error.
-    result = AAudioStreamBuilder_getSampleRate(aaudioBuilder1, &sampleRate); // stale token
-    EXPECT_EQ(AAUDIO_ERROR_INVALID_HANDLE, result);
-
-    // Second builder should still be valid.
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_getSampleRate(aaudioBuilder2, &sampleRate));
-    EXPECT_EQ(requestedSampleRate2, sampleRate);
-
-    // Delete the second builder.
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder2));
-
-    // Now it should no longer be valid. Assumes HandlerTracker used.
-    EXPECT_EQ(AAUDIO_ERROR_INVALID_HANDLE, AAudioStreamBuilder_getSampleRate(aaudioBuilder2, &sampleRate));
-}
-
-// Test creating a default stream with everything unspecified.
-TEST(test_aaudio_api, aaudio_stream_unspecified) {
-    AAudioStreamBuilder aaudioBuilder;
-    AAudioStream aaudioStream;
-    aaudio_result_t result = AAUDIO_OK;
-
-    // Use an AAudioStreamBuilder to define the stream.
-    result = AAudio_createStreamBuilder(&aaudioBuilder);
-    ASSERT_EQ(AAUDIO_OK, result);
-
-    // Create an AAudioStream using the Builder.
-    ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
-
-    // Cleanup
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder));
-    EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
-}
-
-// Test Writing to an AAudioStream
-void runtest_aaudio_stream(aaudio_sharing_mode_t requestedSharingMode) {
-    const aaudio_sample_rate_t requestedSampleRate = 48000;
-    const aaudio_sample_rate_t requestedSamplesPerFrame = 2;
-    const aaudio_audio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM16;
-
-    aaudio_sample_rate_t actualSampleRate = -1;
-    int32_t actualSamplesPerFrame = -1;
-    aaudio_audio_format_t actualDataFormat = AAUDIO_FORMAT_INVALID;
-    aaudio_sharing_mode_t actualSharingMode;
-    aaudio_size_frames_t framesPerBurst = -1;
-    int writeLoops = 0;
-
-    aaudio_size_frames_t framesWritten = 0;
-    aaudio_size_frames_t framesPrimed = 0;
-    aaudio_position_frames_t framesTotal = 0;
-    aaudio_position_frames_t aaudioFramesRead = 0;
-    aaudio_position_frames_t aaudioFramesRead1 = 0;
-    aaudio_position_frames_t aaudioFramesRead2 = 0;
-    aaudio_position_frames_t aaudioFramesWritten = 0;
-
-    aaudio_nanoseconds_t timeoutNanos;
-
-    aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
-    AAudioStreamBuilder aaudioBuilder;
-    AAudioStream aaudioStream;
-
-    aaudio_result_t result = AAUDIO_OK;
-
-    // Use an AAudioStreamBuilder to define the stream.
-    result = AAudio_createStreamBuilder(&aaudioBuilder);
-    ASSERT_EQ(AAUDIO_OK, result);
-
-    // Request stream properties.
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_setSampleRate(aaudioBuilder, requestedSampleRate));
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_setSamplesPerFrame(aaudioBuilder, requestedSamplesPerFrame));
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_setFormat(aaudioBuilder, requestedDataFormat));
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_setSharingMode(aaudioBuilder, requestedSharingMode));
-
-    // Create an AAudioStream using the Builder.
-    ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder));
-
-    EXPECT_EQ(AAUDIO_OK, AAudioStream_getState(aaudioStream, &state));
-    EXPECT_EQ(AAUDIO_STREAM_STATE_OPEN, state);
-
-    // Check to see what kind of stream we actually got.
-    EXPECT_EQ(AAUDIO_OK, AAudioStream_getSampleRate(aaudioStream, &actualSampleRate));
-    ASSERT_TRUE(actualSampleRate >= 44100 && actualSampleRate <= 96000);  // TODO what is range?
-
-    EXPECT_EQ(AAUDIO_OK, AAudioStream_getSamplesPerFrame(aaudioStream, &actualSamplesPerFrame));
-    ASSERT_TRUE(actualSamplesPerFrame >= 1 && actualSamplesPerFrame <= 16); // TODO what is max?
-
-    EXPECT_EQ(AAUDIO_OK, AAudioStream_getSharingMode(aaudioStream, &actualSharingMode));
-    ASSERT_TRUE(actualSharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE
-                || actualSharingMode == AAUDIO_SHARING_MODE_LEGACY);
-
-    EXPECT_EQ(AAUDIO_OK, AAudioStream_getFormat(aaudioStream, &actualDataFormat));
-    EXPECT_NE(AAUDIO_FORMAT_INVALID, actualDataFormat);
-
-    EXPECT_EQ(AAUDIO_OK, AAudioStream_getFramesPerBurst(aaudioStream, &framesPerBurst));
-    ASSERT_TRUE(framesPerBurst >= 16 && framesPerBurst <= 1024); // TODO what is min/max?
-
-    // Allocate a buffer for the audio data.
-    // TODO handle possibility of other data formats
-    ASSERT_TRUE(actualDataFormat == AAUDIO_FORMAT_PCM16);
-    size_t dataSizeSamples = framesPerBurst * actualSamplesPerFrame;
-    int16_t *data = new int16_t[dataSizeSamples];
-    ASSERT_TRUE(nullptr != data);
-    memset(data, 0, sizeof(int16_t) * dataSizeSamples);
-
-    // Prime the buffer.
-    timeoutNanos = 0;
-    do {
-        framesWritten = AAudioStream_write(aaudioStream, data, framesPerBurst, timeoutNanos);
-        // There should be some room for priming the buffer.
-        framesTotal += framesWritten;
-        ASSERT_GE(framesWritten, 0);
-        ASSERT_LE(framesWritten, framesPerBurst);
-    } while (framesWritten > 0);
-    ASSERT_TRUE(framesTotal > 0);
-
-    // Start/write/pause more than once to see if it fails after the first time.
-    // Write some data and measure the rate to see if the timing is OK.
-    for (int numLoops = 0; numLoops < 2; numLoops++) {
-        // Start and wait for server to respond.
-        ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream));
-        ASSERT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(aaudioStream,
-                                                         AAUDIO_STREAM_STATE_STARTING,
-                                                         &state,
-                                                         DEFAULT_STATE_TIMEOUT));
-        EXPECT_EQ(AAUDIO_STREAM_STATE_STARTED, state);
-
-        // Write some data while we are running. Read counter should be advancing.
-        writeLoops = 1 * actualSampleRate / framesPerBurst; // 1 second
-        ASSERT_LT(2, writeLoops); // detect absurdly high framesPerBurst
-        timeoutNanos = 10 * AAUDIO_NANOS_PER_SECOND * framesPerBurst / actualSampleRate; // bursts
-        framesWritten = 1;
-        ASSERT_EQ(AAUDIO_OK, AAudioStream_getFramesRead(aaudioStream, &aaudioFramesRead));
-        aaudioFramesRead1 = aaudioFramesRead;
-        aaudio_nanoseconds_t beginTime = AAudio_getNanoseconds(AAUDIO_CLOCK_MONOTONIC);
-        do {
-            framesWritten = AAudioStream_write(aaudioStream, data, framesPerBurst, timeoutNanos);
-            ASSERT_GE(framesWritten, 0);
-            ASSERT_LE(framesWritten, framesPerBurst);
-
-            framesTotal += framesWritten;
-            EXPECT_EQ(AAUDIO_OK, AAudioStream_getFramesWritten(aaudioStream, &aaudioFramesWritten));
-            EXPECT_EQ(framesTotal, aaudioFramesWritten);
-
-            // Try to get a more accurate measure of the sample rate.
-            if (beginTime == 0) {
-                EXPECT_EQ(AAUDIO_OK, AAudioStream_getFramesRead(aaudioStream, &aaudioFramesRead));
-                if (aaudioFramesRead > aaudioFramesRead1) { // is read pointer advancing
-                    beginTime = AAudio_getNanoseconds(AAUDIO_CLOCK_MONOTONIC);
-                    aaudioFramesRead1 = aaudioFramesRead;
-                }
-            }
-        } while (framesWritten > 0 && writeLoops-- > 0);
-
-        EXPECT_EQ(AAUDIO_OK, AAudioStream_getFramesRead(aaudioStream, &aaudioFramesRead2));
-        aaudio_nanoseconds_t endTime = AAudio_getNanoseconds(AAUDIO_CLOCK_MONOTONIC);
-        ASSERT_GT(aaudioFramesRead2, 0);
-        ASSERT_GT(aaudioFramesRead2, aaudioFramesRead1);
-        ASSERT_LE(aaudioFramesRead2, aaudioFramesWritten);
-
-        // TODO why is legacy so inaccurate?
-        const double rateTolerance = 200.0; // arbitrary tolerance for sample rate
-        if (requestedSharingMode != AAUDIO_SHARING_MODE_LEGACY) {
-            // Calculate approximate sample rate and compare with stream rate.
-            double seconds = (endTime - beginTime) / (double) AAUDIO_NANOS_PER_SECOND;
-            double measuredRate = (aaudioFramesRead2 - aaudioFramesRead1) / seconds;
-            ASSERT_NEAR(actualSampleRate, measuredRate, rateTolerance);
-        }
-
-        // Request async pause and wait for server to say that it has completed the pause.
-        ASSERT_EQ(AAUDIO_OK, AAudioStream_requestPause(aaudioStream));
-        EXPECT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(aaudioStream,
-                                                AAUDIO_STREAM_STATE_PAUSING,
-                                                &state,
-                                                DEFAULT_STATE_TIMEOUT));
-        EXPECT_EQ(AAUDIO_STREAM_STATE_PAUSED, state);
-    }
-
-    // Make sure the read counter is not advancing when we are paused.
-    ASSERT_EQ(AAUDIO_OK, AAudioStream_getFramesRead(aaudioStream, &aaudioFramesRead));
-    ASSERT_GE(aaudioFramesRead, aaudioFramesRead2); // monotonic increase
-
-    // Use this to sleep by waiting for something that won't happen.
-    AAudioStream_waitForStateChange(aaudioStream, AAUDIO_STREAM_STATE_PAUSED, &state, timeoutNanos);
-    ASSERT_EQ(AAUDIO_OK, AAudioStream_getFramesRead(aaudioStream, &aaudioFramesRead2));
-    EXPECT_EQ(aaudioFramesRead, aaudioFramesRead2);
-
-    // ------------------- TEST FLUSH -----------------
-    // Prime the buffer.
-    timeoutNanos = 0;
-    writeLoops = 100;
-    do {
-        framesWritten = AAudioStream_write(aaudioStream, data, framesPerBurst, timeoutNanos);
-        framesTotal += framesWritten;
-    } while (framesWritten > 0 && writeLoops-- > 0);
-    EXPECT_EQ(0, framesWritten);
-
-    // Flush and wait for server to respond.
-    ASSERT_EQ(AAUDIO_OK, AAudioStream_requestFlush(aaudioStream));
-    EXPECT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(aaudioStream,
-                                                     AAUDIO_STREAM_STATE_FLUSHING,
-                                                     &state,
-                                                     DEFAULT_STATE_TIMEOUT));
-    EXPECT_EQ(AAUDIO_STREAM_STATE_FLUSHED, state);
-
-    // After a flush, the read counter should be caught up with the write counter.
-    EXPECT_EQ(AAUDIO_OK, AAudioStream_getFramesWritten(aaudioStream, &aaudioFramesWritten));
-    EXPECT_EQ(framesTotal, aaudioFramesWritten);
-    EXPECT_EQ(AAUDIO_OK, AAudioStream_getFramesRead(aaudioStream, &aaudioFramesRead));
-    EXPECT_EQ(aaudioFramesRead, aaudioFramesWritten);
-
-    // The buffer should be empty after a flush so we should be able to write.
-    framesWritten = AAudioStream_write(aaudioStream, data, framesPerBurst, timeoutNanos);
-    // There should be some room for priming the buffer.
-    ASSERT_TRUE(framesWritten > 0 && framesWritten <= framesPerBurst);
-
-    EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
-}
-
-// Test Writing to an AAudioStream using LEGACY sharing mode.
-TEST(test_aaudio_api, aaudio_stream_legacy) {
-    runtest_aaudio_stream(AAUDIO_SHARING_MODE_LEGACY);
-}
-
-// Test Writing to an AAudioStream using EXCLUSIVE sharing mode.
-TEST(test_aaudio_api, aaudio_stream_exclusive) {
-    runtest_aaudio_stream(AAUDIO_SHARING_MODE_EXCLUSIVE);
-}
-
-#define AAUDIO_THREAD_ANSWER          1826375
-#define AAUDIO_THREAD_DURATION_MSEC       500
-
-static void *TestAAudioStreamThreadProc(void *arg) {
-    AAudioStream aaudioStream = (AAudioStream) reinterpret_cast<size_t>(arg);
-    aaudio_stream_state_t state;
-
-    // Use this to sleep by waiting for something that won't happen.
-    EXPECT_EQ(AAUDIO_OK, AAudioStream_getState(aaudioStream, &state));
-    AAudioStream_waitForStateChange(aaudioStream, AAUDIO_STREAM_STATE_PAUSED, &state,
-            AAUDIO_THREAD_DURATION_MSEC * AAUDIO_NANOS_PER_MILLISECOND);
-    return reinterpret_cast<void *>(AAUDIO_THREAD_ANSWER);
-}
-
-// Test creating a stream related thread.
-TEST(test_aaudio_api, aaudio_stream_thread_basic) {
-    AAudioStreamBuilder aaudioBuilder;
-    AAudioStream aaudioStream;
-    aaudio_result_t result = AAUDIO_OK;
-    void *threadResult;
-
-    // Use an AAudioStreamBuilder to define the stream.
-    result = AAudio_createStreamBuilder(&aaudioBuilder);
-    ASSERT_EQ(AAUDIO_OK, result);
-
-    // Create an AAudioStream using the Builder.
-    ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
-
-    // Start a thread.
-    ASSERT_EQ(AAUDIO_OK, AAudioStream_createThread(aaudioStream,
-            10 * AAUDIO_NANOS_PER_MILLISECOND,
-            TestAAudioStreamThreadProc,
-            reinterpret_cast<void *>(aaudioStream)));
-    // Thread already started.
-    ASSERT_NE(AAUDIO_OK, AAudioStream_createThread(aaudioStream,   // should fail!
-            10 * AAUDIO_NANOS_PER_MILLISECOND,
-            TestAAudioStreamThreadProc,
-            reinterpret_cast<void *>(aaudioStream)));
-
-    // Wait for the thread to finish.
-    ASSERT_EQ(AAUDIO_OK, AAudioStream_joinThread(aaudioStream,
-            &threadResult, 2 * AAUDIO_THREAD_DURATION_MSEC * AAUDIO_NANOS_PER_MILLISECOND));
-    // The thread returns a special answer.
-    ASSERT_EQ(AAUDIO_THREAD_ANSWER, (int)reinterpret_cast<size_t>(threadResult));
-
-    // Thread should already be joined.
-    ASSERT_NE(AAUDIO_OK, AAudioStream_joinThread(aaudioStream,  // should fail!
-            &threadResult, 2 * AAUDIO_THREAD_DURATION_MSEC * AAUDIO_NANOS_PER_MILLISECOND));
-
-    // Cleanup
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder));
-    EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
-}
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 3235e81..78f28ae 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -61,7 +61,7 @@
 #include "include/SharedMemoryBuffer.h"
 #include "omx/OMXUtils.h"
 
-#include <android/hidl/memory/1.0/IAllocator.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
 #include <android/hidl/memory/1.0/IMemory.h>
 #include "omx/hal/1.0/utils/WOmxNode.h"
 
@@ -575,7 +575,7 @@
 
     changeState(mUninitializedState);
 
-    updateTrebleFlag();
+    mTrebleFlag = false;
 }
 
 ACodec::~ACodec() {
@@ -6229,11 +6229,12 @@
     CHECK(mCodec->mOMXNode == NULL);
 
     OMXClient client;
-    if ((mCodec->updateTrebleFlag() ?
-            client.connectTreble() : client.connect()) != OK) {
+    bool trebleFlag;
+    if (client.connect(&trebleFlag) != OK) {
         mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
         return false;
     }
+    mCodec->setTrebleFlag(trebleFlag);
 
     sp<IOMX> omx = client.interface();
 
@@ -6553,7 +6554,7 @@
 
     if (mCodec->mCreateInputBuffersSuspended) {
         err = statusFromBinderStatus(
-                mCodec->mGraphicBufferSource->setSuspend(true));
+                mCodec->mGraphicBufferSource->setSuspend(true, -1));
 
         if (err != OK) {
             ALOGE("[%s] Unable to configure option to suspend (err %d)",
@@ -7117,8 +7118,10 @@
             return INVALID_OPERATION;
         }
 
+        int64_t suspendStartTimeUs = -1;
+        (void) params->findInt64("drop-start-time-us", &suspendStartTimeUs);
         status_t err = statusFromBinderStatus(
-                mGraphicBufferSource->setSuspend(dropInputFrames != 0));
+                mGraphicBufferSource->setSuspend(dropInputFrames != 0, suspendStartTimeUs));
 
         if (err != OK) {
             ALOGE("Failed to set parameter 'drop-input-frames' (err %d)", err);
@@ -7126,6 +7129,22 @@
         }
     }
 
+    int64_t stopTimeUs;
+    if (params->findInt64("stop-time-us", &stopTimeUs)) {
+        if (mGraphicBufferSource == NULL) {
+            ALOGE("[%s] Invalid to set stop time without surface",
+                    mComponentName.c_str());
+            return INVALID_OPERATION;
+        }
+        status_t err = statusFromBinderStatus(
+                mGraphicBufferSource->setStopTimeUs(stopTimeUs));
+
+        if (err != OK) {
+            ALOGE("Failed to set parameter 'stop-time-us' (err %d)", err);
+            return err;
+        }
+    }
+
     int32_t dummy;
     if (params->findInt32("request-sync", &dummy)) {
         status_t err = requestIDRFrame();
@@ -7676,8 +7695,7 @@
     }
 
     OMXClient client;
-    status_t err = getTrebleFlag() ?
-            client.connectTreble() : client.connect();
+    status_t err = client.connect();
     if (err != OK) {
         return err;
     }
@@ -7893,11 +7911,8 @@
     return OK;
 }
 
-bool ACodec::updateTrebleFlag() {
-    mTrebleFlag = bool(property_get_bool("debug.treble_omx", 0));
-    ALOGV("updateTrebleFlag() returns %s",
-            mTrebleFlag ? "true" : "false");
-    return mTrebleFlag;
+void ACodec::setTrebleFlag(bool trebleFlag) {
+    mTrebleFlag = trebleFlag;
 }
 
 bool ACodec::getTrebleFlag() const {
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index 296394b..259e134 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -20,6 +20,7 @@
 
 #include <numeric>
 
+#include <android/media/IDescrambler.h>
 #include <binder/MemoryDealer.h>
 #include <media/openmax/OMX_Core.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -33,7 +34,8 @@
 #include "include/SharedMemoryBuffer.h"
 
 namespace android {
-
+using binder::Status;
+using MediaDescrambler::DescrambleInfo;
 using BufferInfo = ACodecBufferChannel::BufferInfo;
 using BufferInfoIterator = std::vector<const BufferInfo>::const_iterator;
 
@@ -92,7 +94,7 @@
         const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern,
         const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
         AString *errorDetailMsg) {
-    if (mCrypto == nullptr) {
+    if (!hasCryptoOrDescrambler()) {
         return -ENOSYS;
     }
     std::shared_ptr<const std::vector<const BufferInfo>> array(
@@ -116,9 +118,47 @@
         destination.mType = ICrypto::kDestinationTypeSharedMemory;
         destination.mSharedMemory = mDecryptDestination;
     }
-    ssize_t result = mCrypto->decrypt(key, iv, mode, pattern,
-            it->mSharedEncryptedBuffer, it->mClientBuffer->offset(),
-            subSamples, numSubSamples, destination, errorDetailMsg);
+
+    ssize_t result = -1;
+    if (mCrypto != NULL) {
+        result = mCrypto->decrypt(key, iv, mode, pattern,
+                    it->mSharedEncryptedBuffer, it->mClientBuffer->offset(),
+                    subSamples, numSubSamples, destination, errorDetailMsg);
+    } else {
+        DescrambleInfo descrambleInfo;
+        descrambleInfo.dstType = destination.mType ==
+                ICrypto::kDestinationTypeSharedMemory ?
+                DescrambleInfo::kDestinationTypeVmPointer :
+                DescrambleInfo::kDestinationTypeNativeHandle;
+        descrambleInfo.scramblingControl = key != NULL ?
+                (DescramblerPlugin::ScramblingControl)key[0] :
+                DescramblerPlugin::kScrambling_Unscrambled;
+        descrambleInfo.numSubSamples = numSubSamples;
+        descrambleInfo.subSamples = (DescramblerPlugin::SubSample *)subSamples;
+        descrambleInfo.srcMem = it->mSharedEncryptedBuffer;
+        descrambleInfo.srcOffset = 0;
+        descrambleInfo.dstPtr = NULL;
+        descrambleInfo.dstOffset = 0;
+
+        int32_t descrambleResult = -1;
+        Status status = mDescrambler->descramble(descrambleInfo, &descrambleResult);
+
+        if (status.isOk()) {
+            result = descrambleResult;
+        }
+
+        if (result < 0) {
+            ALOGE("descramble failed, exceptionCode=%d, err=%d, result=%zd",
+                    status.exceptionCode(), status.transactionError(), result);
+        } else {
+            ALOGV("descramble succeeded, result=%zd", result);
+        }
+
+        if (result > 0 && destination.mType == ICrypto::kDestinationTypeSharedMemory) {
+            memcpy(destination.mSharedMemory->pointer(),
+                    (uint8_t*)it->mSharedEncryptedBuffer->pointer(), result);
+        }
+    }
 
     if (result < 0) {
         return result;
@@ -212,8 +252,7 @@
 }
 
 void ACodecBufferChannel::setInputBufferArray(const std::vector<BufferAndId> &array) {
-    bool secure = (mCrypto != nullptr);
-    if (secure) {
+    if (hasCryptoOrDescrambler()) {
         size_t totalSize = std::accumulate(
                 array.begin(), array.end(), 0u,
                 [alignment = MemoryDealer::getAllocationAlignment()]
@@ -232,7 +271,7 @@
     std::vector<const BufferInfo> inputBuffers;
     for (const BufferAndId &elem : array) {
         sp<IMemory> sharedEncryptedBuffer;
-        if (secure) {
+        if (hasCryptoOrDescrambler()) {
             sharedEncryptedBuffer = mDealer->allocate(elem.mBuffer->capacity());
         }
         inputBuffers.emplace_back(elem.mBuffer, elem.mBufferId, sharedEncryptedBuffer);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 410dbc9..f25f15d 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -93,6 +93,8 @@
         libui \
         libutils \
         libvorbisidec \
+        libmediadrm \
+        libnativewindow \
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_color_conversion \
@@ -115,6 +117,7 @@
         libRScpp \
         libhidlbase \
         libhidlmemory \
+        android.hidl.allocator@1.0 \
         android.hidl.memory@1.0 \
         android.hardware.media.omx@1.0 \
         android.hardware.media.omx@1.0-utils \
@@ -128,7 +131,8 @@
 LOCAL_CFLAGS += -DENABLE_STAGEFRIGHT_EXPERIMENTS
 endif
 
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
+LOCAL_SANITIZE_DIAG := cfi
 
 LOCAL_MODULE:= libstagefright
 
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 4a965ba..ded79f3 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -130,7 +130,7 @@
         }
 
         String8 cacheConfig;
-        bool disconnectAtHighwatermark;
+        bool disconnectAtHighwatermark = false;
         KeyedVector<String8, String8> nonCacheSpecificHeaders;
         if (headers != NULL) {
             nonCacheSpecificHeaders = *headers;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 0a9efad..a017737 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1396,6 +1396,28 @@
             }
             break;
         }
+        case FOURCC('m', 'e', 't', 't'):
+        {
+            *offset += chunk_size;
+
+            if (mLastTrack == NULL)
+                return ERROR_MALFORMED;
+
+            sp<ABuffer> buffer = new ABuffer(chunk_data_size);
+            if (buffer->data() == NULL) {
+                return NO_MEMORY;
+            }
+
+            if (mDataSource->readAt(
+                        data_offset, buffer->data(), chunk_data_size) < chunk_data_size) {
+                return ERROR_IO;
+            }
+
+            String8 mimeFormat((const char *)(buffer->data()), chunk_data_size);
+            mLastTrack->meta->setCString(kKeyMIMEType, mimeFormat.string());
+
+            break;
+        }
 
         case FOURCC('m', 'p', '4', 'a'):
         case FOURCC('e', 'n', 'c', 'a'):
@@ -2802,6 +2824,10 @@
 }
 
 status_t MPEG4Extractor::parseITunesMetaData(off64_t offset, size_t size) {
+    if (size == 0) {
+        return OK;
+    }
+
     if (size < 4 || size == SIZE_MAX) {
         return ERROR_MALFORMED;
     }
@@ -4555,8 +4581,8 @@
         // fall through
     }
 
-    off64_t offset;
-    size_t size;
+    off64_t offset = 0;
+    size_t size = 0;
     uint32_t cts, stts;
     bool isSyncSample;
     bool newBuffer = false;
@@ -5117,6 +5143,10 @@
     return NULL;
 }
 
+void MPEG4Extractor::populateMetrics() {
+    ALOGV("MPEG4Extractor::populateMetrics");
+}
+
 static bool LegacySniffMPEG4(
         const sp<DataSource> &source, String8 *mimeType, float *confidence) {
     uint8_t header[8];
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index a332cce..8728b6f 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -23,6 +23,7 @@
 #include "include/SharedMemoryBuffer.h"
 #include "include/SoftwareRenderer.h"
 
+#include <android/media/IDescrambler.h>
 #include <binder/IMemory.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -680,8 +681,17 @@
 
 status_t MediaCodec::configure(
         const sp<AMessage> &format,
+        const sp<Surface> &nativeWindow,
+        const sp<ICrypto> &crypto,
+        uint32_t flags) {
+    return configure(format, nativeWindow, crypto, NULL, flags);
+}
+
+status_t MediaCodec::configure(
+        const sp<AMessage> &format,
         const sp<Surface> &surface,
         const sp<ICrypto> &crypto,
+        const sp<IDescrambler> &descrambler,
         uint32_t flags) {
     sp<AMessage> msg = new AMessage(kWhatConfigure, this);
 
@@ -710,8 +720,12 @@
     msg->setInt32("flags", flags);
     msg->setObject("surface", surface);
 
-    if (crypto != NULL) {
-        msg->setPointer("crypto", crypto.get());
+    if (crypto != NULL || descrambler != NULL) {
+        if (crypto != NULL) {
+            msg->setPointer("crypto", crypto.get());
+        } else {
+            msg->setPointer("descrambler", descrambler.get());
+        }
         if (mAnalyticsItem != NULL) {
             // XXX: save indication that it's crypto in some way...
             mAnalyticsItem->setInt32("crypto", 1);
@@ -758,6 +772,51 @@
     return err;
 }
 
+status_t MediaCodec::releaseCrypto()
+{
+    ALOGV("releaseCrypto");
+
+    sp<AMessage> msg = new AMessage(kWhatDrmReleaseCrypto, this);
+
+    sp<AMessage> response;
+    status_t status = msg->postAndAwaitResponse(&response);
+
+    if (status == OK && response != NULL) {
+        CHECK(response->findInt32("status", &status));
+        ALOGV("releaseCrypto ret: %d ", status);
+    }
+    else {
+        ALOGE("releaseCrypto err: %d", status);
+    }
+
+    return status;
+}
+
+void MediaCodec::onReleaseCrypto(const sp<AMessage>& msg)
+{
+    status_t status = INVALID_OPERATION;
+    if (mCrypto != NULL) {
+        ALOGV("onReleaseCrypto: mCrypto: %p (%d)", mCrypto.get(), mCrypto->getStrongCount());
+        mBufferChannel->setCrypto(NULL);
+        // TODO change to ALOGV
+        ALOGD("onReleaseCrypto: [before clear]  mCrypto: %p (%d)",
+                mCrypto.get(), mCrypto->getStrongCount());
+        mCrypto.clear();
+
+        status = OK;
+    }
+    else {
+        ALOGW("onReleaseCrypto: No mCrypto. err: %d", status);
+    }
+
+    sp<AMessage> response = new AMessage;
+    response->setInt32("status", status);
+
+    sp<AReplyToken> replyID;
+    CHECK(msg->senderAwaitsResponse(&replyID));
+    response->postReply(replyID);
+}
+
 status_t MediaCodec::setInputSurface(
         const sp<PersistentSurface> &surface) {
     sp<AMessage> msg = new AMessage(kWhatSetInputSurface, this);
@@ -1938,9 +1997,23 @@
                 crypto = NULL;
             }
 
+            ALOGV("kWhatConfigure: Old mCrypto: %p (%d)",
+                    mCrypto.get(), (mCrypto != NULL ? mCrypto->getStrongCount() : 0));
+
             mCrypto = static_cast<ICrypto *>(crypto);
             mBufferChannel->setCrypto(mCrypto);
 
+            ALOGV("kWhatConfigure: New mCrypto: %p (%d)",
+                    mCrypto.get(), (mCrypto != NULL ? mCrypto->getStrongCount() : 0));
+
+            void *descrambler;
+            if (!msg->findPointer("descrambler", &descrambler)) {
+                descrambler = NULL;
+            }
+
+            mDescrambler = static_cast<IDescrambler *>(descrambler);
+            mBufferChannel->setDescrambler(mDescrambler);
+
             uint32_t flags;
             CHECK(msg->findInt32("flags", (int32_t *)&flags));
 
@@ -1961,7 +2034,6 @@
             CHECK(msg->senderAwaitsResponse(&replyID));
 
             status_t err = OK;
-            sp<Surface> surface;
 
             switch (mState) {
                 case CONFIGURED:
@@ -2471,6 +2543,12 @@
             break;
         }
 
+        case kWhatDrmReleaseCrypto:
+        {
+            onReleaseCrypto(msg);
+            break;
+        }
+
         default:
             TRESPASS();
     }
@@ -2530,7 +2608,12 @@
         delete mSoftRenderer;
         mSoftRenderer = NULL;
 
+        if ( mCrypto != NULL ) {
+            ALOGV("setState: ~mCrypto: %p (%d)",
+                    mCrypto.get(), (mCrypto != NULL ? mCrypto->getStrongCount() : 0));
+        }
         mCrypto.clear();
+        mDescrambler.clear();
         handleSetSurface(NULL);
 
         mInputFormat.clear();
@@ -2635,7 +2718,7 @@
     CryptoPlugin::Pattern pattern;
 
     if (msg->findSize("size", &size)) {
-        if (mCrypto != NULL) {
+        if (hasCryptoOrDescrambler()) {
             ss.mNumBytesOfClearData = size;
             ss.mNumBytesOfEncryptedData = 0;
 
@@ -2647,7 +2730,9 @@
             pattern.mSkipBlocks = 0;
         }
     } else {
-        if (mCrypto == NULL) {
+        if (!hasCryptoOrDescrambler()) {
+            ALOGE("[%s] queuing secure buffer without mCrypto or mDescrambler!",
+                    mComponentName.c_str());
             return -EINVAL;
         }
 
@@ -2696,7 +2781,7 @@
 
     sp<MediaCodecBuffer> buffer = info->mData;
     status_t err = OK;
-    if (mCrypto != NULL) {
+    if (hasCryptoOrDescrambler()) {
         AString *errorDetailMsg;
         CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg));
 
@@ -2853,7 +2938,7 @@
             return ALREADY_EXISTS;
         }
 
-        err = native_window_api_connect(surface.get(), NATIVE_WINDOW_API_MEDIA);
+        err = nativeWindowConnect(surface.get(), "connectToSurface");
         if (err == OK) {
             // Require a fresh set of buffers after each connect by using a unique generation
             // number. Rely on the fact that max supported process id by Linux is 2^22.
@@ -2868,12 +2953,12 @@
             // This is needed as the consumer may be holding onto stale frames that it can reattach
             // to this surface after disconnect/connect, and those free frames would inherit the new
             // generation number. Disconnecting after setting a unique generation prevents this.
-            native_window_api_disconnect(surface.get(), NATIVE_WINDOW_API_MEDIA);
-            err = native_window_api_connect(surface.get(), NATIVE_WINDOW_API_MEDIA);
+            nativeWindowDisconnect(surface.get(), "connectToSurface(reconnect)");
+            err = nativeWindowConnect(surface.get(), "connectToSurface(reconnect)");
         }
 
         if (err != OK) {
-            ALOGE("native_window_api_connect returned an error: %s (%d)", strerror(-err), err);
+            ALOGE("nativeWindowConnect returned an error: %s (%d)", strerror(-err), err);
         }
     }
     // do not return ALREADY_EXISTS unless surfaces are the same
@@ -2885,9 +2970,9 @@
     if (mSurface != NULL) {
         // Resetting generation is not technically needed, but there is no need to keep it either
         mSurface->setGenerationNumber(0);
-        err = native_window_api_disconnect(mSurface.get(), NATIVE_WINDOW_API_MEDIA);
+        err = nativeWindowDisconnect(mSurface.get(), "disconnectFromSurface");
         if (err != OK) {
-            ALOGW("native_window_api_disconnect returned an error: %s (%d)", strerror(-err), err);
+            ALOGW("nativeWindowDisconnect returned an error: %s (%d)", strerror(-err), err);
         }
         // assume disconnected even on error
         mSurface.clear();
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index d3b34b7..1dcba29 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -169,12 +169,41 @@
     return sRemoteList;
 }
 
+// Treblized media codec list will be located in /odm/etc or /vendor/etc.
+static const char *kConfigLocationList[] =
+        {"/odm/etc", "/vendor/etc", "/etc"};
+static const int kConfigLocationListSize =
+        (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
+
+#define MEDIA_CODECS_CONFIG_FILE_PATH_MAX_LENGTH 128
+
+static bool findMediaCodecListFileFullPath(const char *file_name, char *out_path) {
+    for (int i = 0; i < kConfigLocationListSize; i++) {
+        snprintf(out_path,
+                 MEDIA_CODECS_CONFIG_FILE_PATH_MAX_LENGTH,
+                 "%s/%s",
+                 kConfigLocationList[i],
+                 file_name);
+        struct stat file_stat;
+        if (stat(out_path, &file_stat) == 0 && S_ISREG(file_stat.st_mode)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 MediaCodecList::MediaCodecList()
     : mInitCheck(NO_INIT),
       mUpdate(false),
       mGlobalSettings(new AMessage()) {
-    parseTopLevelXMLFile("/etc/media_codecs.xml");
-    parseTopLevelXMLFile("/etc/media_codecs_performance.xml", true/* ignore_errors */);
+    char config_file_path[MEDIA_CODECS_CONFIG_FILE_PATH_MAX_LENGTH];
+    if (findMediaCodecListFileFullPath("media_codecs.xml", config_file_path)) {
+        parseTopLevelXMLFile(config_file_path);
+    }
+    if (findMediaCodecListFileFullPath("media_codecs_performance.xml",
+                                       config_file_path)) {
+        parseTopLevelXMLFile(config_file_path, true/* ignore_errors */);
+    }
     parseTopLevelXMLFile(kProfilingResults, true/* ignore_errors */);
 }
 
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 5981b35..059a730 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -363,8 +363,20 @@
     return postSynchronouslyAndReturnError(msg);
 }
 
-status_t MediaCodecSource::pause() {
-    (new AMessage(kWhatPause, mReflector))->post();
+
+status_t MediaCodecSource::setStopStimeUs(int64_t stopTimeUs) {
+    if (!(mFlags & FLAG_USE_SURFACE_INPUT)) {
+        return OK;
+    }
+    sp<AMessage> msg = new AMessage(kWhatSetStopTimeOffset, mReflector);
+    msg->setInt64("stop-time-us", stopTimeUs);
+    return postSynchronouslyAndReturnError(msg);
+}
+
+status_t MediaCodecSource::pause(MetaData* params) {
+    sp<AMessage> msg = new AMessage(kWhatPause, mReflector);
+    msg->setObject("meta", params);
+    msg->post();
     return OK;
 }
 
@@ -624,22 +636,13 @@
     }
 }
 
-void MediaCodecSource::suspend() {
-    CHECK(mFlags & FLAG_USE_SURFACE_INPUT);
-    if (mEncoder != NULL) {
-        sp<AMessage> params = new AMessage;
-        params->setInt32("drop-input-frames", true);
-        mEncoder->setParameters(params);
-    }
-}
-
-void MediaCodecSource::resume(int64_t skipFramesBeforeUs) {
+void MediaCodecSource::resume(int64_t resumeStartTimeUs) {
     CHECK(mFlags & FLAG_USE_SURFACE_INPUT);
     if (mEncoder != NULL) {
         sp<AMessage> params = new AMessage;
         params->setInt32("drop-input-frames", false);
-        if (skipFramesBeforeUs > 0) {
-            params->setInt64("skip-frames-before", skipFramesBeforeUs);
+        if (resumeStartTimeUs > 0) {
+            params->setInt64("drop-start-time-us", resumeStartTimeUs);
         }
         mEncoder->setParameters(params);
     }
@@ -661,7 +664,7 @@
                 mFirstSampleSystemTimeUs = systemTime() / 1000;
                 if (mPausePending) {
                     mPausePending = false;
-                    onPause();
+                    onPause(mFirstSampleSystemTimeUs);
                     mbuf->release();
                     mAvailEncoderInputIndices.push_back(bufferIndex);
                     return OK;
@@ -728,6 +731,10 @@
         ALOGE("Failed to start while we're stopping");
         return INVALID_OPERATION;
     }
+    int64_t startTimeUs;
+    if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
+        startTimeUs = -1ll;
+    }
 
     if (mStarted) {
         ALOGI("MediaCodecSource (%s) resuming", mIsVideo ? "video" : "audio");
@@ -739,7 +746,7 @@
             mEncoder->requestIDRFrame();
         }
         if (mFlags & FLAG_USE_SURFACE_INPUT) {
-            resume();
+            resume(startTimeUs);
         } else {
             CHECK(mPuller != NULL);
             mPuller->resume();
@@ -752,11 +759,14 @@
     status_t err = OK;
 
     if (mFlags & FLAG_USE_SURFACE_INPUT) {
-        int64_t startTimeUs;
-        if (!params || !params->findInt64(kKeyTime, &startTimeUs)) {
-            startTimeUs = -1ll;
+        if (mEncoder != NULL) {
+            sp<AMessage> params = new AMessage;
+            params->setInt32("drop-input-frames", false);
+            if (startTimeUs >= 0) {
+                params->setInt64("skip-frames-before", startTimeUs);
+            }
+            mEncoder->setParameters(params);
         }
-        resume(startTimeUs);
     } else {
         CHECK(mPuller != NULL);
         sp<MetaData> meta = params;
@@ -781,9 +791,12 @@
     return OK;
 }
 
-void MediaCodecSource::onPause() {
-    if (mFlags & FLAG_USE_SURFACE_INPUT) {
-        suspend();
+void MediaCodecSource::onPause(int64_t pauseStartTimeUs) {
+    if ((mFlags & FLAG_USE_SURFACE_INPUT) && (mEncoder != NULL)) {
+        sp<AMessage> params = new AMessage;
+        params->setInt32("drop-input-frames", true);
+        params->setInt64("drop-start-time-us", pauseStartTimeUs);
+        mEncoder->setParameters(params);
     } else {
         CHECK(mPuller != NULL);
         mPuller->pause();
@@ -871,7 +884,7 @@
                             mFirstSampleSystemTimeUs = systemTime() / 1000;
                             if (mPausePending) {
                                 mPausePending = false;
-                                onPause();
+                                onPause(mFirstSampleSystemTimeUs);
                                 mbuf->release();
                                 break;
                             }
@@ -1000,6 +1013,7 @@
             ALOGV("source (%s) stopped", mIsVideo ? "video" : "audio");
         }
         signalEOS();
+        break;
     }
 
     case kWhatPause:
@@ -1007,7 +1021,14 @@
         if (mFirstSampleSystemTimeUs < 0) {
             mPausePending = true;
         } else {
-            onPause();
+            sp<RefBase> obj;
+            CHECK(msg->findObject("meta", &obj));
+            MetaData *params = static_cast<MetaData *>(obj.get());
+            int64_t pauseStartTimeUs = -1;
+            if (params == NULL || !params->findInt64(kKeyTime, &pauseStartTimeUs)) {
+                pauseStartTimeUs = -1ll;
+            }
+            onPause(pauseStartTimeUs);
         }
         break;
     }
@@ -1030,6 +1051,26 @@
         response->postReply(replyID);
         break;
     }
+    case kWhatSetStopTimeOffset:
+    {
+        sp<AReplyToken> replyID;
+        CHECK(msg->senderAwaitsResponse(&replyID));
+        status_t err = OK;
+        int64_t stopTimeUs;
+        CHECK(msg->findInt64("stop-time-us", &stopTimeUs));
+
+        // Propagate the timestamp offset to GraphicBufferSource.
+        if (mFlags & FLAG_USE_SURFACE_INPUT) {
+            sp<AMessage> params = new AMessage;
+            params->setInt64("stop-time-us", stopTimeUs);
+            err = mEncoder->setParameters(params);
+        }
+
+        sp<AMessage> response = new AMessage;
+        response->setInt32("err", err);
+        response->postReply(replyID);
+        break;
+    }
     case kWhatGetFirstSampleSystemTimeUs:
     {
         sp<AReplyToken> replyID;
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 677d43e..62c0d8a 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -55,7 +55,7 @@
 namespace android {
 
 // key for media statistics
-static const char *KeyName_Extractor = "extractor";
+static const char *kKeyExtractor = "extractor";
 // attrs for media statistics
 
 MediaExtractor::MediaExtractor() {
@@ -67,7 +67,7 @@
 
     mAnalyticsItem = NULL;
     if (MEDIA_LOG) {
-        mAnalyticsItem = new MediaAnalyticsItem(KeyName_Extractor);
+        mAnalyticsItem = new MediaAnalyticsItem(kKeyExtractor);
         (void) mAnalyticsItem->generateSessionID();
     }
 }
@@ -93,6 +93,23 @@
     return new MetaData;
 }
 
+status_t MediaExtractor::getMetrics(Parcel *reply) {
+
+    if (mAnalyticsItem == NULL || reply == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    populateMetrics();
+    mAnalyticsItem->writeToParcel(reply);
+
+    return OK;
+}
+
+void MediaExtractor::populateMetrics() {
+    ALOGV("MediaExtractor::populateMetrics");
+    // normally overridden in subclasses
+}
+
 uint32_t MediaExtractor::flags() const {
     return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
 }
@@ -247,24 +264,23 @@
        // track the container format (mpeg, aac, wvm, etc)
        if (MEDIA_LOG) {
           if (ret->mAnalyticsItem != NULL) {
+              size_t ntracks = ret->countTracks();
               ret->mAnalyticsItem->setCString("fmt",  ret->name());
               // tracks (size_t)
-              ret->mAnalyticsItem->setInt32("ntrk",  ret->countTracks());
+              ret->mAnalyticsItem->setInt32("ntrk",  ntracks);
               // metadata
               sp<MetaData> pMetaData = ret->getMetaData();
               if (pMetaData != NULL) {
                 String8 xx = pMetaData->toString();
-                ALOGD("metadata says: %s", xx.string());
-                // can grab various fields like:
                 // 'titl' -- but this verges into PII
                 // 'mime'
                 const char *mime = NULL;
                 if (pMetaData->findCString(kKeyMIMEType, &mime)) {
                     ret->mAnalyticsItem->setCString("mime",  mime);
                 }
-                // what else is interesting here?
+                // what else is interesting and not already available?
               }
-          }
+	  }
        }
     }
 
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index d25ce6c..ea3ed28 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -35,6 +35,7 @@
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
+#include <android/media/ICas.h>
 
 namespace android {
 
@@ -82,6 +83,10 @@
         return ERROR_UNSUPPORTED;
     }
 
+    if (mCas != NULL) {
+        mImpl->setMediaCas(mCas);
+    }
+
     status_t err = updateDurationAndBitrate();
     if (err == OK) {
         mDataSource = dataSource;
@@ -114,6 +119,10 @@
         return ERROR_UNSUPPORTED;
     }
 
+    if (mCas != NULL) {
+        mImpl->setMediaCas(mCas);
+    }
+
     err = updateDurationAndBitrate();
     if (err == OK) {
         mDataSource = fileSource;
@@ -140,6 +149,10 @@
         return ERROR_UNSUPPORTED;
     }
 
+    if (mCas != NULL) {
+        mImpl->setMediaCas(mCas);
+    }
+
     err = updateDurationAndBitrate();
     if (err == OK) {
         mDataSource = source;
@@ -148,6 +161,27 @@
     return err;
 }
 
+status_t NuMediaExtractor::setMediaCas(const sp<ICas> &cas) {
+    ALOGV("setMediaCas: cas=%p", cas.get());
+
+    Mutex::Autolock autoLock(mLock);
+
+    if (cas == NULL) {
+        return BAD_VALUE;
+    }
+
+    if (mImpl != NULL) {
+        mImpl->setMediaCas(cas);
+        status_t err = updateDurationAndBitrate();
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    mCas = cas;
+    return OK;
+}
+
 status_t NuMediaExtractor::updateDurationAndBitrate() {
     if (mImpl->countTracks() > kMaxTrackCount) {
         return ERROR_UNSUPPORTED;
@@ -569,6 +603,11 @@
     return OK;
 }
 
+status_t NuMediaExtractor::getMetrics(Parcel *reply) {
+    status_t status = mImpl->getMetrics(reply);
+    return status;
+}
+
 bool NuMediaExtractor::getTotalBitrate(int64_t *bitrate) const {
     if (mTotalBitrate >= 0) {
         *bitrate = mTotalBitrate;
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index b4e694c..b77ee1d 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -22,6 +22,7 @@
 #endif
 
 #include <utils/Log.h>
+#include <cutils/properties.h>
 
 #include <binder/IServiceManager.h>
 #include <media/IMediaCodecService.h>
@@ -36,7 +37,22 @@
 OMXClient::OMXClient() {
 }
 
-status_t OMXClient::connect() {
+status_t OMXClient::connect(bool* trebleFlag) {
+    int32_t trebleOmx = property_get_int32("persist.media.treble_omx", -1);
+    if ((trebleOmx == 1) || ((trebleOmx == -1) &&
+            property_get_bool("persist.hal.binderization", 0))) {
+        if (trebleFlag != nullptr) {
+            *trebleFlag = true;
+        }
+        return connectTreble();
+    }
+    if (trebleFlag != nullptr) {
+        *trebleFlag = false;
+    }
+    return connectLegacy();
+}
+
+status_t OMXClient::connectLegacy() {
     sp<IServiceManager> sm = defaultServiceManager();
     sp<IBinder> codecbinder = sm->getService(String16("media.codec"));
     sp<IMediaCodecService> codecservice = interface_cast<IMediaCodecService>(codecbinder);
@@ -67,6 +83,7 @@
         return NO_INIT;
     }
     mOMX = new utils::LWOmx(tOmx);
+    ALOGI("Treble IOmx obtained");
     return OK;
 }
 
diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
index 54c9fa3..4134698 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/libstagefright/SampleIterator.cpp
@@ -305,8 +305,16 @@
         return ERROR_OUT_OF_RANGE;
     }
 
-    while (sampleIndex >= mTTSSampleIndex + mTTSCount) {
-        if (mTimeToSampleIndex == mTable->mTimeToSampleCount) {
+    while (true) {
+        if (mTTSSampleIndex > UINT32_MAX - mTTSCount) {
+            return ERROR_OUT_OF_RANGE;
+        }
+        if(sampleIndex < mTTSSampleIndex + mTTSCount) {
+            break;
+        }
+        if (mTimeToSampleIndex == mTable->mTimeToSampleCount ||
+            (mTTSDuration != 0 && mTTSCount > UINT32_MAX / mTTSDuration) ||
+            mTTSSampleTime > UINT32_MAX - (mTTSCount * mTTSDuration)) {
             return ERROR_OUT_OF_RANGE;
         }
 
diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
index 568837a..82e959e 100644
--- a/media/libstagefright/SurfaceUtils.cpp
+++ b/media/libstagefright/SurfaceUtils.cpp
@@ -31,15 +31,15 @@
 
     // In some cases we need to reconnect so that we can dequeue all buffers
     if (reconnect) {
-        err = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
+        err = nativeWindowDisconnect(nativeWindow, "setNativeWindowSizeFormatAndUsage");
         if (err != NO_ERROR) {
-            ALOGE("native_window_api_disconnect failed: %s (%d)", strerror(-err), -err);
+            ALOGE("nativeWindowDisconnect failed: %s (%d)", strerror(-err), -err);
             return err;
         }
 
-        err = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
+        err = nativeWindowConnect(nativeWindow, "setNativeWindowSizeFormatAndUsage");
         if (err != NO_ERROR) {
-            ALOGE("native_window_api_connect failed: %s (%d)", strerror(-err), -err);
+            ALOGE("nativeWindowConnect failed: %s (%d)", strerror(-err), -err);
             return err;
         }
     }
@@ -127,7 +127,7 @@
     // We need to reconnect to the ANativeWindow as a CPU client to ensure that
     // no frames get dropped by SurfaceFlinger assuming that these are video
     // frames.
-    err = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
+    err = nativeWindowDisconnect(nativeWindow, "pushBlankBuffersToNativeWindow");
     if (err != NO_ERROR) {
         ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err), -err);
         return err;
@@ -136,7 +136,7 @@
     err = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_CPU);
     if (err != NO_ERROR) {
         ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err);
-        (void)native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
+        (void)nativeWindowConnect(nativeWindow, "pushBlankBuffersToNativeWindow(err)");
         return err;
     }
 
@@ -219,7 +219,7 @@
         }
     }
 
-    err2 = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
+    err2 = nativeWindowConnect(nativeWindow, "pushBlankBuffersToNativeWindow(err2)");
     if (err2 != NO_ERROR) {
         ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err);
         if (err == NO_ERROR) {
@@ -230,5 +230,22 @@
     return err;
 }
 
+status_t nativeWindowConnect(ANativeWindow *surface, const char *reason) {
+    ALOGD("connecting to surface %p, reason %s", surface, reason);
+
+    status_t err = native_window_api_connect(surface, NATIVE_WINDOW_API_MEDIA);
+    ALOGE_IF(err != OK, "Failed to connect to surface %p, err %d", surface, err);
+
+    return err;
+}
+
+status_t nativeWindowDisconnect(ANativeWindow *surface, const char *reason) {
+    ALOGD("disconnecting from surface %p, reason %s", surface, reason);
+
+    status_t err = native_window_api_disconnect(surface, NATIVE_WINDOW_API_MEDIA);
+    ALOGE_IF(err != OK, "Failed to disconnect from surface %p, err %d", surface, err);
+
+    return err;
+}
 }  // namespace android
 
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index ec02fb9..e8c46e3 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -610,6 +610,22 @@
     sp<AMessage> msg = new AMessage;
     msg->setString("mime", mime);
 
+    uint32_t type;
+    const void *data;
+    size_t size;
+    if (meta->findData(kKeyCas, &type, &data, &size)) {
+        sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
+        msg->setBuffer("cas", buffer);
+        memcpy(buffer->data(), data, size);
+    }
+
+    if (!strncasecmp("video/scrambled", mime, 15)
+            || !strncasecmp("audio/scrambled", mime, 15)) {
+
+        *format = msg;
+        return OK;
+    }
+
     int64_t durationUs;
     if (meta->findInt64(kKeyDuration, &durationUs)) {
         msg->setInt64("durationUs", durationUs);
@@ -759,9 +775,6 @@
         msg->setInt32("frame-rate", fps);
     }
 
-    uint32_t type;
-    const void *data;
-    size_t size;
     if (meta->findData(kKeyAVCC, &type, &data, &size)) {
         // Parse the AVCDecoderConfigurationRecord
 
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp
index ab0a228..96bbb85 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp
@@ -62,8 +62,7 @@
 }
 
 SoftAACEncoder::~SoftAACEncoder() {
-    delete[] mInputFrame;
-    mInputFrame = NULL;
+    onReset();
 
     if (mEncoderHandle) {
         CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
@@ -579,6 +578,17 @@
     }
 }
 
+void SoftAACEncoder::onReset() {
+    delete[] mInputFrame;
+    mInputFrame = NULL;
+    mInputSize = 0;
+
+    mSentCodecSpecificData = false;
+    mInputTimeUs = -1ll;
+    mSawInputEOS = false;
+    mSignalledError = false;
+}
+
 }  // namespace android
 
 android::SoftOMXComponent *createSoftOMXComponent(
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder.h
index d148eb7..981cbbb 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder.h
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder.h
@@ -43,6 +43,8 @@
 
     virtual void onQueueFilled(OMX_U32 portIndex);
 
+    virtual void onReset();
+
 private:
     enum {
         kNumBuffers             = 4,
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
index 63215ec..5f516cb 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
@@ -72,8 +72,7 @@
 SoftAACEncoder2::~SoftAACEncoder2() {
     aacEncClose(&mAACEncoder);
 
-    delete[] mInputFrame;
-    mInputFrame = NULL;
+    onReset();
 }
 
 void SoftAACEncoder2::initPorts() {
@@ -703,6 +702,17 @@
     }
 }
 
+void SoftAACEncoder2::onReset() {
+    delete[] mInputFrame;
+    mInputFrame = NULL;
+    mInputSize = 0;
+
+    mSentCodecSpecificData = false;
+    mInputTimeUs = -1ll;
+    mSawInputEOS = false;
+    mSignalledError = false;
+}
+
 }  // namespace android
 
 android::SoftOMXComponent *createSoftOMXComponent(
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
index bce9c24..f1b81e1 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.h
@@ -42,6 +42,8 @@
 
     virtual void onQueueFilled(OMX_U32 portIndex);
 
+    virtual void onReset();
+
 private:
     enum {
         kNumBuffers             = 4,
diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
index 9e7a3be..b057ffe 100644
--- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
+++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
@@ -30,7 +30,6 @@
 #include <media/stagefright/Utils.h>
 #include <OMX_IndexExt.h>
 #include <OMX_VideoExt.h>
-#include <ui/Rect.h>
 
 #include "ih264_typedefs.h"
 #include "iv2.h"
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
index f496b0c..6d4cb69 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
@@ -30,8 +30,6 @@
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
-#include <ui/Rect.h>
-#include <ui/GraphicBufferMapper.h>
 
 #include "SoftMPEG4Encoder.h"
 
@@ -99,6 +97,7 @@
 
 SoftMPEG4Encoder::~SoftMPEG4Encoder() {
     ALOGV("Destruct SoftMPEG4Encoder");
+    onReset();
     releaseEncoder();
     List<BufferInfo *> &outQueue = getPortQueue(1);
     List<BufferInfo *> &inQueue = getPortQueue(0);
@@ -201,22 +200,15 @@
 }
 
 OMX_ERRORTYPE SoftMPEG4Encoder::releaseEncoder() {
-    if (!mStarted) {
-        return OMX_ErrorNone;
+    if (mEncParams) {
+        delete mEncParams;
+        mEncParams = NULL;
     }
 
-    PVCleanUpVideoEncoder(mHandle);
-
-    free(mInputFrameData);
-    mInputFrameData = NULL;
-
-    delete mEncParams;
-    mEncParams = NULL;
-
-    delete mHandle;
-    mHandle = NULL;
-
-    mStarted = false;
+    if (mHandle) {
+        delete mHandle;
+        mHandle = NULL;
+    }
 
     return OMX_ErrorNone;
 }
@@ -514,6 +506,19 @@
     }
 }
 
+void SoftMPEG4Encoder::onReset() {
+    if (!mStarted) {
+        return;
+    }
+
+    PVCleanUpVideoEncoder(mHandle);
+
+    free(mInputFrameData);
+    mInputFrameData = NULL;
+
+    mStarted = false;
+}
+
 }  // namespace android
 
 android::SoftOMXComponent *createSoftOMXComponent(
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
index bb6ea92..ae8cb6f 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.h
@@ -48,6 +48,8 @@
 
     virtual void onQueueFilled(OMX_U32 portIndex);
 
+    virtual void onReset();
+
 protected:
     virtual ~SoftMPEG4Encoder();
 
diff --git a/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h b/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h
index 337bff0..adb0dd4 100644
--- a/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h
+++ b/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h
@@ -50,6 +50,7 @@
 
 
 
+    __attribute__((no_sanitize("integer")))
     __inline int32 pv_abs(int32 a)
     {
         int32 b = (a < 0) ? -a : a;
@@ -59,49 +60,58 @@
 
 
 
+    __attribute__((no_sanitize("integer")))
     __inline Int32 fxp_mul32_Q30(const Int32 a, const Int32 b)
     {
         return (Int32)(((int64)(a) * b) >> 30);
     }
 
+    __attribute__((no_sanitize("integer")))
     __inline Int32 fxp_mac32_Q30(const Int32 a, const Int32 b, Int32 L_add)
     {
         return (L_add + (Int32)(((int64)(a) * b) >> 30));
     }
 
+    __attribute__((no_sanitize("integer")))
     __inline Int32 fxp_mul32_Q32(const Int32 a, const Int32 b)
     {
         return (Int32)(((int64)(a) * b) >> 32);
     }
 
 
+    __attribute__((no_sanitize("integer")))
     __inline Int32 fxp_mul32_Q28(const Int32 a, const Int32 b)
     {
         return (Int32)(((int64)(a) * b) >> 28);
     }
 
+    __attribute__((no_sanitize("integer")))
     __inline Int32 fxp_mul32_Q27(const Int32 a, const Int32 b)
     {
         return (Int32)(((int64)(a) * b) >> 27);
     }
 
+    __attribute__((no_sanitize("integer")))
     __inline Int32 fxp_mul32_Q26(const Int32 a, const Int32 b)
     {
         return (Int32)(((int64)(a) * b) >> 26);
     }
 
 
+    __attribute__((no_sanitize("integer")))
     __inline Int32 fxp_mac32_Q32(Int32 L_add, const Int32 a, const Int32 b)
     {
         return (L_add + (Int32)(((int64)(a) * b) >> 32));
     }
 
+    __attribute__((no_sanitize("integer")))
     __inline Int32 fxp_msb32_Q32(Int32 L_sub, const Int32 a, const Int32 b)
     {
         return (L_sub - ((Int32)(((int64)(a) * b) >> 32)));
     }
 
 
+    __attribute__((no_sanitize("integer")))
     __inline Int32 fxp_mul32_Q29(const Int32 a, const Int32 b)
     {
         return (Int32)(((int64)(a) * b) >> 29);
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_16.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_16.cpp
index 9b9ae4b..cc99d5c 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_16.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_16.cpp
@@ -149,6 +149,7 @@
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
 
+__attribute__((no_sanitize("integer")))
 void pvmp3_dct_16(int32 vec[], int32 flag)
 {
     int32 tmp0;
@@ -308,6 +309,7 @@
 /*----------------------------------------------------------------------------
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
+__attribute__((no_sanitize("integer")))
 void pvmp3_merge_in_place_N32(int32 vec[])
 {
 
@@ -366,6 +368,7 @@
 
 
 
+__attribute__((no_sanitize("integer")))
 void pvmp3_split(int32 *vect)
 {
 
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp
index d30ce4a..bbb247d 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp
@@ -117,6 +117,7 @@
 ; FUNCTION CODE
 ----------------------------------------------------------------------------*/
 
+__attribute__((no_sanitize("integer")))
 void pvmp3_dct_9(int32 vec[])
 {
 
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_mdct_18.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_mdct_18.cpp
index 09a735b..324290e 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_mdct_18.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_mdct_18.cpp
@@ -129,6 +129,7 @@
 
 
 
+__attribute__((no_sanitize("integer")))
 void pvmp3_mdct_18(int32 vec[], int32 *history, const int32 *window)
 {
     int32 i;
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
index 5609032..8d69bd5 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
@@ -712,7 +712,9 @@
         if (inputBufferHeader->nTimeStamp > mLastTimestamp) {
             frameDuration = (uint32_t)(inputBufferHeader->nTimeStamp - mLastTimestamp);
         } else {
-            frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / mFramerate);
+            // Use default of 30 fps in case of 0 frame rate.
+            uint32_t framerate = mFramerate ?: (30 << 16);
+            frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / framerate);
         }
         mLastTimestamp = inputBufferHeader->nTimeStamp;
         codec_return = vpx_codec_encode(
@@ -766,6 +768,11 @@
     }
 }
 
+void SoftVPXEncoder::onReset() {
+    releaseEncoder();
+    mLastTimestamp = 0x7FFFFFFFFFFFFFFFLL;
+}
+
 }  // namespace android
 
 android::SoftOMXComponent *createSoftOMXComponent(
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
index 86e71da..86dfad7 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
@@ -93,6 +93,8 @@
     // encoding of the frame
     virtual void onQueueFilled(OMX_U32 portIndex);
 
+    virtual void onReset();
+
     // Initializes vpx encoder with available settings.
     status_t initEncoder();
 
diff --git a/media/libstagefright/colorconversion/Android.mk b/media/libstagefright/colorconversion/Android.mk
index ba74740..1e7a4cc 100644
--- a/media/libstagefright/colorconversion/Android.mk
+++ b/media/libstagefright/colorconversion/Android.mk
@@ -10,11 +10,15 @@
         $(TOP)/hardware/msm7k \
         $(TOP)/external/libyuv/files/include
 
+LOCAL_SHARED_LIBRARIES := \
+        libui \
+
 LOCAL_STATIC_LIBRARIES := \
         libyuv_static \
 
 LOCAL_CFLAGS += -Werror
-LOCAL_SANITIZE := signed-integer-overflow
+LOCAL_SANITIZE := signed-integer-overflow cfi
+LOCAL_SANITIZE_DIAG := cfi
 
 LOCAL_MODULE:= libstagefright_color_conversion
 
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index bbc4d26..54487b3 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -24,7 +24,8 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <system/window.h>
 #include <ui/GraphicBufferMapper.h>
-#include <gui/IGraphicBufferProducer.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
 
 namespace android {
 
diff --git a/media/libstagefright/filters/Android.mk b/media/libstagefright/filters/Android.mk
index 830d2aa..d4ecfcc 100644
--- a/media/libstagefright/filters/Android.mk
+++ b/media/libstagefright/filters/Android.mk
@@ -23,9 +23,13 @@
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 
 LOCAL_SHARED_LIBRARIES := \
+        libgui \
         libmedia \
         libhidlmemory \
 
 LOCAL_MODULE:= libstagefright_mediafilter
 
+LOCAL_SANITIZE := cfi
+LOCAL_SANITIZE_DIAG := cfi
+
 include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index f7bd3f2..3548f96 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -26,15 +26,18 @@
 
     include_dirs: ["frameworks/av/include/media/stagefright/foundation"],
 
+    export_include_dirs: ["include"],
+
     shared_libs: [
         "libbinder",
         "libutils",
+        "libui",
         "libcutils",
         "liblog",
         "libpowermanager",
     ],
 
-    export_shared_lib_headers: ["libbinder"],
+    export_shared_lib_headers: ["libbinder", "libui"],
 
     cflags: [
         "-Wno-multichar",
diff --git a/media/libstagefright/foundation/include b/media/libstagefright/foundation/include
new file mode 120000
index 0000000..3a1af68
--- /dev/null
+++ b/media/libstagefright/foundation/include
@@ -0,0 +1 @@
+../include/
\ No newline at end of file
diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk
index 19ada73..827703e 100644
--- a/media/libstagefright/id3/Android.mk
+++ b/media/libstagefright/id3/Android.mk
@@ -5,7 +5,8 @@
 	ID3.cpp
 
 LOCAL_CFLAGS += -Werror -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
+LOCAL_SANITIZE_DIAG := cfi
 
 LOCAL_SHARED_LIBRARIES := libmedia
 
diff --git a/include/media/stagefright/AACWriter.h b/media/libstagefright/include/AACWriter.h
similarity index 100%
rename from include/media/stagefright/AACWriter.h
rename to media/libstagefright/include/AACWriter.h
diff --git a/include/media/stagefright/ACodec.h b/media/libstagefright/include/ACodec.h
similarity index 98%
rename from include/media/stagefright/ACodec.h
rename to media/libstagefright/include/ACodec.h
index 814a643..998716f 100644
--- a/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/ACodec.h
@@ -29,6 +29,7 @@
 #include <media/stagefright/SkipCutBuffer.h>
 #include <utils/NativeHandle.h>
 #include <OMX_Audio.h>
+#include <hardware/gralloc.h>
 
 #define TRACK_BUFFER_TIMING     0
 
@@ -42,11 +43,20 @@
 struct DataConverter;
 
 // Treble shared memory
-namespace hidl { namespace memory { namespace V1_0 {
+namespace hidl {
+namespace allocator {
+namespace V1_0 {
 struct IAllocator;
+} // V1_0
+} // allocator
+namespace memory {
+namespace V1_0 {
 struct IMemory;
-}}};
-typedef hidl::memory::V1_0::IAllocator TAllocator;
+} // V1_0
+} // memory
+} // hidl
+
+typedef hidl::allocator::V1_0::IAllocator TAllocator;
 typedef hidl::memory::V1_0::IMemory TMemory;
 
 struct ACodec : public AHierarchicalStateMachine, public CodecBase {
@@ -94,9 +104,8 @@
 
     static status_t getOMXChannelMapping(size_t numChannels, OMX_AUDIO_CHANNELTYPE map[]);
 
-    // Read the flag from "media.use_treble_omx", save it locally, and return
-    // it.
-    bool updateTrebleFlag();
+    // Save the flag.
+    void setTrebleFlag(bool trebleFlag);
     // Return the saved flag.
     bool getTrebleFlag() const;
 
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
index ce9bd3c..02468c1 100644
--- a/media/libstagefright/include/ACodecBufferChannel.h
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -126,6 +126,10 @@
     // 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;
+
+    bool hasCryptoOrDescrambler() {
+        return mCrypto != NULL || mDescrambler != NULL;
+    }
 };
 
 }  // namespace android
diff --git a/include/media/stagefright/AMRWriter.h b/media/libstagefright/include/AMRWriter.h
similarity index 100%
rename from include/media/stagefright/AMRWriter.h
rename to media/libstagefright/include/AMRWriter.h
diff --git a/include/media/stagefright/AudioPlayer.h b/media/libstagefright/include/AudioPlayer.h
similarity index 100%
rename from include/media/stagefright/AudioPlayer.h
rename to media/libstagefright/include/AudioPlayer.h
diff --git a/include/media/stagefright/AudioSource.h b/media/libstagefright/include/AudioSource.h
similarity index 100%
rename from include/media/stagefright/AudioSource.h
rename to media/libstagefright/include/AudioSource.h
diff --git a/include/media/stagefright/BufferProducerWrapper.h b/media/libstagefright/include/BufferProducerWrapper.h
similarity index 100%
rename from include/media/stagefright/BufferProducerWrapper.h
rename to media/libstagefright/include/BufferProducerWrapper.h
diff --git a/include/media/stagefright/CameraSource.h b/media/libstagefright/include/CameraSource.h
similarity index 100%
rename from include/media/stagefright/CameraSource.h
rename to media/libstagefright/include/CameraSource.h
diff --git a/include/media/stagefright/CameraSourceTimeLapse.h b/media/libstagefright/include/CameraSourceTimeLapse.h
similarity index 100%
rename from include/media/stagefright/CameraSourceTimeLapse.h
rename to media/libstagefright/include/CameraSourceTimeLapse.h
diff --git a/include/media/stagefright/CodecBase.h b/media/libstagefright/include/CodecBase.h
similarity index 97%
rename from include/media/stagefright/CodecBase.h
rename to media/libstagefright/include/CodecBase.h
index cfbaea4..845146d 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/CodecBase.h
@@ -35,9 +35,10 @@
 #include <utils/NativeHandle.h>
 
 #include <system/graphics.h>
+#include <android/media/IDescrambler.h>
 
 namespace android {
-
+using namespace media;
 class BufferChannelBase;
 class BufferProducerWrapper;
 class MediaCodecBuffer;
@@ -259,6 +260,10 @@
         mCrypto = crypto;
     }
 
+    inline void setDescrambler(const sp<IDescrambler> &descrambler) {
+        mDescrambler = descrambler;
+    }
+
     /**
      * Queue an input buffer into the buffer channel.
      *
@@ -317,6 +322,7 @@
 protected:
     std::unique_ptr<CodecBase::BufferCallback> mCallback;
     sp<ICrypto> mCrypto;
+    sp<IDescrambler> mDescrambler;
 };
 
 }  // namespace android
diff --git a/include/media/stagefright/ColorConverter.h b/media/libstagefright/include/ColorConverter.h
similarity index 100%
rename from include/media/stagefright/ColorConverter.h
rename to media/libstagefright/include/ColorConverter.h
diff --git a/include/media/stagefright/DataSource.h b/media/libstagefright/include/DataSource.h
similarity index 100%
rename from include/media/stagefright/DataSource.h
rename to media/libstagefright/include/DataSource.h
diff --git a/include/media/stagefright/DataURISource.h b/media/libstagefright/include/DataURISource.h
similarity index 100%
rename from include/media/stagefright/DataURISource.h
rename to media/libstagefright/include/DataURISource.h
diff --git a/include/media/stagefright/FileSource.h b/media/libstagefright/include/FileSource.h
similarity index 100%
rename from include/media/stagefright/FileSource.h
rename to media/libstagefright/include/FileSource.h
diff --git a/include/media/stagefright/FrameRenderTracker.h b/media/libstagefright/include/FrameRenderTracker.h
similarity index 100%
rename from include/media/stagefright/FrameRenderTracker.h
rename to media/libstagefright/include/FrameRenderTracker.h
diff --git a/include/media/stagefright/JPEGSource.h b/media/libstagefright/include/JPEGSource.h
similarity index 100%
rename from include/media/stagefright/JPEGSource.h
rename to media/libstagefright/include/JPEGSource.h
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
index ef55620..2a75298f 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/libstagefright/include/MPEG2TSExtractor.h
@@ -45,6 +45,8 @@
 
     virtual sp<MetaData> getMetaData();
 
+    virtual status_t setMediaCas(const sp<ICas> &cas) override;
+
     virtual uint32_t flags() const;
     virtual const char * name() { return "MPEG2TSExtractor"; }
 
@@ -70,7 +72,10 @@
 
     off64_t mOffset;
 
+    static bool isScrambledFormat(const sp<MetaData> &format);
+
     void init();
+    void addSource(const sp<AnotherPacketSource> &impl);
     // Try to feed more data from source to parser.
     // |isInit| means this function is called inside init(). This is a signal to
     // save SyncEvent so that init() can add SyncPoint after it updates |mSourceImpls|.
diff --git a/include/media/stagefright/MPEG2TSWriter.h b/media/libstagefright/include/MPEG2TSWriter.h
similarity index 100%
rename from include/media/stagefright/MPEG2TSWriter.h
rename to media/libstagefright/include/MPEG2TSWriter.h
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index fa05886..f847119 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -66,6 +66,8 @@
 protected:
     virtual ~MPEG4Extractor();
 
+    virtual void populateMetrics();
+
 private:
 
     struct PsshInfo {
diff --git a/include/media/stagefright/MPEG4Writer.h b/media/libstagefright/include/MPEG4Writer.h
similarity index 100%
rename from include/media/stagefright/MPEG4Writer.h
rename to media/libstagefright/include/MPEG4Writer.h
diff --git a/include/media/stagefright/MediaAdapter.h b/media/libstagefright/include/MediaAdapter.h
similarity index 100%
rename from include/media/stagefright/MediaAdapter.h
rename to media/libstagefright/include/MediaAdapter.h
diff --git a/include/media/stagefright/MediaBuffer.h b/media/libstagefright/include/MediaBuffer.h
similarity index 100%
rename from include/media/stagefright/MediaBuffer.h
rename to media/libstagefright/include/MediaBuffer.h
diff --git a/include/media/stagefright/MediaBufferGroup.h b/media/libstagefright/include/MediaBufferGroup.h
similarity index 100%
rename from include/media/stagefright/MediaBufferGroup.h
rename to media/libstagefright/include/MediaBufferGroup.h
diff --git a/include/media/stagefright/MediaClock.h b/media/libstagefright/include/MediaClock.h
similarity index 100%
rename from include/media/stagefright/MediaClock.h
rename to media/libstagefright/include/MediaClock.h
diff --git a/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/MediaCodec.h
similarity index 95%
rename from include/media/stagefright/MediaCodec.h
rename to media/libstagefright/include/MediaCodec.h
index 699ae48..30454dc 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/MediaCodec.h
@@ -47,6 +47,10 @@
 struct PersistentSurface;
 class SoftwareRenderer;
 class Surface;
+namespace media {
+class IDescrambler;
+};
+using namespace media;
 
 struct MediaCodec : public AHandler {
     enum ConfigureFlags {
@@ -91,6 +95,15 @@
             const sp<ICrypto> &crypto,
             uint32_t flags);
 
+    status_t configure(
+            const sp<AMessage> &format,
+            const sp<Surface> &nativeWindow,
+            const sp<ICrypto> &crypto,
+            const sp<IDescrambler> &descrambler,
+            uint32_t flags);
+
+    status_t releaseCrypto();
+
     status_t setCallback(const sp<AMessage> &callback);
 
     status_t setOnFrameRenderedNotification(const sp<AMessage> &notify);
@@ -239,6 +252,7 @@
         kWhatSetParameters                  = 'setP',
         kWhatSetCallback                    = 'setC',
         kWhatSetNotification                = 'setN',
+        kWhatDrmReleaseCrypto               = 'rDrm',
     };
 
     enum {
@@ -342,6 +356,8 @@
 
     sp<ICrypto> mCrypto;
 
+    sp<IDescrambler> mDescrambler;
+
     List<sp<ABuffer> > mCSD;
 
     sp<AMessage> mActivityNotify;
@@ -385,6 +401,10 @@
     status_t connectToSurface(const sp<Surface> &surface);
     status_t disconnectFromSurface();
 
+    bool hasCryptoOrDescrambler() {
+        return mCrypto != NULL || mDescrambler != NULL;
+    }
+
     void postActivityNotificationIfPossible();
 
     void onInputBufferAvailable();
@@ -416,6 +436,8 @@
         mStickyError = err;
     }
 
+    void onReleaseCrypto(const sp<AMessage>& msg);
+
     DISALLOW_EVIL_CONSTRUCTORS(MediaCodec);
 };
 
diff --git a/include/media/stagefright/MediaCodecList.h b/media/libstagefright/include/MediaCodecList.h
similarity index 100%
rename from include/media/stagefright/MediaCodecList.h
rename to media/libstagefright/include/MediaCodecList.h
diff --git a/include/media/stagefright/MediaCodecSource.h b/media/libstagefright/include/MediaCodecSource.h
similarity index 79%
rename from include/media/stagefright/MediaCodecSource.h
rename to media/libstagefright/include/MediaCodecSource.h
index f9a46a9..5e99b78 100644
--- a/include/media/stagefright/MediaCodecSource.h
+++ b/media/libstagefright/include/MediaCodecSource.h
@@ -54,7 +54,7 @@
     // MediaSource
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop();
-    virtual status_t pause();
+    virtual status_t pause(MetaData *params = NULL);
     virtual sp<MetaData> getFormat();
     virtual status_t read(
             MediaBuffer **buffer,
@@ -66,6 +66,12 @@
     // for AHandlerReflector
     void onMessageReceived(const sp<AMessage> &msg);
 
+    // Set GraphicBufferSource stop time. GraphicBufferSource will stop
+    // after receiving a buffer with timestamp larger or equal than stopTimeUs.
+    // All the buffers with timestamp larger or equal to stopTimeUs will be
+    // discarded. stopTimeUs uses SYSTEM_TIME_MONOTONIC time base.
+    status_t setStopStimeUs(int64_t stopTimeUs);
+
 protected:
     virtual ~MediaCodecSource();
 
@@ -79,6 +85,7 @@
         kWhatStop,
         kWhatPause,
         kWhatSetInputBufferTimeOffset,
+        kWhatSetStopTimeOffset,
         kWhatGetFirstSampleSystemTimeUs,
         kWhatStopStalled,
     };
@@ -91,13 +98,23 @@
             uint32_t flags = 0);
 
     status_t onStart(MetaData *params);
-    void onPause();
+
+    // Pause the source at pauseStartTimeUs. For non-surface input,
+    // buffers will be dropped immediately. For surface input, buffers
+    // with timestamp smaller than pauseStartTimeUs will still be encoded.
+    // Buffers with timestamp larger or queal to pauseStartTimeUs will be
+    // dropped. pauseStartTimeUs uses SYSTEM_TIME_MONOTONIC time base.
+    void onPause(int64_t pauseStartTimeUs);
+
     status_t init();
     status_t initEncoder();
     void releaseEncoder();
     status_t feedEncoderInputBuffers();
-    void suspend();
-    void resume(int64_t skipFramesBeforeUs = -1ll);
+    // Resume GraphicBufferSource at resumeStartTimeUs. Buffers
+    // from GraphicBufferSource with timestamp larger or equal to
+    // resumeStartTimeUs will be encoded. resumeStartTimeUs uses
+    // SYSTEM_TIME_MONOTONIC time base.
+    void resume(int64_t resumeStartTimeUs = -1ll);
     void signalEOS(status_t err = ERROR_END_OF_STREAM);
     bool reachedEOS();
     status_t postSynchronouslyAndReturnError(const sp<AMessage> &msg);
diff --git a/include/media/stagefright/MediaDefs.h b/media/libstagefright/include/MediaDefs.h
similarity index 100%
rename from include/media/stagefright/MediaDefs.h
rename to media/libstagefright/include/MediaDefs.h
diff --git a/include/media/stagefright/MediaErrors.h b/media/libstagefright/include/MediaErrors.h
similarity index 100%
rename from include/media/stagefright/MediaErrors.h
rename to media/libstagefright/include/MediaErrors.h
diff --git a/include/media/stagefright/MediaExtractor.h b/media/libstagefright/include/MediaExtractor.h
similarity index 92%
rename from include/media/stagefright/MediaExtractor.h
rename to media/libstagefright/include/MediaExtractor.h
index 211f794..073391f 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/media/libstagefright/include/MediaExtractor.h
@@ -23,7 +23,10 @@
 #include <media/MediaAnalyticsItem.h>
 
 namespace android {
-
+namespace media {
+class ICas;
+};
+using namespace media;
 class DataSource;
 struct MediaSource;
 class MetaData;
@@ -48,6 +51,8 @@
     // returns an empty metadata object.
     virtual sp<MetaData> getMetaData();
 
+    status_t getMetrics(Parcel *reply);
+
     enum Flags {
         CAN_SEEK_BACKWARD  = 1,  // the "seek 10secs back button"
         CAN_SEEK_FORWARD   = 2,  // the "seek 10secs forward button"
@@ -65,6 +70,9 @@
     }
     virtual void setUID(uid_t /*uid*/) {
     }
+    virtual status_t setMediaCas(const sp<ICas> &cas) override {
+        return INVALID_OPERATION;
+    }
 
     virtual const char * name() { return "<unspecified>"; }
 
@@ -74,6 +82,8 @@
 
     MediaAnalyticsItem *mAnalyticsItem;
 
+    virtual void populateMetrics();
+
 private:
 
     typedef bool (*SnifferFunc)(
diff --git a/include/media/stagefright/MediaFilter.h b/media/libstagefright/include/MediaFilter.h
similarity index 100%
rename from include/media/stagefright/MediaFilter.h
rename to media/libstagefright/include/MediaFilter.h
diff --git a/include/media/stagefright/MediaHTTP.h b/media/libstagefright/include/MediaHTTP.h
similarity index 100%
rename from include/media/stagefright/MediaHTTP.h
rename to media/libstagefright/include/MediaHTTP.h
diff --git a/include/media/stagefright/MediaMuxer.h b/media/libstagefright/include/MediaMuxer.h
similarity index 100%
rename from include/media/stagefright/MediaMuxer.h
rename to media/libstagefright/include/MediaMuxer.h
diff --git a/include/media/stagefright/MediaSource.h b/media/libstagefright/include/MediaSource.h
similarity index 100%
rename from include/media/stagefright/MediaSource.h
rename to media/libstagefright/include/MediaSource.h
diff --git a/include/media/stagefright/MediaSync.h b/media/libstagefright/include/MediaSync.h
similarity index 100%
rename from include/media/stagefright/MediaSync.h
rename to media/libstagefright/include/MediaSync.h
diff --git a/include/media/stagefright/MediaWriter.h b/media/libstagefright/include/MediaWriter.h
similarity index 100%
rename from include/media/stagefright/MediaWriter.h
rename to media/libstagefright/include/MediaWriter.h
diff --git a/include/media/stagefright/MetaData.h b/media/libstagefright/include/MetaData.h
similarity index 99%
rename from include/media/stagefright/MetaData.h
rename to media/libstagefright/include/MetaData.h
index 6ba7b32..214f4ff 100644
--- a/include/media/stagefright/MetaData.h
+++ b/media/libstagefright/include/MetaData.h
@@ -176,6 +176,7 @@
     kKeyCryptoDefaultIVSize = 'cryS',  // int32_t
 
     kKeyPssh              = 'pssh',  // raw data
+    kKeyCas               = ' cas',
 
     // Please see MediaFormat.KEY_IS_AUTOSELECT.
     kKeyTrackIsAutoselect = 'auto', // bool (int32_t)
diff --git a/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/NuMediaExtractor.h
similarity index 95%
rename from include/media/stagefright/NuMediaExtractor.h
rename to media/libstagefright/include/NuMediaExtractor.h
index e414757..3e3cc17 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/NuMediaExtractor.h
@@ -28,6 +28,10 @@
 #include <utils/Vector.h>
 
 namespace android {
+namespace media {
+class ICas;
+}
+using namespace media;
 
 struct ABuffer;
 struct AMessage;
@@ -60,6 +64,8 @@
 
     status_t setDataSource(const sp<DataSource> &datasource);
 
+    status_t setMediaCas(const sp<ICas> &cas);
+
     size_t countTracks() const;
     status_t getTrackFormat(size_t index, sp<AMessage> *format, uint32_t flags = 0) const;
 
@@ -78,6 +84,7 @@
     status_t getSampleTrackIndex(size_t *trackIndex);
     status_t getSampleTime(int64_t *sampleTimeUs);
     status_t getSampleMeta(sp<MetaData> *sampleMeta);
+    status_t getMetrics(Parcel *reply);
 
     bool getCachedDuration(int64_t *durationUs, bool *eos) const;
 
@@ -108,6 +115,7 @@
     sp<DataSource> mDataSource;
 
     sp<IMediaExtractor> mImpl;
+    sp<ICas> mCas;
 
     Vector<TrackInfo> mSelectedTracks;
     int64_t mTotalBitrate;  // in bits/sec
diff --git a/include/media/stagefright/OMXClient.h b/media/libstagefright/include/OMXClient.h
similarity index 92%
rename from include/media/stagefright/OMXClient.h
rename to media/libstagefright/include/OMXClient.h
index 6b86cbf..315f19b 100644
--- a/include/media/stagefright/OMXClient.h
+++ b/media/libstagefright/include/OMXClient.h
@@ -26,7 +26,8 @@
 public:
     OMXClient();
 
-    status_t connect();
+    status_t connect(bool* trebleFlag = nullptr);
+    status_t connectLegacy();
     status_t connectTreble();
     void disconnect();
 
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index c7e60ca..8e08d15 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -30,6 +30,7 @@
 #include <android/hidl/memory/1.0/IMemory.h>
 
 namespace android {
+class GraphicBuffer;
 class IOMXBufferSource;
 class IOMXObserver;
 struct OMXMaster;
diff --git a/include/media/stagefright/PersistentSurface.h b/media/libstagefright/include/PersistentSurface.h
similarity index 100%
rename from include/media/stagefright/PersistentSurface.h
rename to media/libstagefright/include/PersistentSurface.h
diff --git a/include/media/stagefright/ProcessInfo.h b/media/libstagefright/include/ProcessInfo.h
similarity index 100%
rename from include/media/stagefright/ProcessInfo.h
rename to media/libstagefright/include/ProcessInfo.h
diff --git a/include/media/stagefright/ProcessInfoInterface.h b/media/libstagefright/include/ProcessInfoInterface.h
similarity index 100%
rename from include/media/stagefright/ProcessInfoInterface.h
rename to media/libstagefright/include/ProcessInfoInterface.h
diff --git a/include/media/stagefright/RenderScriptWrapper.h b/media/libstagefright/include/RenderScriptWrapper.h
similarity index 100%
rename from include/media/stagefright/RenderScriptWrapper.h
rename to media/libstagefright/include/RenderScriptWrapper.h
diff --git a/include/media/stagefright/SimpleDecodingSource.h b/media/libstagefright/include/SimpleDecodingSource.h
similarity index 100%
rename from include/media/stagefright/SimpleDecodingSource.h
rename to media/libstagefright/include/SimpleDecodingSource.h
diff --git a/include/media/stagefright/SkipCutBuffer.h b/media/libstagefright/include/SkipCutBuffer.h
similarity index 100%
rename from include/media/stagefright/SkipCutBuffer.h
rename to media/libstagefright/include/SkipCutBuffer.h
diff --git a/include/media/stagefright/StagefrightMediaScanner.h b/media/libstagefright/include/StagefrightMediaScanner.h
similarity index 100%
rename from include/media/stagefright/StagefrightMediaScanner.h
rename to media/libstagefright/include/StagefrightMediaScanner.h
diff --git a/include/media/stagefright/SurfaceMediaSource.h b/media/libstagefright/include/SurfaceMediaSource.h
similarity index 100%
rename from include/media/stagefright/SurfaceMediaSource.h
rename to media/libstagefright/include/SurfaceMediaSource.h
diff --git a/include/media/stagefright/SurfaceUtils.h b/media/libstagefright/include/SurfaceUtils.h
similarity index 89%
rename from include/media/stagefright/SurfaceUtils.h
rename to media/libstagefright/include/SurfaceUtils.h
index 13d580c..a7747c7 100644
--- a/include/media/stagefright/SurfaceUtils.h
+++ b/media/libstagefright/include/SurfaceUtils.h
@@ -33,6 +33,8 @@
         ANativeWindow *nativeWindow /* nonnull */,
         int width, int height, int format, int rotation, int usage, bool reconnect);
 status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */);
+status_t nativeWindowConnect(ANativeWindow *surface, const char *reason);
+status_t nativeWindowDisconnect(ANativeWindow *surface, const char *reason);
 
 } // namespace android
 
diff --git a/include/media/stagefright/Utils.h b/media/libstagefright/include/Utils.h
similarity index 100%
rename from include/media/stagefright/Utils.h
rename to media/libstagefright/include/Utils.h
diff --git a/include/media/stagefright/VideoFrameScheduler.h b/media/libstagefright/include/VideoFrameScheduler.h
similarity index 100%
rename from include/media/stagefright/VideoFrameScheduler.h
rename to media/libstagefright/include/VideoFrameScheduler.h
diff --git a/include/media/stagefright/YUVCanvas.h b/media/libstagefright/include/YUVCanvas.h
similarity index 100%
rename from include/media/stagefright/YUVCanvas.h
rename to media/libstagefright/include/YUVCanvas.h
diff --git a/include/media/stagefright/YUVImage.h b/media/libstagefright/include/YUVImage.h
similarity index 100%
rename from include/media/stagefright/YUVImage.h
rename to media/libstagefright/include/YUVImage.h
diff --git a/include/media/stagefright/foundation/AAtomizer.h b/media/libstagefright/include/foundation/AAtomizer.h
similarity index 100%
rename from include/media/stagefright/foundation/AAtomizer.h
rename to media/libstagefright/include/foundation/AAtomizer.h
diff --git a/include/media/stagefright/foundation/ABase.h b/media/libstagefright/include/foundation/ABase.h
similarity index 100%
rename from include/media/stagefright/foundation/ABase.h
rename to media/libstagefright/include/foundation/ABase.h
diff --git a/include/media/stagefright/foundation/ABitReader.h b/media/libstagefright/include/foundation/ABitReader.h
similarity index 100%
rename from include/media/stagefright/foundation/ABitReader.h
rename to media/libstagefright/include/foundation/ABitReader.h
diff --git a/include/media/stagefright/foundation/ABuffer.h b/media/libstagefright/include/foundation/ABuffer.h
similarity index 100%
rename from include/media/stagefright/foundation/ABuffer.h
rename to media/libstagefright/include/foundation/ABuffer.h
diff --git a/include/media/stagefright/foundation/AData.h b/media/libstagefright/include/foundation/AData.h
similarity index 100%
rename from include/media/stagefright/foundation/AData.h
rename to media/libstagefright/include/foundation/AData.h
diff --git a/include/media/stagefright/foundation/ADebug.h b/media/libstagefright/include/foundation/ADebug.h
similarity index 100%
rename from include/media/stagefright/foundation/ADebug.h
rename to media/libstagefright/include/foundation/ADebug.h
diff --git a/include/media/stagefright/foundation/AHandler.h b/media/libstagefright/include/foundation/AHandler.h
similarity index 100%
rename from include/media/stagefright/foundation/AHandler.h
rename to media/libstagefright/include/foundation/AHandler.h
diff --git a/include/media/stagefright/foundation/AHandlerReflector.h b/media/libstagefright/include/foundation/AHandlerReflector.h
similarity index 100%
rename from include/media/stagefright/foundation/AHandlerReflector.h
rename to media/libstagefright/include/foundation/AHandlerReflector.h
diff --git a/include/media/stagefright/foundation/AHierarchicalStateMachine.h b/media/libstagefright/include/foundation/AHierarchicalStateMachine.h
similarity index 100%
rename from include/media/stagefright/foundation/AHierarchicalStateMachine.h
rename to media/libstagefright/include/foundation/AHierarchicalStateMachine.h
diff --git a/include/media/stagefright/foundation/ALookup.h b/media/libstagefright/include/foundation/ALookup.h
similarity index 100%
rename from include/media/stagefright/foundation/ALookup.h
rename to media/libstagefright/include/foundation/ALookup.h
diff --git a/include/media/stagefright/foundation/ALooper.h b/media/libstagefright/include/foundation/ALooper.h
similarity index 100%
rename from include/media/stagefright/foundation/ALooper.h
rename to media/libstagefright/include/foundation/ALooper.h
diff --git a/include/media/stagefright/foundation/ALooperRoster.h b/media/libstagefright/include/foundation/ALooperRoster.h
similarity index 100%
rename from include/media/stagefright/foundation/ALooperRoster.h
rename to media/libstagefright/include/foundation/ALooperRoster.h
diff --git a/include/media/stagefright/foundation/AMessage.h b/media/libstagefright/include/foundation/AMessage.h
similarity index 100%
rename from include/media/stagefright/foundation/AMessage.h
rename to media/libstagefright/include/foundation/AMessage.h
diff --git a/include/media/stagefright/foundation/ANetworkSession.h b/media/libstagefright/include/foundation/ANetworkSession.h
similarity index 100%
rename from include/media/stagefright/foundation/ANetworkSession.h
rename to media/libstagefright/include/foundation/ANetworkSession.h
diff --git a/include/media/stagefright/foundation/AString.h b/media/libstagefright/include/foundation/AString.h
similarity index 100%
rename from include/media/stagefright/foundation/AString.h
rename to media/libstagefright/include/foundation/AString.h
diff --git a/include/media/stagefright/foundation/AStringUtils.h b/media/libstagefright/include/foundation/AStringUtils.h
similarity index 100%
rename from include/media/stagefright/foundation/AStringUtils.h
rename to media/libstagefright/include/foundation/AStringUtils.h
diff --git a/include/media/stagefright/foundation/AUtils.h b/media/libstagefright/include/foundation/AUtils.h
similarity index 100%
rename from include/media/stagefright/foundation/AUtils.h
rename to media/libstagefright/include/foundation/AUtils.h
diff --git a/include/media/stagefright/foundation/AWakeLock.h b/media/libstagefright/include/foundation/AWakeLock.h
similarity index 100%
rename from include/media/stagefright/foundation/AWakeLock.h
rename to media/libstagefright/include/foundation/AWakeLock.h
diff --git a/include/media/stagefright/foundation/ColorUtils.h b/media/libstagefright/include/foundation/ColorUtils.h
similarity index 100%
rename from include/media/stagefright/foundation/ColorUtils.h
rename to media/libstagefright/include/foundation/ColorUtils.h
diff --git a/include/media/stagefright/foundation/Flagged.h b/media/libstagefright/include/foundation/Flagged.h
similarity index 100%
rename from include/media/stagefright/foundation/Flagged.h
rename to media/libstagefright/include/foundation/Flagged.h
diff --git a/include/media/stagefright/foundation/MediaBufferBase.h b/media/libstagefright/include/foundation/MediaBufferBase.h
similarity index 100%
rename from include/media/stagefright/foundation/MediaBufferBase.h
rename to media/libstagefright/include/foundation/MediaBufferBase.h
diff --git a/include/media/stagefright/foundation/Mutexed.h b/media/libstagefright/include/foundation/Mutexed.h
similarity index 100%
rename from include/media/stagefright/foundation/Mutexed.h
rename to media/libstagefright/include/foundation/Mutexed.h
diff --git a/include/media/stagefright/foundation/ParsedMessage.h b/media/libstagefright/include/foundation/ParsedMessage.h
similarity index 100%
rename from include/media/stagefright/foundation/ParsedMessage.h
rename to media/libstagefright/include/foundation/ParsedMessage.h
diff --git a/include/media/stagefright/foundation/TypeTraits.h b/media/libstagefright/include/foundation/TypeTraits.h
similarity index 100%
rename from include/media/stagefright/foundation/TypeTraits.h
rename to media/libstagefright/include/foundation/TypeTraits.h
diff --git a/include/media/stagefright/foundation/base64.h b/media/libstagefright/include/foundation/base64.h
similarity index 100%
rename from include/media/stagefright/foundation/base64.h
rename to media/libstagefright/include/foundation/base64.h
diff --git a/include/media/stagefright/foundation/hexdump.h b/media/libstagefright/include/foundation/hexdump.h
similarity index 100%
rename from include/media/stagefright/foundation/hexdump.h
rename to media/libstagefright/include/foundation/hexdump.h
diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk
index 7dd0863..7de5dbe 100644
--- a/media/libstagefright/matroska/Android.mk
+++ b/media/libstagefright/matroska/Android.mk
@@ -10,7 +10,8 @@
         $(TOP)/frameworks/av/media/libstagefright/include \
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
+LOCAL_SANITIZE_DIAG := cfi
 
 LOCAL_SHARED_LIBRARIES := libmedia
 
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index a974671..81179d1 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -1288,8 +1288,51 @@
                     continue;
                 }
 
-                meta->setInt32(kKeyWidth, vtrack->GetWidth());
-                meta->setInt32(kKeyHeight, vtrack->GetHeight());
+                const long long width = vtrack->GetWidth();
+                const long long height = vtrack->GetHeight();
+                if (width <= 0 || width > INT32_MAX) {
+                    ALOGW("track width exceeds int32_t, %lld", width);
+                    continue;
+                }
+                if (height <= 0 || height > INT32_MAX) {
+                    ALOGW("track height exceeds int32_t, %lld", height);
+                    continue;
+                }
+                meta->setInt32(kKeyWidth, (int32_t)width);
+                meta->setInt32(kKeyHeight, (int32_t)height);
+
+                // setting display width/height is optional
+                const long long displayUnit = vtrack->GetDisplayUnit();
+                const long long displayWidth = vtrack->GetDisplayWidth();
+                const long long displayHeight = vtrack->GetDisplayHeight();
+                if (displayWidth > 0 && displayWidth <= INT32_MAX
+                        && displayHeight > 0 && displayHeight <= INT32_MAX) {
+                    switch (displayUnit) {
+                    case 0: // pixels
+                        meta->setInt32(kKeyDisplayWidth, (int32_t)displayWidth);
+                        meta->setInt32(kKeyDisplayHeight, (int32_t)displayHeight);
+                        break;
+                    case 1: // centimeters
+                    case 2: // inches
+                    case 3: // aspect ratio
+                    {
+                        // Physical layout size is treated the same as aspect ratio.
+                        // Note: displayWidth and displayHeight are never zero as they are
+                        // checked in the if above.
+                        const long long computedWidth =
+                                std::max(width, height * displayWidth / displayHeight);
+                        const long long computedHeight =
+                                std::max(height, width * displayHeight / displayWidth);
+                        if (computedWidth <= INT32_MAX && computedHeight <= INT32_MAX) {
+                            meta->setInt32(kKeyDisplayWidth, (int32_t)computedWidth);
+                            meta->setInt32(kKeyDisplayHeight, (int32_t)computedHeight);
+                        }
+                        break;
+                    }
+                    default: // unknown display units, perhaps future version of spec.
+                        break;
+                    }
+                }
 
                 getColorInformation(vtrack, meta);
 
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 4975d9a..47caf61 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -17,13 +17,14 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "ATSParser"
 #include <utils/Log.h>
-
 #include "ATSParser.h"
-
 #include "AnotherPacketSource.h"
+#include "CasManager.h"
 #include "ESQueue.h"
 #include "include/avc_utils.h"
 
+#include <android/media/IDescrambler.h>
+#include <binder/MemoryDealer.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -40,6 +41,8 @@
 #include <inttypes.h>
 
 namespace android {
+using binder::Status;
+using MediaDescrambler::DescrambleInfo;
 
 // I want the expression "y" evaluated even if verbose logging is off.
 #define MY_LOGV(x, y) \
@@ -60,6 +63,8 @@
     bool parsePID(
             unsigned pid, unsigned continuity_counter,
             unsigned payload_unit_start_indicator,
+            unsigned transport_scrambling_control,
+            unsigned random_access_indicator,
             ABitReader *br, status_t *err, SyncEvent *event);
 
     void signalDiscontinuity(
@@ -90,14 +95,21 @@
         return mParser->mFlags;
     }
 
+    sp<CasManager> casManager() const {
+        return mParser->mCasManager;
+    }
+
     uint64_t firstPTS() const {
         return mFirstPTS;
     }
 
+    void updateCasSessions();
+
 private:
     struct StreamInfo {
         unsigned mType;
         unsigned mPID;
+        int32_t mCASystemId;
     };
 
     ATSParser *mParser;
@@ -110,6 +122,8 @@
 
     status_t parseProgramMap(ABitReader *br);
     int64_t recoverPTS(uint64_t PTS_33bit);
+    bool findCADescriptor(
+            ABitReader *br, unsigned infoLength, CADescriptor *caDescriptor);
     bool switchPIDs(const Vector<StreamInfo> &infos);
 
     DISALLOW_EVIL_CONSTRUCTORS(Program);
@@ -119,18 +133,25 @@
     Stream(Program *program,
            unsigned elementaryPID,
            unsigned streamType,
-           unsigned PCR_PID);
+           unsigned PCR_PID,
+           int32_t CA_system_ID);
 
     unsigned type() const { return mStreamType; }
     unsigned pid() const { return mElementaryPID; }
     void setPID(unsigned pid) { mElementaryPID = pid; }
 
+    void setCasSession(
+            const sp<IDescrambler> &descrambler,
+            const std::vector<uint8_t> &sessionId);
+
     // Parse the payload and set event when PES with a sync frame is detected.
     // This method knows when a PES starts; so record mPesStartOffsets in that
     // case.
     status_t parse(
             unsigned continuity_counter,
             unsigned payload_unit_start_indicator,
+            unsigned transport_scrambling_control,
+            unsigned random_access_indicator,
             ABitReader *br,
             SyncEvent *event);
 
@@ -150,6 +171,11 @@
     virtual ~Stream();
 
 private:
+    struct SubSampleInfo {
+        size_t subSampleSize;
+        unsigned transport_scrambling_mode;
+        unsigned random_access_indicator;
+    };
     Program *mProgram;
     unsigned mElementaryPID;
     unsigned mStreamType;
@@ -166,10 +192,26 @@
 
     ElementaryStreamQueue *mQueue;
 
+    bool mScrambled;
+    sp<IMemory> mMem;
+    sp<MemoryDealer> mDealer;
+    sp<ABuffer> mDescrambledBuffer;
+    List<SubSampleInfo> mSubSamples;
+    sp<IDescrambler> mDescrambler;
+
     // Flush accumulated payload if necessary --- i.e. at EOS or at the start of
     // another payload. event is set if the flushed payload is PES with a sync
     // frame.
     status_t flush(SyncEvent *event);
+
+    // Flush accumulated payload for scrambled streams if necessary --- i.e. at
+    // EOS or at the start of another payload. event is set if the flushed
+    // payload is PES with a sync frame.
+    status_t flushScrambled(SyncEvent *event);
+
+    // Check if a PES packet is scrambled at PES level.
+    uint32_t getPesScramblingControl(ABitReader *br, int32_t *pesOffset);
+
     // Strip and parse PES headers and pass remaining payload into onPayload
     // with parsed metadata. event is set if the PES contains a sync frame.
     status_t parsePES(ABitReader *br, SyncEvent *event);
@@ -179,7 +221,13 @@
     // and timestamp of the packet.
     void onPayloadData(
             unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS,
-            const uint8_t *data, size_t size, SyncEvent *event);
+            unsigned PES_scrambling_control,
+            const uint8_t *data, size_t size,
+            int32_t payloadOffset, SyncEvent *event);
+
+    // Ensure internal buffers can hold specified size, and will re-allocate
+    // as needed.
+    void ensureBufferCapacity(size_t size);
 
     DISALLOW_EVIL_CONSTRUCTORS(Stream);
 };
@@ -254,6 +302,8 @@
 bool ATSParser::Program::parsePID(
         unsigned pid, unsigned continuity_counter,
         unsigned payload_unit_start_indicator,
+        unsigned transport_scrambling_control,
+        unsigned random_access_indicator,
         ABitReader *br, status_t *err, SyncEvent *event) {
     *err = OK;
 
@@ -263,7 +313,11 @@
     }
 
     *err = mStreams.editValueAt(index)->parse(
-            continuity_counter, payload_unit_start_indicator, br, event);
+            continuity_counter,
+            payload_unit_start_indicator,
+            transport_scrambling_control,
+            random_access_indicator,
+            br, event);
 
     return true;
 }
@@ -359,6 +413,38 @@
     return success;
 }
 
+bool ATSParser::Program::findCADescriptor(
+        ABitReader *br, unsigned infoLength,
+        ATSParser::CADescriptor *caDescriptor) {
+    bool found = false;
+    while (infoLength > 2) {
+        unsigned descriptor_tag = br->getBits(8);
+        ALOGV("      tag = 0x%02x", descriptor_tag);
+
+        unsigned descriptor_length = br->getBits(8);
+        ALOGV("      len = %u", descriptor_length);
+
+        infoLength -= 2;
+        if (descriptor_length > infoLength) {
+            break;
+        }
+        if (descriptor_tag == 9 && descriptor_length >= 4) {
+            found = true;
+            caDescriptor->mSystemID = br->getBits(16);
+            caDescriptor->mPID = br->getBits(16) & 0x1fff;
+            infoLength -= 4;
+            caDescriptor->mPrivateData.assign(
+                    br->data(), br->data() + descriptor_length - 4);
+            break;
+        } else {
+            infoLength -= descriptor_length;
+            br->skipBits(descriptor_length * 8);
+        }
+    }
+    br->skipBits(infoLength * 8);
+    return found;
+}
+
 status_t ATSParser::Program::parseProgramMap(ABitReader *br) {
     unsigned table_id = br->getBits(8);
     ALOGV("  table_id = %u", table_id);
@@ -395,7 +481,13 @@
     unsigned program_info_length = br->getBits(12);
     ALOGV("  program_info_length = %u", program_info_length);
 
-    br->skipBits(program_info_length * 8);  // skip descriptors
+    // descriptors
+    CADescriptor programCA;
+    bool hasProgramCA = findCADescriptor(br, program_info_length, &programCA);
+    if (hasProgramCA && !mParser->mCasManager->addProgram(
+            mProgramNumber, programCA)) {
+        return ERROR_MALFORMED;
+    }
 
     Vector<StreamInfo> infos;
 
@@ -419,28 +511,17 @@
         unsigned ES_info_length = br->getBits(12);
         ALOGV("    ES_info_length = %u", ES_info_length);
 
-#if 0
-        br->skipBits(ES_info_length * 8);  // skip descriptors
-#else
-        unsigned info_bytes_remaining = ES_info_length;
-        while (info_bytes_remaining >= 2) {
-            MY_LOGV("      tag = 0x%02x", br->getBits(8));
-
-            unsigned descLength = br->getBits(8);
-            ALOGV("      len = %u", descLength);
-
-            if (info_bytes_remaining < descLength) {
-                return ERROR_MALFORMED;
-            }
-            br->skipBits(descLength * 8);
-
-            info_bytes_remaining -= descLength + 2;
+        CADescriptor streamCA;
+        bool hasStreamCA = findCADescriptor(br, ES_info_length, &streamCA);
+        if (hasStreamCA && !mParser->mCasManager->addStream(
+                mProgramNumber, elementaryPID, streamCA)) {
+            return ERROR_MALFORMED;
         }
-#endif
-
         StreamInfo info;
         info.mType = streamType;
         info.mPID = elementaryPID;
+        info.mCASystemId = hasProgramCA ? programCA.mSystemID :
+                           hasStreamCA ? streamCA.mSystemID  : -1;
         infos.push(info);
 
         infoBytesRemaining -= 5 + ES_info_length;
@@ -490,19 +571,29 @@
         }
     }
 
+    bool isAddingScrambledStream = false;
     for (size_t i = 0; i < infos.size(); ++i) {
         StreamInfo &info = infos.editItemAt(i);
 
+        if (mParser->mCasManager->isCAPid(info.mPID)) {
+            // skip CA streams (EMM/ECM)
+            continue;
+        }
         ssize_t index = mStreams.indexOfKey(info.mPID);
 
         if (index < 0) {
             sp<Stream> stream = new Stream(
-                    this, info.mPID, info.mType, PCR_PID);
+                    this, info.mPID, info.mType, PCR_PID, info.mCASystemId);
 
+            isAddingScrambledStream |= info.mCASystemId >= 0;
             mStreams.add(info.mPID, stream);
         }
     }
 
+    if (isAddingScrambledStream) {
+        ALOGI("Receiving scrambled streams without descrambler!");
+        return ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED;
+    }
     return OK;
 }
 
@@ -586,13 +677,27 @@
     return timeUs;
 }
 
+void ATSParser::Program::updateCasSessions() {
+    for (size_t i = 0; i < mStreams.size(); ++i) {
+        sp<Stream> &stream = mStreams.editValueAt(i);
+        sp<IDescrambler> descrambler;
+        std::vector<uint8_t> sessionId;
+        if (mParser->mCasManager->getCasSession(
+                mProgramNumber, stream->pid(), &descrambler, &sessionId)) {
+            stream->setCasSession(descrambler, sessionId);
+        }
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
+static const size_t kInitialStreamBufferSize = 192 * 1024;
 
 ATSParser::Stream::Stream(
         Program *program,
         unsigned elementaryPID,
         unsigned streamType,
-        unsigned PCR_PID)
+        unsigned PCR_PID,
+        int32_t CA_system_ID)
     : mProgram(program),
       mElementaryPID(elementaryPID),
       mStreamType(streamType),
@@ -601,54 +706,71 @@
       mPayloadStarted(false),
       mEOSReached(false),
       mPrevPTS(0),
-      mQueue(NULL) {
+      mQueue(NULL),
+      mScrambled(CA_system_ID >= 0) {
+    ALOGV("new stream PID 0x%02x, type 0x%02x, scrambled %d",
+            elementaryPID, streamType, mScrambled);
+
+    uint32_t flags = (isVideo() && mScrambled) ?
+            ElementaryStreamQueue::kFlag_ScrambledData : 0;
+
+    ElementaryStreamQueue::Mode mode = ElementaryStreamQueue::INVALID;
+
     switch (mStreamType) {
         case STREAMTYPE_H264:
-            mQueue = new ElementaryStreamQueue(
-                    ElementaryStreamQueue::H264,
-                    (mProgram->parserFlags() & ALIGNED_VIDEO_DATA)
-                        ? ElementaryStreamQueue::kFlag_AlignedData : 0);
+            mode = ElementaryStreamQueue::H264;
+            flags |= (mProgram->parserFlags() & ALIGNED_VIDEO_DATA) ?
+                    ElementaryStreamQueue::kFlag_AlignedData : 0;
             break;
+
         case STREAMTYPE_MPEG2_AUDIO_ADTS:
-            mQueue = new ElementaryStreamQueue(ElementaryStreamQueue::AAC);
+            mode = ElementaryStreamQueue::AAC;
             break;
+
         case STREAMTYPE_MPEG1_AUDIO:
         case STREAMTYPE_MPEG2_AUDIO:
-            mQueue = new ElementaryStreamQueue(
-                    ElementaryStreamQueue::MPEG_AUDIO);
+            mode = ElementaryStreamQueue::MPEG_AUDIO;
             break;
 
         case STREAMTYPE_MPEG1_VIDEO:
         case STREAMTYPE_MPEG2_VIDEO:
-            mQueue = new ElementaryStreamQueue(
-                    ElementaryStreamQueue::MPEG_VIDEO);
+            mode = ElementaryStreamQueue::MPEG_VIDEO;
             break;
 
         case STREAMTYPE_MPEG4_VIDEO:
-            mQueue = new ElementaryStreamQueue(
-                    ElementaryStreamQueue::MPEG4_VIDEO);
+            mode = ElementaryStreamQueue::MPEG4_VIDEO;
             break;
 
         case STREAMTYPE_LPCM_AC3:
         case STREAMTYPE_AC3:
-            mQueue = new ElementaryStreamQueue(
-                    ElementaryStreamQueue::AC3);
+            mode = ElementaryStreamQueue::AC3;
             break;
 
         case STREAMTYPE_METADATA:
-            mQueue = new ElementaryStreamQueue(
-                    ElementaryStreamQueue::METADATA);
+            mode = ElementaryStreamQueue::METADATA;
             break;
 
         default:
-            break;
+            ALOGE("stream PID 0x%02x has invalid stream type 0x%02x",
+                    elementaryPID, streamType);
+            return;
     }
 
-    ALOGV("new stream PID 0x%02x, type 0x%02x", elementaryPID, streamType);
+    mQueue = new ElementaryStreamQueue(mode, flags);
 
     if (mQueue != NULL) {
-        mBuffer = new ABuffer(192 * 1024);
-        mBuffer->setRange(0, 0);
+        ensureBufferCapacity(kInitialStreamBufferSize);
+
+        if (mScrambled && (isAudio() || isVideo())) {
+            // Set initial format to scrambled
+            sp<MetaData> meta = new MetaData();
+            meta->setCString(kKeyMIMEType,
+                    isAudio() ? MEDIA_MIMETYPE_AUDIO_SCRAMBLED
+                              : MEDIA_MIMETYPE_VIDEO_SCRAMBLED);
+            // for DrmInitData
+            meta->setData(kKeyCas, 0, &CA_system_ID, sizeof(CA_system_ID));
+            mSource = new AnotherPacketSource(meta);
+        }
     }
 }
 
@@ -657,10 +779,57 @@
     mQueue = NULL;
 }
 
+void ATSParser::Stream::ensureBufferCapacity(size_t neededSize) {
+    if (mBuffer != NULL && mBuffer->capacity() >= neededSize) {
+        return;
+    }
+
+    ALOGV("ensureBufferCapacity: current size %zu, new size %zu, scrambled %d",
+            mBuffer == NULL ? 0 : mBuffer->capacity(), neededSize, mScrambled);
+
+    sp<ABuffer> newBuffer, newScrambledBuffer;
+    sp<IMemory> newMem;
+    sp<MemoryDealer> newDealer;
+    if (mScrambled) {
+        size_t alignment = MemoryDealer::getAllocationAlignment();
+        neededSize = (neededSize + (alignment - 1)) & ~(alignment - 1);
+        // Align to multiples of 64K.
+        neededSize = (neededSize + 65535) & ~65535;
+        newDealer = new MemoryDealer(neededSize, "ATSParser");
+        newMem = newDealer->allocate(neededSize);
+        newScrambledBuffer = new ABuffer(newMem->pointer(), newMem->size());
+
+        if (mDescrambledBuffer != NULL) {
+            memcpy(newScrambledBuffer->data(),
+                    mDescrambledBuffer->data(), mDescrambledBuffer->size());
+            newScrambledBuffer->setRange(0, mDescrambledBuffer->size());
+        } else {
+            newScrambledBuffer->setRange(0, 0);
+        }
+        mMem = newMem;
+        mDealer = newDealer;
+        mDescrambledBuffer = newScrambledBuffer;
+    } else {
+        // Align to multiples of 64K.
+        neededSize = (neededSize + 65535) & ~65535;
+    }
+
+    newBuffer = new ABuffer(neededSize);
+    if (mBuffer != NULL) {
+        memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size());
+        newBuffer->setRange(0, mBuffer->size());
+    } else {
+        newBuffer->setRange(0, 0);
+    }
+    mBuffer = newBuffer;
+}
+
 status_t ATSParser::Stream::parse(
         unsigned continuity_counter,
-        unsigned payload_unit_start_indicator, ABitReader *br,
-        SyncEvent *event) {
+        unsigned payload_unit_start_indicator,
+        unsigned transport_scrambling_control,
+        unsigned random_access_indicator,
+        ABitReader *br, SyncEvent *event) {
     if (mQueue == NULL) {
         return OK;
     }
@@ -672,6 +841,7 @@
         mPayloadStarted = false;
         mPesStartOffsets.clear();
         mBuffer->setRange(0, 0);
+        mSubSamples.clear();
         mExpectedContinuityCounter = -1;
 
 #if 0
@@ -725,21 +895,16 @@
     }
 
     size_t neededSize = mBuffer->size() + payloadSizeBits / 8;
-    if (mBuffer->capacity() < neededSize) {
-        // Increment in multiples of 64K.
-        neededSize = (neededSize + 65535) & ~65535;
-
-        ALOGI("resizing buffer to %zu bytes", neededSize);
-
-        sp<ABuffer> newBuffer = new ABuffer(neededSize);
-        memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size());
-        newBuffer->setRange(0, mBuffer->size());
-        mBuffer = newBuffer;
-    }
+    ensureBufferCapacity(neededSize);
 
     memcpy(mBuffer->data() + mBuffer->size(), br->data(), payloadSizeBits / 8);
     mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8);
 
+    if (mScrambled) {
+        mSubSamples.push_back({payloadSizeBits / 8,
+                 transport_scrambling_control, random_access_indicator});
+    }
+
     return OK;
 }
 
@@ -789,6 +954,7 @@
     mPesStartOffsets.clear();
     mEOSReached = false;
     mBuffer->setRange(0, 0);
+    mSubSamples.clear();
 
     bool clearFormat = false;
     if (isAudio()) {
@@ -817,7 +983,15 @@
     }
 
     if (mSource != NULL) {
-        mSource->queueDiscontinuity(type, extra, true);
+        sp<MetaData> meta = mSource->getFormat();
+        const char* mime;
+        if (clearFormat && meta != NULL && meta->findCString(kKeyMIMEType, &mime)
+                && (!strncasecmp(mime, MEDIA_MIMETYPE_AUDIO_SCRAMBLED, 15)
+                 || !strncasecmp(mime, MEDIA_MIMETYPE_VIDEO_SCRAMBLED, 15))){
+            mSource->clear();
+        } else {
+            mSource->queueDiscontinuity(type, extra, true);
+        }
     }
 }
 
@@ -830,6 +1004,8 @@
 }
 
 status_t ATSParser::Stream::parsePES(ABitReader *br, SyncEvent *event) {
+    const uint8_t *basePtr = br->data();
+
     unsigned packet_startcode_prefix = br->getBits(24);
 
     ALOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix);
@@ -859,7 +1035,9 @@
             return ERROR_MALFORMED;
         }
 
-        MY_LOGV("PES_scrambling_control = %u", br->getBits(2));
+        unsigned PES_scrambling_control = br->getBits(2);
+        ALOGV("PES_scrambling_control = %u", PES_scrambling_control);
+
         MY_LOGV("PES_priority = %u", br->getBits(1));
         MY_LOGV("data_alignment_indicator = %u", br->getBits(1));
         MY_LOGV("copyright = %u", br->getBits(1));
@@ -992,6 +1170,7 @@
         br->skipBits(optional_bytes_remaining * 8);
 
         // ES data follows.
+        int32_t pesOffset = br->data() - basePtr;
 
         if (PES_packet_length != 0) {
             if (PES_packet_length < PES_header_data_length + 3) {
@@ -1009,21 +1188,26 @@
                 return ERROR_MALFORMED;
             }
 
+            ALOGV("There's %u bytes of payload, PES_packet_length=%u, offset=%d",
+                    dataLength, PES_packet_length, pesOffset);
+
             onPayloadData(
-                    PTS_DTS_flags, PTS, DTS, br->data(), dataLength, event);
+                    PTS_DTS_flags, PTS, DTS, PES_scrambling_control,
+                    br->data(), dataLength, pesOffset, event);
 
             br->skipBits(dataLength * 8);
         } else {
             onPayloadData(
-                    PTS_DTS_flags, PTS, DTS,
-                    br->data(), br->numBitsLeft() / 8, event);
+                    PTS_DTS_flags, PTS, DTS, PES_scrambling_control,
+                    br->data(), br->numBitsLeft() / 8, pesOffset, event);
 
             size_t payloadSizeBits = br->numBitsLeft();
             if (payloadSizeBits % 8 != 0u) {
                 return ERROR_MALFORMED;
             }
 
-            ALOGV("There's %zu bytes of payload.", payloadSizeBits / 8);
+            ALOGV("There's %zu bytes of payload, offset=%d",
+                    payloadSizeBits / 8, pesOffset);
         }
     } else if (stream_id == 0xbe) {  // padding_stream
         if (PES_packet_length == 0u) {
@@ -1040,6 +1224,200 @@
     return OK;
 }
 
+uint32_t ATSParser::Stream::getPesScramblingControl(
+        ABitReader *br, int32_t *pesOffset) {
+    unsigned packet_startcode_prefix = br->getBits(24);
+
+    ALOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix);
+
+    if (packet_startcode_prefix != 1) {
+        ALOGV("unit does not start with startcode.");
+        return 0;
+    }
+
+    if (br->numBitsLeft() < 48) {
+        return 0;
+    }
+
+    unsigned stream_id = br->getBits(8);
+    ALOGV("stream_id = 0x%02x", stream_id);
+
+    br->skipBits(16); // PES_packet_length
+
+    if (stream_id != 0xbc  // program_stream_map
+            && stream_id != 0xbe  // padding_stream
+            && stream_id != 0xbf  // private_stream_2
+            && stream_id != 0xf0  // ECM
+            && stream_id != 0xf1  // EMM
+            && stream_id != 0xff  // program_stream_directory
+            && stream_id != 0xf2  // DSMCC
+            && stream_id != 0xf8) {  // H.222.1 type E
+        if (br->getBits(2) != 2u) {
+            return 0;
+        }
+
+        unsigned PES_scrambling_control = br->getBits(2);
+        ALOGV("PES_scrambling_control = %u", PES_scrambling_control);
+
+        if (PES_scrambling_control == 0) {
+            return 0;
+        }
+
+        br->skipBits(12); // don't care
+
+        unsigned PES_header_data_length = br->getBits(8);
+        ALOGV("PES_header_data_length = %u", PES_header_data_length);
+
+        if (PES_header_data_length * 8 > br->numBitsLeft()) {
+            return 0;
+        }
+
+        *pesOffset = 9 + PES_header_data_length;
+        ALOGD("found PES_scrambling_control=%d, PES offset=%d",
+                PES_scrambling_control, *pesOffset);
+        return PES_scrambling_control;
+    }
+
+    return 0;
+}
+
+status_t ATSParser::Stream::flushScrambled(SyncEvent *event) {
+    if (mDescrambler == NULL) {
+        ALOGE("received scrambled packets without descrambler!");
+        return UNKNOWN_ERROR;
+    }
+
+    if (mDescrambledBuffer == NULL || mMem == NULL) {
+        ALOGE("received scrambled packets without shared memory!");
+
+        return UNKNOWN_ERROR;
+    }
+
+    int32_t pesOffset = 0;
+    int32_t descrambleSubSamples = 0, descrambleBytes = 0;
+    uint32_t tsScramblingControl = 0, pesScramblingControl = 0;
+
+    // First, go over subsamples to find TS-level scrambling key id, and
+    // calculate how many subsample we need to descramble (assuming we don't
+    // have PES-level scrambling).
+    for (auto it = mSubSamples.begin(); it != mSubSamples.end(); it++) {
+        if (it->transport_scrambling_mode != 0) {
+            // TODO: handle keyId change, use the first non-zero keyId for now.
+            if (tsScramblingControl == 0) {
+                tsScramblingControl = it->transport_scrambling_mode;
+            }
+        }
+        if (tsScramblingControl == 0 || descrambleSubSamples == 0
+                || !mQueue->isScrambled()) {
+            descrambleSubSamples++;
+            descrambleBytes += it->subSampleSize;
+        }
+    }
+    // If not scrambled at TS-level, check PES-level scrambling
+    if (tsScramblingControl == 0) {
+        ABitReader br(mBuffer->data(), mBuffer->size());
+        pesScramblingControl = getPesScramblingControl(&br, &pesOffset);
+        // If not scrambled at PES-level either, or scrambled at PES-level but
+        // requires output to remain scrambled, we don't need to descramble
+        // anything.
+        if (pesScramblingControl == 0 || mQueue->isScrambled()) {
+            descrambleSubSamples = 0;
+            descrambleBytes = 0;
+        }
+    }
+
+    uint32_t sctrl = tsScramblingControl != 0 ?
+            tsScramblingControl : pesScramblingControl;
+
+    // Perform the 1st pass descrambling if needed
+    if (descrambleBytes > 0) {
+        memcpy(mDescrambledBuffer->data(), mBuffer->data(), descrambleBytes);
+        mDescrambledBuffer->setRange(0, descrambleBytes);
+
+        sp<ABuffer> subSamples = new ABuffer(
+                sizeof(DescramblerPlugin::SubSample) * descrambleSubSamples);
+
+        DescrambleInfo info;
+        info.dstType = DescrambleInfo::kDestinationTypeVmPointer;
+        info.scramblingControl = (DescramblerPlugin::ScramblingControl)sctrl;
+        info.numSubSamples = descrambleSubSamples;
+        info.subSamples = (DescramblerPlugin::SubSample *)subSamples->data();
+        info.srcMem = mMem;
+        info.srcOffset = 0;
+        info.dstPtr = NULL; // in-place descrambling into srcMem
+        info.dstOffset = 0;
+
+        int32_t i = 0;
+        for (auto it = mSubSamples.begin();
+                it != mSubSamples.end() && i < descrambleSubSamples; it++, i++) {
+            if (it->transport_scrambling_mode != 0 || pesScramblingControl != 0) {
+                info.subSamples[i].mNumBytesOfClearData = 0;
+                info.subSamples[i].mNumBytesOfEncryptedData = it->subSampleSize;
+            } else {
+                info.subSamples[i].mNumBytesOfClearData = it->subSampleSize;
+                info.subSamples[i].mNumBytesOfEncryptedData = 0;
+            }
+        }
+        // If scrambled at PES-level, PES header should be skipped
+        if (pesScramblingControl != 0) {
+            info.srcOffset = info.dstOffset = pesOffset;
+            info.subSamples[0].mNumBytesOfEncryptedData -= pesOffset;
+        }
+
+        int32_t result;
+        Status status = mDescrambler->descramble(info, &result);
+
+        if (!status.isOk()) {
+            ALOGE("[stream %d] descramble failed, exceptionCode=%d",
+                    mElementaryPID, status.exceptionCode());
+            return UNKNOWN_ERROR;
+        }
+
+        ALOGV("[stream %d] descramble succeeded, %d bytes",
+                mElementaryPID, result);
+        memcpy(mBuffer->data(), mDescrambledBuffer->data(), descrambleBytes);
+    }
+
+    if (mQueue->isScrambled()) {
+        // Queue subSample info for scrambled queue
+        sp<ABuffer> clearSizesBuffer = new ABuffer(mSubSamples.size() * 4);
+        sp<ABuffer> encSizesBuffer = new ABuffer(mSubSamples.size() * 4);
+        int32_t *clearSizePtr = (int32_t*)clearSizesBuffer->data();
+        int32_t *encSizePtr = (int32_t*)encSizesBuffer->data();
+        int32_t isSync = 0;
+        int32_t i = 0;
+        for (auto it = mSubSamples.begin();
+                it != mSubSamples.end(); it++, i++) {
+            if ((it->transport_scrambling_mode == 0
+                    && pesScramblingControl == 0)
+                    || i < descrambleSubSamples) {
+                clearSizePtr[i] = it->subSampleSize;
+                encSizePtr[i] = 0;
+            } else {
+                clearSizePtr[i] = 0;
+                encSizePtr[i] = it->subSampleSize;
+            }
+            isSync |= it->random_access_indicator;
+        }
+        // Pass the original TS subsample size now. The PES header adjust
+        // will be applied when the scrambled AU is dequeued.
+        mQueue->appendScrambledData(
+                mBuffer->data(), mBuffer->size(), sctrl,
+                isSync, clearSizesBuffer, encSizesBuffer);
+    }
+
+    ABitReader br(mBuffer->data(), mBuffer->size());
+    status_t err = parsePES(&br, event);
+
+    if (err != OK) {
+        ALOGE("[stream %d] failed to parse descrambled PES, err=%d",
+                mElementaryPID, err);
+    }
+
+    return err;
+}
+
+
 status_t ATSParser::Stream::flush(SyncEvent *event) {
     if (mBuffer == NULL || mBuffer->size() == 0) {
         return OK;
@@ -1047,9 +1425,14 @@
 
     ALOGV("flushing stream 0x%04x size = %zu", mElementaryPID, mBuffer->size());
 
-    ABitReader br(mBuffer->data(), mBuffer->size());
-
-    status_t err = parsePES(&br, event);
+    status_t err = OK;
+    if (mScrambled) {
+        err = flushScrambled(event);
+        mSubSamples.clear();
+    } else {
+        ABitReader br(mBuffer->data(), mBuffer->size());
+        err = parsePES(&br, event);
+    }
 
     mBuffer->setRange(0, 0);
 
@@ -1058,7 +1441,9 @@
 
 void ATSParser::Stream::onPayloadData(
         unsigned PTS_DTS_flags, uint64_t PTS, uint64_t /* DTS */,
-        const uint8_t *data, size_t size, SyncEvent *event) {
+        unsigned PES_scrambling_control,
+        const uint8_t *data, size_t size,
+        int32_t payloadOffset, SyncEvent *event) {
 #if 0
     ALOGI("payload streamType 0x%02x, PTS = 0x%016llx, dPTS = %lld",
           mStreamType,
@@ -1074,7 +1459,8 @@
         timeUs = mProgram->convertPTSToTimestamp(PTS);
     }
 
-    status_t err = mQueue->appendData(data, size, timeUs);
+    status_t err = mQueue->appendData(
+            data, size, timeUs, payloadOffset, PES_scrambling_control);
 
     if (mEOSReached) {
         mQueue->signalEOS();
@@ -1096,9 +1482,11 @@
 
                 const char *mime;
                 if (meta->findCString(kKeyMIMEType, &mime)
-                        && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
-                        && !IsIDR(accessUnit)) {
-                    continue;
+                        && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+                    int32_t sync = 0;
+                    if (!accessUnit->meta()->findInt32("isSync", &sync) || !sync) {
+                        continue;
+                    }
                 }
                 mSource = new AnotherPacketSource(meta);
                 mSource->queueAccessUnit(accessUnit);
@@ -1178,6 +1566,18 @@
     return NULL;
 }
 
+void ATSParser::Stream::setCasSession(
+        const sp<IDescrambler> &descrambler,
+        const std::vector<uint8_t> &sessionId) {
+    if (mSource != NULL && mDescrambler == NULL && descrambler != NULL) {
+        signalDiscontinuity(DISCONTINUITY_FORMAT_ONLY, NULL);
+        mDescrambler = descrambler;
+        if (mQueue->isScrambled()) {
+            mQueue->setCasSession(sessionId);
+        }
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 ATSParser::ATSParser(uint32_t flags)
@@ -1189,6 +1589,7 @@
       mNumTSPacketsParsed(0),
       mNumPCRs(0) {
     mPSISections.add(0 /* PID */, new PSISection);
+    mCasManager = new CasManager();
 }
 
 ATSParser::~ATSParser() {
@@ -1205,6 +1606,17 @@
     return parseTS(&br, event);
 }
 
+status_t ATSParser::setMediaCas(const sp<ICas> &cas) {
+    status_t err = mCasManager->setMediaCas(cas);
+    if (err != OK) {
+        return err;
+    }
+    for (size_t i = 0; i < mPrograms.size(); ++i) {
+        mPrograms.editItemAt(i)->updateCasSessions();
+    }
+    return OK;
+}
+
 void ATSParser::signalDiscontinuity(
         DiscontinuityType type, const sp<AMessage> &extra) {
     int64_t mediaTimeUs;
@@ -1331,6 +1743,8 @@
         ABitReader *br, unsigned PID,
         unsigned continuity_counter,
         unsigned payload_unit_start_indicator,
+        unsigned transport_scrambling_control,
+        unsigned random_access_indicator,
         SyncEvent *event) {
     ssize_t sectionIndex = mPSISections.indexOfKey(PID);
 
@@ -1402,7 +1816,10 @@
     for (size_t i = 0; i < mPrograms.size(); ++i) {
         status_t err;
         if (mPrograms.editItemAt(i)->parsePID(
-                    PID, continuity_counter, payload_unit_start_indicator,
+                    PID, continuity_counter,
+                    payload_unit_start_indicator,
+                    transport_scrambling_control,
+                    random_access_indicator,
                     br, &err, event)) {
             if (err != OK) {
                 return err;
@@ -1414,13 +1831,19 @@
     }
 
     if (!handled) {
+        handled = mCasManager->parsePID(br, PID);
+    }
+
+    if (!handled) {
         ALOGV("PID 0x%04x not handled.", PID);
     }
 
     return OK;
 }
 
-status_t ATSParser::parseAdaptationField(ABitReader *br, unsigned PID) {
+status_t ATSParser::parseAdaptationField(
+        ABitReader *br, unsigned PID, unsigned *random_access_indicator) {
+    *random_access_indicator = 0;
     unsigned adaptation_field_length = br->getBits(8);
 
     if (adaptation_field_length > 0) {
@@ -1435,7 +1858,16 @@
             ALOGV("PID 0x%04x: discontinuity_indicator = 1 (!!!)", PID);
         }
 
-        br->skipBits(2);
+        *random_access_indicator = br->getBits(1);
+        if (*random_access_indicator) {
+            ALOGV("PID 0x%04x: random_access_indicator = 1", PID);
+        }
+
+        unsigned elementary_stream_priority_indicator = br->getBits(1);
+        if (elementary_stream_priority_indicator) {
+            ALOGV("PID 0x%04x: elementary_stream_priority_indicator = 1", PID);
+        }
+
         unsigned PCR_flag = br->getBits(1);
 
         size_t numBitsRead = 4;
@@ -1501,7 +1933,8 @@
     unsigned PID = br->getBits(13);
     ALOGV("PID = 0x%04x", PID);
 
-    MY_LOGV("transport_scrambling_control = %u", br->getBits(2));
+    unsigned transport_scrambling_control = br->getBits(2);
+    ALOGV("transport_scrambling_control = %u", transport_scrambling_control);
 
     unsigned adaptation_field_control = br->getBits(2);
     ALOGV("adaptation_field_control = %u", adaptation_field_control);
@@ -1513,13 +1946,17 @@
 
     status_t err = OK;
 
+    unsigned random_access_indicator = 0;
     if (adaptation_field_control == 2 || adaptation_field_control == 3) {
-        err = parseAdaptationField(br, PID);
+        err = parseAdaptationField(br, PID, &random_access_indicator);
     }
     if (err == OK) {
         if (adaptation_field_control == 1 || adaptation_field_control == 3) {
             err = parsePID(br, PID, continuity_counter,
-                    payload_unit_start_indicator, event);
+                    payload_unit_start_indicator,
+                    transport_scrambling_control,
+                    random_access_indicator,
+                    event);
         }
     }
 
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index faae6c9..4a88713 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -26,11 +26,17 @@
 #include <utils/KeyedVector.h>
 #include <utils/Vector.h>
 #include <utils/RefBase.h>
+#include <vector>
 
 namespace android {
-
+namespace media {
+class ICas;
+class IDescrambler;
+};
+using namespace media;
 class ABitReader;
 struct ABuffer;
+struct AnotherPacketSource;
 
 struct ATSParser : public RefBase {
     enum DiscontinuityType {
@@ -100,6 +106,8 @@
 
     explicit ATSParser(uint32_t flags = 0);
 
+    status_t setMediaCas(const sp<ICas> &cas);
+
     // Feed a TS packet into the parser. uninitialized event with the start
     // offset of this TS packet goes in, and if the parser detects PES with
     // a sync frame, the event will be initiailzed with the start offset of the
@@ -150,6 +158,14 @@
     struct Program;
     struct Stream;
     struct PSISection;
+    struct CasManager;
+    struct CADescriptor {
+        int32_t mSystemID;
+        unsigned mPID;
+        std::vector<uint8_t> mPrivateData;
+    };
+
+    sp<CasManager> mCasManager;
 
     uint32_t mFlags;
     Vector<sp<Program> > mPrograms;
@@ -181,9 +197,13 @@
         ABitReader *br, unsigned PID,
         unsigned continuity_counter,
         unsigned payload_unit_start_indicator,
+        unsigned transport_scrambling_control,
+        unsigned random_access_indicator,
         SyncEvent *event);
 
-    status_t parseAdaptationField(ABitReader *br, unsigned PID);
+    status_t parseAdaptationField(
+            ABitReader *br, unsigned PID, unsigned *random_access_indicator);
+
     // see feedTSPacket().
     status_t parseTS(ABitReader *br, SyncEvent *event);
 
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
index 92c386c..5140e66 100644
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -5,6 +5,7 @@
 LOCAL_SRC_FILES:=                 \
         AnotherPacketSource.cpp   \
         ATSParser.cpp             \
+        CasManager.cpp            \
         ESQueue.cpp               \
         MPEG2PSExtractor.cpp      \
         MPEG2TSExtractor.cpp      \
@@ -14,7 +15,8 @@
 	$(TOP)/frameworks/native/include/media/openmax
 
 LOCAL_CFLAGS += -Werror -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
+LOCAL_SANITIZE_DIAG := cfi
 
 LOCAL_SHARED_LIBRARIES := libmedia
 
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 548f44e..433b1fc 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -204,25 +204,53 @@
         }
 
         MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
+        sp<MetaData> bufmeta = mediaBuffer->meta_data();
 
-        mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
+        bufmeta->setInt64(kKeyTime, timeUs);
 
         int32_t isSync;
         if (buffer->meta()->findInt32("isSync", &isSync)) {
-            mediaBuffer->meta_data()->setInt32(kKeyIsSyncFrame, isSync);
+            bufmeta->setInt32(kKeyIsSyncFrame, isSync);
         }
 
         sp<ABuffer> sei;
         if (buffer->meta()->findBuffer("sei", &sei) && sei != NULL) {
-            mediaBuffer->meta_data()->setData(kKeySEI, 0, sei->data(), sei->size());
+            bufmeta->setData(kKeySEI, 0, sei->data(), sei->size());
         }
 
         sp<ABuffer> mpegUserData;
         if (buffer->meta()->findBuffer("mpegUserData", &mpegUserData) && mpegUserData != NULL) {
-            mediaBuffer->meta_data()->setData(
+            bufmeta->setData(
                     kKeyMpegUserData, 0, mpegUserData->data(), mpegUserData->size());
         }
 
+        int32_t cryptoMode;
+        if (buffer->meta()->findInt32("cryptoMode", &cryptoMode)) {
+            int32_t cryptoKey;
+            sp<ABuffer> clearBytesBuffer, encBytesBuffer;
+
+            CHECK(buffer->meta()->findInt32("cryptoKey", &cryptoKey));
+            CHECK(buffer->meta()->findBuffer("clearBytes", &clearBytesBuffer)
+                    && clearBytesBuffer != NULL);
+            CHECK(buffer->meta()->findBuffer("encBytes", &encBytesBuffer)
+                    && encBytesBuffer != NULL);
+
+            bufmeta->setInt32(kKeyCryptoMode, cryptoMode);
+
+            uint8_t array[16] = {0};
+            bufmeta->setData(kKeyCryptoIV, 0, array, 16);
+
+            array[0] = (uint8_t) (cryptoKey & 0xff);
+            bufmeta->setData(kKeyCryptoKey, 0, array, 16);
+
+            bufmeta->setData(kKeyPlainSizes, 0,
+                    clearBytesBuffer->data(), clearBytesBuffer->size());
+
+            bufmeta->setData(kKeyEncryptedSizes, 0,
+                    encBytesBuffer->data(), encBytesBuffer->size());
+        }
+
+
         *out = mediaBuffer;
         return OK;
     }
diff --git a/media/libstagefright/mpeg2ts/CasManager.cpp b/media/libstagefright/mpeg2ts/CasManager.cpp
new file mode 100644
index 0000000..4e34a30
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/CasManager.cpp
@@ -0,0 +1,330 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "CasManager"
+#include "CasManager.h"
+
+#include <android/media/ICas.h>
+#include <android/media/IDescrambler.h>
+#include <android/media/IMediaCasService.h>
+#include <binder/IServiceManager.h>
+#include <media/stagefright/foundation/ABitReader.h>
+#include <utils/Log.h>
+
+namespace android {
+using binder::Status;
+
+struct ATSParser::CasManager::ProgramCasManager : public RefBase {
+    ProgramCasManager(unsigned programNumber, const CADescriptor &descriptor);
+    ProgramCasManager(unsigned programNumber);
+
+    bool addStream(unsigned elementaryPID, const CADescriptor &descriptor);
+
+    status_t setMediaCas(const sp<ICas> &cas, PidToSessionMap &sessionMap);
+
+    bool getCasSession(unsigned elementaryPID,
+            sp<IDescrambler> *descrambler, std::vector<uint8_t> *sessionId) const;
+
+    void closeAllSessions(const sp<ICas>& cas);
+
+private:
+    struct CasSession {
+        CasSession() {}
+        CasSession(const CADescriptor &descriptor) :
+            mCADescriptor(descriptor) {}
+
+        CADescriptor mCADescriptor;
+        std::vector<uint8_t> mSessionId;
+        sp<IDescrambler> mDescrambler;
+    };
+    status_t initSession(
+             const sp<ICas>& cas, PidToSessionMap &sessionMap,
+             CasSession *session, unsigned programNumber, unsigned elementaryPID);
+    void closeSession(const sp<ICas>& cas, const CasSession &casSession);
+
+    unsigned mProgramNumber;
+    bool mHasProgramCas;
+    CasSession mProgramCas;
+    KeyedVector<unsigned, CasSession> mStreamPidToCasMap;
+};
+
+ATSParser::CasManager::ProgramCasManager::ProgramCasManager(
+        unsigned programNumber, const CADescriptor &descriptor) :
+    mProgramNumber(programNumber),
+    mHasProgramCas(true),
+    mProgramCas(descriptor) {}
+
+ATSParser::CasManager::ProgramCasManager::ProgramCasManager(
+        unsigned programNumber) :
+    mProgramNumber(programNumber),
+    mHasProgramCas(false) {}
+
+bool ATSParser::CasManager::ProgramCasManager::addStream(
+        unsigned elementaryPID, const CADescriptor &descriptor) {
+    ssize_t index = mStreamPidToCasMap.indexOfKey(elementaryPID);
+    if (index >= 0) {
+        return false;
+    }
+    ALOGV("addStream: program=%d, elementaryPID=%d, CA_system_ID=0x%x",
+            mProgramNumber, elementaryPID, descriptor.mSystemID);
+    mStreamPidToCasMap.add(elementaryPID, CasSession(descriptor));
+    return true;
+}
+
+status_t ATSParser::CasManager::ProgramCasManager::setMediaCas(
+        const sp<ICas> &cas, PidToSessionMap &sessionMap) {
+    if (mHasProgramCas) {
+        return initSession(cas, sessionMap, &mProgramCas, mProgramNumber, 0);
+    }
+    for (size_t index = 0; index < mStreamPidToCasMap.size(); index++) {
+        unsigned elementaryPID = mStreamPidToCasMap.keyAt(index);
+        status_t err;
+        if ((err = initSession(cas, sessionMap,
+                &mStreamPidToCasMap.editValueAt(index),
+                mProgramNumber, elementaryPID)) != OK) {
+            return err;
+        }
+    }
+    return OK;
+}
+
+bool ATSParser::CasManager::ProgramCasManager::getCasSession(
+        unsigned elementaryPID, sp<IDescrambler> *descrambler,
+        std::vector<uint8_t> *sessionId) const {
+    if (mHasProgramCas) {
+        *descrambler = mProgramCas.mDescrambler;
+        *sessionId = mProgramCas.mSessionId;
+        return true;
+    }
+    ssize_t index = mStreamPidToCasMap.indexOfKey(elementaryPID);
+    if (index < 0) {
+        return false;
+    }
+
+    *descrambler = mStreamPidToCasMap[index].mDescrambler;
+    *sessionId = mStreamPidToCasMap[index].mSessionId;
+    return true;
+}
+
+status_t ATSParser::CasManager::ProgramCasManager::initSession(
+         const sp<ICas>& cas, PidToSessionMap &sessionMap,
+         CasSession *session, unsigned programNumber, unsigned elementaryPID) {
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IBinder> casServiceBinder = sm->getService(String16("media.cas"));
+    sp<IMediaCasService> casService =
+            interface_cast<IMediaCasService>(casServiceBinder);
+
+    if (casService == NULL) {
+        ALOGE("Cannot obtain IMediaCasService");
+        return NO_INIT;
+    }
+
+    sp<IDescrambler> descrambler;
+    std::vector<uint8_t> sessionId;
+    const CADescriptor &descriptor = session->mCADescriptor;
+
+    Status status;
+    if (elementaryPID == 0) {
+        status = cas->openSession(programNumber, &sessionId);
+    } else {
+        status = cas->openSessionForStream(
+                programNumber, elementaryPID, &sessionId);
+    }
+    if (!status.isOk()) {
+        ALOGE("Failed to open session: exception=%d, error=%d",
+                status.exceptionCode(), status.serviceSpecificErrorCode());
+        goto l_fail;
+    }
+
+    cas->setSessionPrivateData(sessionId, descriptor.mPrivateData);
+    if (!status.isOk()) {
+        ALOGE("Failed to set private data: exception=%d, error=%d",
+                status.exceptionCode(), status.serviceSpecificErrorCode());
+        goto l_fail;
+    }
+
+    status = casService->createDescrambler(descriptor.mSystemID, &descrambler);
+    if (!status.isOk() || descrambler == NULL) {
+        ALOGE("Failed to create descrambler: : exception=%d, error=%d",
+                status.exceptionCode(), status.serviceSpecificErrorCode());
+        goto l_fail;
+    }
+
+    status = descrambler->setMediaCasSession(sessionId);
+    if (!status.isOk()) {
+        ALOGE("Failed to init descrambler: : exception=%d, error=%d",
+                status.exceptionCode(), status.serviceSpecificErrorCode());
+        goto l_fail;
+    }
+
+    session->mSessionId = sessionId;
+    session->mDescrambler = descrambler;
+    sessionMap.add(descriptor.mPID, sessionId);
+
+    return OK;
+
+l_fail:
+    if (!sessionId.empty()) {
+        cas->closeSession(sessionId);
+    }
+    if (descrambler != NULL) {
+        descrambler->release();
+    }
+    return NO_INIT;
+}
+
+void ATSParser::CasManager::ProgramCasManager::closeSession(
+        const sp<ICas>& cas, const CasSession &casSession) {
+    if (casSession.mDescrambler != NULL) {
+        casSession.mDescrambler->release();
+    }
+    if (!casSession.mSessionId.empty()) {
+        cas->closeSession(casSession.mSessionId);
+    }
+}
+
+void ATSParser::CasManager::ProgramCasManager::closeAllSessions(
+        const sp<ICas>& cas) {
+    if (mHasProgramCas) {
+        closeSession(cas, mProgramCas);
+    }
+    for (size_t index = 0; index < mStreamPidToCasMap.size(); index++) {
+        closeSession(cas, mStreamPidToCasMap.editValueAt(index));
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+ATSParser::CasManager::CasManager() : mSystemId(-1) {}
+
+ATSParser::CasManager::~CasManager() {
+    // Explictly close the sessions opened by us, since the CAS object is owned
+    // by the app and may not go away after the parser is destroyed, and the app
+    // may not have information about the sessions.
+    if (mICas != NULL) {
+        for (size_t index = 0; index < mProgramCasMap.size(); index++) {
+            mProgramCasMap.editValueAt(index)->closeAllSessions(mICas);
+        }
+    }
+}
+
+bool ATSParser::CasManager::setSystemId(int32_t CA_system_ID) {
+    if (mSystemId == -1) {
+        // Verify the CA_system_ID is within range on the first program
+        if (CA_system_ID < 0 || CA_system_ID > 0xffff) {
+            ALOGE("Invalid CA_system_id: %d", CA_system_ID);
+            return false;
+        }
+        mSystemId = CA_system_ID;
+    } else if (mSystemId != CA_system_ID) {
+        // All sessions need to be under the same CA system
+        ALOGE("Multiple CA systems not allowed: %d vs %d",
+                mSystemId, CA_system_ID);
+        return false;
+    }
+    return true;
+}
+
+status_t ATSParser::CasManager::setMediaCas(const sp<ICas> &cas) {
+    if (cas == NULL) {
+        ALOGE("setMediaCas: received NULL object");
+        return BAD_VALUE;
+    }
+    if (mICas != NULL) {
+        ALOGW("setMediaCas: already set");
+        return ALREADY_EXISTS;
+    }
+    for (size_t index = 0; index < mProgramCasMap.size(); index++) {
+        status_t err;
+        if ((err = mProgramCasMap.editValueAt(
+                index)->setMediaCas(cas, mCAPidToSessionIdMap)) != OK) {
+            return err;
+        }
+    }
+    mICas = cas;
+    return OK;
+}
+
+bool ATSParser::CasManager::addProgram(
+        unsigned programNumber, const CADescriptor &descriptor) {
+    if (!setSystemId(descriptor.mSystemID)) {
+        return false;
+    }
+
+    ssize_t index = mProgramCasMap.indexOfKey(programNumber);
+    if (index < 0) {
+        ALOGV("addProgram: programNumber=%d, CA_system_ID=0x%x",
+                programNumber, descriptor.mSystemID);
+        mProgramCasMap.add(programNumber,
+                new ProgramCasManager(programNumber, descriptor));
+        mCAPidSet.insert(descriptor.mPID);
+    }
+    return true;
+}
+
+bool ATSParser::CasManager::addStream(
+        unsigned programNumber, unsigned elementaryPID,
+        const CADescriptor &descriptor) {
+    if (!setSystemId(descriptor.mSystemID)) {
+        return false;
+    }
+
+    ssize_t index = mProgramCasMap.indexOfKey(programNumber);
+    sp<ProgramCasManager> programCasManager;
+    if (index < 0) {
+        ALOGV("addProgram (no CADescriptor): programNumber=%d", programNumber);
+        programCasManager = new ProgramCasManager(programNumber);
+        mProgramCasMap.add(programNumber, programCasManager);
+    } else {
+        programCasManager = mProgramCasMap.editValueAt(index);
+    }
+    if (programCasManager->addStream(elementaryPID, descriptor)) {
+        mCAPidSet.insert(descriptor.mPID);
+    }
+    return true;
+}
+
+bool ATSParser::CasManager::getCasSession(
+        unsigned programNumber, unsigned elementaryPID,
+        sp<IDescrambler> *descrambler, std::vector<uint8_t> *sessionId) const {
+    ssize_t index = mProgramCasMap.indexOfKey(programNumber);
+    if (index < 0) {
+        return false;
+    }
+    return mProgramCasMap[index]->getCasSession(
+            elementaryPID, descrambler, sessionId);
+}
+
+bool ATSParser::CasManager::isCAPid(unsigned pid) {
+    return mCAPidSet.find(pid) != mCAPidSet.end();
+}
+
+bool ATSParser::CasManager::parsePID(ABitReader *br, unsigned pid) {
+    ssize_t index = mCAPidToSessionIdMap.indexOfKey(pid);
+    if (index < 0) {
+        return false;
+    }
+    MediaCas::ParcelableCasData ecm(br->data(), br->numBitsLeft() / 8);
+    Status status = mICas->processEcm(mCAPidToSessionIdMap[index], ecm);
+    if (!status.isOk()) {
+        ALOGE("Failed to process ECM: exception=%d, error=%d",
+                status.exceptionCode(), status.serviceSpecificErrorCode());
+    }
+    return true; // handled
+}
+
+}  // namespace android
diff --git a/media/libstagefright/mpeg2ts/CasManager.h b/media/libstagefright/mpeg2ts/CasManager.h
new file mode 100644
index 0000000..a7a3de9
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/CasManager.h
@@ -0,0 +1,64 @@
+/*
+ * 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_NDEBUG 0
+
+#include "ATSParser.h"
+#include <utils/KeyedVector.h>
+#include <set>
+
+namespace android {
+namespace media {
+class ICas;
+class IDescrambler;
+}
+
+struct ATSParser::CasManager : public RefBase {
+    CasManager();
+    virtual ~CasManager();
+
+    status_t setMediaCas(const sp<ICas> &cas);
+
+    bool addProgram(
+            unsigned programNumber, const CADescriptor &descriptor);
+
+    bool addStream(
+            unsigned programNumber, unsigned elementaryPID,
+            const CADescriptor &descriptor);
+
+    bool getCasSession(
+            unsigned programNumber, unsigned elementaryPID,
+            sp<IDescrambler> *descrambler,
+            std::vector<uint8_t> *sessionId) const;
+
+    bool isCAPid(unsigned pid);
+
+    bool parsePID(ABitReader *br, unsigned pid);
+
+private:
+    typedef KeyedVector<unsigned, std::vector<uint8_t> > PidToSessionMap;
+    struct ProgramCasManager;
+
+    bool setSystemId(int32_t CA_system_ID);
+
+    int32_t mSystemId;
+    sp<ICas> mICas;
+    KeyedVector<unsigned, sp<ProgramCasManager> > mProgramCasMap;
+    PidToSessionMap mCAPidToSessionIdMap;
+    std::set<uint32_t> mCAPidSet;
+};
+
+}  // namespace android
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 96ca405..b933002 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -28,6 +28,8 @@
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/hardware/CryptoAPI.h>
 
 #include "include/avc_utils.h"
 
@@ -53,6 +55,11 @@
 
     mRangeInfos.clear();
 
+    if (mScrambledBuffer != NULL) {
+        mScrambledBuffer->setRange(0, 0);
+    }
+    mScrambledRangeInfos.clear();
+
     if (clearFormat) {
         mFormat.clear();
     }
@@ -246,7 +253,8 @@
 }
 
 status_t ElementaryStreamQueue::appendData(
-        const void *data, size_t size, int64_t timeUs) {
+        const void *data, size_t size, int64_t timeUs,
+        int32_t payloadOffset, uint32_t pesScramblingControl) {
 
     if (mEOSReached) {
         ALOGE("appending data after EOS");
@@ -276,7 +284,7 @@
                     return ERROR_MALFORMED;
                 }
 
-                if (startOffset > 0) {
+                if (mFormat == NULL && startOffset > 0) {
                     ALOGI("found something resembling an H.264/MPEG syncword "
                           "at offset %zd",
                           startOffset);
@@ -451,6 +459,8 @@
     RangeInfo info;
     info.mLength = size;
     info.mTimestampUs = timeUs;
+    info.mPesOffset = payloadOffset;
+    info.mPesScramblingControl = pesScramblingControl;
     mRangeInfos.push_back(info);
 
 #if 0
@@ -463,8 +473,129 @@
     return OK;
 }
 
+void ElementaryStreamQueue::appendScrambledData(
+        const void *data, size_t size,
+        int32_t keyId, bool isSync,
+        sp<ABuffer> clearSizes, sp<ABuffer> encSizes) {
+    if (!isScrambled()) {
+        return;
+    }
+
+    size_t neededSize = (mScrambledBuffer == NULL ? 0 : mScrambledBuffer->size()) + size;
+    if (mScrambledBuffer == NULL || neededSize > mScrambledBuffer->capacity()) {
+        neededSize = (neededSize + 65535) & ~65535;
+
+        ALOGI("resizing scrambled buffer to size %zu", neededSize);
+
+        sp<ABuffer> buffer = new ABuffer(neededSize);
+        if (mScrambledBuffer != NULL) {
+            memcpy(buffer->data(), mScrambledBuffer->data(), mScrambledBuffer->size());
+            buffer->setRange(0, mScrambledBuffer->size());
+        } else {
+            buffer->setRange(0, 0);
+        }
+
+        mScrambledBuffer = buffer;
+    }
+    memcpy(mScrambledBuffer->data() + mScrambledBuffer->size(), data, size);
+    mScrambledBuffer->setRange(0, mScrambledBuffer->size() + size);
+
+    ScrambledRangeInfo scrambledInfo;
+    scrambledInfo.mLength = size;
+    scrambledInfo.mKeyId = keyId;
+    scrambledInfo.mIsSync = isSync;
+    scrambledInfo.mClearSizes = clearSizes;
+    scrambledInfo.mEncSizes = encSizes;
+
+    ALOGV("[stream %d] appending scrambled range: size=%zu", mMode, size);
+
+    mScrambledRangeInfos.push_back(scrambledInfo);
+}
+
+sp<ABuffer> ElementaryStreamQueue::dequeueScrambledAccessUnit() {
+    size_t nextScan = mBuffer->size();
+    mBuffer->setRange(0, 0);
+    int32_t pesOffset = 0, pesScramblingControl = 0;
+    int64_t timeUs = fetchTimestamp(nextScan, &pesOffset, &pesScramblingControl);
+    if (timeUs < 0ll) {
+        ALOGE("Negative timeUs");
+        return NULL;
+    }
+
+    // return scrambled unit
+    int32_t keyId = pesScramblingControl, isSync = 0, scrambledLength = 0;
+    sp<ABuffer> clearSizes, encSizes;
+    while (mScrambledRangeInfos.size() > mRangeInfos.size()) {
+        auto it = mScrambledRangeInfos.begin();
+        ALOGV("[stream %d] fetching scrambled range: size=%zu", mMode, it->mLength);
+
+        if (scrambledLength > 0) {
+            // This shouldn't happen since we always dequeue the entire PES.
+            ALOGW("Discarding srambled length %d", scrambledLength);
+        }
+        scrambledLength = it->mLength;
+
+        // TODO: handle key id change, use first non-zero keyId for now
+        if (keyId == 0) {
+            keyId = it->mKeyId;
+        }
+        clearSizes = it->mClearSizes;
+        encSizes = it->mEncSizes;
+        isSync = it->mIsSync;
+        mScrambledRangeInfos.erase(it);
+    }
+    if (scrambledLength == 0) {
+        ALOGE("[stream %d] empty scrambled unit!", mMode);
+        return NULL;
+    }
+
+    // skip the PES header, and copy the rest into scrambled access unit
+    sp<ABuffer> scrambledAccessUnit = ABuffer::CreateAsCopy(
+            mScrambledBuffer->data() + pesOffset,
+            scrambledLength - pesOffset);
+
+    // fix up first sample size after skipping the PES header
+    if (pesOffset > 0) {
+        int32_t &firstClearSize = *(int32_t*)clearSizes->data();
+        int32_t &firstEncSize = *(int32_t*)encSizes->data();
+        // Cut away the PES header
+        if (firstClearSize >= pesOffset) {
+            // This is for TS-level scrambling, we descrambled the first
+            // (or it was clear to begin with)
+            firstClearSize -= pesOffset;
+        } else if (firstEncSize >= pesOffset) {
+            // This can only be PES-level scrambling
+            firstEncSize -= pesOffset;
+        }
+    }
+
+    scrambledAccessUnit->meta()->setInt64("timeUs", timeUs);
+    if (isSync) {
+        scrambledAccessUnit->meta()->setInt32("isSync", 1);
+    }
+
+    // fill in CryptoInfo fields for AnotherPacketSource::read()
+    // MediaCas doesn't use cryptoMode, but set to non-zero value here.
+    scrambledAccessUnit->meta()->setInt32(
+            "cryptoMode", CryptoPlugin::kMode_AES_CBC);
+    scrambledAccessUnit->meta()->setInt32("cryptoKey", keyId);
+    scrambledAccessUnit->meta()->setBuffer("clearBytes", clearSizes);
+    scrambledAccessUnit->meta()->setBuffer("encBytes", encSizes);
+
+    memmove(mScrambledBuffer->data(),
+            mScrambledBuffer->data() + scrambledLength,
+            mScrambledBuffer->size() - scrambledLength);
+
+    mScrambledBuffer->setRange(0, mScrambledBuffer->size() - scrambledLength);
+
+    ALOGV("[stream %d] dequeued scrambled AU: timeUs=%lld, size=%zu",
+            mMode, (long long)timeUs, scrambledAccessUnit->size());
+
+    return scrambledAccessUnit;
+}
+
 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
-    if ((mFlags & kFlag_AlignedData) && mMode == H264) {
+    if ((mFlags & kFlag_AlignedData) && mMode == H264 && !isScrambled()) {
         if (mRangeInfos.empty()) {
             return NULL;
         }
@@ -751,7 +882,8 @@
     return accessUnit;
 }
 
-int64_t ElementaryStreamQueue::fetchTimestamp(size_t size) {
+int64_t ElementaryStreamQueue::fetchTimestamp(
+        size_t size, int32_t *pesOffset, int32_t *pesScramblingControl) {
     int64_t timeUs = -1;
     bool first = true;
 
@@ -764,6 +896,12 @@
 
         if (first) {
             timeUs = info->mTimestampUs;
+            if (pesOffset != NULL) {
+                *pesOffset = info->mPesOffset;
+            }
+            if (pesScramblingControl != NULL) {
+                *pesScramblingControl = info->mPesScramblingControl;
+            }
             first = false;
         }
 
@@ -787,6 +925,25 @@
 }
 
 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
+    if (isScrambled()) {
+        if (mBuffer == NULL || mBuffer->size() == 0) {
+            return NULL;
+        }
+        if (mFormat == NULL) {
+            mFormat = MakeAVCCodecSpecificData(mBuffer);
+            if (mFormat == NULL) {
+                ALOGI("Creating dummy AVC format for scrambled content");
+                mFormat = new MetaData;
+                mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+                mFormat->setInt32(kKeyWidth, 1280);
+                mFormat->setInt32(kKeyHeight, 720);
+            }
+            // for DrmInitData
+            mFormat->setData(kKeyCas, 0, mCasSessionId.data(), mCasSessionId.size());
+        }
+        return dequeueScrambledAccessUnit();
+    }
+
     const uint8_t *data = mBuffer->data();
 
     size_t size = mBuffer->size();
@@ -1045,6 +1202,23 @@
 }
 
 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() {
+    if (isScrambled()) {
+        if (mBuffer == NULL || mBuffer->size() == 0) {
+            return NULL;
+        }
+        if (mFormat == NULL) {
+            ALOGI("Creating dummy MPEG format for scrambled content");
+            mFormat = new MetaData;
+            mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
+            mFormat->setInt32(kKeyWidth, 1280);
+            mFormat->setInt32(kKeyHeight, 720);
+
+            // for DrmInitData
+            mFormat->setData(kKeyCas, 0, mCasSessionId.data(), mCasSessionId.size());
+        }
+        return dequeueScrambledAccessUnit();
+    }
+
     const uint8_t *data = mBuffer->data();
     size_t size = mBuffer->size();
 
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index 56f0706..6941e3f 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -22,6 +22,7 @@
 #include <utils/Errors.h>
 #include <utils/List.h>
 #include <utils/RefBase.h>
+#include <vector>
 
 namespace android {
 
@@ -30,6 +31,7 @@
 
 struct ElementaryStreamQueue {
     enum Mode {
+        INVALID = 0,
         H264,
         AAC,
         AC3,
@@ -43,10 +45,19 @@
     enum Flags {
         // Data appended to the queue is always at access unit boundaries.
         kFlag_AlignedData = 1,
+        kFlag_ScrambledData = 2,
     };
     explicit ElementaryStreamQueue(Mode mode, uint32_t flags = 0);
 
-    status_t appendData(const void *data, size_t size, int64_t timeUs);
+    status_t appendData(const void *data, size_t size,
+            int64_t timeUs, int32_t payloadOffset = 0,
+            uint32_t pesScramblingControl = 0);
+
+    void appendScrambledData(
+            const void *data, size_t size,
+            int32_t keyId, bool isSync,
+            sp<ABuffer> clearSizes, sp<ABuffer> encSizes);
+
     void signalEOS();
     void clear(bool clearFormat);
 
@@ -54,10 +65,29 @@
 
     sp<MetaData> getFormat();
 
+    bool isScrambled() {
+        return (mFlags & kFlag_ScrambledData) != 0;
+    }
+
+    void setCasSession(const std::vector<uint8_t> &sessionId) {
+        mCasSessionId = sessionId;
+    }
+
 private:
     struct RangeInfo {
         int64_t mTimestampUs;
         size_t mLength;
+        int32_t mPesOffset;
+        uint32_t mPesScramblingControl;
+    };
+
+    struct ScrambledRangeInfo {
+        //int64_t mTimestampUs;
+        size_t mLength;
+        int32_t mKeyId;
+        int32_t mIsSync;
+        sp<ABuffer> mClearSizes;
+        sp<ABuffer> mEncSizes;
     };
 
     Mode mMode;
@@ -67,6 +97,10 @@
     sp<ABuffer> mBuffer;
     List<RangeInfo> mRangeInfos;
 
+    sp<ABuffer> mScrambledBuffer;
+    List<ScrambledRangeInfo> mScrambledRangeInfos;
+    std::vector<uint8_t> mCasSessionId;
+
     sp<MetaData> mFormat;
 
     sp<ABuffer> dequeueAccessUnitH264();
@@ -80,7 +114,11 @@
 
     // consume a logical (compressed) access unit of size "size",
     // returns its timestamp in us (or -1 if no time information).
-    int64_t fetchTimestamp(size_t size);
+    int64_t fetchTimestamp(size_t size,
+            int32_t *pesOffset = NULL,
+            int32_t *pesScramblingControl = NULL);
+
+    sp<ABuffer> dequeueScrambledAccessUnit();
 
     DISALLOW_EVIL_CONSTRUCTORS(ElementaryStreamQueue);
 };
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index bde33dc..c3f1274 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -148,12 +148,46 @@
     return meta;
 }
 
+//static
+bool MPEG2TSExtractor::isScrambledFormat(const sp<MetaData> &format) {
+    const char *mime;
+    return format->findCString(kKeyMIMEType, &mime)
+            && (!strcasecmp(MEDIA_MIMETYPE_VIDEO_SCRAMBLED, mime)
+                    || !strcasecmp(MEDIA_MIMETYPE_AUDIO_SCRAMBLED, mime));
+}
+
+status_t MPEG2TSExtractor::setMediaCas(const sp<ICas> &cas) {
+    ALOGD("setMediaCas: %p", cas.get());
+
+    status_t err = mParser->setMediaCas(cas);
+    if (err == OK) {
+        ALOGI("All tracks now have descramblers");
+        init();
+    }
+    return err;
+}
+
+void MPEG2TSExtractor::addSource(const sp<AnotherPacketSource> &impl) {
+    bool found = false;
+    for (size_t i = 0; i < mSourceImpls.size(); i++) {
+        if (mSourceImpls[i] == impl) {
+            found = true;
+            break;
+        }
+    }
+    if (!found) {
+        mSourceImpls.push(impl);
+    }
+}
+
 void MPEG2TSExtractor::init() {
     bool haveAudio = false;
     bool haveVideo = false;
     int64_t startTime = ALooper::GetNowUs();
 
-    while (feedMore(true /* isInit */) == OK) {
+    status_t err;
+    while ((err = feedMore(true /* isInit */)) == OK
+            || err == ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED) {
         if (haveAudio && haveVideo) {
             addSyncPoint_l(mLastSyncEvent);
             mLastSyncEvent.reset();
@@ -165,10 +199,15 @@
                         ATSParser::VIDEO).get();
 
             if (impl != NULL) {
-                haveVideo = true;
-                mSourceImpls.push(impl);
-                mSyncPoints.push();
-                mSeekSyncPoints = &mSyncPoints.editTop();
+                sp<MetaData> format = impl->getFormat();
+                if (format != NULL) {
+                    haveVideo = true;
+                    addSource(impl);
+                    if (!isScrambledFormat(format)) {
+                        mSyncPoints.push();
+                        mSeekSyncPoints = &mSyncPoints.editTop();
+                    }
+                }
             }
         }
 
@@ -178,11 +217,16 @@
                         ATSParser::AUDIO).get();
 
             if (impl != NULL) {
-                haveAudio = true;
-                mSourceImpls.push(impl);
-                mSyncPoints.push();
-                if (!haveVideo) {
-                    mSeekSyncPoints = &mSyncPoints.editTop();
+                sp<MetaData> format = impl->getFormat();
+                if (format != NULL) {
+                    haveAudio = true;
+                    addSource(impl);
+                    if (!isScrambledFormat(format)) {
+                        mSyncPoints.push();
+                        if (!haveVideo) {
+                            mSeekSyncPoints = &mSyncPoints.editTop();
+                        }
+                    }
                 }
             }
         }
@@ -190,6 +234,16 @@
         addSyncPoint_l(mLastSyncEvent);
         mLastSyncEvent.reset();
 
+        // ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED is returned when the mpeg2ts
+        // is scrambled but we don't have a MediaCas object set. The extraction
+        // will only continue when setMediaCas() is called successfully.
+        if (err == ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED) {
+            ALOGI("stopped parsing scrambled content, "
+                  "haveAudio=%d, haveVideo=%d, elaspedTime=%" PRId64,
+                    haveAudio, haveVideo, ALooper::GetNowUs() - startTime);
+            return;
+        }
+
         // Wait only for 2 seconds to detect audio/video streams.
         if (ALooper::GetNowUs() - startTime > 2000000ll) {
             break;
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 4909100..2f457ac 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -43,15 +43,46 @@
 
 static const OMX_U32 kPortIndexInput = 0;
 
+class GraphicBufferSource::OmxBufferSource : public BnOMXBufferSource {
+public:
+    GraphicBufferSource* mSource;
+
+    OmxBufferSource(GraphicBufferSource* source): mSource(source) {
+    }
+
+    Status onOmxExecuting() override {
+        return mSource->onOmxExecuting();
+    }
+
+    Status onOmxIdle() override {
+        return mSource->onOmxIdle();
+    }
+
+    Status onOmxLoaded() override {
+        return mSource->onOmxLoaded();
+    }
+
+    Status onInputBufferAdded(int bufferId) override {
+        return mSource->onInputBufferAdded(bufferId);
+    }
+
+    Status onInputBufferEmptied(
+            int bufferId, const OMXFenceParcelable& fenceParcel) override {
+        return mSource->onInputBufferEmptied(bufferId, fenceParcel);
+    }
+};
+
 GraphicBufferSource::GraphicBufferSource() :
     mInitCheck(UNKNOWN_ERROR),
     mExecuting(false),
     mSuspended(false),
+    mStopTimeUs(-1),
     mLastDataSpace(HAL_DATASPACE_UNKNOWN),
     mNumFramesAvailable(0),
     mNumBufferAcquired(0),
     mEndOfStream(false),
     mEndOfStreamSent(false),
+    mLastActionTimeUs(-1ll),
     mPrevOriginalTimeUs(-1ll),
     mSkipFramesBeforeNs(-1ll),
     mRepeatAfterUs(-1ll),
@@ -66,7 +97,8 @@
     mTimePerFrameUs(-1ll),
     mPrevCaptureUs(-1ll),
     mPrevFrameUs(-1ll),
-    mInputBufferTimeOffsetUs(0ll) {
+    mInputBufferTimeOffsetUs(0ll),
+    mOmxBufferSource(new OmxBufferSource(this)) {
     ALOGV("GraphicBufferSource");
 
     String8 name("GraphicBufferSource");
@@ -141,7 +173,7 @@
 
     // If EOS has already been signaled, and there are no more frames to
     // submit, try to send EOS now as well.
-    if (mEndOfStream && mNumFramesAvailable == 0) {
+    if (mStopTimeUs == -1 && mEndOfStream && mNumFramesAvailable == 0) {
         submitEndOfInputStream_l();
     }
 
@@ -318,8 +350,8 @@
         ALOGV("buffer freed, %zu frames avail (eos=%d)",
                 mNumFramesAvailable, mEndOfStream);
         fillCodecBuffer_l();
-    } else if (mEndOfStream) {
-        // No frames available, but EOS is pending, so use this buffer to
+    } else if (mEndOfStream && mStopTimeUs == -1) {
+        // No frames available, but EOS is pending and no stop time, so use this buffer to
         // send that.
         ALOGV("buffer freed, EOS pending");
         submitEndOfInputStream_l();
@@ -357,7 +389,7 @@
 bool GraphicBufferSource::fillCodecBuffer_l() {
     CHECK(mExecuting && mNumFramesAvailable > 0);
 
-    if (mSuspended) {
+    if (mSuspended && mActionQueue.empty()) {
         return false;
     }
 
@@ -378,8 +410,85 @@
         return false;
     }
 
+    int64_t itemTimeUs = item.mTimestamp / 1000;
+
     mNumFramesAvailable--;
 
+    // Process ActionItem in the Queue if there is any. If a buffer's timestamp
+    // is smaller than the first action's timestamp, no action need to be performed.
+    // If buffer's timestamp is larger or equal than the last action's timestamp,
+    // only the last action needs to be performed as all the acitions before the
+    // the action are overridden by the last action. For the other cases, traverse
+    // the Queue to find the newest action that with timestamp smaller or equal to
+    // the buffer's timestamp. For example, an action queue like
+    // [pause, 1s], [resume 2us], [pause 3us], [resume 4us], [pause 5us].... Upon
+    // receiving a buffer with timestamp 3.5us, only the action [pause, 3us] needs
+    // to be handled and [pause, 1us], [resume 2us] will be discarded.
+    bool dropped = false;
+    bool done = false;
+    if (!mActionQueue.empty()) {
+        // First scan to check if bufferTimestamp is smaller than first action's timestamp.
+        ActionItem nextAction = *(mActionQueue.begin());
+        if (itemTimeUs < nextAction.mActionTimeUs) {
+            ALOGV("No action. buffer timestamp %lld us < action timestamp: %lld us",
+                (long long)itemTimeUs, (long long)nextAction.mActionTimeUs);
+            // All the actions are ahead. No action need to perform now.
+            // Release the buffer if is in suspended state, or process the buffer
+            // if not in suspended state.
+            dropped = mSuspended;
+            done = true;
+        }
+
+        if (!done) {
+            List<ActionItem>::iterator it = mActionQueue.begin();
+            while(it != mActionQueue.end()) {
+                nextAction = *it;
+                mActionQueue.erase(it);
+                if (nextAction.mActionTimeUs > itemTimeUs) {
+                    break;
+                }
+                ++it;
+            }
+
+            CHECK(itemTimeUs >= nextAction.mActionTimeUs);
+            switch (nextAction.mAction) {
+                case ActionItem::PAUSE:
+                {
+                    mSuspended = true;
+                    dropped = true;
+                    ALOGV("RUNNING/PAUSE -> PAUSE at buffer %lld us  PAUSE Time: %lld us",
+                            (long long)itemTimeUs, (long long)nextAction.mActionTimeUs);
+                    break;
+                }
+                case ActionItem::RESUME:
+                {
+                    mSuspended = false;
+                    ALOGV("PAUSE/RUNNING -> RUNNING at buffer %lld us  RESUME Time: %lld us",
+                            (long long)itemTimeUs, (long long)nextAction.mActionTimeUs);
+                    break;
+                }
+                case ActionItem::STOP:
+                {
+                    ALOGV("RUNNING/PAUSE -> STOP at buffer %lld us  STOP Time: %lld us",
+                            (long long)itemTimeUs, (long long)nextAction.mActionTimeUs);
+                    dropped = true;
+                    // Clear the whole ActionQueue as recording is done
+                    mActionQueue.clear();
+                    submitEndOfInputStream_l();
+                    break;
+                }
+                default:
+                    ALOGE("Unknown action type");
+                    return false;
+            }
+        }
+    }
+
+    if (dropped) {
+        releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
+        return true;
+    }
+
     if (item.mDataSpace != mLastDataSpace) {
         onDataSpaceChanged_l(
                 item.mDataSpace, (android_pixel_format)mBufferSlot[item.mSlot]->getPixelFormat());
@@ -389,7 +498,6 @@
 
     // only submit sample if start time is unspecified, or sample
     // is queued after the specified start time
-    bool dropped = false;
     if (mSkipFramesBeforeNs < 0ll || item.mTimestamp >= mSkipFramesBeforeNs) {
         // if start time is set, offset time stamp by start time
         if (mSkipFramesBeforeNs > 0) {
@@ -689,12 +797,12 @@
     ALOGV("onFrameAvailable exec=%d avail=%zu",
             mExecuting, mNumFramesAvailable);
 
-    if (mOMXNode == NULL || mEndOfStream || mSuspended) {
-        if (mEndOfStream) {
+    if (mOMXNode == NULL || mEndOfStreamSent || (mSuspended && mActionQueue.empty())) {
+        if (mEndOfStreamSent) {
             // This should only be possible if a new buffer was queued after
             // EOS was signaled, i.e. the app is misbehaving.
 
-            ALOGW("onFrameAvailable: EOS is set, ignoring frame");
+            ALOGW("onFrameAvailable: EOS is sent, ignoring frame");
         } else {
             ALOGV("onFrameAvailable: suspended, ignoring frame");
         }
@@ -766,7 +874,7 @@
     // Do setInputSurface() first, the node will try to enable metadata
     // mode on input, and does necessary error checking. If this fails,
     // we can't use this input surface on the node.
-    status_t err = omxNode->setInputSurface(this);
+    status_t err = omxNode->setInputSurface(mOmxBufferSource);
     if (err != NO_ERROR) {
         ALOGE("Unable to set input surface: %d", err);
         return Status::fromServiceSpecificError(err);
@@ -845,44 +953,74 @@
         mPrevCaptureUs = -1ll;
         mPrevFrameUs = -1ll;
         mInputBufferTimeOffsetUs = 0;
+        mStopTimeUs = -1;
+        mActionQueue.clear();
     }
 
     return Status::ok();
 }
 
-Status GraphicBufferSource::setSuspend(bool suspend) {
-    ALOGV("setSuspend=%d", suspend);
+Status GraphicBufferSource::setSuspend(bool suspend, int64_t suspendStartTimeUs) {
+    ALOGV("setSuspend=%d at time %lld us", suspend, (long long)suspendStartTimeUs);
 
     Mutex::Autolock autoLock(mMutex);
 
-    if (suspend) {
-        mSuspended = true;
-
-        while (mNumFramesAvailable > 0) {
-            BufferItem item;
-            status_t err = acquireBuffer(&item);
-
-            if (err != OK) {
-                ALOGE("setSuspend: acquireBuffer returned err=%d", err);
-                break;
-            }
-
-            --mNumFramesAvailable;
-
-            releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
-        }
-        return Status::ok();
+    if (mStopTimeUs != -1) {
+        ALOGE("setSuspend failed as STOP action is pending");
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
     }
 
-    mSuspended = false;
+    // Push the action to the queue.
+    if (suspendStartTimeUs != -1) {
+        // suspendStartTimeUs must be smaller or equal to current systemTime.
+        int64_t currentSystemTimeUs = systemTime() / 1000;
+        if (suspendStartTimeUs > currentSystemTimeUs) {
+            ALOGE("setSuspend failed. %lld is larger than current system time %lld us",
+                    (long long)suspendStartTimeUs, (long long)currentSystemTimeUs);
+            return Status::fromServiceSpecificError(INVALID_OPERATION);
+        }
+        if (mLastActionTimeUs != -1 && suspendStartTimeUs < mLastActionTimeUs) {
+            ALOGE("setSuspend failed. %lld is smaller than last action time %lld us",
+                    (long long)suspendStartTimeUs, (long long)mLastActionTimeUs);
+            return Status::fromServiceSpecificError(INVALID_OPERATION);
+        }
+        mLastActionTimeUs = suspendStartTimeUs;
+        ActionItem action;
+        action.mAction = suspend ? ActionItem::PAUSE : ActionItem::RESUME;
+        action.mActionTimeUs = suspendStartTimeUs;
+        ALOGV("Push %s action into actionQueue", suspend ? "PAUSE" : "RESUME");
+        mActionQueue.push_back(action);
+    } else {
+        if (suspend) {
+            mSuspended = true;
 
-    if (mExecuting && mNumFramesAvailable == 0 && mRepeatBufferDeferred) {
-        if (repeatLatestBuffer_l()) {
-            ALOGV("suspend/deferred repeatLatestBuffer_l SUCCESS");
+            while (mNumFramesAvailable > 0) {
+                BufferItem item;
+                status_t err = acquireBuffer(&item);
 
-            mRepeatBufferDeferred = false;
+                if (err != OK) {
+                    ALOGE("setSuspend: acquireBuffer returned err=%d", err);
+                    break;
+                }
+
+                --mNumFramesAvailable;
+
+                releaseBuffer(item.mSlot, item.mFrameNumber, item.mFence);
+            }
+            return Status::ok();
         } else {
-            ALOGV("suspend/deferred repeatLatestBuffer_l FAILURE");
+
+            mSuspended = false;
+
+            if (mExecuting && mNumFramesAvailable == 0 && mRepeatBufferDeferred) {
+                if (repeatLatestBuffer_l()) {
+                    ALOGV("suspend/deferred repeatLatestBuffer_l SUCCESS");
+
+                    mRepeatBufferDeferred = false;
+                } else {
+                    ALOGV("suspend/deferred repeatLatestBuffer_l FAILURE");
+                }
+            }
         }
     }
     return Status::ok();
@@ -943,6 +1081,36 @@
     return Status::ok();
 }
 
+Status GraphicBufferSource::setStopTimeUs(int64_t stopTimeUs) {
+    ALOGV("setStopTimeUs: %lld us", (long long)stopTimeUs);
+    Mutex::Autolock autoLock(mMutex);
+
+    if (mStopTimeUs != -1) {
+        // Ignore if stop time has already been set
+        return Status::ok();
+    }
+
+    // stopTimeUs must be smaller or equal to current systemTime.
+    int64_t currentSystemTimeUs = systemTime() / 1000;
+    if (stopTimeUs > currentSystemTimeUs) {
+        ALOGE("setStopTimeUs failed. %lld is larger than current system time %lld us",
+            (long long)stopTimeUs, (long long)currentSystemTimeUs);
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
+    }
+    if (mLastActionTimeUs != -1 && stopTimeUs < mLastActionTimeUs) {
+        ALOGE("setSuspend failed. %lld is smaller than last action time %lld us",
+            (long long)stopTimeUs, (long long)mLastActionTimeUs);
+        return Status::fromServiceSpecificError(INVALID_OPERATION);
+    }
+    mLastActionTimeUs = stopTimeUs;
+    ActionItem action;
+    action.mAction = ActionItem::STOP;
+    action.mActionTimeUs = stopTimeUs;
+    mActionQueue.push_back(action);
+    mStopTimeUs = stopTimeUs;
+    return Status::ok();
+}
+
 Status GraphicBufferSource::setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) {
     ALOGV("setTimeLapseConfig: timePerFrameUs=%lld, timePerCaptureUs=%lld",
             (long long)timePerFrameUs, (long long)timePerCaptureUs);
@@ -983,15 +1151,15 @@
 
     // Set the end-of-stream flag.  If no frames are pending from the
     // BufferQueue, and a codec buffer is available, and we're executing,
-    // we initiate the EOS from here.  Otherwise, we'll let
-    // codecBufferEmptied() (or omxExecuting) do it.
+    // and there is no stop timestamp, we initiate the EOS from here.
+    // Otherwise, we'll let codecBufferEmptied() (or omxExecuting) do it.
     //
     // Note: if there are no pending frames and all codec buffers are
     // available, we *must* submit the EOS from here or we'll just
     // stall since no future events are expected.
     mEndOfStream = true;
 
-    if (mExecuting && mNumFramesAvailable == 0) {
+    if (mStopTimeUs == -1 && mExecuting && mNumFramesAvailable == 0) {
         submitEndOfInputStream_l();
     }
 
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 80fe078..475548e 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -55,7 +55,6 @@
  * things up until we're ready to go.
  */
 class GraphicBufferSource : public BnGraphicBufferSource,
-                            public BnOMXBufferSource,
                             public BufferQueue::ConsumerListener {
 public:
     GraphicBufferSource();
@@ -77,39 +76,43 @@
     // This is called when OMX transitions to OMX_StateExecuting, which means
     // we can start handing it buffers.  If we already have buffers of data
     // sitting in the BufferQueue, this will send them to the codec.
-    Status onOmxExecuting() override;
+    Status onOmxExecuting();
 
     // This is called when OMX transitions to OMX_StateIdle, indicating that
     // the codec is meant to return all buffers back to the client for them
     // to be freed. Do NOT submit any more buffers to the component.
-    Status onOmxIdle() override;
+    Status onOmxIdle();
 
     // This is called when OMX transitions to OMX_StateLoaded, indicating that
     // we are shutting down.
-    Status onOmxLoaded() override;
+    Status onOmxLoaded();
 
     // A "codec buffer", i.e. a buffer that can be used to pass data into
     // the encoder, has been allocated.  (This call does not call back into
     // OMXNodeInstance.)
-    Status onInputBufferAdded(int32_t bufferID) override;
+    Status onInputBufferAdded(int32_t bufferID);
 
     // Called from OnEmptyBufferDone.  If we have a BQ buffer available,
     // fill it with a new frame of data; otherwise, just mark it as available.
     Status onInputBufferEmptied(
-            int32_t bufferID, const OMXFenceParcelable& fenceParcel) override;
+            int32_t bufferID, const OMXFenceParcelable& fenceParcel);
 
     // Configure the buffer source to be used with an OMX node with the default
     // data space.
     Status configure(const sp<IOMXNode>& omxNode, int32_t dataSpace) override;
 
-    // This is called after the last input frame has been submitted.  We
-    // need to submit an empty buffer with the EOS flag set.  If we don't
-    // have a codec buffer ready, we just set the mEndOfStream flag.
+    // This is called after the last input frame has been submitted or buffer
+    // timestamp is greater or equal than stopTimeUs. We need to submit an empty
+    // buffer with the EOS flag set.  If we don't have a codec buffer ready,
+    // we just set the mEndOfStream flag.
     Status signalEndOfInputStream() override;
 
     // If suspend is true, all incoming buffers (including those currently
-    // in the BufferQueue) will be discarded until the suspension is lifted.
-    Status setSuspend(bool suspend) override;
+    // in the BufferQueue) with timestamp larger than timeUs will be discarded
+    // until the suspension is lifted. If suspend is false, all incoming buffers
+    // including those currently in the BufferQueue) with timestamp larger than
+    // timeUs will be processed. timeUs uses SYSTEM_TIME_MONOTONIC time base.
+    Status setSuspend(bool suspend, int64_t timeUs) override;
 
     // Specifies the interval after which we requeue the buffer previously
     // queued to the encoder. This is useful in the case of surface flinger
@@ -136,6 +139,10 @@
     // be dropped and not submitted to encoder
     Status setStartTimeUs(int64_t startTimeUs) override;
 
+    // Sets the stop time us (in system time), samples after which should be dropped
+    // and not submitted to encoder. timeUs uses SYSTEM_TIME_MONOTONIC time base.
+    Status setStopTimeUs(int64_t stopTimeUs) override;
+
     // Sets the desired color aspects, e.g. to be used when producer does not specify a dataspace.
     Status setColorAspects(int32_t aspectsPacked) override;
 
@@ -230,6 +237,9 @@
 
     bool mSuspended;
 
+    // The time to stop sending buffers.
+    int64_t mStopTimeUs;
+
     // Last dataspace seen
     android_dataspace mLastDataSpace;
 
@@ -260,6 +270,25 @@
     // Tracks codec buffers.
     Vector<CodecBuffer> mCodecBuffers;
 
+    struct ActionItem {
+        typedef enum {
+            PAUSE,
+            RESUME,
+            STOP
+        } ActionType;
+        ActionType mAction;
+        int64_t mActionTimeUs;
+    };
+
+    // Maintain last action timestamp to ensure all the action timestamps are
+    // monotonically increasing.
+    int64_t mLastActionTimeUs;
+
+    // An action queue that queue up all the actions sent to GraphicBufferSource.
+    // STOP action should only show up at the end of the list as all the actions
+    // after a STOP action will be discarded. mActionQueue is protected by mMutex.
+    List<ActionItem> mActionQueue;
+
     ////
     friend struct AHandlerReflector<GraphicBufferSource>;
 
@@ -301,6 +330,9 @@
 
     ColorAspects mColorAspects;
 
+    class OmxBufferSource;
+    sp<OmxBufferSource> mOmxBufferSource;
+
     void onMessageReceived(const sp<AMessage> &msg);
 
     DISALLOW_EVIL_CONSTRUCTORS(GraphicBufferSource);
diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
index adf846a..c49403d 100644
--- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
@@ -30,8 +30,8 @@
 #include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/MediaDefs.h>
 
-#include <ui/GraphicBuffer.h>
 #include <ui/GraphicBufferMapper.h>
+#include <ui/Rect.h>
 
 #include <OMX_IndexExt.h>
 
diff --git a/media/libstagefright/omx/hal/1.0/impl/Android.mk b/media/libstagefright/omx/hal/1.0/impl/Android.mk
index ccd19d8..09424b5 100644
--- a/media/libstagefright/omx/hal/1.0/impl/Android.mk
+++ b/media/libstagefright/omx/hal/1.0/impl/Android.mk
@@ -2,7 +2,6 @@
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := android.hardware.media.omx@1.0-impl
-LOCAL_MODULE_RELATIVE_PATH := hw
 LOCAL_SRC_FILES := \
     WGraphicBufferSource.cpp \
     WOmx.cpp \
@@ -12,7 +11,6 @@
     WOmxObserver.cpp \
     WOmxProducerListener.cpp \
     Omx.cpp \
-    OmxNode.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
     libmedia \
@@ -28,18 +26,21 @@
     libcutils \
     libbinder \
     liblog \
+    libbase \
     android.hardware.media.omx@1.0 \
     android.hardware.graphics.common@1.0 \
     android.hardware.media@1.0 \
     android.hidl.base@1.0 \
 
+LOCAL_C_FLAGS += \
+    -Wno-unused-parameter \
+    -Werror
+
 LOCAL_C_INCLUDES += \
-        $(TOP) \
-        $(TOP)/frameworks/av/include/media \
-        $(TOP)/frameworks/av/media/libstagefright/include \
-        $(TOP)/frameworks/av/media/libstagefright/omx \
-        $(TOP)/frameworks/native/include/media/hardware \
-        $(TOP)/frameworks/native/include/media/openmax \
+        $(TOP)/frameworks/av/include \
+        $(TOP)/frameworks/av/media/libstagefright \
         $(TOP)/frameworks/native/include \
+        $(TOP)/frameworks/native/include/media/openmax \
+        $(TOP)/frameworks/native/include/media/hardware \
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/omx/hal/1.0/impl/Conversion.h b/media/libstagefright/omx/hal/1.0/impl/Conversion.h
index d27a496..117d1c8 100644
--- a/media/libstagefright/omx/hal/1.0/impl/Conversion.h
+++ b/media/libstagefright/omx/hal/1.0/impl/Conversion.h
@@ -17,29 +17,26 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__CONVERSION_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0__CONVERSION_H
 
+#include <vector>
+#include <list>
+
+#include <unistd.h>
+
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 #include <hidlmemory/mapping.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-
-#include <unistd.h>
-#include <vector>
-#include <list>
 
 #include <binder/Binder.h>
 #include <binder/Status.h>
 #include <ui/FenceTime.h>
-
-#include <OMXFenceParcelable.h>
+#include <media/OMXFenceParcelable.h>
 #include <cutils/native_handle.h>
 #include <gui/IGraphicBufferProducer.h>
 
-#include <IOMX.h>
+#include <media/OMXBuffer.h>
 #include <VideoAPI.h>
-#include <OMXBuffer.h>
-#include <android/IOMXBufferSource.h>
-#include <android/IGraphicBufferSource.h>
 
+#include <android/hidl/memory/1.0/IMemory.h>
 #include <android/hardware/media/omx/1.0/types.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
@@ -49,6 +46,9 @@
 #include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
 #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
 
+#include <android/IGraphicBufferSource.h>
+#include <android/IOMXBufferSource.h>
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -177,25 +177,6 @@
  */
 
 /**
- * \brief Convert `binder::Status` to `Return<void>`.
- *
- * \param[in] l The source `binder::Status`.
- * \return The corresponding `Return<void>`.
- */
-// 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(
-                l.serviceSpecificErrorCode(),
-                l.exceptionMessage());
-    }
-    return ::android::hardware::Status::fromExceptionCode(
-            l.exceptionCode(),
-            l.exceptionMessage());
-}
-
-/**
  * \brief Convert `Return<void>` to `binder::Status`.
  *
  * \param[in] t The source `Return<void>`.
@@ -294,7 +275,7 @@
     if (!*nh) {
         return false;
     }
-    t->fence = inHidlHandle(*nh);
+    t->fence = *nh;
     switch (l.type) {
         case omx_message::EVENT:
             t->type = Message::Type::EVENT;
@@ -560,6 +541,76 @@
 }
 
 /**
+ * \brief Wrap `GraphicBuffer` in `AnwBuffer`.
+ *
+ * \param[out] t The wrapper of type `AnwBuffer`.
+ * \param[in] l The source `GraphicBuffer`.
+ */
+// wrap: GraphicBuffer -> AnwBuffer
+inline void wrapAs(AnwBuffer* t, GraphicBuffer const& l) {
+    t->attr.width = l.getWidth();
+    t->attr.height = l.getHeight();
+    t->attr.stride = l.getStride();
+    t->attr.format = static_cast<PixelFormat>(l.getPixelFormat());
+    t->attr.layerCount = l.getLayerCount();
+    t->attr.usage = l.getUsage();
+    t->attr.id = l.getId();
+    t->attr.generationNumber = l.getGenerationNumber();
+    t->nativeHandle = hidl_handle(l.handle);
+}
+
+/**
+ * \brief Convert `AnwBuffer` to `GraphicBuffer`.
+ *
+ * \param[out] l The destination `GraphicBuffer`.
+ * \param[in] t The source `AnwBuffer`.
+ *
+ * This function will duplicate all file descriptors in \p t.
+ */
+// convert: AnwBuffer -> GraphicBuffer
+// Ref: frameworks/native/libs/ui/GraphicBuffer.cpp: GraphicBuffer::flatten
+inline bool convertTo(GraphicBuffer* l, AnwBuffer const& t) {
+    native_handle_t* handle = t.nativeHandle == nullptr ?
+            nullptr : native_handle_clone(t.nativeHandle);
+
+    size_t const numInts = 12 + (handle ? handle->numInts : 0);
+    int32_t* ints = new int32_t[numInts];
+
+    size_t numFds = static_cast<size_t>(handle ? handle->numFds : 0);
+    int* fds = new int[numFds];
+
+    ints[0] = 'GBFR';
+    ints[1] = static_cast<int32_t>(t.attr.width);
+    ints[2] = static_cast<int32_t>(t.attr.height);
+    ints[3] = static_cast<int32_t>(t.attr.stride);
+    ints[4] = static_cast<int32_t>(t.attr.format);
+    ints[5] = static_cast<int32_t>(t.attr.layerCount);
+    ints[6] = static_cast<int32_t>(t.attr.usage);
+    ints[7] = static_cast<int32_t>(t.attr.id >> 32);
+    ints[8] = static_cast<int32_t>(t.attr.id & 0xFFFFFFFF);
+    ints[9] = static_cast<int32_t>(t.attr.generationNumber);
+    ints[10] = 0;
+    ints[11] = 0;
+    if (handle) {
+        ints[10] = static_cast<int32_t>(handle->numFds);
+        ints[11] = static_cast<int32_t>(handle->numInts);
+        int* intsStart = handle->data + handle->numFds;
+        std::copy(handle->data, intsStart, fds);
+        std::copy(intsStart, intsStart + handle->numInts, &ints[12]);
+    }
+
+    void const* constBuffer = static_cast<void const*>(ints);
+    size_t size = numInts * sizeof(int32_t);
+    int const* constFds = static_cast<int const*>(fds);
+    status_t status = l->unflatten(constBuffer, size, constFds, numFds);
+
+    delete [] fds;
+    delete [] ints;
+    native_handle_delete(handle);
+    return status == NO_ERROR;
+}
+
+/**
  * \brief Wrap `OMXBuffer` in `CodecBuffer`.
  *
  * \param[out] t The wrapper of type `CodecBuffer`.
@@ -568,8 +619,8 @@
  */
 // wrap: OMXBuffer -> CodecBuffer
 inline bool wrapAs(CodecBuffer* t, OMXBuffer const& l) {
-    t->nativeHandle = hidl_handle();
     t->sharedMemory = hidl_memory();
+    t->nativeHandle = hidl_handle();
     switch (l.mBufferType) {
         case OMXBuffer::kBufferTypeInvalid: {
             t->type = CodecBuffer::Type::INVALID;
@@ -592,6 +643,15 @@
         }
         case OMXBuffer::kBufferTypeANWBuffer: {
             t->type = CodecBuffer::Type::ANW_BUFFER;
+            if (l.mGraphicBuffer == nullptr) {
+                t->attr.anwBuffer.width = 0;
+                t->attr.anwBuffer.height = 0;
+                t->attr.anwBuffer.stride = 0;
+                t->attr.anwBuffer.format = static_cast<PixelFormat>(1);
+                t->attr.anwBuffer.layerCount = 0;
+                t->attr.anwBuffer.usage = 0;
+                return true;
+            }
             t->attr.anwBuffer.width = l.mGraphicBuffer->getWidth();
             t->attr.anwBuffer.height = l.mGraphicBuffer->getHeight();
             t->attr.anwBuffer.stride = l.mGraphicBuffer->getStride();
@@ -599,12 +659,12 @@
                     l.mGraphicBuffer->getPixelFormat());
             t->attr.anwBuffer.layerCount = l.mGraphicBuffer->getLayerCount();
             t->attr.anwBuffer.usage = l.mGraphicBuffer->getUsage();
-            t->nativeHandle = hidl_handle(l.mGraphicBuffer->handle);
+            t->nativeHandle = l.mGraphicBuffer->handle;
             return true;
         }
         case OMXBuffer::kBufferTypeNativeHandle: {
             t->type = CodecBuffer::Type::NATIVE_HANDLE;
-            t->nativeHandle = hidl_handle(l.mNativeHandle->handle());
+            t->nativeHandle = l.mNativeHandle->handle();
             return true;
         }
     }
@@ -636,16 +696,18 @@
             return true;
         }
         case CodecBuffer::Type::ANW_BUFFER: {
-            *l = OMXBuffer(sp<GraphicBuffer>(new GraphicBuffer(
-                    t.attr.anwBuffer.width,
-                    t.attr.anwBuffer.height,
-                    static_cast<::android::PixelFormat>(
-                            t.attr.anwBuffer.format),
-                    t.attr.anwBuffer.layerCount,
-                    t.attr.anwBuffer.usage,
-                    t.attr.anwBuffer.stride,
-                    native_handle_clone(t.nativeHandle),
-                    true)));
+            if (t.nativeHandle.getNativeHandle() == nullptr) {
+                *l = OMXBuffer(sp<GraphicBuffer>(nullptr));
+                return true;
+            }
+            AnwBuffer anwBuffer;
+            anwBuffer.nativeHandle = t.nativeHandle;
+            anwBuffer.attr = t.attr.anwBuffer;
+            sp<GraphicBuffer> graphicBuffer = new GraphicBuffer();
+            if (!convertTo(graphicBuffer.get(), anwBuffer)) {
+                return false;
+            }
+            *l = OMXBuffer(graphicBuffer);
             return true;
         }
         case CodecBuffer::Type::NATIVE_HANDLE: {
@@ -820,76 +882,6 @@
 }
 
 /**
- * \brief Wrap `GraphicBuffer` in `AnwBuffer`.
- *
- * \param[out] t The wrapper of type `AnwBuffer`.
- * \param[in] l The source `GraphicBuffer`.
- */
-// wrap: GraphicBuffer -> AnwBuffer
-inline void wrapAs(AnwBuffer* t, GraphicBuffer const& l) {
-    t->attr.width = l.getWidth();
-    t->attr.height = l.getHeight();
-    t->attr.stride = l.getStride();
-    t->attr.format = static_cast<PixelFormat>(l.getPixelFormat());
-    t->attr.layerCount = l.getLayerCount();
-    t->attr.usage = l.getUsage();
-    t->attr.id = l.getId();
-    t->attr.generationNumber = l.getGenerationNumber();
-    t->nativeHandle = hidl_handle(l.handle);
-}
-
-/**
- * \brief Convert `AnwBuffer` to `GraphicBuffer`.
- *
- * \param[out] l The destination `GraphicBuffer`.
- * \param[in] t The source `AnwBuffer`.
- *
- * This function will duplicate all file descriptors in \p t.
- */
-// convert: AnwBuffer -> GraphicBuffer
-// Ref: frameworks/native/libs/ui/GraphicBuffer.cpp: GraphicBuffer::flatten
-inline bool convertTo(GraphicBuffer* l, AnwBuffer const& t) {
-    native_handle_t* handle = t.nativeHandle == nullptr ?
-            nullptr : native_handle_clone(t.nativeHandle);
-
-    size_t const numInts = 12 + (handle ? handle->numInts : 0);
-    int32_t* ints = new int32_t[numInts];
-
-    size_t numFds = static_cast<size_t>(handle ? handle->numFds : 0);
-    int* fds = new int[numFds];
-
-    ints[0] = 'GBFR';
-    ints[1] = static_cast<int32_t>(t.attr.width);
-    ints[2] = static_cast<int32_t>(t.attr.height);
-    ints[3] = static_cast<int32_t>(t.attr.stride);
-    ints[4] = static_cast<int32_t>(t.attr.format);
-    ints[5] = static_cast<int32_t>(t.attr.layerCount);
-    ints[6] = static_cast<int32_t>(t.attr.usage);
-    ints[7] = static_cast<int32_t>(t.attr.id >> 32);
-    ints[8] = static_cast<int32_t>(t.attr.id & 0xFFFFFFFF);
-    ints[9] = static_cast<int32_t>(t.attr.generationNumber);
-    ints[10] = 0;
-    ints[11] = 0;
-    if (handle) {
-        ints[10] = static_cast<int32_t>(handle->numFds);
-        ints[11] = static_cast<int32_t>(handle->numInts);
-        int* intsStart = handle->data + handle->numFds;
-        std::copy(handle->data, intsStart, fds);
-        std::copy(intsStart, intsStart + handle->numInts, &ints[12]);
-    }
-
-    void const* constBuffer = static_cast<void const*>(ints);
-    size_t size = numInts * sizeof(int32_t);
-    int const* constFds = static_cast<int const*>(fds);
-    status_t status = l->unflatten(constBuffer, size, constFds, numFds);
-
-    delete [] fds;
-    delete [] ints;
-    native_handle_delete(handle);
-    return status == NO_ERROR;
-}
-
-/**
  * Conversion functions for types outside media
  * ============================================
  *
@@ -1026,7 +1018,7 @@
         if (*nh == nullptr) {
             return NO_MEMORY;
         }
-        *fence = hidl_handle(*nh);
+        *fence = *nh;
         ++fds;
         --numFds;
     } else {
@@ -1272,6 +1264,7 @@
         return NO_MEMORY;
     }
 
+    *nh = nullptr;
     ::android::FenceTime::Snapshot::State state;
     FlattenableUtils::read(buffer, size, state);
     switch (state) {
@@ -1483,9 +1476,10 @@
  */
 inline size_t getFlattenedSize(
         IOmxBufferProducer::FrameEventHistoryDelta const& t) {
-    size_t size = 4;
-    for (size_t i = 0; i < t.size(); ++i) {
-        size += getFlattenedSize(t[i]);
+    size_t size = 4 + // mDeltas.size()
+            sizeof(t.compositorTiming);
+    for (size_t i = 0; i < t.deltas.size(); ++i) {
+        size += getFlattenedSize(t.deltas[i]);
     }
     return size;
 }
@@ -1500,8 +1494,8 @@
 inline size_t getFdCount(
         IOmxBufferProducer::FrameEventHistoryDelta const& t) {
     size_t numFds = 0;
-    for (size_t i = 0; i < t.size(); ++i) {
-        numFds += getFdCount(t[i]);
+    for (size_t i = 0; i < t.deltas.size(); ++i) {
+        numFds += getFdCount(t.deltas[i]);
     }
     return numFds;
 }
@@ -1529,17 +1523,19 @@
         return NO_MEMORY;
     }
 
+    FlattenableUtils::read(buffer, size, t->compositorTiming);
+
     uint32_t deltaCount = 0;
     FlattenableUtils::read(buffer, size, deltaCount);
     if (static_cast<size_t>(deltaCount) >
             ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
         return BAD_VALUE;
     }
-    t->resize(deltaCount);
+    t->deltas.resize(deltaCount);
     nh->resize(deltaCount);
     for (size_t deltaIndex = 0; deltaIndex < deltaCount; ++deltaIndex) {
         status_t status = unflatten(
-                &((*t)[deltaIndex]), &((*nh)[deltaIndex]),
+                &(t->deltas[deltaIndex]), &((*nh)[deltaIndex]),
                 buffer, size, fds, numFds);
         if (status != NO_ERROR) {
             return status;
@@ -1563,16 +1559,18 @@
 inline status_t flatten(
         IOmxBufferProducer::FrameEventHistoryDelta const& t,
         void*& buffer, size_t& size, int*& fds, size_t& numFds) {
-    if (t.size() > ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+    if (t.deltas.size() > ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
         return BAD_VALUE;
     }
     if (size < getFlattenedSize(t)) {
         return NO_MEMORY;
     }
 
-    FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.size()));
-    for (size_t deltaIndex = 0; deltaIndex < t.size(); ++deltaIndex) {
-        status_t status = flatten(t[deltaIndex], buffer, size, fds, numFds);
+    FlattenableUtils::write(buffer, size, t.compositorTiming);
+
+    FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.deltas.size()));
+    for (size_t deltaIndex = 0; deltaIndex < t.deltas.size(); ++deltaIndex) {
+        status_t status = flatten(t.deltas[deltaIndex], buffer, size, fds, numFds);
         if (status != NO_ERROR) {
             return status;
         }
@@ -1868,6 +1866,7 @@
  * \brief Flatten `IOmxBufferProducer::QueueBufferInput`.
  *
  * \param[in] t The source `IOmxBufferProducer::QueueBufferInput`.
+ * \param[out] nh The native handle cloned from `t.fence`.
  * \param[in,out] buffer The pointer to the flat non-fd buffer.
  * \param[in,out] size The size of the flat non-fd buffer.
  * \param[in,out] fds The pointer to the flat fd buffer.
@@ -1876,6 +1875,7 @@
  *
  * This function will duplicate the file descriptor in `t.fence`. */
 inline status_t flatten(IOmxBufferProducer::QueueBufferInput const& t,
+        native_handle_t** nh,
         void*& buffer, size_t& size, int*& fds, size_t& numFds) {
     if (size < getFlattenedSize(t)) {
         return NO_MEMORY;
@@ -1895,7 +1895,9 @@
     FlattenableUtils::write(buffer, size, t.stickyTransform);
     FlattenableUtils::write(buffer, size, t.getFrameTimestamps);
 
-    status_t status = flattenFence(t.fence, buffer, size, fds, numFds);
+    *nh = t.fence.getNativeHandle() == nullptr ?
+            nullptr : native_handle_clone(t.fence);
+    status_t status = flattenFence(hidl_handle(*nh), buffer, size, fds, numFds);
     if (status != NO_ERROR) {
         return status;
     }
@@ -2037,7 +2039,8 @@
     size_t size = baseSize;
     int* fds = baseFds.get();
     size_t numFds = baseNumFds;
-    if (flatten(t, buffer, size, fds, numFds) != NO_ERROR) {
+    native_handle_t* nh;
+    if (flatten(t, &nh, buffer, size, fds, numFds) != NO_ERROR) {
         return false;
     }
 
@@ -2046,9 +2049,12 @@
     int const* constFds = static_cast<int const*>(baseFds.get());
     numFds = baseNumFds;
     if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+        native_handle_close(nh);
+        native_handle_delete(nh);
         return false;
     }
 
+    native_handle_delete(nh);
     return true;
 }
 
@@ -2082,6 +2088,7 @@
     t->transformHint = l.transformHint;
     t->numPendingBuffers = l.numPendingBuffers;
     t->nextFrameNumber = l.nextFrameNumber;
+    t->bufferReplaced = l.bufferReplaced;
     return true;
 }
 
@@ -2107,6 +2114,7 @@
     l->transformHint = t.transformHint;
     l->numPendingBuffers = t.numPendingBuffers;
     l->nextFrameNumber = t.nextFrameNumber;
+    l->bufferReplaced = t.bufferReplaced;
     return true;
 }
 
diff --git a/media/libstagefright/omx/hal/1.0/impl/Omx.cpp b/media/libstagefright/omx/hal/1.0/impl/Omx.cpp
index eddcc77..a9f29e9 100644
--- a/media/libstagefright/omx/hal/1.0/impl/Omx.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/Omx.cpp
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
+#include <ios>
 #include <list>
 
-#include "Omx.h"
-#include <IOMX.h>
-#include <OMXMaster.h>
-#include <OMXNodeInstance.h>
-#include <GraphicBufferSource.h>
+#include <android-base/logging.h>
 #include <gui/IGraphicBufferProducer.h>
-
+#include <OMX_Core.h>
 #include <OMX_AsString.h>
-#include <OMXUtils.h>
+
+#include "../../../OMXUtils.h"
+#include "../../../OMXMaster.h"
+#include "../../../GraphicBufferSource.h"
 
 #include "WOmxNode.h"
 #include "WOmxObserver.h"
@@ -32,6 +32,8 @@
 #include "WGraphicBufferSource.h"
 #include "Conversion.h"
 
+#include "Omx.h"
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -102,9 +104,10 @@
             instance.get(), &handle);
 
     if (err != OMX_ErrorNone) {
-        ALOGE("FAILED to allocate omx component '%s' err=%s(%#x)",
-                name.c_str(), asString(err), err);
-
+        LOG(ERROR) << "Failed to allocate omx component "
+                "'" << name.c_str() << "' "
+                " err=" << asString(err) <<
+                "(0x" << std::hex << unsigned(err) << ")";
         _hidl_cb(toStatus(StatusFromOMXError(err)), nullptr);
         return Void();
     }
@@ -125,8 +128,9 @@
     sp<GraphicBufferSource> graphicBufferSource = new GraphicBufferSource();
     status_t err = graphicBufferSource->initCheck();
     if (err != OK) {
-        ALOGE("Failed to create persistent input surface: %s (%d)",
-                strerror(-err), err);
+        LOG(ERROR) << "Failed to create persistent input surface: "
+                << strerror(-err) << " "
+                "(" << int(err) << ")";
         _hidl_cb(toStatus(err), nullptr, nullptr);
         return Void();
     }
@@ -147,7 +151,7 @@
         ssize_t index = mLiveNodes.indexOfKey(who);
 
         if (index < 0) {
-            ALOGE("b/27597103, nonexistent observer on serviceDied");
+            LOG(ERROR) << "b/27597103, nonexistent observer on serviceDied";
             android_errorWriteLog(0x534e4554, "27597103");
             return;
         }
diff --git a/media/libstagefright/omx/hal/1.0/impl/Omx.h b/media/libstagefright/omx/hal/1.0/impl/Omx.h
index 7633820..3e9ea73 100644
--- a/media/libstagefright/omx/hal/1.0/impl/Omx.h
+++ b/media/libstagefright/omx/hal/1.0/impl/Omx.h
@@ -17,13 +17,12 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMX_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMX_H
 
-#include <android/hardware/media/omx/1.0/IOmx.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
-#include <OmxNodeOwner.h>
+#include "../../../../include/OMXNodeInstance.h"
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
 
 namespace android {
 
diff --git a/media/libstagefright/omx/hal/1.0/impl/OmxNode.cpp b/media/libstagefright/omx/hal/1.0/impl/OmxNode.cpp
deleted file mode 100644
index f62269f..0000000
--- a/media/libstagefright/omx/hal/1.0/impl/OmxNode.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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.
- */
-
-#include <IOMX.h>
-#include <OMXNodeInstance.h>
-#include "OmxNode.h"
-#include "WOmxNode.h"
-#include "WOmxObserver.h"
-#include "Conversion.h"
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace omx {
-namespace V1_0 {
-namespace implementation {
-
-// Methods from ::android::hardware::media::omx::V1_0::IOmxNode follow.
-Return<Status> OmxNode::freeNode() {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> OmxNode::sendCommand(uint32_t cmd, int32_t param) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<void> OmxNode::getParameter(uint32_t index, const hidl_vec<uint8_t>& inParams, getParameter_cb _hidl_cb) {
-    // TODO implement
-    return Void();
-}
-
-Return<Status> OmxNode::setParameter(uint32_t index, const hidl_vec<uint8_t>& params) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<void> OmxNode::getConfig(uint32_t index, const hidl_vec<uint8_t>& inConfig, getConfig_cb _hidl_cb) {
-    // TODO implement
-    return Void();
-}
-
-Return<Status> OmxNode::setConfig(uint32_t index, const hidl_vec<uint8_t>& config) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> OmxNode::setPortMode(uint32_t portIndex, PortMode mode) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> OmxNode::prepareForAdaptivePlayback(uint32_t portIndex, bool enable, uint32_t maxFrameWidth, uint32_t maxFrameHeight) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<void> OmxNode::configureVideoTunnelMode(uint32_t portIndex, bool tunneled, uint32_t audioHwSync, configureVideoTunnelMode_cb _hidl_cb) {
-    // TODO implement
-    return Void();
-}
-
-Return<void> OmxNode::getGraphicBufferUsage(uint32_t portIndex, getGraphicBufferUsage_cb _hidl_cb) {
-    // TODO implement
-    return Void();
-}
-
-Return<Status> OmxNode::setInputSurface(const sp<IOmxBufferSource>& bufferSource) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<void> OmxNode::allocateSecureBuffer(uint32_t portIndex, uint64_t size, allocateSecureBuffer_cb _hidl_cb) {
-    // TODO implement
-    return Void();
-}
-
-Return<void> OmxNode::useBuffer(uint32_t portIndex, const CodecBuffer& omxBuffer, useBuffer_cb _hidl_cb) {
-    // TODO implement
-    return Void();
-}
-
-Return<Status> OmxNode::freeBuffer(uint32_t portIndex, uint32_t buffer) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> OmxNode::fillBuffer(uint32_t buffer, const CodecBuffer& omxBuffer, const hidl_handle& fence) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<Status> OmxNode::emptyBuffer(uint32_t buffer, const CodecBuffer& omxBuffer, uint32_t flags, uint64_t timestampUs, const hidl_handle& fence) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-Return<void> OmxNode::getExtensionIndex(const hidl_string& parameterName, getExtensionIndex_cb _hidl_cb) {
-    // TODO implement
-    return Void();
-}
-
-Return<Status> OmxNode::dispatchMessage(const Message& msg) {
-    // TODO implement
-    return ::android::hardware::media::omx::V1_0::Status {};
-}
-
-OmxNode::OmxNode(OmxNodeOwner* owner, sp<IOmxObserver> const& observer, char const* name) {
-    mLNode = new OMXNodeInstance(owner, new LWOmxObserver(observer), name);
-}
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace omx
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
diff --git a/media/libstagefright/omx/hal/1.0/impl/OmxNode.h b/media/libstagefright/omx/hal/1.0/impl/OmxNode.h
deleted file mode 100644
index fc19306..0000000
--- a/media/libstagefright/omx/hal/1.0/impl/OmxNode.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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 ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMXNODE_H
-#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMXNODE_H
-
-#include <android/hardware/media/omx/1.0/IOmxNode.h>
-#include <android/hardware/media/omx/1.0/IOmxObserver.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-#include <OMXNodeInstance.h>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace omx {
-namespace V1_0 {
-namespace implementation {
-
-using ::android::hardware::media::omx::V1_0::CodecBuffer;
-using ::android::hardware::media::omx::V1_0::IOmxBufferSource;
-using ::android::hardware::media::omx::V1_0::IOmxNode;
-using ::android::hardware::media::omx::V1_0::IOmxObserver;
-using ::android::hardware::media::omx::V1_0::Message;
-using ::android::hardware::media::omx::V1_0::PortMode;
-using ::android::hardware::media::omx::V1_0::Status;
-using ::android::hidl::base::V1_0::IBase;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-using ::android::OMXNodeInstance;
-using ::android::OmxNodeOwner;
-
-/**
- * Wrapper classes for conversion
- * ==============================
- *
- * Naming convention:
- * - LW = Legacy Wrapper --- It wraps a Treble object inside a legacy object.
- * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
- */
-
-struct OmxNode : public IOmxNode {
-    Return<Status> freeNode() override;
-    Return<Status> sendCommand(uint32_t cmd, int32_t param) override;
-    Return<void> getParameter(uint32_t index, const hidl_vec<uint8_t>& inParams, getParameter_cb _hidl_cb) override;
-    Return<Status> setParameter(uint32_t index, const hidl_vec<uint8_t>& params) override;
-    Return<void> getConfig(uint32_t index, const hidl_vec<uint8_t>& inConfig, getConfig_cb _hidl_cb) override;
-    Return<Status> setConfig(uint32_t index, const hidl_vec<uint8_t>& config) override;
-    Return<Status> setPortMode(uint32_t portIndex, PortMode mode) override;
-    Return<Status> prepareForAdaptivePlayback(uint32_t portIndex, bool enable, uint32_t maxFrameWidth, uint32_t maxFrameHeight) override;
-    Return<void> configureVideoTunnelMode(uint32_t portIndex, bool tunneled, uint32_t audioHwSync, configureVideoTunnelMode_cb _hidl_cb) override;
-    Return<void> getGraphicBufferUsage(uint32_t portIndex, getGraphicBufferUsage_cb _hidl_cb) override;
-    Return<Status> setInputSurface(const sp<IOmxBufferSource>& bufferSource) override;
-    Return<void> allocateSecureBuffer(uint32_t portIndex, uint64_t size, allocateSecureBuffer_cb _hidl_cb) override;
-    Return<void> useBuffer(uint32_t portIndex, const CodecBuffer& omxBuffer, useBuffer_cb _hidl_cb) override;
-    Return<Status> freeBuffer(uint32_t portIndex, uint32_t buffer) override;
-    Return<Status> fillBuffer(uint32_t buffer, const CodecBuffer& omxBuffer, const hidl_handle& fence) override;
-    Return<Status> emptyBuffer(uint32_t buffer, const CodecBuffer& omxBuffer, uint32_t flags, uint64_t timestampUs, const hidl_handle& fence) override;
-    Return<void> getExtensionIndex(const hidl_string& parameterName, getExtensionIndex_cb _hidl_cb) override;
-    Return<Status> dispatchMessage(const Message& msg) override;
-
-    OmxNode(OmxNodeOwner* owner, sp<IOmxObserver> const& observer, char const* name);
-protected:
-    sp<OMXNodeInstance> mLNode;
-};
-
-}  // namespace implementation
-}  // namespace V1_0
-}  // namespace omx
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMXNODE_H
diff --git a/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.cpp b/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.cpp
index 9de8e3e..884e87b 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.cpp
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-#include "WGraphicBufferSource.h"
-#include "Conversion.h"
-#include "WOmxNode.h"
 #include <stagefright/foundation/ColorUtils.h>
 
+#include "WGraphicBufferSource.h"
+#include "WOmxNode.h"
+#include "Conversion.h"
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -39,8 +40,9 @@
             new TWOmxNode(omxNode), toHardwareDataspace(dataSpace)));
 }
 
-::android::binder::Status LWGraphicBufferSource::setSuspend(bool suspend) {
-    return toBinderStatus(mBase->setSuspend(suspend));
+::android::binder::Status LWGraphicBufferSource::setSuspend(
+        bool suspend, int64_t timeUs) {
+    return toBinderStatus(mBase->setSuspend(suspend, timeUs));
 }
 
 ::android::binder::Status LWGraphicBufferSource::setRepeatPreviousFrameDelayUs(
@@ -63,6 +65,11 @@
     return toBinderStatus(mBase->setStartTimeUs(startTimeUs));
 }
 
+::android::binder::Status LWGraphicBufferSource::setStopTimeUs(
+        int64_t stopTimeUs) {
+    return toBinderStatus(mBase->setStopTimeUs(stopTimeUs));
+}
+
 ::android::binder::Status LWGraphicBufferSource::setColorAspects(
         int32_t aspects) {
     return toBinderStatus(mBase->setColorAspects(
@@ -78,10 +85,6 @@
     return toBinderStatus(mBase->signalEndOfInputStream());
 }
 
-::android::IBinder* LWGraphicBufferSource::onAsBinder() {
-    return nullptr;
-}
-
 // TWGraphicBufferSource
 TWGraphicBufferSource::TWGraphicBufferSource(
         sp<LGraphicBufferSource> const& base) : mBase(base) {
@@ -89,47 +92,57 @@
 
 Return<void> TWGraphicBufferSource::configure(
         const sp<IOmxNode>& omxNode, Dataspace dataspace) {
-    return toHardwareStatus(mBase->configure(
-            new LWOmxNode(omxNode),
-            toRawDataspace(dataspace)));
+    mBase->configure(new LWOmxNode(omxNode), toRawDataspace(dataspace));
+    return Void();
 }
 
-Return<void> TWGraphicBufferSource::setSuspend(bool suspend) {
-    return toHardwareStatus(mBase->setSuspend(suspend));
+Return<void> TWGraphicBufferSource::setSuspend(
+        bool suspend, int64_t timeUs) {
+    mBase->setSuspend(suspend, timeUs);
+    return Void();
 }
 
 Return<void> TWGraphicBufferSource::setRepeatPreviousFrameDelayUs(
         int64_t repeatAfterUs) {
-    return toHardwareStatus(mBase->setRepeatPreviousFrameDelayUs(
-            repeatAfterUs));
+    mBase->setRepeatPreviousFrameDelayUs(repeatAfterUs);
+    return Void();
 }
 
 Return<void> TWGraphicBufferSource::setMaxFps(float maxFps) {
-    return toHardwareStatus(mBase->setMaxFps(maxFps));
+    mBase->setMaxFps(maxFps);
+    return Void();
 }
 
 Return<void> TWGraphicBufferSource::setTimeLapseConfig(
         int64_t timePerFrameUs, int64_t timePerCaptureUs) {
-    return toHardwareStatus(mBase->setTimeLapseConfig(
-            timePerFrameUs, timePerCaptureUs));
+    mBase->setTimeLapseConfig(timePerFrameUs, timePerCaptureUs);
+    return Void();
 }
 
 Return<void> TWGraphicBufferSource::setStartTimeUs(int64_t startTimeUs) {
-    return toHardwareStatus(mBase->setStartTimeUs(startTimeUs));
+    mBase->setStartTimeUs(startTimeUs);
+    return Void();
+}
+
+Return<void> TWGraphicBufferSource::setStopTimeUs(int64_t stopTimeUs) {
+    mBase->setStopTimeUs(stopTimeUs);
+    return Void();
 }
 
 Return<void> TWGraphicBufferSource::setColorAspects(
         const ColorAspects& aspects) {
-    return toHardwareStatus(mBase->setColorAspects(toCompactColorAspects(
-            aspects)));
+    mBase->setColorAspects(toCompactColorAspects(aspects));
+    return Void();
 }
 
 Return<void> TWGraphicBufferSource::setTimeOffsetUs(int64_t timeOffsetUs) {
-    return toHardwareStatus(mBase->setTimeOffsetUs(timeOffsetUs));
+    mBase->setTimeOffsetUs(timeOffsetUs);
+    return Void();
 }
 
 Return<void> TWGraphicBufferSource::signalEndOfInputStream() {
-    return toHardwareStatus(mBase->signalEndOfInputStream());
+    mBase->signalEndOfInputStream();
+    return Void();
 }
 
 }  // namespace implementation
diff --git a/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.h b/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.h
index 0b9f2ed..bd60c46 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WGraphicBufferSource.h
@@ -17,16 +17,17 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERSOURCE_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERSOURCE_H
 
-#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <frameworks/native/include/binder/Binder.h>
-#include <IOMX.h>
-#include <android/IGraphicBufferSource.h>
-#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <media/IOMX.h>
+#include <binder/Binder.h>
 
 #include <android/hardware/graphics/common/1.0/types.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+
+#include <android/BnGraphicBufferSource.h>
 
 namespace android {
 namespace hardware {
@@ -60,26 +61,26 @@
  */
 
 typedef ::android::IGraphicBufferSource LGraphicBufferSource;
+typedef ::android::BnGraphicBufferSource BnGraphicBufferSource;
 typedef ::android::hardware::media::omx::V1_0::IGraphicBufferSource
         TGraphicBufferSource;
 
-struct LWGraphicBufferSource : public LGraphicBufferSource {
+struct LWGraphicBufferSource : public BnGraphicBufferSource {
     sp<TGraphicBufferSource> mBase;
     LWGraphicBufferSource(sp<TGraphicBufferSource> const& base);
     ::android::binder::Status configure(
             const sp<IOMXNode>& omxNode, int32_t dataSpace) override;
-    ::android::binder::Status setSuspend(bool suspend) override;
+    ::android::binder::Status setSuspend(bool suspend, int64_t timeUs) override;
     ::android::binder::Status setRepeatPreviousFrameDelayUs(
             int64_t repeatAfterUs) override;
     ::android::binder::Status setMaxFps(float maxFps) override;
     ::android::binder::Status setTimeLapseConfig(
             int64_t timePerFrameUs, int64_t timePerCaptureUs) override;
     ::android::binder::Status setStartTimeUs(int64_t startTimeUs) override;
+    ::android::binder::Status setStopTimeUs(int64_t stopTimeUs) override;
     ::android::binder::Status setColorAspects(int32_t aspects) override;
     ::android::binder::Status setTimeOffsetUs(int64_t timeOffsetsUs) override;
     ::android::binder::Status signalEndOfInputStream() override;
-protected:
-    ::android::IBinder* onAsBinder() override;
 };
 
 struct TWGraphicBufferSource : public TGraphicBufferSource {
@@ -87,12 +88,13 @@
     TWGraphicBufferSource(sp<LGraphicBufferSource> const& base);
     Return<void> configure(
             const sp<IOmxNode>& omxNode, Dataspace dataspace) override;
-    Return<void> setSuspend(bool suspend) override;
+    Return<void> setSuspend(bool suspend, int64_t timeUs) override;
     Return<void> setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) override;
     Return<void> setMaxFps(float maxFps) override;
     Return<void> setTimeLapseConfig(
             int64_t timePerFrameUs, int64_t timePerCaptureUs) override;
     Return<void> setStartTimeUs(int64_t startTimeUs) override;
+    Return<void> setStopTimeUs(int64_t stopTimeUs) override;
     Return<void> setColorAspects(const ColorAspects& aspects) override;
     Return<void> setTimeOffsetUs(int64_t timeOffsetUs) override;
     Return<void> signalEndOfInputStream() override;
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmx.cpp b/media/libstagefright/omx/hal/1.0/impl/WOmx.cpp
index 0fa8c4c..da1c23d 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmx.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmx.cpp
@@ -79,10 +79,6 @@
     return transStatus == NO_ERROR ? fnStatus : transStatus;
 }
 
-::android::IBinder* LWOmx::onAsBinder() {
-    return nullptr;
-}
-
 // TWOmx
 TWOmx::TWOmx(sp<IOMX> const& base) : mBase(base) {
 }
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmx.h b/media/libstagefright/omx/hal/1.0/impl/WOmx.h
index 5618d27..3cb002e 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmx.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmx.h
@@ -17,11 +17,12 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMX_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMX_H
 
-#include <android/hardware/media/omx/1.0/IOmx.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <IOMX.h>
+#include "../../../../include/OMXNodeInstance.h"
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
 
 namespace android {
 namespace hardware {
@@ -45,6 +46,7 @@
 
 using ::android::List;
 using ::android::IOMX;
+using ::android::BnOMX;
 
 /**
  * Wrapper classes for conversion
@@ -55,7 +57,7 @@
  * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
  */
 
-struct LWOmx : public IOMX {
+struct LWOmx : public BnOMX {
     sp<IOmx> mBase;
     LWOmx(sp<IOmx> const& base);
     status_t listNodes(List<IOMX::ComponentInfo>* list) override;
@@ -66,8 +68,6 @@
     status_t createInputSurface(
             sp<::android::IGraphicBufferProducer>* bufferProducer,
             sp<::android::IGraphicBufferSource>* bufferSource) override;
-protected:
-    ::android::IBinder* onAsBinder() override;
 };
 
 struct TWOmx : public IOmx {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.cpp b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.cpp
index a459c9f..b6b9a3b 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.cpp
@@ -14,8 +14,13 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "WOmxBufferProducer-impl"
+
+#include <android-base/logging.h>
+
 #include "WOmxBufferProducer.h"
 #include "WOmxProducerListener.h"
+#include "Conversion.h"
 
 namespace android {
 namespace hardware {
@@ -62,23 +67,29 @@
             width, height,
             static_cast<::android::PixelFormat>(format), usage,
             getFrameTimestamps ? &outTimestamps : nullptr);
-
     hidl_handle tFence;
-    native_handle_t* nh;
-    if (!wrapAs(&tFence, &nh, *fence)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::dequeueBuffer(): "
-                "Cannot wrap Fence in hidl_handle"));
-    }
     FrameEventHistoryDelta tOutTimestamps;
+
+    native_handle_t* nh = nullptr;
+    if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
+        LOG(ERROR) << "TWOmxBufferProducer::dequeueBuffer - "
+                "Invalid output fence";
+        _hidl_cb(toStatus(status),
+                 static_cast<int32_t>(slot),
+                 tFence,
+                 tOutTimestamps);
+        return Void();
+    }
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (getFrameTimestamps && !wrapAs(&tOutTimestamps, &nhAA, outTimestamps)) {
+        LOG(ERROR) << "TWOmxBufferProducer::dequeueBuffer - "
+                "Invalid output timestamps";
+        _hidl_cb(toStatus(status),
+                 static_cast<int32_t>(slot),
+                 tFence,
+                 tOutTimestamps);
         native_handle_delete(nh);
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::dequeueBuffer(): "
-                "Cannot wrap Fence in hidl_handle"));
+        return Void();
     }
 
     _hidl_cb(toStatus(status),
@@ -89,9 +100,7 @@
     if (getFrameTimestamps) {
         for (auto& nhA : nhAA) {
             for (auto& handle : nhA) {
-                if (handle != nullptr) {
-                    native_handle_delete(handle);
-                }
+                native_handle_delete(handle);
             }
         }
     }
@@ -107,16 +116,22 @@
     sp<GraphicBuffer> outBuffer;
     sp<Fence> outFence;
     status_t status = mBase->detachNextBuffer(&outBuffer, &outFence);
-
     AnwBuffer tBuffer;
-    wrapAs(&tBuffer, *outBuffer);
     hidl_handle tFence;
-    native_handle_t* nh;
-    if (!wrapAs(&tFence, &nh, *outFence)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::detachNextBuffer(): "
-                "Cannot wrap Fence in hidl_handle"));
+
+    if (outBuffer == nullptr) {
+        LOG(ERROR) << "TWOmxBufferProducer::detachNextBuffer - "
+                "Invalid output buffer";
+        _hidl_cb(toStatus(status), tBuffer, tFence);
+        return Void();
+    }
+    wrapAs(&tBuffer, *outBuffer);
+    native_handle_t* nh = nullptr;
+    if ((outFence != nullptr) && !wrapAs(&tFence, &nh, *outFence)) {
+        LOG(ERROR) << "TWOmxBufferProducer::detachNextBuffer - "
+                "Invalid output fence";
+        _hidl_cb(toStatus(status), tBuffer, tFence);
+        return Void();
     }
 
     _hidl_cb(toStatus(status), tBuffer, tFence);
@@ -130,10 +145,10 @@
     int outSlot;
     sp<GraphicBuffer> lBuffer = new GraphicBuffer();
     if (!convertTo(lBuffer.get(), buffer)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::attachBuffer(): "
-                "Cannot convert AnwBuffer to GraphicBuffer"));
+        LOG(ERROR) << "TWOmxBufferProducer::attachBuffer - "
+                "Invalid input native window buffer";
+        _hidl_cb(toStatus(BAD_VALUE), -1);
+        return Void();
     }
     status_t status = mBase->attachBuffer(&outSlot, lBuffer);
 
@@ -144,38 +159,34 @@
 Return<void> TWOmxBufferProducer::queueBuffer(
         int32_t slot, const QueueBufferInput& input,
         queueBuffer_cb _hidl_cb) {
+    QueueBufferOutput tOutput;
     IGraphicBufferProducer::QueueBufferInput lInput(
             0, false, HAL_DATASPACE_UNKNOWN,
             ::android::Rect(0, 0, 1, 1),
             NATIVE_WINDOW_SCALING_MODE_FREEZE,
             0, ::android::Fence::NO_FENCE);
     if (!convertTo(&lInput, input)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::queueBuffer(): "
-                "Cannot convert IOmxBufferProducer::QueueBufferInput "
-                "to IGraphicBufferProducer::QueueBufferInput"));
+        LOG(ERROR) << "TWOmxBufferProducer::queueBuffer - "
+                "Invalid input";
+        _hidl_cb(toStatus(BAD_VALUE), tOutput);
+        return Void();
     }
     IGraphicBufferProducer::QueueBufferOutput lOutput;
     status_t status = mBase->queueBuffer(
             static_cast<int>(slot), lInput, &lOutput);
 
-    QueueBufferOutput tOutput;
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (!wrapAs(&tOutput, &nhAA, lOutput)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::queueBuffer(): "
-                "Cannot wrap IGraphicBufferProducer::QueueBufferOutput "
-                "in IOmxBufferProducer::QueueBufferOutput"));
+        LOG(ERROR) << "TWOmxBufferProducer::queueBuffer - "
+                "Invalid output";
+        _hidl_cb(toStatus(BAD_VALUE), tOutput);
+        return Void();
     }
 
     _hidl_cb(toStatus(status), tOutput);
     for (auto& nhA : nhAA) {
         for (auto& nh : nhA) {
-            if (nh != nullptr) {
-                native_handle_delete(nh);
-            }
+            native_handle_delete(nh);
         }
     }
     return Void();
@@ -185,10 +196,9 @@
         int32_t slot, const hidl_handle& fence) {
     sp<Fence> lFence = new Fence();
     if (!convertTo(lFence.get(), fence)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::cancelBuffer(): "
-                "Cannot convert hidl_handle to Fence"));
+        LOG(ERROR) << "TWOmxBufferProducer::cancelBuffer - "
+                "Invalid input fence";
+        return toStatus(BAD_VALUE);
     }
     return toStatus(mBase->cancelBuffer(static_cast<int>(slot), lFence));
 }
@@ -203,7 +213,8 @@
 Return<void> TWOmxBufferProducer::connect(
         const sp<IOmxProducerListener>& listener,
         int32_t api, bool producerControlledByApp, connect_cb _hidl_cb) {
-    sp<IProducerListener> lListener = new LWOmxProducerListener(listener);
+    sp<IProducerListener> lListener = listener == nullptr ?
+            nullptr : new LWOmxProducerListener(listener);
     IGraphicBufferProducer::QueueBufferOutput lOutput;
     status_t status = mBase->connect(lListener,
             static_cast<int>(api),
@@ -213,19 +224,16 @@
     QueueBufferOutput tOutput;
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (!wrapAs(&tOutput, &nhAA, lOutput)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::connect(): "
-                "Cannot wrap IGraphicBufferProducer::QueueBufferOutput "
-                "in IOmxBufferProducer::QueueBufferOutput"));
+        LOG(ERROR) << "TWOmxBufferProducer::connect - "
+                "Invalid output";
+        _hidl_cb(toStatus(status), tOutput);
+        return Void();
     }
 
     _hidl_cb(toStatus(status), tOutput);
     for (auto& nhA : nhAA) {
         for (auto& nh : nhA) {
-            if (nh != nullptr) {
-                native_handle_delete(nh);
-            }
+            native_handle_delete(nh);
         }
     }
     return Void();
@@ -286,14 +294,19 @@
             &lOutBuffer, &lOutFence, lOutTransformMatrix);
 
     AnwBuffer tOutBuffer;
-    wrapAs(&tOutBuffer, *lOutBuffer);
+    if (lOutBuffer != nullptr) {
+        wrapAs(&tOutBuffer, *lOutBuffer);
+    }
     hidl_handle tOutFence;
-    native_handle_t* nh;
-    if (!wrapAs(&tOutFence, &nh, *lOutFence)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::getLastQueuedBuffer(): "
-                "Cannot wrap Fence in hidl_handle"));
+    native_handle_t* nh = nullptr;
+    if ((lOutFence == nullptr) || !wrapAs(&tOutFence, &nh, *lOutFence)) {
+        LOG(ERROR) << "TWOmxBufferProducer::getLastQueuedBuffer - "
+                "Invalid output fence";
+        _hidl_cb(toStatus(status),
+                tOutBuffer,
+                tOutFence,
+                hidl_array<float, 16>());
+        return Void();
     }
     hidl_array<float, 16> tOutTransformMatrix(lOutTransformMatrix);
 
@@ -310,19 +323,16 @@
     FrameEventHistoryDelta tDelta;
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (!wrapAs(&tDelta, &nhAA, lDelta)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::getFrameTimestamps(): "
-                "Cannot wrap ::android::FrameEventHistoryDelta "
-                "in FrameEventHistoryDelta"));
+        LOG(ERROR) << "TWOmxBufferProducer::getFrameTimestamps - "
+                "Invalid output frame timestamps";
+        _hidl_cb(tDelta);
+        return Void();
     }
 
     _hidl_cb(tDelta);
     for (auto& nhA : nhAA) {
         for (auto& nh : nhA) {
-            if (nh != nullptr) {
-                native_handle_delete(nh);
-            }
+            native_handle_delete(nh);
         }
     }
     return Void();
@@ -382,9 +392,13 @@
                 fnStatus = toStatusT(status);
                 *slot = tSlot;
                 if (!convertTo(fence->get(), tFence)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::dequeueBuffer - "
+                            "Invalid output fence";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 if (outTimestamps && !convertTo(outTimestamps, tTs)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::dequeueBuffer - "
+                            "Invalid output timestamps";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -407,9 +421,13 @@
                     hidl_handle const& tFence) {
                 fnStatus = toStatusT(status);
                 if (!convertTo(outFence->get(), tFence)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::detachNextBuffer - "
+                            "Invalid output fence";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 if (!convertTo(outBuffer->get(), tBuffer)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::detachNextBuffer - "
+                            "Invalid output buffer";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -436,6 +454,8 @@
     IOmxBufferProducer::QueueBufferInput tInput;
     native_handle_t* nh;
     if (!wrapAs(&tInput, &nh, input)) {
+        LOG(ERROR) << "LWOmxBufferProducer::queueBuffer - "
+                "Invalid input";
         return BAD_VALUE;
     }
     status_t fnStatus;
@@ -445,6 +465,8 @@
                     IOmxBufferProducer::QueueBufferOutput const& tOutput) {
                 fnStatus = toStatusT(status);
                 if (!convertTo(output, tOutput)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::queueBuffer - "
+                            "Invalid output";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -454,8 +476,10 @@
 
 status_t LWOmxBufferProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
     hidl_handle tFence;
-    native_handle_t* nh;
-    if (!wrapAs(&tFence, &nh, *fence)) {
+    native_handle_t* nh = nullptr;
+    if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
+        LOG(ERROR) << "LWOmxBufferProducer::cancelBuffer - "
+                "Invalid input fence";
         return BAD_VALUE;
     }
 
@@ -479,7 +503,8 @@
 status_t LWOmxBufferProducer::connect(
         const sp<IProducerListener>& listener, int api,
         bool producerControlledByApp, QueueBufferOutput* output) {
-    sp<IOmxProducerListener> tListener = new TWOmxProducerListener(listener);
+    sp<IOmxProducerListener> tListener = listener == nullptr ?
+            nullptr : new TWOmxProducerListener(listener);
     status_t fnStatus;
     status_t transStatus = toStatusT(mBase->connect(
             tListener, static_cast<int32_t>(api), producerControlledByApp,
@@ -488,6 +513,8 @@
                     IOmxBufferProducer::QueueBufferOutput const& tOutput) {
                 fnStatus = toStatusT(status);
                 if (!convertTo(output, tOutput)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::connect - "
+                            "Invalid output";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -552,10 +579,14 @@
                 fnStatus = toStatusT(status);
                 *outBuffer = new GraphicBuffer();
                 if (!convertTo(outBuffer->get(), buffer)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::getLastQueuedBuffer - "
+                            "Invalid output buffer";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 *outFence = new Fence();
                 if (!convertTo(outFence->get(), fence)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::getLastQueuedBuffer - "
+                            "Invalid output fence";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 std::copy(transformMatrix.data(),
@@ -582,10 +613,6 @@
     return transStatus == NO_ERROR ? fnStatus : transStatus;
 }
 
-::android::IBinder* LWOmxBufferProducer::onAsBinder() {
-    return nullptr;
-}
-
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace omx
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.h b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.h
index a991f49..8520160 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferProducer.h
@@ -17,13 +17,14 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERPRODUCER_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERPRODUCER_H
 
-#include <android/hardware/media/omx/1.0/IOmxBufferProducer.h>
-#include <binder/Binder.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
+
+#include <binder/Binder.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/IProducerListener.h>
-#include "Conversion.h"
+
+#include <android/hardware/media/omx/1.0/IOmxBufferProducer.h>
 
 namespace android {
 namespace hardware {
@@ -47,6 +48,7 @@
 using ::android::sp;
 
 using ::android::IGraphicBufferProducer;
+using ::android::BnGraphicBufferProducer;
 using ::android::IProducerListener;
 
 struct TWOmxBufferProducer : public IOmxBufferProducer {
@@ -91,7 +93,7 @@
     Return<void> getUniqueId(getUniqueId_cb _hidl_cb) override;
 };
 
-struct LWOmxBufferProducer : public IGraphicBufferProducer {
+struct LWOmxBufferProducer : public BnGraphicBufferProducer {
     sp<IOmxBufferProducer> mBase;
     LWOmxBufferProducer(sp<IOmxBufferProducer> const& base);
 
@@ -128,8 +130,6 @@
           sp<Fence>* outFence, float outTransformMatrix[16]) override;
     void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override;
     status_t getUniqueId(uint64_t* outId) const override;
-protected:
-    ::android::IBinder* onAsBinder() override;
 };
 
 }  // namespace implementation
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.cpp b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.cpp
index 2e00894..803283a 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.cpp
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
+#include <utils/String8.h>
+
 #include "WOmxBufferSource.h"
 #include "Conversion.h"
-#include <utils/String8.h>
-#include <cutils/native_handle.h>
 
 namespace android {
 namespace hardware {
@@ -61,49 +61,44 @@
     ::android::binder::Status status = toBinderStatus(
             mBase->onInputBufferEmptied(
             static_cast<uint32_t>(bufferId), fence));
-    if (native_handle_delete(fenceNh) != 0) {
-        return ::android::binder::Status::fromExceptionCode(
-                ::android::binder::Status::EX_NULL_POINTER,
-                "Cannot delete native handle");
-    }
+    native_handle_close(fenceNh);
+    native_handle_delete(fenceNh);
     return status;
 }
 
-::android::IBinder* LWOmxBufferSource::onAsBinder() {
-    return nullptr;
-}
-
 // TWOmxBufferSource
 TWOmxBufferSource::TWOmxBufferSource(sp<IOMXBufferSource> const& base) :
     mBase(base) {
 }
 
 Return<void> TWOmxBufferSource::onOmxExecuting() {
-    return toHardwareStatus(mBase->onOmxExecuting());
+    mBase->onOmxExecuting();
+    return Void();
 }
 
 Return<void> TWOmxBufferSource::onOmxIdle() {
-    return toHardwareStatus(mBase->onOmxIdle());
+    mBase->onOmxIdle();
+    return Void();
 }
 
 Return<void> TWOmxBufferSource::onOmxLoaded() {
-    return toHardwareStatus(mBase->onOmxLoaded());
+    mBase->onOmxLoaded();
+    return Void();
 }
 
 Return<void> TWOmxBufferSource::onInputBufferAdded(uint32_t buffer) {
-    return toHardwareStatus(mBase->onInputBufferAdded(
-            static_cast<int32_t>(buffer)));
+    mBase->onInputBufferAdded(int32_t(buffer));
+    return Void();
 }
 
 Return<void> TWOmxBufferSource::onInputBufferEmptied(
         uint32_t buffer, hidl_handle const& fence) {
     OMXFenceParcelable fenceParcelable;
     if (!convertTo(&fenceParcelable, fence)) {
-      return ::android::hardware::Status::fromExceptionCode(
-              ::android::hardware::Status::EX_BAD_PARCELABLE);
+        return Void();
     }
-    return toHardwareStatus(mBase->onInputBufferEmptied(
-            static_cast<int32_t>(buffer), fenceParcelable));
+    mBase->onInputBufferEmptied(int32_t(buffer), fenceParcelable);
+    return Void();
 }
 
 }  // namespace implementation
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.h b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.h
index a2e940f..9b27796 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxBufferSource.h
@@ -17,13 +17,14 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERSOURCE_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERSOURCE_H
 
-#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <frameworks/native/include/binder/Binder.h>
-#include <android/IOMXBufferSource.h>
-#include <OMXFenceParcelable.h>
+#include <binder/Binder.h>
+#include <media/OMXFenceParcelable.h>
+
+#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
+#include <android/BnOMXBufferSource.h>
 
 namespace android {
 namespace hardware {
@@ -45,6 +46,7 @@
 
 using ::android::OMXFenceParcelable;
 using ::android::IOMXBufferSource;
+using ::android::BnOMXBufferSource;
 
 /**
  * Wrapper classes for conversion
@@ -55,7 +57,7 @@
  * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
  */
 
-struct LWOmxBufferSource : public IOMXBufferSource {
+struct LWOmxBufferSource : public BnOMXBufferSource {
     sp<IOmxBufferSource> mBase;
     LWOmxBufferSource(sp<IOmxBufferSource> const& base);
     ::android::binder::Status onOmxExecuting() override;
@@ -64,8 +66,6 @@
     ::android::binder::Status onInputBufferAdded(int32_t bufferID) override;
     ::android::binder::Status onInputBufferEmptied(
             int32_t bufferID, OMXFenceParcelable const& fenceParcel) override;
-protected:
-    ::android::IBinder* onAsBinder() override;
 };
 
 struct TWOmxBufferSource : public IOmxBufferSource {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxNode.cpp b/media/libstagefright/omx/hal/1.0/impl/WOmxNode.cpp
index 6b21138..dc5c8e1 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxNode.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxNode.cpp
@@ -14,14 +14,12 @@
  * limitations under the License.
  */
 
-#include <IOMX.h>
-#include <OMXNodeInstance.h>
+#include <algorithm>
+
 #include "WOmxNode.h"
 #include "WOmxBufferSource.h"
 #include "Conversion.h"
 
-#include <algorithm>
-
 namespace android {
 namespace hardware {
 namespace media {
@@ -252,10 +250,6 @@
     return toStatusT(mBase->setQuirks(static_cast<uint32_t>(quirks)));;
 }
 
-::android::IBinder* LWOmxNode::onAsBinder() {
-    return nullptr;
-}
-
 // TWOmxNode
 TWOmxNode::TWOmxNode(sp<IOMXNode> const& base) : mBase(base) {
 }
@@ -281,7 +275,8 @@
 }
 
 Return<Status> TWOmxNode::setParameter(
-        uint32_t index, hidl_vec<uint8_t> const& params) {
+        uint32_t index, hidl_vec<uint8_t> const& inParams) {
+    hidl_vec<uint8_t> params(inParams);
     return toStatus(mBase->setParameter(
             toEnumIndexType(index),
             static_cast<void const*>(params.data()),
@@ -301,7 +296,8 @@
 }
 
 Return<Status> TWOmxNode::setConfig(
-        uint32_t index, const hidl_vec<uint8_t>& config) {
+        uint32_t index, const hidl_vec<uint8_t>& inConfig) {
+    hidl_vec<uint8_t> config(inConfig);
     return toStatus(mBase->setConfig(
             toEnumIndexType(index),
             static_cast<void const*>(config.data()),
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxNode.h b/media/libstagefright/omx/hal/1.0/impl/WOmxNode.h
index d606f3a..75816ba 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxNode.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxNode.h
@@ -17,13 +17,16 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXNODE_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXNODE_H
 
-#include <android/hardware/media/omx/1.0/IOmxNode.h>
-#include <android/hardware/media/omx/1.0/IOmxObserver.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
 #include <utils/Errors.h>
 
+#include "../../../../include/OMXNodeInstance.h"
+
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -56,7 +59,7 @@
  * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
  */
 
-struct LWOmxNode : public IOMXNode {
+struct LWOmxNode : public BnOMXNode {
     sp<IOmxNode> mBase;
     LWOmxNode(sp<IOmxNode> const& base);
     status_t freeNode() override;
@@ -103,8 +106,6 @@
 
     // TODO: this is temporary, will be removed when quirks move to OMX side.
     status_t setQuirks(OMX_U32 quirks) override;
-protected:
-    ::android::IBinder* onAsBinder() override;
 };
 
 struct TWOmxNode : public IOmxNode {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.cpp b/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.cpp
index d5549fb..354db29 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.cpp
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
-#include "WOmxObserver.h"
+#define LOG_TAG "WOmxObserver-impl"
 
 #include <vector>
 
+#include <android-base/logging.h>
 #include <cutils/native_handle.h>
-#include <frameworks/native/include/binder/Binder.h>
+#include <binder/Binder.h>
 
+#include "WOmxObserver.h"
 #include "Conversion.h"
 
 namespace android {
@@ -43,17 +45,16 @@
         wrapAs(&tMessages[i], &handles[i], message);
         ++i;
     }
-    mBase->onMessages(tMessages);
+    auto transResult = mBase->onMessages(tMessages);
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "LWOmxObserver::onMessages - Transaction failed";
+    }
     for (auto& handle : handles) {
         native_handle_close(handle);
         native_handle_delete(handle);
     }
 }
 
-::android::IBinder* LWOmxObserver::onAsBinder() {
-    return nullptr;
-}
-
 // TWOmxObserver
 TWOmxObserver::TWOmxObserver(sp<IOMXObserver> const& base) : mBase(base) {
 }
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.h b/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.h
index 85593c3..7075513 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxObserver.h
@@ -17,12 +17,14 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXOBSERVER_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXOBSERVER_H
 
-#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <list>
+
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <IOMX.h>
-#include <list>
+#include <media/IOMX.h>
+
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
 
 namespace android {
 namespace hardware {
@@ -43,6 +45,7 @@
 using ::android::sp;
 
 using ::android::IOMXObserver;
+using ::android::BnOMXObserver;
 using ::android::omx_message;
 
 /**
@@ -54,12 +57,10 @@
  * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
  */
 
-struct LWOmxObserver : public IOMXObserver {
+struct LWOmxObserver : public BnOMXObserver {
     sp<IOmxObserver> mBase;
     LWOmxObserver(sp<IOmxObserver> const& base);
     void onMessages(std::list<omx_message> const& lMessages) override;
-protected:
-    ::android::IBinder* onAsBinder() override;
 };
 
 struct TWOmxObserver : public IOmxObserver {
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxProducerListener.cpp b/media/libstagefright/omx/hal/1.0/impl/WOmxProducerListener.cpp
index fa6e9aa..a5eed35 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxProducerListener.cpp
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxProducerListener.cpp
@@ -52,11 +52,6 @@
     return static_cast<bool>(mBase->needsReleaseNotify());
 }
 
-::android::IBinder* LWOmxProducerListener::onAsBinder() {
-    return nullptr;
-}
-
-
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace omx
diff --git a/media/libstagefright/omx/hal/1.0/impl/WOmxProducerListener.h b/media/libstagefright/omx/hal/1.0/impl/WOmxProducerListener.h
index b93a555..e60032e 100644
--- a/media/libstagefright/omx/hal/1.0/impl/WOmxProducerListener.h
+++ b/media/libstagefright/omx/hal/1.0/impl/WOmxProducerListener.h
@@ -17,13 +17,14 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXPRODUCERLISTENER_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXPRODUCERLISTENER_H
 
-#include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
 #include <binder/IBinder.h>
 #include <gui/IProducerListener.h>
 
+#include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -42,6 +43,7 @@
 using ::android::sp;
 
 using ::android::IProducerListener;
+using ::android::BnProducerListener;
 
 struct TWOmxProducerListener : public IOmxProducerListener {
     sp<IProducerListener> mBase;
@@ -50,14 +52,12 @@
     Return<bool> needsReleaseNotify() override;
 };
 
-class LWOmxProducerListener : public IProducerListener {
+class LWOmxProducerListener : public BnProducerListener {
 public:
     sp<IOmxProducerListener> mBase;
     LWOmxProducerListener(sp<IOmxProducerListener> const& base);
     void onBufferReleased() override;
     bool needsReleaseNotify() override;
-protected:
-    ::android::IBinder* onAsBinder() override;
 };
 
 }  // namespace implementation
diff --git a/media/libstagefright/omx/hal/1.0/utils/Android.mk b/media/libstagefright/omx/hal/1.0/utils/Android.mk
index 6930c87..c44ce25 100644
--- a/media/libstagefright/omx/hal/1.0/utils/Android.mk
+++ b/media/libstagefright/omx/hal/1.0/utils/Android.mk
@@ -25,18 +25,17 @@
     libcutils \
     libbinder \
     liblog \
+    libbase \
     android.hardware.media.omx@1.0 \
     android.hardware.graphics.common@1.0 \
     android.hardware.media@1.0 \
     android.hidl.base@1.0 \
 
 LOCAL_C_INCLUDES += \
-        $(TOP) \
-        $(TOP)/frameworks/av/include/media \
-        $(TOP)/frameworks/av/media/libstagefright/include \
-        $(TOP)/frameworks/av/media/libstagefright/omx \
-        $(TOP)/frameworks/native/include/media/hardware \
-        $(TOP)/frameworks/native/include/media/openmax \
+        $(TOP)/frameworks/av/include \
+        $(TOP)/frameworks/av/media/libstagefright \
         $(TOP)/frameworks/native/include \
+        $(TOP)/frameworks/native/include/media/openmax \
+        $(TOP)/frameworks/native/include/media/hardware \
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/omx/hal/1.0/utils/Conversion.h b/media/libstagefright/omx/hal/1.0/utils/Conversion.h
index 6f4d864..c4876ac 100644
--- a/media/libstagefright/omx/hal/1.0/utils/Conversion.h
+++ b/media/libstagefright/omx/hal/1.0/utils/Conversion.h
@@ -17,29 +17,26 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0__CONVERSION_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0__CONVERSION_H
 
+#include <vector>
+#include <list>
+
+#include <unistd.h>
+
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 #include <hidlmemory/mapping.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-
-#include <unistd.h>
-#include <vector>
-#include <list>
 
 #include <binder/Binder.h>
 #include <binder/Status.h>
 #include <ui/FenceTime.h>
-
-#include <OMXFenceParcelable.h>
+#include <media/OMXFenceParcelable.h>
 #include <cutils/native_handle.h>
 #include <gui/IGraphicBufferProducer.h>
 
-#include <IOMX.h>
+#include <media/OMXBuffer.h>
 #include <VideoAPI.h>
-#include <OMXBuffer.h>
-#include <android/IOMXBufferSource.h>
-#include <android/IGraphicBufferSource.h>
 
+#include <android/hidl/memory/1.0/IMemory.h>
 #include <android/hardware/media/omx/1.0/types.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
@@ -49,6 +46,9 @@
 #include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
 #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
 
+#include <android/IGraphicBufferSource.h>
+#include <android/IOMXBufferSource.h>
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -177,25 +177,6 @@
  */
 
 /**
- * \brief Convert `binder::Status` to `Return<void>`.
- *
- * \param[in] l The source `binder::Status`.
- * \return The corresponding `Return<void>`.
- */
-// 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(
-                l.serviceSpecificErrorCode(),
-                l.exceptionMessage());
-    }
-    return ::android::hardware::Status::fromExceptionCode(
-            l.exceptionCode(),
-            l.exceptionMessage());
-}
-
-/**
  * \brief Convert `Return<void>` to `binder::Status`.
  *
  * \param[in] t The source `Return<void>`.
@@ -294,7 +275,7 @@
     if (!*nh) {
         return false;
     }
-    t->fence = inHidlHandle(*nh);
+    t->fence = *nh;
     switch (l.type) {
         case omx_message::EVENT:
             t->type = Message::Type::EVENT;
@@ -560,6 +541,76 @@
 }
 
 /**
+ * \brief Wrap `GraphicBuffer` in `AnwBuffer`.
+ *
+ * \param[out] t The wrapper of type `AnwBuffer`.
+ * \param[in] l The source `GraphicBuffer`.
+ */
+// wrap: GraphicBuffer -> AnwBuffer
+inline void wrapAs(AnwBuffer* t, GraphicBuffer const& l) {
+    t->attr.width = l.getWidth();
+    t->attr.height = l.getHeight();
+    t->attr.stride = l.getStride();
+    t->attr.format = static_cast<PixelFormat>(l.getPixelFormat());
+    t->attr.layerCount = l.getLayerCount();
+    t->attr.usage = l.getUsage();
+    t->attr.id = l.getId();
+    t->attr.generationNumber = l.getGenerationNumber();
+    t->nativeHandle = hidl_handle(l.handle);
+}
+
+/**
+ * \brief Convert `AnwBuffer` to `GraphicBuffer`.
+ *
+ * \param[out] l The destination `GraphicBuffer`.
+ * \param[in] t The source `AnwBuffer`.
+ *
+ * This function will duplicate all file descriptors in \p t.
+ */
+// convert: AnwBuffer -> GraphicBuffer
+// Ref: frameworks/native/libs/ui/GraphicBuffer.cpp: GraphicBuffer::flatten
+inline bool convertTo(GraphicBuffer* l, AnwBuffer const& t) {
+    native_handle_t* handle = t.nativeHandle == nullptr ?
+            nullptr : native_handle_clone(t.nativeHandle);
+
+    size_t const numInts = 12 + (handle ? handle->numInts : 0);
+    int32_t* ints = new int32_t[numInts];
+
+    size_t numFds = static_cast<size_t>(handle ? handle->numFds : 0);
+    int* fds = new int[numFds];
+
+    ints[0] = 'GBFR';
+    ints[1] = static_cast<int32_t>(t.attr.width);
+    ints[2] = static_cast<int32_t>(t.attr.height);
+    ints[3] = static_cast<int32_t>(t.attr.stride);
+    ints[4] = static_cast<int32_t>(t.attr.format);
+    ints[5] = static_cast<int32_t>(t.attr.layerCount);
+    ints[6] = static_cast<int32_t>(t.attr.usage);
+    ints[7] = static_cast<int32_t>(t.attr.id >> 32);
+    ints[8] = static_cast<int32_t>(t.attr.id & 0xFFFFFFFF);
+    ints[9] = static_cast<int32_t>(t.attr.generationNumber);
+    ints[10] = 0;
+    ints[11] = 0;
+    if (handle) {
+        ints[10] = static_cast<int32_t>(handle->numFds);
+        ints[11] = static_cast<int32_t>(handle->numInts);
+        int* intsStart = handle->data + handle->numFds;
+        std::copy(handle->data, intsStart, fds);
+        std::copy(intsStart, intsStart + handle->numInts, &ints[12]);
+    }
+
+    void const* constBuffer = static_cast<void const*>(ints);
+    size_t size = numInts * sizeof(int32_t);
+    int const* constFds = static_cast<int const*>(fds);
+    status_t status = l->unflatten(constBuffer, size, constFds, numFds);
+
+    delete [] fds;
+    delete [] ints;
+    native_handle_delete(handle);
+    return status == NO_ERROR;
+}
+
+/**
  * \brief Wrap `OMXBuffer` in `CodecBuffer`.
  *
  * \param[out] t The wrapper of type `CodecBuffer`.
@@ -568,8 +619,8 @@
  */
 // wrap: OMXBuffer -> CodecBuffer
 inline bool wrapAs(CodecBuffer* t, OMXBuffer const& l) {
-    t->nativeHandle = hidl_handle();
     t->sharedMemory = hidl_memory();
+    t->nativeHandle = hidl_handle();
     switch (l.mBufferType) {
         case OMXBuffer::kBufferTypeInvalid: {
             t->type = CodecBuffer::Type::INVALID;
@@ -592,6 +643,15 @@
         }
         case OMXBuffer::kBufferTypeANWBuffer: {
             t->type = CodecBuffer::Type::ANW_BUFFER;
+            if (l.mGraphicBuffer == nullptr) {
+                t->attr.anwBuffer.width = 0;
+                t->attr.anwBuffer.height = 0;
+                t->attr.anwBuffer.stride = 0;
+                t->attr.anwBuffer.format = static_cast<PixelFormat>(1);
+                t->attr.anwBuffer.layerCount = 0;
+                t->attr.anwBuffer.usage = 0;
+                return true;
+            }
             t->attr.anwBuffer.width = l.mGraphicBuffer->getWidth();
             t->attr.anwBuffer.height = l.mGraphicBuffer->getHeight();
             t->attr.anwBuffer.stride = l.mGraphicBuffer->getStride();
@@ -599,12 +659,12 @@
                     l.mGraphicBuffer->getPixelFormat());
             t->attr.anwBuffer.layerCount = l.mGraphicBuffer->getLayerCount();
             t->attr.anwBuffer.usage = l.mGraphicBuffer->getUsage();
-            t->nativeHandle = hidl_handle(l.mGraphicBuffer->handle);
+            t->nativeHandle = l.mGraphicBuffer->handle;
             return true;
         }
         case OMXBuffer::kBufferTypeNativeHandle: {
             t->type = CodecBuffer::Type::NATIVE_HANDLE;
-            t->nativeHandle = hidl_handle(l.mNativeHandle->handle());
+            t->nativeHandle = l.mNativeHandle->handle();
             return true;
         }
     }
@@ -636,16 +696,18 @@
             return true;
         }
         case CodecBuffer::Type::ANW_BUFFER: {
-            *l = OMXBuffer(sp<GraphicBuffer>(new GraphicBuffer(
-                    t.attr.anwBuffer.width,
-                    t.attr.anwBuffer.height,
-                    static_cast<::android::PixelFormat>(
-                            t.attr.anwBuffer.format),
-                    t.attr.anwBuffer.layerCount,
-                    t.attr.anwBuffer.usage,
-                    t.attr.anwBuffer.stride,
-                    native_handle_clone(t.nativeHandle),
-                    true)));
+            if (t.nativeHandle.getNativeHandle() == nullptr) {
+                *l = OMXBuffer(sp<GraphicBuffer>(nullptr));
+                return true;
+            }
+            AnwBuffer anwBuffer;
+            anwBuffer.nativeHandle = t.nativeHandle;
+            anwBuffer.attr = t.attr.anwBuffer;
+            sp<GraphicBuffer> graphicBuffer = new GraphicBuffer();
+            if (!convertTo(graphicBuffer.get(), anwBuffer)) {
+                return false;
+            }
+            *l = OMXBuffer(graphicBuffer);
             return true;
         }
         case CodecBuffer::Type::NATIVE_HANDLE: {
@@ -820,76 +882,6 @@
 }
 
 /**
- * \brief Wrap `GraphicBuffer` in `AnwBuffer`.
- *
- * \param[out] t The wrapper of type `AnwBuffer`.
- * \param[in] l The source `GraphicBuffer`.
- */
-// wrap: GraphicBuffer -> AnwBuffer
-inline void wrapAs(AnwBuffer* t, GraphicBuffer const& l) {
-    t->attr.width = l.getWidth();
-    t->attr.height = l.getHeight();
-    t->attr.stride = l.getStride();
-    t->attr.format = static_cast<PixelFormat>(l.getPixelFormat());
-    t->attr.layerCount = l.getLayerCount();
-    t->attr.usage = l.getUsage();
-    t->attr.id = l.getId();
-    t->attr.generationNumber = l.getGenerationNumber();
-    t->nativeHandle = hidl_handle(l.handle);
-}
-
-/**
- * \brief Convert `AnwBuffer` to `GraphicBuffer`.
- *
- * \param[out] l The destination `GraphicBuffer`.
- * \param[in] t The source `AnwBuffer`.
- *
- * This function will duplicate all file descriptors in \p t.
- */
-// convert: AnwBuffer -> GraphicBuffer
-// Ref: frameworks/native/libs/ui/GraphicBuffer.cpp: GraphicBuffer::flatten
-inline bool convertTo(GraphicBuffer* l, AnwBuffer const& t) {
-    native_handle_t* handle = t.nativeHandle == nullptr ?
-            nullptr : native_handle_clone(t.nativeHandle);
-
-    size_t const numInts = 12 + (handle ? handle->numInts : 0);
-    int32_t* ints = new int32_t[numInts];
-
-    size_t numFds = static_cast<size_t>(handle ? handle->numFds : 0);
-    int* fds = new int[numFds];
-
-    ints[0] = 'GBFR';
-    ints[1] = static_cast<int32_t>(t.attr.width);
-    ints[2] = static_cast<int32_t>(t.attr.height);
-    ints[3] = static_cast<int32_t>(t.attr.stride);
-    ints[4] = static_cast<int32_t>(t.attr.format);
-    ints[5] = static_cast<int32_t>(t.attr.layerCount);
-    ints[6] = static_cast<int32_t>(t.attr.usage);
-    ints[7] = static_cast<int32_t>(t.attr.id >> 32);
-    ints[8] = static_cast<int32_t>(t.attr.id & 0xFFFFFFFF);
-    ints[9] = static_cast<int32_t>(t.attr.generationNumber);
-    ints[10] = 0;
-    ints[11] = 0;
-    if (handle) {
-        ints[10] = static_cast<int32_t>(handle->numFds);
-        ints[11] = static_cast<int32_t>(handle->numInts);
-        int* intsStart = handle->data + handle->numFds;
-        std::copy(handle->data, intsStart, fds);
-        std::copy(intsStart, intsStart + handle->numInts, &ints[12]);
-    }
-
-    void const* constBuffer = static_cast<void const*>(ints);
-    size_t size = numInts * sizeof(int32_t);
-    int const* constFds = static_cast<int const*>(fds);
-    status_t status = l->unflatten(constBuffer, size, constFds, numFds);
-
-    delete [] fds;
-    delete [] ints;
-    native_handle_delete(handle);
-    return status == NO_ERROR;
-}
-
-/**
  * Conversion functions for types outside media
  * ============================================
  *
@@ -1026,7 +1018,7 @@
         if (*nh == nullptr) {
             return NO_MEMORY;
         }
-        *fence = hidl_handle(*nh);
+        *fence = *nh;
         ++fds;
         --numFds;
     } else {
@@ -1272,6 +1264,7 @@
         return NO_MEMORY;
     }
 
+    *nh = nullptr;
     ::android::FenceTime::Snapshot::State state;
     FlattenableUtils::read(buffer, size, state);
     switch (state) {
@@ -1483,9 +1476,10 @@
  */
 inline size_t getFlattenedSize(
         IOmxBufferProducer::FrameEventHistoryDelta const& t) {
-    size_t size = 4;
-    for (size_t i = 0; i < t.size(); ++i) {
-        size += getFlattenedSize(t[i]);
+    size_t size = 4 + // mDeltas.size()
+            sizeof(t.compositorTiming);
+    for (size_t i = 0; i < t.deltas.size(); ++i) {
+        size += getFlattenedSize(t.deltas[i]);
     }
     return size;
 }
@@ -1500,8 +1494,8 @@
 inline size_t getFdCount(
         IOmxBufferProducer::FrameEventHistoryDelta const& t) {
     size_t numFds = 0;
-    for (size_t i = 0; i < t.size(); ++i) {
-        numFds += getFdCount(t[i]);
+    for (size_t i = 0; i < t.deltas.size(); ++i) {
+        numFds += getFdCount(t.deltas[i]);
     }
     return numFds;
 }
@@ -1529,17 +1523,19 @@
         return NO_MEMORY;
     }
 
+    FlattenableUtils::read(buffer, size, t->compositorTiming);
+
     uint32_t deltaCount = 0;
     FlattenableUtils::read(buffer, size, deltaCount);
     if (static_cast<size_t>(deltaCount) >
             ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
         return BAD_VALUE;
     }
-    t->resize(deltaCount);
+    t->deltas.resize(deltaCount);
     nh->resize(deltaCount);
     for (size_t deltaIndex = 0; deltaIndex < deltaCount; ++deltaIndex) {
         status_t status = unflatten(
-                &((*t)[deltaIndex]), &((*nh)[deltaIndex]),
+                &(t->deltas[deltaIndex]), &((*nh)[deltaIndex]),
                 buffer, size, fds, numFds);
         if (status != NO_ERROR) {
             return status;
@@ -1563,16 +1559,18 @@
 inline status_t flatten(
         IOmxBufferProducer::FrameEventHistoryDelta const& t,
         void*& buffer, size_t& size, int*& fds, size_t& numFds) {
-    if (t.size() > ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+    if (t.deltas.size() > ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
         return BAD_VALUE;
     }
     if (size < getFlattenedSize(t)) {
         return NO_MEMORY;
     }
 
-    FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.size()));
-    for (size_t deltaIndex = 0; deltaIndex < t.size(); ++deltaIndex) {
-        status_t status = flatten(t[deltaIndex], buffer, size, fds, numFds);
+    FlattenableUtils::write(buffer, size, t.compositorTiming);
+
+    FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.deltas.size()));
+    for (size_t deltaIndex = 0; deltaIndex < t.deltas.size(); ++deltaIndex) {
+        status_t status = flatten(t.deltas[deltaIndex], buffer, size, fds, numFds);
         if (status != NO_ERROR) {
             return status;
         }
@@ -1868,6 +1866,7 @@
  * \brief Flatten `IOmxBufferProducer::QueueBufferInput`.
  *
  * \param[in] t The source `IOmxBufferProducer::QueueBufferInput`.
+ * \param[out] nh The native handle cloned from `t.fence`.
  * \param[in,out] buffer The pointer to the flat non-fd buffer.
  * \param[in,out] size The size of the flat non-fd buffer.
  * \param[in,out] fds The pointer to the flat fd buffer.
@@ -1876,6 +1875,7 @@
  *
  * This function will duplicate the file descriptor in `t.fence`. */
 inline status_t flatten(IOmxBufferProducer::QueueBufferInput const& t,
+        native_handle_t** nh,
         void*& buffer, size_t& size, int*& fds, size_t& numFds) {
     if (size < getFlattenedSize(t)) {
         return NO_MEMORY;
@@ -1895,7 +1895,9 @@
     FlattenableUtils::write(buffer, size, t.stickyTransform);
     FlattenableUtils::write(buffer, size, t.getFrameTimestamps);
 
-    status_t status = flattenFence(t.fence, buffer, size, fds, numFds);
+    *nh = t.fence.getNativeHandle() == nullptr ?
+            nullptr : native_handle_clone(t.fence);
+    status_t status = flattenFence(hidl_handle(*nh), buffer, size, fds, numFds);
     if (status != NO_ERROR) {
         return status;
     }
@@ -2037,7 +2039,8 @@
     size_t size = baseSize;
     int* fds = baseFds.get();
     size_t numFds = baseNumFds;
-    if (flatten(t, buffer, size, fds, numFds) != NO_ERROR) {
+    native_handle_t* nh;
+    if (flatten(t, &nh, buffer, size, fds, numFds) != NO_ERROR) {
         return false;
     }
 
@@ -2046,9 +2049,12 @@
     int const* constFds = static_cast<int const*>(baseFds.get());
     numFds = baseNumFds;
     if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+        native_handle_close(nh);
+        native_handle_delete(nh);
         return false;
     }
 
+    native_handle_delete(nh);
     return true;
 }
 
@@ -2082,6 +2088,7 @@
     t->transformHint = l.transformHint;
     t->numPendingBuffers = l.numPendingBuffers;
     t->nextFrameNumber = l.nextFrameNumber;
+    t->bufferReplaced = l.bufferReplaced;
     return true;
 }
 
@@ -2107,6 +2114,7 @@
     l->transformHint = t.transformHint;
     l->numPendingBuffers = t.numPendingBuffers;
     l->nextFrameNumber = t.nextFrameNumber;
+    l->bufferReplaced = t.bufferReplaced;
     return true;
 }
 
diff --git a/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.cpp b/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.cpp
index 037e9b2..0ba6060 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.cpp
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-#include "WGraphicBufferSource.h"
-#include "Conversion.h"
-#include "WOmxNode.h"
 #include <stagefright/foundation/ColorUtils.h>
 
+#include "WGraphicBufferSource.h"
+#include "WOmxNode.h"
+#include "Conversion.h"
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -39,8 +40,9 @@
             new TWOmxNode(omxNode), toHardwareDataspace(dataSpace)));
 }
 
-::android::binder::Status LWGraphicBufferSource::setSuspend(bool suspend) {
-    return toBinderStatus(mBase->setSuspend(suspend));
+::android::binder::Status LWGraphicBufferSource::setSuspend(
+        bool suspend, int64_t timeUs) {
+    return toBinderStatus(mBase->setSuspend(suspend, timeUs));
 }
 
 ::android::binder::Status LWGraphicBufferSource::setRepeatPreviousFrameDelayUs(
@@ -63,6 +65,11 @@
     return toBinderStatus(mBase->setStartTimeUs(startTimeUs));
 }
 
+::android::binder::Status LWGraphicBufferSource::setStopTimeUs(
+        int64_t stopTimeUs) {
+    return toBinderStatus(mBase->setStopTimeUs(stopTimeUs));
+}
+
 ::android::binder::Status LWGraphicBufferSource::setColorAspects(
         int32_t aspects) {
     return toBinderStatus(mBase->setColorAspects(
@@ -78,10 +85,6 @@
     return toBinderStatus(mBase->signalEndOfInputStream());
 }
 
-::android::IBinder* LWGraphicBufferSource::onAsBinder() {
-    return nullptr;
-}
-
 // TWGraphicBufferSource
 TWGraphicBufferSource::TWGraphicBufferSource(
         sp<LGraphicBufferSource> const& base) : mBase(base) {
@@ -89,47 +92,57 @@
 
 Return<void> TWGraphicBufferSource::configure(
         const sp<IOmxNode>& omxNode, Dataspace dataspace) {
-    return toHardwareStatus(mBase->configure(
-            new LWOmxNode(omxNode),
-            toRawDataspace(dataspace)));
+    mBase->configure(new LWOmxNode(omxNode), toRawDataspace(dataspace));
+    return Void();
 }
 
-Return<void> TWGraphicBufferSource::setSuspend(bool suspend) {
-    return toHardwareStatus(mBase->setSuspend(suspend));
+Return<void> TWGraphicBufferSource::setSuspend(
+        bool suspend, int64_t timeUs) {
+    mBase->setSuspend(suspend, timeUs);
+    return Void();
 }
 
 Return<void> TWGraphicBufferSource::setRepeatPreviousFrameDelayUs(
         int64_t repeatAfterUs) {
-    return toHardwareStatus(mBase->setRepeatPreviousFrameDelayUs(
-            repeatAfterUs));
+    mBase->setRepeatPreviousFrameDelayUs(repeatAfterUs);
+    return Void();
 }
 
 Return<void> TWGraphicBufferSource::setMaxFps(float maxFps) {
-    return toHardwareStatus(mBase->setMaxFps(maxFps));
+    mBase->setMaxFps(maxFps);
+    return Void();
 }
 
 Return<void> TWGraphicBufferSource::setTimeLapseConfig(
         int64_t timePerFrameUs, int64_t timePerCaptureUs) {
-    return toHardwareStatus(mBase->setTimeLapseConfig(
-            timePerFrameUs, timePerCaptureUs));
+    mBase->setTimeLapseConfig(timePerFrameUs, timePerCaptureUs);
+    return Void();
 }
 
 Return<void> TWGraphicBufferSource::setStartTimeUs(int64_t startTimeUs) {
-    return toHardwareStatus(mBase->setStartTimeUs(startTimeUs));
+    mBase->setStartTimeUs(startTimeUs);
+    return Void();
+}
+
+Return<void> TWGraphicBufferSource::setStopTimeUs(int64_t stopTimeUs) {
+    mBase->setStopTimeUs(stopTimeUs);
+    return Void();
 }
 
 Return<void> TWGraphicBufferSource::setColorAspects(
         const ColorAspects& aspects) {
-    return toHardwareStatus(mBase->setColorAspects(toCompactColorAspects(
-            aspects)));
+    mBase->setColorAspects(toCompactColorAspects(aspects));
+    return Void();
 }
 
 Return<void> TWGraphicBufferSource::setTimeOffsetUs(int64_t timeOffsetUs) {
-    return toHardwareStatus(mBase->setTimeOffsetUs(timeOffsetUs));
+    mBase->setTimeOffsetUs(timeOffsetUs);
+    return Void();
 }
 
 Return<void> TWGraphicBufferSource::signalEndOfInputStream() {
-    return toHardwareStatus(mBase->signalEndOfInputStream());
+    mBase->signalEndOfInputStream();
+    return Void();
 }
 
 }  // namespace utils
diff --git a/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.h b/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.h
index 17a4486..1090d52 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WGraphicBufferSource.h
@@ -17,16 +17,17 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERSOURCE_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERSOURCE_H
 
-#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <frameworks/native/include/binder/Binder.h>
-#include <IOMX.h>
-#include <android/IGraphicBufferSource.h>
-#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <media/IOMX.h>
+#include <binder/Binder.h>
 
 #include <android/hardware/graphics/common/1.0/types.h>
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+
+#include <android/BnGraphicBufferSource.h>
 
 namespace android {
 namespace hardware {
@@ -60,26 +61,26 @@
  */
 
 typedef ::android::IGraphicBufferSource LGraphicBufferSource;
+typedef ::android::BnGraphicBufferSource BnGraphicBufferSource;
 typedef ::android::hardware::media::omx::V1_0::IGraphicBufferSource
         TGraphicBufferSource;
 
-struct LWGraphicBufferSource : public LGraphicBufferSource {
+struct LWGraphicBufferSource : public BnGraphicBufferSource {
     sp<TGraphicBufferSource> mBase;
     LWGraphicBufferSource(sp<TGraphicBufferSource> const& base);
     ::android::binder::Status configure(
             const sp<IOMXNode>& omxNode, int32_t dataSpace) override;
-    ::android::binder::Status setSuspend(bool suspend) override;
+    ::android::binder::Status setSuspend(bool suspend, int64_t timeUs) override;
     ::android::binder::Status setRepeatPreviousFrameDelayUs(
             int64_t repeatAfterUs) override;
     ::android::binder::Status setMaxFps(float maxFps) override;
     ::android::binder::Status setTimeLapseConfig(
             int64_t timePerFrameUs, int64_t timePerCaptureUs) override;
     ::android::binder::Status setStartTimeUs(int64_t startTimeUs) override;
+    ::android::binder::Status setStopTimeUs(int64_t stopTimeUs) override;
     ::android::binder::Status setColorAspects(int32_t aspects) override;
     ::android::binder::Status setTimeOffsetUs(int64_t timeOffsetsUs) override;
     ::android::binder::Status signalEndOfInputStream() override;
-protected:
-    ::android::IBinder* onAsBinder() override;
 };
 
 struct TWGraphicBufferSource : public TGraphicBufferSource {
@@ -87,12 +88,13 @@
     TWGraphicBufferSource(sp<LGraphicBufferSource> const& base);
     Return<void> configure(
             const sp<IOmxNode>& omxNode, Dataspace dataspace) override;
-    Return<void> setSuspend(bool suspend) override;
+    Return<void> setSuspend(bool suspend, int64_t timeUs) override;
     Return<void> setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) override;
     Return<void> setMaxFps(float maxFps) override;
     Return<void> setTimeLapseConfig(
             int64_t timePerFrameUs, int64_t timePerCaptureUs) override;
     Return<void> setStartTimeUs(int64_t startTimeUs) override;
+    Return<void> setStopTimeUs(int64_t stopTimeUs) override;
     Return<void> setColorAspects(const ColorAspects& aspects) override;
     Return<void> setTimeOffsetUs(int64_t timeOffsetUs) override;
     Return<void> signalEndOfInputStream() override;
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmx.cpp b/media/libstagefright/omx/hal/1.0/utils/WOmx.cpp
index 07c9255..00f40cd 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmx.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmx.cpp
@@ -79,10 +79,6 @@
     return transStatus == NO_ERROR ? fnStatus : transStatus;
 }
 
-::android::IBinder* LWOmx::onAsBinder() {
-    return nullptr;
-}
-
 // TWOmx
 TWOmx::TWOmx(sp<IOMX> const& base) : mBase(base) {
 }
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmx.h b/media/libstagefright/omx/hal/1.0/utils/WOmx.h
index 26affad..7860f46 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmx.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmx.h
@@ -17,11 +17,12 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMX_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMX_H
 
-#include <android/hardware/media/omx/1.0/IOmx.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <IOMX.h>
+#include "../../../../include/OMXNodeInstance.h"
+
+#include <android/hardware/media/omx/1.0/IOmx.h>
 
 namespace android {
 namespace hardware {
@@ -45,6 +46,7 @@
 
 using ::android::List;
 using ::android::IOMX;
+using ::android::BnOMX;
 
 /**
  * Wrapper classes for conversion
@@ -55,7 +57,7 @@
  * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
  */
 
-struct LWOmx : public IOMX {
+struct LWOmx : public BnOMX {
     sp<IOmx> mBase;
     LWOmx(sp<IOmx> const& base);
     status_t listNodes(List<IOMX::ComponentInfo>* list) override;
@@ -66,8 +68,6 @@
     status_t createInputSurface(
             sp<::android::IGraphicBufferProducer>* bufferProducer,
             sp<::android::IGraphicBufferSource>* bufferSource) override;
-protected:
-    ::android::IBinder* onAsBinder() override;
 };
 
 struct TWOmx : public IOmx {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.cpp b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.cpp
index 49f2706..e9a93b9 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.cpp
@@ -14,8 +14,13 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "WOmxBufferProducer-utils"
+
+#include <android-base/logging.h>
+
 #include "WOmxBufferProducer.h"
 #include "WOmxProducerListener.h"
+#include "Conversion.h"
 
 namespace android {
 namespace hardware {
@@ -62,23 +67,29 @@
             width, height,
             static_cast<::android::PixelFormat>(format), usage,
             getFrameTimestamps ? &outTimestamps : nullptr);
-
     hidl_handle tFence;
-    native_handle_t* nh;
-    if (!wrapAs(&tFence, &nh, *fence)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::dequeueBuffer(): "
-                "Cannot wrap Fence in hidl_handle"));
-    }
     FrameEventHistoryDelta tOutTimestamps;
+
+    native_handle_t* nh = nullptr;
+    if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
+        LOG(ERROR) << "TWOmxBufferProducer::dequeueBuffer - "
+                "Invalid output fence";
+        _hidl_cb(toStatus(status),
+                 static_cast<int32_t>(slot),
+                 tFence,
+                 tOutTimestamps);
+        return Void();
+    }
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (getFrameTimestamps && !wrapAs(&tOutTimestamps, &nhAA, outTimestamps)) {
+        LOG(ERROR) << "TWOmxBufferProducer::dequeueBuffer - "
+                "Invalid output timestamps";
+        _hidl_cb(toStatus(status),
+                 static_cast<int32_t>(slot),
+                 tFence,
+                 tOutTimestamps);
         native_handle_delete(nh);
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::dequeueBuffer(): "
-                "Cannot wrap Fence in hidl_handle"));
+        return Void();
     }
 
     _hidl_cb(toStatus(status),
@@ -89,9 +100,7 @@
     if (getFrameTimestamps) {
         for (auto& nhA : nhAA) {
             for (auto& handle : nhA) {
-                if (handle != nullptr) {
-                    native_handle_delete(handle);
-                }
+                native_handle_delete(handle);
             }
         }
     }
@@ -107,16 +116,22 @@
     sp<GraphicBuffer> outBuffer;
     sp<Fence> outFence;
     status_t status = mBase->detachNextBuffer(&outBuffer, &outFence);
-
     AnwBuffer tBuffer;
-    wrapAs(&tBuffer, *outBuffer);
     hidl_handle tFence;
-    native_handle_t* nh;
-    if (!wrapAs(&tFence, &nh, *outFence)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::detachNextBuffer(): "
-                "Cannot wrap Fence in hidl_handle"));
+
+    if (outBuffer == nullptr) {
+        LOG(ERROR) << "TWOmxBufferProducer::detachNextBuffer - "
+                "Invalid output buffer";
+        _hidl_cb(toStatus(status), tBuffer, tFence);
+        return Void();
+    }
+    wrapAs(&tBuffer, *outBuffer);
+    native_handle_t* nh = nullptr;
+    if ((outFence != nullptr) && !wrapAs(&tFence, &nh, *outFence)) {
+        LOG(ERROR) << "TWOmxBufferProducer::detachNextBuffer - "
+                "Invalid output fence";
+        _hidl_cb(toStatus(status), tBuffer, tFence);
+        return Void();
     }
 
     _hidl_cb(toStatus(status), tBuffer, tFence);
@@ -130,10 +145,10 @@
     int outSlot;
     sp<GraphicBuffer> lBuffer = new GraphicBuffer();
     if (!convertTo(lBuffer.get(), buffer)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::attachBuffer(): "
-                "Cannot convert AnwBuffer to GraphicBuffer"));
+        LOG(ERROR) << "TWOmxBufferProducer::attachBuffer - "
+                "Invalid input native window buffer";
+        _hidl_cb(toStatus(BAD_VALUE), -1);
+        return Void();
     }
     status_t status = mBase->attachBuffer(&outSlot, lBuffer);
 
@@ -144,38 +159,34 @@
 Return<void> TWOmxBufferProducer::queueBuffer(
         int32_t slot, const QueueBufferInput& input,
         queueBuffer_cb _hidl_cb) {
+    QueueBufferOutput tOutput;
     IGraphicBufferProducer::QueueBufferInput lInput(
             0, false, HAL_DATASPACE_UNKNOWN,
             ::android::Rect(0, 0, 1, 1),
             NATIVE_WINDOW_SCALING_MODE_FREEZE,
             0, ::android::Fence::NO_FENCE);
     if (!convertTo(&lInput, input)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::queueBuffer(): "
-                "Cannot convert IOmxBufferProducer::QueueBufferInput "
-                "to IGraphicBufferProducer::QueueBufferInput"));
+        LOG(ERROR) << "TWOmxBufferProducer::queueBuffer - "
+                "Invalid input";
+        _hidl_cb(toStatus(BAD_VALUE), tOutput);
+        return Void();
     }
     IGraphicBufferProducer::QueueBufferOutput lOutput;
     status_t status = mBase->queueBuffer(
             static_cast<int>(slot), lInput, &lOutput);
 
-    QueueBufferOutput tOutput;
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (!wrapAs(&tOutput, &nhAA, lOutput)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::queueBuffer(): "
-                "Cannot wrap IGraphicBufferProducer::QueueBufferOutput "
-                "in IOmxBufferProducer::QueueBufferOutput"));
+        LOG(ERROR) << "TWOmxBufferProducer::queueBuffer - "
+                "Invalid output";
+        _hidl_cb(toStatus(BAD_VALUE), tOutput);
+        return Void();
     }
 
     _hidl_cb(toStatus(status), tOutput);
     for (auto& nhA : nhAA) {
         for (auto& nh : nhA) {
-            if (nh != nullptr) {
-                native_handle_delete(nh);
-            }
+            native_handle_delete(nh);
         }
     }
     return Void();
@@ -185,10 +196,9 @@
         int32_t slot, const hidl_handle& fence) {
     sp<Fence> lFence = new Fence();
     if (!convertTo(lFence.get(), fence)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::cancelBuffer(): "
-                "Cannot convert hidl_handle to Fence"));
+        LOG(ERROR) << "TWOmxBufferProducer::cancelBuffer - "
+                "Invalid input fence";
+        return toStatus(BAD_VALUE);
     }
     return toStatus(mBase->cancelBuffer(static_cast<int>(slot), lFence));
 }
@@ -203,7 +213,8 @@
 Return<void> TWOmxBufferProducer::connect(
         const sp<IOmxProducerListener>& listener,
         int32_t api, bool producerControlledByApp, connect_cb _hidl_cb) {
-    sp<IProducerListener> lListener = new LWOmxProducerListener(listener);
+    sp<IProducerListener> lListener = listener == nullptr ?
+            nullptr : new LWOmxProducerListener(listener);
     IGraphicBufferProducer::QueueBufferOutput lOutput;
     status_t status = mBase->connect(lListener,
             static_cast<int>(api),
@@ -213,19 +224,16 @@
     QueueBufferOutput tOutput;
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (!wrapAs(&tOutput, &nhAA, lOutput)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::connect(): "
-                "Cannot wrap IGraphicBufferProducer::QueueBufferOutput "
-                "in IOmxBufferProducer::QueueBufferOutput"));
+        LOG(ERROR) << "TWOmxBufferProducer::connect - "
+                "Invalid output";
+        _hidl_cb(toStatus(status), tOutput);
+        return Void();
     }
 
     _hidl_cb(toStatus(status), tOutput);
     for (auto& nhA : nhAA) {
         for (auto& nh : nhA) {
-            if (nh != nullptr) {
-                native_handle_delete(nh);
-            }
+            native_handle_delete(nh);
         }
     }
     return Void();
@@ -286,14 +294,19 @@
             &lOutBuffer, &lOutFence, lOutTransformMatrix);
 
     AnwBuffer tOutBuffer;
-    wrapAs(&tOutBuffer, *lOutBuffer);
+    if (lOutBuffer != nullptr) {
+        wrapAs(&tOutBuffer, *lOutBuffer);
+    }
     hidl_handle tOutFence;
-    native_handle_t* nh;
-    if (!wrapAs(&tOutFence, &nh, *lOutFence)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::getLastQueuedBuffer(): "
-                "Cannot wrap Fence in hidl_handle"));
+    native_handle_t* nh = nullptr;
+    if ((lOutFence == nullptr) || !wrapAs(&tOutFence, &nh, *lOutFence)) {
+        LOG(ERROR) << "TWOmxBufferProducer::getLastQueuedBuffer - "
+                "Invalid output fence";
+        _hidl_cb(toStatus(status),
+                tOutBuffer,
+                tOutFence,
+                hidl_array<float, 16>());
+        return Void();
     }
     hidl_array<float, 16> tOutTransformMatrix(lOutTransformMatrix);
 
@@ -310,19 +323,16 @@
     FrameEventHistoryDelta tDelta;
     std::vector<std::vector<native_handle_t*> > nhAA;
     if (!wrapAs(&tDelta, &nhAA, lDelta)) {
-        return ::android::hardware::Status::fromExceptionCode(
-                ::android::hardware::Status::EX_BAD_PARCELABLE,
-                String8("TWOmxBufferProducer::getFrameTimestamps(): "
-                "Cannot wrap ::android::FrameEventHistoryDelta "
-                "in FrameEventHistoryDelta"));
+        LOG(ERROR) << "TWOmxBufferProducer::getFrameTimestamps - "
+                "Invalid output frame timestamps";
+        _hidl_cb(tDelta);
+        return Void();
     }
 
     _hidl_cb(tDelta);
     for (auto& nhA : nhAA) {
         for (auto& nh : nhA) {
-            if (nh != nullptr) {
-                native_handle_delete(nh);
-            }
+            native_handle_delete(nh);
         }
     }
     return Void();
@@ -382,9 +392,13 @@
                 fnStatus = toStatusT(status);
                 *slot = tSlot;
                 if (!convertTo(fence->get(), tFence)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::dequeueBuffer - "
+                            "Invalid output fence";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 if (outTimestamps && !convertTo(outTimestamps, tTs)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::dequeueBuffer - "
+                            "Invalid output timestamps";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -407,9 +421,13 @@
                     hidl_handle const& tFence) {
                 fnStatus = toStatusT(status);
                 if (!convertTo(outFence->get(), tFence)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::detachNextBuffer - "
+                            "Invalid output fence";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 if (!convertTo(outBuffer->get(), tBuffer)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::detachNextBuffer - "
+                            "Invalid output buffer";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -436,6 +454,8 @@
     IOmxBufferProducer::QueueBufferInput tInput;
     native_handle_t* nh;
     if (!wrapAs(&tInput, &nh, input)) {
+        LOG(ERROR) << "LWOmxBufferProducer::queueBuffer - "
+                "Invalid input";
         return BAD_VALUE;
     }
     status_t fnStatus;
@@ -445,6 +465,8 @@
                     IOmxBufferProducer::QueueBufferOutput const& tOutput) {
                 fnStatus = toStatusT(status);
                 if (!convertTo(output, tOutput)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::queueBuffer - "
+                            "Invalid output";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -454,8 +476,10 @@
 
 status_t LWOmxBufferProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
     hidl_handle tFence;
-    native_handle_t* nh;
-    if (!wrapAs(&tFence, &nh, *fence)) {
+    native_handle_t* nh = nullptr;
+    if ((fence == nullptr) || !wrapAs(&tFence, &nh, *fence)) {
+        LOG(ERROR) << "LWOmxBufferProducer::cancelBuffer - "
+                "Invalid input fence";
         return BAD_VALUE;
     }
 
@@ -479,7 +503,8 @@
 status_t LWOmxBufferProducer::connect(
         const sp<IProducerListener>& listener, int api,
         bool producerControlledByApp, QueueBufferOutput* output) {
-    sp<IOmxProducerListener> tListener = new TWOmxProducerListener(listener);
+    sp<IOmxProducerListener> tListener = listener == nullptr ?
+            nullptr : new TWOmxProducerListener(listener);
     status_t fnStatus;
     status_t transStatus = toStatusT(mBase->connect(
             tListener, static_cast<int32_t>(api), producerControlledByApp,
@@ -488,6 +513,8 @@
                     IOmxBufferProducer::QueueBufferOutput const& tOutput) {
                 fnStatus = toStatusT(status);
                 if (!convertTo(output, tOutput)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::connect - "
+                            "Invalid output";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
             }));
@@ -552,10 +579,14 @@
                 fnStatus = toStatusT(status);
                 *outBuffer = new GraphicBuffer();
                 if (!convertTo(outBuffer->get(), buffer)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::getLastQueuedBuffer - "
+                            "Invalid output buffer";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 *outFence = new Fence();
                 if (!convertTo(outFence->get(), fence)) {
+                    LOG(ERROR) << "LWOmxBufferProducer::getLastQueuedBuffer - "
+                            "Invalid output fence";
                     fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
                 }
                 std::copy(transformMatrix.data(),
@@ -582,10 +613,6 @@
     return transStatus == NO_ERROR ? fnStatus : transStatus;
 }
 
-::android::IBinder* LWOmxBufferProducer::onAsBinder() {
-    return nullptr;
-}
-
 }  // namespace utils
 }  // namespace V1_0
 }  // namespace omx
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.h b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.h
index 46abd27..54b9078 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferProducer.h
@@ -17,13 +17,14 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERPRODUCER_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERPRODUCER_H
 
-#include <android/hardware/media/omx/1.0/IOmxBufferProducer.h>
-#include <binder/Binder.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
+
+#include <binder/Binder.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/IProducerListener.h>
-#include "Conversion.h"
+
+#include <android/hardware/media/omx/1.0/IOmxBufferProducer.h>
 
 namespace android {
 namespace hardware {
@@ -47,6 +48,7 @@
 using ::android::sp;
 
 using ::android::IGraphicBufferProducer;
+using ::android::BnGraphicBufferProducer;
 using ::android::IProducerListener;
 
 struct TWOmxBufferProducer : public IOmxBufferProducer {
@@ -91,7 +93,7 @@
     Return<void> getUniqueId(getUniqueId_cb _hidl_cb) override;
 };
 
-struct LWOmxBufferProducer : public IGraphicBufferProducer {
+struct LWOmxBufferProducer : public BnGraphicBufferProducer {
     sp<IOmxBufferProducer> mBase;
     LWOmxBufferProducer(sp<IOmxBufferProducer> const& base);
 
@@ -128,8 +130,6 @@
           sp<Fence>* outFence, float outTransformMatrix[16]) override;
     void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override;
     status_t getUniqueId(uint64_t* outId) const override;
-protected:
-    ::android::IBinder* onAsBinder() override;
 };
 
 }  // namespace utils
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.cpp b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.cpp
index 1ebd9a7..fe565e6 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.cpp
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
+#include <utils/String8.h>
+
 #include "WOmxBufferSource.h"
 #include "Conversion.h"
-#include <utils/String8.h>
-#include <cutils/native_handle.h>
 
 namespace android {
 namespace hardware {
@@ -61,49 +61,44 @@
     ::android::binder::Status status = toBinderStatus(
             mBase->onInputBufferEmptied(
             static_cast<uint32_t>(bufferId), fence));
-    if (native_handle_delete(fenceNh) != 0) {
-        return ::android::binder::Status::fromExceptionCode(
-                ::android::binder::Status::EX_NULL_POINTER,
-                "Cannot delete native handle");
-    }
+    native_handle_close(fenceNh);
+    native_handle_delete(fenceNh);
     return status;
 }
 
-::android::IBinder* LWOmxBufferSource::onAsBinder() {
-    return nullptr;
-}
-
 // TWOmxBufferSource
 TWOmxBufferSource::TWOmxBufferSource(sp<IOMXBufferSource> const& base) :
     mBase(base) {
 }
 
 Return<void> TWOmxBufferSource::onOmxExecuting() {
-    return toHardwareStatus(mBase->onOmxExecuting());
+    mBase->onOmxExecuting();
+    return Void();
 }
 
 Return<void> TWOmxBufferSource::onOmxIdle() {
-    return toHardwareStatus(mBase->onOmxIdle());
+    mBase->onOmxIdle();
+    return Void();
 }
 
 Return<void> TWOmxBufferSource::onOmxLoaded() {
-    return toHardwareStatus(mBase->onOmxLoaded());
+    mBase->onOmxLoaded();
+    return Void();
 }
 
 Return<void> TWOmxBufferSource::onInputBufferAdded(uint32_t buffer) {
-    return toHardwareStatus(mBase->onInputBufferAdded(
-            static_cast<int32_t>(buffer)));
+    mBase->onInputBufferAdded(int32_t(buffer));
+    return Void();
 }
 
 Return<void> TWOmxBufferSource::onInputBufferEmptied(
         uint32_t buffer, hidl_handle const& fence) {
     OMXFenceParcelable fenceParcelable;
     if (!convertTo(&fenceParcelable, fence)) {
-      return ::android::hardware::Status::fromExceptionCode(
-              ::android::hardware::Status::EX_BAD_PARCELABLE);
+        return Void();
     }
-    return toHardwareStatus(mBase->onInputBufferEmptied(
-            static_cast<int32_t>(buffer), fenceParcelable));
+    mBase->onInputBufferEmptied(int32_t(buffer), fenceParcelable);
+    return Void();
 }
 
 }  // namespace utils
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.h b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.h
index 3bf35c5..086f648 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxBufferSource.h
@@ -17,13 +17,14 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERSOURCE_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXBUFFERSOURCE_H
 
-#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <frameworks/native/include/binder/Binder.h>
-#include <android/IOMXBufferSource.h>
-#include <OMXFenceParcelable.h>
+#include <binder/Binder.h>
+#include <media/OMXFenceParcelable.h>
+
+#include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
+#include <android/BnOMXBufferSource.h>
 
 namespace android {
 namespace hardware {
@@ -45,6 +46,7 @@
 
 using ::android::OMXFenceParcelable;
 using ::android::IOMXBufferSource;
+using ::android::BnOMXBufferSource;
 
 /**
  * Wrapper classes for conversion
@@ -55,7 +57,7 @@
  * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
  */
 
-struct LWOmxBufferSource : public IOMXBufferSource {
+struct LWOmxBufferSource : public BnOMXBufferSource {
     sp<IOmxBufferSource> mBase;
     LWOmxBufferSource(sp<IOmxBufferSource> const& base);
     ::android::binder::Status onOmxExecuting() override;
@@ -64,8 +66,6 @@
     ::android::binder::Status onInputBufferAdded(int32_t bufferID) override;
     ::android::binder::Status onInputBufferEmptied(
             int32_t bufferID, OMXFenceParcelable const& fenceParcel) override;
-protected:
-    ::android::IBinder* onAsBinder() override;
 };
 
 struct TWOmxBufferSource : public IOmxBufferSource {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxNode.cpp b/media/libstagefright/omx/hal/1.0/utils/WOmxNode.cpp
index 6764ba8..df191c7 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxNode.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxNode.cpp
@@ -14,14 +14,12 @@
  * limitations under the License.
  */
 
-#include <IOMX.h>
-#include <OMXNodeInstance.h>
+#include <algorithm>
+
 #include "WOmxNode.h"
 #include "WOmxBufferSource.h"
 #include "Conversion.h"
 
-#include <algorithm>
-
 namespace android {
 namespace hardware {
 namespace media {
@@ -252,10 +250,6 @@
     return toStatusT(mBase->setQuirks(static_cast<uint32_t>(quirks)));;
 }
 
-::android::IBinder* LWOmxNode::onAsBinder() {
-    return nullptr;
-}
-
 // TWOmxNode
 TWOmxNode::TWOmxNode(sp<IOMXNode> const& base) : mBase(base) {
 }
@@ -281,7 +275,8 @@
 }
 
 Return<Status> TWOmxNode::setParameter(
-        uint32_t index, hidl_vec<uint8_t> const& params) {
+        uint32_t index, hidl_vec<uint8_t> const& inParams) {
+    hidl_vec<uint8_t> params(inParams);
     return toStatus(mBase->setParameter(
             toEnumIndexType(index),
             static_cast<void const*>(params.data()),
@@ -301,7 +296,8 @@
 }
 
 Return<Status> TWOmxNode::setConfig(
-        uint32_t index, const hidl_vec<uint8_t>& config) {
+        uint32_t index, const hidl_vec<uint8_t>& inConfig) {
+    hidl_vec<uint8_t> config(inConfig);
     return toStatus(mBase->setConfig(
             toEnumIndexType(index),
             static_cast<void const*>(config.data()),
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxNode.h b/media/libstagefright/omx/hal/1.0/utils/WOmxNode.h
index cb0b1a7..46dfb49 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxNode.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxNode.h
@@ -17,13 +17,16 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXNODE_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXNODE_H
 
-#include <android/hardware/media/omx/1.0/IOmxNode.h>
-#include <android/hardware/media/omx/1.0/IOmxObserver.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
 #include <utils/Errors.h>
 
+#include "../../../../include/OMXNodeInstance.h"
+
+#include <android/hardware/media/omx/1.0/IOmxNode.h>
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -56,7 +59,7 @@
  * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
  */
 
-struct LWOmxNode : public IOMXNode {
+struct LWOmxNode : public BnOMXNode {
     sp<IOmxNode> mBase;
     LWOmxNode(sp<IOmxNode> const& base);
     status_t freeNode() override;
@@ -103,8 +106,6 @@
 
     // TODO: this is temporary, will be removed when quirks move to OMX side.
     status_t setQuirks(OMX_U32 quirks) override;
-protected:
-    ::android::IBinder* onAsBinder() override;
 };
 
 struct TWOmxNode : public IOmxNode {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.cpp b/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.cpp
index fea5a9a..05ec37e 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.cpp
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
-#include "WOmxObserver.h"
+#define LOG_TAG "WOmxObserver-utils"
 
 #include <vector>
 
+#include <android-base/logging.h>
 #include <cutils/native_handle.h>
-#include <frameworks/native/include/binder/Binder.h>
+#include <binder/Binder.h>
 
+#include "WOmxObserver.h"
 #include "Conversion.h"
 
 namespace android {
@@ -43,17 +45,16 @@
         wrapAs(&tMessages[i], &handles[i], message);
         ++i;
     }
-    mBase->onMessages(tMessages);
+    auto transResult = mBase->onMessages(tMessages);
+    if (!transResult.isOk()) {
+        LOG(ERROR) << "LWOmxObserver::onMessages - Transaction failed";
+    }
     for (auto& handle : handles) {
         native_handle_close(handle);
         native_handle_delete(handle);
     }
 }
 
-::android::IBinder* LWOmxObserver::onAsBinder() {
-    return nullptr;
-}
-
 // TWOmxObserver
 TWOmxObserver::TWOmxObserver(sp<IOMXObserver> const& base) : mBase(base) {
 }
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.h b/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.h
index b1e2eb1..d442218 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxObserver.h
@@ -17,12 +17,14 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXOBSERVER_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXOBSERVER_H
 
-#include <android/hardware/media/omx/1.0/IOmxObserver.h>
+#include <list>
+
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <IOMX.h>
-#include <list>
+#include <media/IOMX.h>
+
+#include <android/hardware/media/omx/1.0/IOmxObserver.h>
 
 namespace android {
 namespace hardware {
@@ -43,6 +45,7 @@
 using ::android::sp;
 
 using ::android::IOMXObserver;
+using ::android::BnOMXObserver;
 using ::android::omx_message;
 
 /**
@@ -54,12 +57,10 @@
  * - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
  */
 
-struct LWOmxObserver : public IOMXObserver {
+struct LWOmxObserver : public BnOMXObserver {
     sp<IOmxObserver> mBase;
     LWOmxObserver(sp<IOmxObserver> const& base);
     void onMessages(std::list<omx_message> const& lMessages) override;
-protected:
-    ::android::IBinder* onAsBinder() override;
 };
 
 struct TWOmxObserver : public IOmxObserver {
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.cpp b/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.cpp
index d43215d..80b0f71 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.cpp
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.cpp
@@ -52,11 +52,6 @@
     return static_cast<bool>(mBase->needsReleaseNotify());
 }
 
-::android::IBinder* LWOmxProducerListener::onAsBinder() {
-    return nullptr;
-}
-
-
 }  // namespace utils
 }  // namespace V1_0
 }  // namespace omx
diff --git a/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.h b/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.h
index 5b5e830..7d20887 100644
--- a/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.h
+++ b/media/libstagefright/omx/hal/1.0/utils/WOmxProducerListener.h
@@ -17,13 +17,14 @@
 #ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXPRODUCERLISTENER_H
 #define ANDROID_HARDWARE_MEDIA_OMX_V1_0_WOMXPRODUCERLISTENER_H
 
-#include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
 #include <binder/IBinder.h>
 #include <gui/IProducerListener.h>
 
+#include <android/hardware/media/omx/1.0/IOmxProducerListener.h>
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -42,6 +43,7 @@
 using ::android::sp;
 
 using ::android::IProducerListener;
+using ::android::BnProducerListener;
 
 struct TWOmxProducerListener : public IOmxProducerListener {
     sp<IProducerListener> mBase;
@@ -50,14 +52,12 @@
     Return<bool> needsReleaseNotify() override;
 };
 
-class LWOmxProducerListener : public IProducerListener {
+class LWOmxProducerListener : public BnProducerListener {
 public:
     sp<IOmxProducerListener> mBase;
     LWOmxProducerListener(sp<IOmxProducerListener> const& base);
     void onBufferReleased() override;
     bool needsReleaseNotify() override;
-protected:
-    ::android::IBinder* onAsBinder() override;
 };
 
 }  // namespace utils
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index 5e4ba10..6d0f189 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -2,15 +2,27 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES =       \
-	OMXHarness.cpp  \
+        OMXHarness.cpp  \
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright libbinder libmedia libutils liblog libstagefright_foundation
+        libstagefright \
+        libbinder \
+        libmedia \
+        libutils \
+        liblog \
+        libstagefright_foundation \
+        libcutils \
+        libhidlbase \
+        libhidlmemory \
+        android.hidl.allocator@1.0 \
+        android.hidl.memory@1.0 \
+        android.hardware.media.omx@1.0 \
+        android.hardware.media.omx@1.0-utils
 
 LOCAL_C_INCLUDES := \
-	$(TOP)/frameworks/av/media/libstagefright \
-	$(TOP)/frameworks/native/include/media/openmax \
-	$(TOP)/system/libhidl/base/include \
+        $(TOP)/frameworks/av/media/libstagefright \
+        $(TOP)/frameworks/native/include/media/openmax \
+        $(TOP)/system/libhidl/base/include \
 
 LOCAL_CFLAGS += -Werror -Wall
 
@@ -29,14 +41,14 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_SRC_FILES := \
-	FrameDropper_test.cpp \
+        FrameDropper_test.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright_omx \
-	libutils \
+        libstagefright_omx \
+        libutils \
 
 LOCAL_C_INCLUDES := \
-	frameworks/av/media/libstagefright/omx \
+        frameworks/av/media/libstagefright/omx \
 
 LOCAL_CFLAGS += -Werror -Wall
 
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 1ce5d1a..8817cf9 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -39,6 +39,8 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/SimpleDecodingSource.h>
 #include <media/OMXBuffer.h>
+#include <android/hardware/media/omx/1.0/IOmx.h>
+#include <omx/hal/1.0/utils/WOmx.h>
 
 #define DEFAULT_TIMEOUT         500000
 
@@ -64,7 +66,7 @@
 /////////////////////////////////////////////////////////////////////
 
 Harness::Harness()
-    : mInitCheck(NO_INIT) {
+    : mInitCheck(NO_INIT), mUseTreble(false) {
     mInitCheck = initOMX();
 }
 
@@ -76,10 +78,23 @@
 }
 
 status_t Harness::initOMX() {
-    sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> binder = sm->getService(String16("media.codec"));
-    sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
-    mOMX = service->getOMX();
+    int32_t trebleOmx = property_get_int32("persist.media.treble_omx", -1);
+    if ((trebleOmx == 1) || ((trebleOmx == -1) &&
+            property_get_bool("persist.hal.binderization", 0))) {
+        using namespace ::android::hardware::media::omx::V1_0;
+        sp<IOmx> tOmx = IOmx::getService();
+        if (tOmx == nullptr) {
+            return NO_INIT;
+        }
+        mOMX = new utils::LWOmx(tOmx);
+        mUseTreble = true;
+    } else {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder = sm->getService(String16("media.codec"));
+        sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
+        mOMX = service->getOMX();
+        mUseTreble = false;
+    }
 
     return mOMX != 0 ? OK : NO_INIT;
 }
@@ -197,7 +212,6 @@
     EXPECT((err) == OK, info " failed")
 
 status_t Harness::allocatePortBuffers(
-        const sp<MemoryDealer> &dealer,
         OMX_U32 portIndex, Vector<Buffer> *buffers) {
     buffers->clear();
 
@@ -207,11 +221,27 @@
 
     for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
         Buffer buffer;
-        buffer.mMemory = dealer->allocate(def.nBufferSize);
         buffer.mFlags = 0;
-        CHECK(buffer.mMemory != NULL);
+        if (mUseTreble) {
+            bool success;
+            auto transStatus = mAllocator->allocate(def.nBufferSize,
+                    [&success, &buffer](
+                            bool s,
+                            hidl_memory const& m) {
+                        success = s;
+                        buffer.mHidlMemory = m;
+                    });
+            EXPECT(transStatus.isOk(),
+                    "Cannot call allocator");
+            EXPECT(success,
+                    "Cannot allocate memory");
+            err = mOMXNode->useBuffer(portIndex, buffer.mHidlMemory, &buffer.mID);
+        } else {
+            buffer.mMemory = mDealer->allocate(def.nBufferSize);
+            CHECK(buffer.mMemory != NULL);
+            err = mOMXNode->useBuffer(portIndex, buffer.mMemory, &buffer.mID);
+        }
 
-        err = mOMXNode->useBuffer(portIndex, buffer.mMemory, &buffer.mID);
         EXPECT_SUCCESS(err, "useBuffer");
 
         buffers->push(buffer);
@@ -279,7 +309,13 @@
         return OK;
     }
 
-    sp<MemoryDealer> dealer = new MemoryDealer(16 * 1024 * 1024, "OMXHarness");
+    if (mUseTreble) {
+        mAllocator = IAllocator::getService("ashmem");
+        EXPECT(mAllocator != nullptr,
+                "Cannot obtain hidl AshmemAllocator");
+    } else {
+        mDealer = new MemoryDealer(16 * 1024 * 1024, "OMXHarness");
+    }
 
     sp<CodecObserver> observer = new CodecObserver(this, ++mCurGeneration);
 
@@ -305,14 +341,14 @@
 
     // Now allocate buffers.
     Vector<Buffer> inputBuffers;
-    err = allocatePortBuffers(dealer, 0, &inputBuffers);
+    err = allocatePortBuffers(0, &inputBuffers);
     EXPECT_SUCCESS(err, "allocatePortBuffers(input)");
 
     err = dequeueMessageForNode(&msg, DEFAULT_TIMEOUT);
     CHECK_EQ(err, (status_t)TIMED_OUT);
 
     Vector<Buffer> outputBuffers;
-    err = allocatePortBuffers(dealer, 1, &outputBuffers);
+    err = allocatePortBuffers(1, &outputBuffers);
     EXPECT_SUCCESS(err, "allocatePortBuffers(output)");
 
     err = dequeueMessageForNode(&msg, DEFAULT_TIMEOUT);
diff --git a/media/libstagefright/omx/tests/OMXHarness.h b/media/libstagefright/omx/tests/OMXHarness.h
index 0fe00a6..4fc0f79 100644
--- a/media/libstagefright/omx/tests/OMXHarness.h
+++ b/media/libstagefright/omx/tests/OMXHarness.h
@@ -23,6 +23,9 @@
 #include <utils/Vector.h>
 #include <utils/threads.h>
 
+#include <binder/MemoryDealer.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
 #include <OMX_Component.h>
 
 namespace android {
@@ -30,12 +33,15 @@
 class MemoryDealer;
 
 struct Harness : public RefBase {
+    typedef hidl::memory::V1_0::IMemory TMemory;
+    typedef hardware::hidl_memory hidl_memory;
     enum BufferFlags {
         kBufferBusy = 1
     };
     struct Buffer {
         IOMX::buffer_id mID;
         sp<IMemory> mMemory;
+        hidl_memory mHidlMemory;
         uint32_t mFlags;
     };
 
@@ -54,7 +60,6 @@
             OMX_U32 portIndex, OMX_PARAM_PORTDEFINITIONTYPE *def);
 
     status_t allocatePortBuffers(
-            const sp<MemoryDealer> &dealer,
             OMX_U32 portIndex, Vector<Buffer> *buffers);
 
     status_t setRole(const char *role);
@@ -74,6 +79,8 @@
     virtual ~Harness();
 
 private:
+    typedef hidl::allocator::V1_0::IAllocator IAllocator;
+
     friend struct NodeReaper;
     struct CodecObserver;
 
@@ -86,6 +93,9 @@
     Condition mMessageAddedCondition;
     int32_t mLastMsgGeneration;
     int32_t mCurGeneration;
+    bool mUseTreble;
+    sp<MemoryDealer> mDealer;
+    sp<IAllocator> mAllocator;
 
     status_t initOMX();
 
diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk
index 0b0facf..70ae46b 100644
--- a/media/libstagefright/timedtext/Android.mk
+++ b/media/libstagefright/timedtext/Android.mk
@@ -5,7 +5,8 @@
         TextDescriptions.cpp      \
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
-LOCAL_SANITIZE := signed-integer-overflow
+LOCAL_SANITIZE := signed-integer-overflow cfi
+LOCAL_SANITIZE_DIAG := cfi
 
 LOCAL_C_INCLUDES:= \
         $(TOP)/frameworks/av/include/media/stagefright/timedtext \
diff --git a/media/libstagefright/webm/Android.mk b/media/libstagefright/webm/Android.mk
index 096fd07..0d55de9 100644
--- a/media/libstagefright/webm/Android.mk
+++ b/media/libstagefright/webm/Android.mk
@@ -4,7 +4,8 @@
 LOCAL_CPPFLAGS += -D__STDINT_LIMITS
 
 LOCAL_CFLAGS += -Werror -Wall
-LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow cfi
+LOCAL_SANITIZE_DIAG := cfi
 
 LOCAL_SRC_FILES:= EbmlUtil.cpp        \
                   WebmElement.cpp     \
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index a4cb66d..f7597db 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -12,23 +12,24 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	main_mediaserver.cpp
+        main_mediaserver.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libresourcemanagerservice \
-	liblog \
-	libmediaplayerservice \
-	libutils \
-	libbinder \
-	libicuuc \
+        libresourcemanagerservice \
+        liblog \
+        libmediaplayerservice \
+        libutils \
+        libbinder \
+        libicuuc \
+        android.hardware.media.omx@1.0 \
 
 LOCAL_STATIC_LIBRARIES := \
         libicuandroid_utils \
         libregistermsext
 
 LOCAL_C_INCLUDES := \
-    frameworks/av/media/libmediaplayerservice \
-    frameworks/av/services/mediaresourcemanager \
+        frameworks/av/media/libmediaplayerservice \
+        frameworks/av/services/mediaresourcemanager \
 
 LOCAL_MODULE:= mediaserver
 LOCAL_32_BIT_ONLY := true
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 82a2627..0bf7854 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -277,19 +277,20 @@
 }
 
 void MtpDevice::print() {
-    if (mDeviceInfo) {
-        mDeviceInfo->print();
+    if (!mDeviceInfo)
+        return;
 
-        if (mDeviceInfo->mDeviceProperties) {
-            ALOGI("***** DEVICE PROPERTIES *****\n");
-            int count = mDeviceInfo->mDeviceProperties->size();
-            for (int i = 0; i < count; i++) {
-                MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
-                MtpProperty* property = getDevicePropDesc(propCode);
-                if (property) {
-                    property->print();
-                    delete property;
-                }
+    mDeviceInfo->print();
+
+    if (mDeviceInfo->mDeviceProperties) {
+        ALOGI("***** DEVICE PROPERTIES *****\n");
+        int count = mDeviceInfo->mDeviceProperties->size();
+        for (int i = 0; i < count; i++) {
+            MtpDeviceProperty propCode = (*mDeviceInfo->mDeviceProperties)[i];
+            MtpProperty* property = getDevicePropDesc(propCode);
+            if (property) {
+                property->print();
+                delete property;
             }
         }
     }
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 6df2065..35dd10f 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -40,7 +40,7 @@
 #define cpu_to_le16(x)  htole16(x)
 #define cpu_to_le32(x)  htole32(x)
 
-#define FUNCTIONFS_ENDPOINT_ALLOC       _IOR('g', 131, __u32)
+#define FUNCTIONFS_ENDPOINT_ALLOC       _IOR('g', 231, __u32)
 
 namespace {
 
@@ -62,8 +62,13 @@
 constexpr int USB_FFS_MAX_WRITE = MTP_BUFFER_SIZE;
 constexpr int USB_FFS_MAX_READ = MTP_BUFFER_SIZE;
 
+static_assert(USB_FFS_MAX_WRITE > 0, "Max r/w values must be > 0!");
+static_assert(USB_FFS_MAX_READ > 0, "Max r/w values must be > 0!");
+
 constexpr unsigned int MAX_MTP_FILE_SIZE = 0xFFFFFFFF;
 
+constexpr size_t ENDPOINT_ALLOC_RETRIES = 10;
+
 struct func_desc {
     struct usb_interface_descriptor intf;
     struct usb_endpoint_descriptor_no_audio sink;
@@ -200,13 +205,13 @@
 const struct usb_ss_ep_comp_descriptor ss_sink_comp = {
     .bLength = sizeof(ss_sink_comp),
     .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-    .bMaxBurst = 2,
+    .bMaxBurst = 6,
 };
 
 const struct usb_ss_ep_comp_descriptor ss_source_comp = {
     .bLength = sizeof(ss_source_comp),
     .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-    .bMaxBurst = 2,
+    .bMaxBurst = 6,
 };
 
 const struct usb_ss_ep_comp_descriptor ss_intr_comp = {
@@ -459,19 +464,28 @@
     mMaxWrite = android::base::GetIntProperty("sys.usb.ffs.max_write", USB_FFS_MAX_WRITE);
     mMaxRead = android::base::GetIntProperty("sys.usb.ffs.max_read", USB_FFS_MAX_READ);
 
-    while (mMaxWrite > USB_FFS_MAX_WRITE && mMaxRead > USB_FFS_MAX_READ) {
+    size_t attempts = 0;
+    while (mMaxWrite >= USB_FFS_MAX_WRITE && mMaxRead >= USB_FFS_MAX_READ &&
+            attempts < ENDPOINT_ALLOC_RETRIES) {
         // If larger contiguous chunks of memory aren't available, attempt to try
         // smaller allocations.
         if (ioctl(mBulkIn, FUNCTIONFS_ENDPOINT_ALLOC, static_cast<__u32>(mMaxWrite)) ||
             ioctl(mBulkOut, FUNCTIONFS_ENDPOINT_ALLOC, static_cast<__u32>(mMaxRead))) {
+            if (errno == ENODEV) {
+                // Driver hasn't enabled endpoints yet.
+                std::this_thread::sleep_for(std::chrono::milliseconds(100));
+                attempts += 1;
+                continue;
+            }
             mMaxWrite /= 2;
             mMaxRead /=2;
         } else {
             return 0;
         }
     }
+    // Try to start MtpServer anyway, with the smallest max r/w values
     PLOG(ERROR) << "Functionfs could not allocate any memory!";
-    return -1;
+    return 0;
 }
 
 int MtpFfsHandle::configure(bool usePtp) {
@@ -583,7 +597,7 @@
     uint64_t file_length = mfr.length;
     uint32_t given_length = std::min(static_cast<uint64_t>(MAX_MTP_FILE_SIZE),
             file_length + sizeof(mtp_data_header));
-    uint64_t offset = 0;
+    uint64_t offset = mfr.offset;
     struct usb_endpoint_descriptor mBulkIn_desc;
     int packet_size;
 
@@ -594,7 +608,10 @@
         packet_size = mBulkIn_desc.wMaxPacketSize;
     }
 
-    int init_read_len = packet_size - sizeof(mtp_data_header);
+    // If file_length is larger than a size_t, truncating would produce the wrong comparison.
+    // Instead, promote the left side to 64 bits, then truncate the small result.
+    int init_read_len = std::min(
+            static_cast<uint64_t>(packet_size - sizeof(mtp_data_header)), file_length);
 
     char *data = mBuffer1.data();
     char *data2 = mBuffer2.data();
@@ -620,10 +637,11 @@
     if (TEMP_FAILURE_RETRY(pread(mfr.fd, reinterpret_cast<char*>(data) +
                     sizeof(mtp_data_header), init_read_len, offset))
             != init_read_len) return -1;
+    if (writeHandle(mBulkIn, data, sizeof(mtp_data_header) + init_read_len) == -1) return -1;
+    if (file_length == static_cast<unsigned>(init_read_len)) return 0;
     file_length -= init_read_len;
     offset += init_read_len;
-    if (writeHandle(mBulkIn, data, packet_size) == -1) return -1;
-    if (file_length == 0) return 0;
+    ret = 0;
 
     // Break down the file into pieces that fit in buffers
     while(file_length > 0) {
diff --git a/media/mtp/MtpFfsHandle.h b/media/mtp/MtpFfsHandle.h
index 44ff0f3..b4d5a97 100644
--- a/media/mtp/MtpFfsHandle.h
+++ b/media/mtp/MtpFfsHandle.h
@@ -59,6 +59,10 @@
     int sendFile(mtp_file_range mfr);
     int sendEvent(mtp_event me);
 
+    /**
+     * Open ffs endpoints and allocate necessary kernel and user memory.
+     * Will sleep until endpoints are enabled, for up to 1 second.
+     */
     int start();
     void close();
 
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 753d833..5a1d6dc 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -1060,6 +1060,9 @@
                 mfr.length = mSendObjectFileSize - initialData;
             }
 
+            mfr.command = 0;
+            mfr.transaction_id = 0;
+
             // transfer the file
             ret = sHandle->receiveFile(mfr);
             if ((ret < 0) && (errno == ECANCELED)) {
@@ -1257,6 +1260,8 @@
             mfr.fd = edit->mFD;
             mfr.offset = offset;
             mfr.length = length;
+            mfr.command = 0;
+            mfr.transaction_id = 0;
 
             // transfer the file
             ret = sHandle->receiveFile(mfr);
diff --git a/media/mtp/tests/MtpFfsHandle_test.cpp b/media/mtp/tests/MtpFfsHandle_test.cpp
index b511041..e575148 100644
--- a/media/mtp/tests/MtpFfsHandle_test.cpp
+++ b/media/mtp/tests/MtpFfsHandle_test.cpp
@@ -20,6 +20,7 @@
 #include <fcntl.h>
 #include <gtest/gtest.h>
 #include <memory>
+#include <random>
 #include <string>
 #include <unistd.h>
 #include <utils/Log.h>
@@ -28,6 +29,8 @@
 
 namespace android {
 
+constexpr int MAX_FILE_CHUNK_SIZE = 3 * 1024 * 1024;
+
 constexpr int TEST_PACKET_SIZE = 512;
 constexpr int SMALL_MULT = 30;
 constexpr int MED_MULT = 510;
@@ -42,6 +45,10 @@
     "BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express o"
     "r implied.\n * Se";
 
+/**
+ * Functional tests for the MtpFfsHandle class. Ensures header and data integrity
+ * by mocking ffs endpoints as pipes to capture input / output.
+ */
 class MtpFfsHandleTest : public ::testing::Test {
 protected:
     std::unique_ptr<IMtpHandle> handle;
@@ -72,6 +79,9 @@
         EXPECT_EQ(pipe(fd), 0);
         intr.reset(fd[0]);
         ffs_handle->mIntr.reset(fd[1]);
+
+        ffs_handle->mBuffer1.resize(MAX_FILE_CHUNK_SIZE);
+        ffs_handle->mBuffer2.resize(MAX_FILE_CHUNK_SIZE);
     }
 
     ~MtpFfsHandleTest() {}
@@ -138,6 +148,7 @@
     mtp_file_range mfr;
     mfr.command = 42;
     mfr.transaction_id = 1337;
+    mfr.offset = 0;
     int size = TEST_PACKET_SIZE * SMALL_MULT;
     char buf[size + sizeof(mtp_data_header) + 1];
     buf[size + sizeof(mtp_data_header)] = '\0';
@@ -166,6 +177,7 @@
     mtp_file_range mfr;
     mfr.command = 42;
     mfr.transaction_id = 1337;
+    mfr.offset = 0;
     int size = TEST_PACKET_SIZE * MED_MULT;
     char buf[size + sizeof(mtp_data_header) + 1];
     buf[size + sizeof(mtp_data_header)] = '\0';
@@ -189,6 +201,70 @@
     EXPECT_EQ(header->transaction_id, static_cast<unsigned int>(1337));
 }
 
+TEST_F(MtpFfsHandleTest, testSendFileMedPartial) {
+    std::stringstream ss;
+    mtp_file_range mfr;
+    mfr.fd = dummy_file.fd;
+    mfr.command = 42;
+    mfr.transaction_id = 1337;
+    int size = TEST_PACKET_SIZE * MED_MULT;
+    char buf[size + 1];
+    buf[size] = '\0';
+
+    for (int i = 0; i < MED_MULT; i++)
+        ss << dummyDataStr;
+
+    EXPECT_EQ(write(dummy_file.fd, ss.str().c_str(), size), size);
+
+    std::random_device rd;
+    std::mt19937 gen(rd());
+    std::uniform_int_distribution<> dis(1, TEST_PACKET_SIZE);
+    int offset = 0;
+    while (offset != size) {
+        mfr.offset = offset;
+        int length = std::min(size - offset, dis(gen));
+        mfr.length = length;
+        char temp_buf[length + sizeof(mtp_data_header)];
+        EXPECT_EQ(handle->sendFile(mfr), 0);
+
+        EXPECT_EQ(read(bulk_in, temp_buf, length + sizeof(mtp_data_header)),
+                static_cast<long>(length + sizeof(mtp_data_header)));
+
+        struct mtp_data_header *header = reinterpret_cast<struct mtp_data_header*>(temp_buf);
+        EXPECT_EQ(header->length, static_cast<unsigned int>(length + sizeof(mtp_data_header)));
+        EXPECT_EQ(header->type, static_cast<unsigned int>(2));
+        EXPECT_EQ(header->command, static_cast<unsigned int>(42));
+        EXPECT_EQ(header->transaction_id, static_cast<unsigned int>(1337));
+        memcpy(buf + offset, temp_buf + sizeof(mtp_data_header), length);
+        offset += length;
+    }
+    EXPECT_STREQ(buf, ss.str().c_str());
+}
+
+TEST_F(MtpFfsHandleTest, testSendFileEmpty) {
+    mtp_file_range mfr;
+    mfr.command = 42;
+    mfr.transaction_id = 1337;
+    mfr.offset = 0;
+    int size = 0;
+    char buf[size + sizeof(mtp_data_header) + 1];
+    buf[size + sizeof(mtp_data_header)] = '\0';
+
+    mfr.length = size;
+    mfr.fd = dummy_file.fd;
+
+    EXPECT_EQ(handle->sendFile(mfr), 0);
+
+    EXPECT_EQ(read(bulk_in, buf, size + sizeof(mtp_data_header)),
+            static_cast<long>(size + sizeof(mtp_data_header)));
+
+    struct mtp_data_header *header = reinterpret_cast<struct mtp_data_header*>(buf);
+    EXPECT_EQ(header->length, static_cast<unsigned int>(size + sizeof(mtp_data_header)));
+    EXPECT_EQ(header->type, static_cast<unsigned int>(2));
+    EXPECT_EQ(header->command, static_cast<unsigned int>(42));
+    EXPECT_EQ(header->transaction_id, static_cast<unsigned int>(1337));
+}
+
 TEST_F(MtpFfsHandleTest, testSendEvent) {
     struct mtp_event event;
     event.length = TEST_PACKET_SIZE;
diff --git a/media/utils/ISchedulingPolicyService.cpp b/media/utils/ISchedulingPolicyService.cpp
index f5bfe20..22fbc97 100644
--- a/media/utils/ISchedulingPolicyService.cpp
+++ b/media/utils/ISchedulingPolicyService.cpp
@@ -37,13 +37,15 @@
     {
     }
 
-    virtual int requestPriority(int32_t pid, int32_t tid, int32_t prio, bool asynchronous)
+    virtual int requestPriority(int32_t pid, int32_t tid,
+                                int32_t prio, bool isForApp, bool asynchronous)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ISchedulingPolicyService::getInterfaceDescriptor());
         data.writeInt32(pid);
         data.writeInt32(tid);
         data.writeInt32(prio);
+        data.writeBool(isForApp);
         uint32_t flags = asynchronous ? IBinder::FLAG_ONEWAY : 0;
         status_t status = remote()->transact(REQUEST_PRIORITY_TRANSACTION, data, &reply, flags);
         if (status != NO_ERROR) {
diff --git a/media/utils/ISchedulingPolicyService.h b/media/utils/ISchedulingPolicyService.h
index b94b191..1015677 100644
--- a/media/utils/ISchedulingPolicyService.h
+++ b/media/utils/ISchedulingPolicyService.h
@@ -27,7 +27,7 @@
     DECLARE_META_INTERFACE(SchedulingPolicyService);
 
     virtual int         requestPriority(/*pid_t*/int32_t pid, /*pid_t*/int32_t tid,
-                                                int32_t prio, bool asynchronous) = 0;
+                                        int32_t prio, bool isForApp, bool asynchronous) = 0;
 
 };
 
diff --git a/media/utils/SchedulingPolicyService.cpp b/media/utils/SchedulingPolicyService.cpp
index 17ee9bc..d7055ef 100644
--- a/media/utils/SchedulingPolicyService.cpp
+++ b/media/utils/SchedulingPolicyService.cpp
@@ -28,7 +28,7 @@
 static const String16 _scheduling_policy("scheduling_policy");
 static Mutex sMutex;
 
-int requestPriority(pid_t pid, pid_t tid, int32_t prio, bool asynchronous)
+int requestPriority(pid_t pid, pid_t tid, int32_t prio, bool isForApp, bool asynchronous)
 {
     // FIXME merge duplicated code related to service lookup, caching, and error recovery
     int ret;
@@ -47,7 +47,7 @@
             sSchedulingPolicyService = sps;
             sMutex.unlock();
         }
-        ret = sps->requestPriority(pid, tid, prio, asynchronous);
+        ret = sps->requestPriority(pid, tid, prio, isForApp, asynchronous);
         if (ret != DEAD_OBJECT) {
             break;
         }
diff --git a/media/utils/include/mediautils/SchedulingPolicyService.h b/media/utils/include/mediautils/SchedulingPolicyService.h
index a9870d4..47d8734 100644
--- a/media/utils/include/mediautils/SchedulingPolicyService.h
+++ b/media/utils/include/mediautils/SchedulingPolicyService.h
@@ -24,7 +24,7 @@
 // The asynchronous parameter should be 'true' to return immediately,
 // after the request is enqueued but not necessarily executed.
 // The default value 'false' means to return after request has been enqueued and executed.
-int requestPriority(pid_t pid, pid_t tid, int32_t prio, bool asynchronous = false);
+int requestPriority(pid_t pid, pid_t tid, int32_t prio, bool isForApp, bool asynchronous = false);
 
 }   // namespace android
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index c737f4b..3d1f268 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -99,6 +99,7 @@
 
 uint32_t AudioFlinger::mScreenState;
 
+
 #ifdef TEE_SINK
 bool AudioFlinger::mTeeSinkInputEnabled = false;
 bool AudioFlinger::mTeeSinkOutputEnabled = false;
@@ -113,6 +114,9 @@
 // we define a minimum time during which a global effect is considered enabled.
 static const nsecs_t kMinGlobalEffectEnabletimeNs = seconds(7200);
 
+Mutex gLock;
+wp<AudioFlinger> gAudioFlinger;
+
 // ----------------------------------------------------------------------------
 
 std::string formatToString(audio_format_t format) {
@@ -202,6 +206,8 @@
     mPatchPanel = new PatchPanel(this);
 
     mMode = AUDIO_MODE_NORMAL;
+
+    gAudioFlinger = this;
 }
 
 AudioFlinger::~AudioFlinger()
@@ -234,6 +240,84 @@
     }
 }
 
+//static
+__attribute__ ((visibility ("default")))
+status_t MmapStreamInterface::openMmapStream(MmapStreamInterface::stream_direction_t direction,
+                                             const audio_attributes_t *attr,
+                                             audio_config_base_t *config,
+                                             const MmapStreamInterface::Client& client,
+                                             audio_port_handle_t *deviceId,
+                                             const sp<MmapStreamCallback>& callback,
+                                             sp<MmapStreamInterface>& interface)
+{
+    sp<AudioFlinger> af;
+    {
+        Mutex::Autolock _l(gLock);
+        af = gAudioFlinger.promote();
+    }
+    status_t ret = NO_INIT;
+    if (af != 0) {
+        ret = af->openMmapStream(
+                direction, attr, config, client, deviceId, callback, interface);
+    }
+    return ret;
+}
+
+status_t AudioFlinger::openMmapStream(MmapStreamInterface::stream_direction_t direction,
+                                      const audio_attributes_t *attr,
+                                      audio_config_base_t *config,
+                                      const MmapStreamInterface::Client& client,
+                                      audio_port_handle_t *deviceId,
+                                      const sp<MmapStreamCallback>& callback,
+                                      sp<MmapStreamInterface>& interface)
+{
+    status_t ret = initCheck();
+    if (ret != NO_ERROR) {
+        return ret;
+    }
+
+    audio_session_t sessionId = (audio_session_t) newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
+    audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT;
+    audio_io_handle_t io;
+    audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+    if (direction == MmapStreamInterface::DIRECTION_OUTPUT) {
+        audio_config_t fullConfig = AUDIO_CONFIG_INITIALIZER;
+        fullConfig.sample_rate = config->sample_rate;
+        fullConfig.channel_mask = config->channel_mask;
+        fullConfig.format = config->format;
+        ret = AudioSystem::getOutputForAttr(attr, &io,
+                                            sessionId,
+                                            &streamType, client.clientUid,
+                                            &fullConfig,
+                                            (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT),
+                                            *deviceId, &portId);
+    } else {
+        ret = AudioSystem::getInputForAttr(attr, &io,
+                                              sessionId,
+                                              client.clientPid,
+                                              client.clientUid,
+                                              config,
+                                              AUDIO_INPUT_FLAG_MMAP_NOIRQ, *deviceId, &portId);
+    }
+    if (ret != NO_ERROR) {
+        return ret;
+    }
+
+    // at this stage, a MmapThread was created when openOutput() or openInput() was called by
+    // audio policy manager and we can retrieve it
+    sp<MmapThread> thread = mMmapThreads.valueFor(io);
+    if (thread != 0) {
+        interface = new MmapThreadHandle(thread);
+        thread->configure(attr, streamType, sessionId, callback, portId);
+    } else {
+        ret = NO_INIT;
+    }
+
+    ALOGV("%s done status %d portId %d", __FUNCTION__, ret, portId);
+
+    return ret;
+}
+
 static const char * const audio_interfaces[] = {
     AUDIO_HARDWARE_MODULE_ID_PRIMARY,
     AUDIO_HARDWARE_MODULE_ID_A2DP,
@@ -398,6 +482,11 @@
             mRecordThreads.valueAt(i)->dump(fd, args);
         }
 
+        // dump mmap threads
+        for (size_t i = 0; i < mMmapThreads.size(); i++) {
+            mMmapThreads.valueAt(i)->dump(fd, args);
+        }
+
         // dump orphan effect chains
         if (mOrphanEffectChains.size() != 0) {
             write(fd, "  Orphan Effect Chains\n", strlen("  Orphan Effect Chains\n"));
@@ -908,11 +997,9 @@
     // assigned to HALs which do not have master mute support will apply master
     // mute during the mix operation.  Threads with HALs which do support master
     // mute will simply ignore the setting.
-    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-        if (mPlaybackThreads.valueAt(i)->isDuplicating()) {
-            continue;
-        }
-        mPlaybackThreads.valueAt(i)->setMasterMute(muted);
+    Vector<VolumeInterface *> volumeInterfaces = getAllVolumeInterfaces_l();
+    for (size_t i = 0; i < volumeInterfaces.size(); i++) {
+        volumeInterfaces[i]->setMasterMute(muted);
     }
 
     return NO_ERROR;
@@ -943,12 +1030,12 @@
 status_t AudioFlinger::checkStreamType(audio_stream_type_t stream) const
 {
     if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
-        ALOGW("setStreamVolume() invalid stream %d", stream);
+        ALOGW("checkStreamType() invalid stream %d", stream);
         return BAD_VALUE;
     }
     pid_t caller = IPCThreadState::self()->getCallingPid();
     if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT && caller != getpid_cached) {
-        ALOGW("setStreamVolume() pid %d cannot use internal stream type %d", caller, stream);
+        ALOGW("checkStreamType() pid %d cannot use internal stream type %d", caller, stream);
         return PERMISSION_DENIED;
     }
 
@@ -970,22 +1057,22 @@
     ALOG_ASSERT(stream != AUDIO_STREAM_PATCH, "attempt to change AUDIO_STREAM_PATCH volume");
 
     AutoMutex lock(mLock);
-    PlaybackThread *thread = NULL;
+    Vector<VolumeInterface *> volumeInterfaces;
     if (output != AUDIO_IO_HANDLE_NONE) {
-        thread = checkPlaybackThread_l(output);
-        if (thread == NULL) {
+        VolumeInterface *volumeInterface = getVolumeInterface_l(output);
+        if (volumeInterface == NULL) {
             return BAD_VALUE;
         }
+        volumeInterfaces.add(volumeInterface);
     }
 
     mStreamTypes[stream].volume = value;
 
-    if (thread == NULL) {
-        for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-            mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value);
-        }
-    } else {
-        thread->setStreamVolume(stream, value);
+    if (volumeInterfaces.size() == 0) {
+        volumeInterfaces = getAllVolumeInterfaces_l();
+    }
+    for (size_t i = 0; i < volumeInterfaces.size(); i++) {
+        volumeInterfaces[i]->setStreamVolume(stream, value);
     }
 
     return NO_ERROR;
@@ -1011,8 +1098,10 @@
 
     AutoMutex lock(mLock);
     mStreamTypes[stream].mute = muted;
-    for (size_t i = 0; i < mPlaybackThreads.size(); i++)
-        mPlaybackThreads.valueAt(i)->setStreamMute(stream, muted);
+    Vector<VolumeInterface *> volumeInterfaces = getAllVolumeInterfaces_l();
+    for (size_t i = 0; i < volumeInterfaces.size(); i++) {
+        volumeInterfaces[i]->setStreamMute(stream, muted);
+    }
 
     return NO_ERROR;
 }
@@ -1027,11 +1116,12 @@
     AutoMutex lock(mLock);
     float volume;
     if (output != AUDIO_IO_HANDLE_NONE) {
-        PlaybackThread *thread = checkPlaybackThread_l(output);
-        if (thread == NULL) {
-            return 0.0f;
+        VolumeInterface *volumeInterface = getVolumeInterface_l(output);
+        if (volumeInterface != NULL) {
+            volume = volumeInterface->streamVolume(stream);
+        } else {
+            volume = 0.0f;
         }
-        volume = thread->streamVolume(stream);
     } else {
         volume = streamVolume_l(stream);
     }
@@ -1132,6 +1222,9 @@
         thread = checkPlaybackThread_l(ioHandle);
         if (thread == 0) {
             thread = checkRecordThread_l(ioHandle);
+            if (thread == 0) {
+                thread = checkMmapThread_l(ioHandle);
+            }
         } else if (thread == primaryPlaybackThread_l()) {
             // indicate output device change to all input threads for pre processing
             AudioParameter param = AudioParameter(keyValuePairs);
@@ -1173,15 +1266,17 @@
         return out_s8;
     }
 
-    PlaybackThread *playbackThread = checkPlaybackThread_l(ioHandle);
-    if (playbackThread != NULL) {
-        return playbackThread->getParameters(keys);
+    ThreadBase *thread = (ThreadBase *)checkPlaybackThread_l(ioHandle);
+    if (thread == NULL) {
+        thread = (ThreadBase *)checkRecordThread_l(ioHandle);
+        if (thread == NULL) {
+            thread = (ThreadBase *)checkMmapThread_l(ioHandle);
+            if (thread == NULL) {
+                String8("");
+            }
+        }
     }
-    RecordThread *recordThread = checkRecordThread_l(ioHandle);
-    if (recordThread != NULL) {
-        return recordThread->getParameters(keys);
-    }
-    return String8("");
+    return thread->getParameters(keys);
 }
 
 size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t format,
@@ -1787,7 +1882,7 @@
 // ----------------------------------------------------------------------------
 
 
-sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_t module,
+sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
                                                             audio_io_handle_t *output,
                                                             audio_config_t *config,
                                                             audio_devices_t devices,
@@ -1843,22 +1938,34 @@
     mHardwareStatus = AUDIO_HW_IDLE;
 
     if (status == NO_ERROR) {
-
-        PlaybackThread *thread;
-        if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
-            thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
-            ALOGV("openOutput_l() created offload output: ID %d thread %p", *output, thread);
-        } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
-                || !isValidPcmSinkFormat(config->format)
-                || !isValidPcmSinkChannelMask(config->channel_mask)) {
-            thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady);
-            ALOGV("openOutput_l() created direct output: ID %d thread %p", *output, thread);
+        if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
+            sp<MmapPlaybackThread> thread =
+                    new MmapPlaybackThread(this, *output, outHwDev, outputStream,
+                                          devices, AUDIO_DEVICE_NONE, mSystemReady);
+            mMmapThreads.add(*output, thread);
+            ALOGV("openOutput_l() created mmap playback thread: ID %d thread %p",
+                  *output, thread.get());
+            return thread;
         } else {
-            thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
-            ALOGV("openOutput_l() created mixer output: ID %d thread %p", *output, thread);
+            sp<PlaybackThread> thread;
+            if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+                thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
+                ALOGV("openOutput_l() created offload output: ID %d thread %p",
+                      *output, thread.get());
+            } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
+                    || !isValidPcmSinkFormat(config->format)
+                    || !isValidPcmSinkChannelMask(config->channel_mask)) {
+                thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady);
+                ALOGV("openOutput_l() created direct output: ID %d thread %p",
+                      *output, thread.get());
+            } else {
+                thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
+                ALOGV("openOutput_l() created mixer output: ID %d thread %p",
+                      *output, thread.get());
+            }
+            mPlaybackThreads.add(*output, thread);
+            return thread;
         }
-        mPlaybackThreads.add(*output, thread);
-        return thread;
     }
 
     return 0;
@@ -1872,8 +1979,8 @@
                                   uint32_t *latencyMs,
                                   audio_output_flags_t flags)
 {
-    ALOGI("openOutput(), module %d Device %x, SamplingRate %d, Format %#08x, Channels %x, flags %x",
-              module,
+    ALOGI("openOutput() this %p, module %d Device %x, SamplingRate %d, Format %#08x, Channels %x, flags %x",
+              this, module,
               (devices != NULL) ? *devices : 0,
               config->sample_rate,
               config->format,
@@ -1886,22 +1993,28 @@
 
     Mutex::Autolock _l(mLock);
 
-    sp<PlaybackThread> thread = openOutput_l(module, output, config, *devices, address, flags);
+    sp<ThreadBase> thread = openOutput_l(module, output, config, *devices, address, flags);
     if (thread != 0) {
-        *latencyMs = thread->latency();
+        if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0) {
+            PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+            *latencyMs = playbackThread->latency();
 
-        // notify client processes of the new output creation
-        thread->ioConfigChanged(AUDIO_OUTPUT_OPENED);
+            // notify client processes of the new output creation
+            playbackThread->ioConfigChanged(AUDIO_OUTPUT_OPENED);
 
-        // the first primary output opened designates the primary hw device
-        if ((mPrimaryHardwareDev == NULL) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
-            ALOGI("Using module %d has the primary audio interface", module);
-            mPrimaryHardwareDev = thread->getOutput()->audioHwDev;
+            // the first primary output opened designates the primary hw device
+            if ((mPrimaryHardwareDev == NULL) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
+                ALOGI("Using module %d has the primary audio interface", module);
+                mPrimaryHardwareDev = playbackThread->getOutput()->audioHwDev;
 
-            AutoMutex lock(mHardwareLock);
-            mHardwareStatus = AUDIO_HW_SET_MODE;
-            mPrimaryHardwareDev->hwDevice()->setMode(mMode);
-            mHardwareStatus = AUDIO_HW_IDLE;
+                AutoMutex lock(mHardwareLock);
+                mHardwareStatus = AUDIO_HW_SET_MODE;
+                mPrimaryHardwareDev->hwDevice()->setMode(mMode);
+                mHardwareStatus = AUDIO_HW_IDLE;
+            }
+        } else {
+            MmapThread *mmapThread = (MmapThread *)thread.get();
+            mmapThread->ioConfigChanged(AUDIO_OUTPUT_OPENED);
         }
         return NO_ERROR;
     }
@@ -1940,54 +2053,68 @@
 {
     // keep strong reference on the playback thread so that
     // it is not destroyed while exit() is executed
-    sp<PlaybackThread> thread;
+    sp<PlaybackThread> playbackThread;
+    sp<MmapPlaybackThread> mmapThread;
     {
         Mutex::Autolock _l(mLock);
-        thread = checkPlaybackThread_l(output);
-        if (thread == NULL) {
-            return BAD_VALUE;
-        }
+        playbackThread = checkPlaybackThread_l(output);
+        if (playbackThread != NULL) {
+            ALOGV("closeOutput() %d", output);
 
-        ALOGV("closeOutput() %d", output);
-
-        if (thread->type() == ThreadBase::MIXER) {
-            for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-                if (mPlaybackThreads.valueAt(i)->isDuplicating()) {
-                    DuplicatingThread *dupThread =
-                            (DuplicatingThread *)mPlaybackThreads.valueAt(i).get();
-                    dupThread->removeOutputTrack((MixerThread *)thread.get());
+            if (playbackThread->type() == ThreadBase::MIXER) {
+                for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+                    if (mPlaybackThreads.valueAt(i)->isDuplicating()) {
+                        DuplicatingThread *dupThread =
+                                (DuplicatingThread *)mPlaybackThreads.valueAt(i).get();
+                        dupThread->removeOutputTrack((MixerThread *)playbackThread.get());
+                    }
                 }
             }
-        }
 
 
-        mPlaybackThreads.removeItem(output);
-        // save all effects to the default thread
-        if (mPlaybackThreads.size()) {
-            PlaybackThread *dstThread = checkPlaybackThread_l(mPlaybackThreads.keyAt(0));
-            if (dstThread != NULL) {
-                // audioflinger lock is held here so the acquisition order of thread locks does not
-                // matter
-                Mutex::Autolock _dl(dstThread->mLock);
-                Mutex::Autolock _sl(thread->mLock);
-                Vector< sp<EffectChain> > effectChains = thread->getEffectChains_l();
-                for (size_t i = 0; i < effectChains.size(); i ++) {
-                    moveEffectChain_l(effectChains[i]->sessionId(), thread.get(), dstThread, true);
+            mPlaybackThreads.removeItem(output);
+            // save all effects to the default thread
+            if (mPlaybackThreads.size()) {
+                PlaybackThread *dstThread = checkPlaybackThread_l(mPlaybackThreads.keyAt(0));
+                if (dstThread != NULL) {
+                    // audioflinger lock is held here so the acquisition order of thread locks does not
+                    // matter
+                    Mutex::Autolock _dl(dstThread->mLock);
+                    Mutex::Autolock _sl(playbackThread->mLock);
+                    Vector< sp<EffectChain> > effectChains = playbackThread->getEffectChains_l();
+                    for (size_t i = 0; i < effectChains.size(); i ++) {
+                        moveEffectChain_l(effectChains[i]->sessionId(), playbackThread.get(), dstThread, true);
+                    }
                 }
             }
+        } else {
+            mmapThread = (MmapPlaybackThread *)checkMmapThread_l(output);
+            if (mmapThread == 0) {
+                return BAD_VALUE;
+            }
+            mMmapThreads.removeItem(output);
+            ALOGV("closing mmapThread %p", mmapThread.get());
         }
         const sp<AudioIoDescriptor> ioDesc = new AudioIoDescriptor();
         ioDesc->mIoHandle = output;
         ioConfigChanged(AUDIO_OUTPUT_CLOSED, ioDesc);
     }
-    thread->exit();
     // The thread entity (active unit of execution) is no longer running here,
     // but the ThreadBase container still exists.
 
-    if (!thread->isDuplicating()) {
-        closeOutputFinish(thread);
+    if (playbackThread != 0) {
+        playbackThread->exit();
+        if (!playbackThread->isDuplicating()) {
+            closeOutputFinish(playbackThread);
+        }
+    } else if (mmapThread != 0) {
+        ALOGV("mmapThread exit()");
+        mmapThread->exit();
+        AudioStreamOut *out = mmapThread->clearOutput();
+        ALOG_ASSERT(out != NULL, "out shouldn't be NULL");
+        // from now on thread->mOutput is NULL
+        delete out;
     }
-
     return NO_ERROR;
 }
 
@@ -2051,7 +2178,7 @@
         return BAD_VALUE;
     }
 
-    sp<RecordThread> thread = openInput_l(module, input, config, *devices, address, source, flags);
+    sp<ThreadBase> thread = openInput_l(module, input, config, *devices, address, source, flags);
 
     if (thread != 0) {
         // notify client processes of the new input creation
@@ -2061,7 +2188,7 @@
     return NO_INIT;
 }
 
-sp<AudioFlinger::RecordThread> AudioFlinger::openInput_l(audio_module_handle_t module,
+sp<AudioFlinger::ThreadBase> AudioFlinger::openInput_l(audio_module_handle_t module,
                                                          audio_io_handle_t *input,
                                                          audio_config_t *config,
                                                          audio_devices_t devices,
@@ -2121,74 +2248,82 @@
     }
 
     if (status == NO_ERROR && inStream != 0) {
-
-#ifdef TEE_SINK
-        // Try to re-use most recently used Pipe to archive a copy of input for dumpsys,
-        // or (re-)create if current Pipe is idle and does not match the new format
-        sp<NBAIO_Sink> teeSink;
-        enum {
-            TEE_SINK_NO,    // don't copy input
-            TEE_SINK_NEW,   // copy input using a new pipe
-            TEE_SINK_OLD,   // copy input using an existing pipe
-        } kind;
-        NBAIO_Format format = Format_from_SR_C(halconfig.sample_rate,
-                audio_channel_count_from_in_mask(halconfig.channel_mask), halconfig.format);
-        if (!mTeeSinkInputEnabled) {
-            kind = TEE_SINK_NO;
-        } else if (!Format_isValid(format)) {
-            kind = TEE_SINK_NO;
-        } else if (mRecordTeeSink == 0) {
-            kind = TEE_SINK_NEW;
-        } else if (mRecordTeeSink->getStrongCount() != 1) {
-            kind = TEE_SINK_NO;
-        } else if (Format_isEqual(format, mRecordTeeSink->format())) {
-            kind = TEE_SINK_OLD;
-        } else {
-            kind = TEE_SINK_NEW;
-        }
-        switch (kind) {
-        case TEE_SINK_NEW: {
-            Pipe *pipe = new Pipe(mTeeSinkInputFrames, format);
-            size_t numCounterOffers = 0;
-            const NBAIO_Format offers[1] = {format};
-            ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers);
-            ALOG_ASSERT(index == 0);
-            PipeReader *pipeReader = new PipeReader(*pipe);
-            numCounterOffers = 0;
-            index = pipeReader->negotiate(offers, 1, NULL, numCounterOffers);
-            ALOG_ASSERT(index == 0);
-            mRecordTeeSink = pipe;
-            mRecordTeeSource = pipeReader;
-            teeSink = pipe;
-            }
-            break;
-        case TEE_SINK_OLD:
-            teeSink = mRecordTeeSink;
-            break;
-        case TEE_SINK_NO:
-        default:
-            break;
-        }
-#endif
-
         AudioStreamIn *inputStream = new AudioStreamIn(inHwDev, inStream, flags);
-
-        // Start record thread
-        // RecordThread requires both input and output device indication to forward to audio
-        // pre processing modules
-        sp<RecordThread> thread = new RecordThread(this,
-                                  inputStream,
-                                  *input,
-                                  primaryOutputDevice_l(),
-                                  devices,
-                                  mSystemReady
+        if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
+            sp<MmapCaptureThread> thread =
+                    new MmapCaptureThread(this, *input,
+                                          inHwDev, inputStream,
+                                          primaryOutputDevice_l(), devices, mSystemReady);
+            mMmapThreads.add(*input, thread);
+            ALOGV("openInput_l() created mmap capture thread: ID %d thread %p", *input, thread.get());
+            return thread;
+        } else {
 #ifdef TEE_SINK
-                                  , teeSink
+            // Try to re-use most recently used Pipe to archive a copy of input for dumpsys,
+            // or (re-)create if current Pipe is idle and does not match the new format
+            sp<NBAIO_Sink> teeSink;
+            enum {
+                TEE_SINK_NO,    // don't copy input
+                TEE_SINK_NEW,   // copy input using a new pipe
+                TEE_SINK_OLD,   // copy input using an existing pipe
+            } kind;
+            NBAIO_Format format = Format_from_SR_C(halconfig.sample_rate,
+                    audio_channel_count_from_in_mask(halconfig.channel_mask), halconfig.format);
+            if (!mTeeSinkInputEnabled) {
+                kind = TEE_SINK_NO;
+            } else if (!Format_isValid(format)) {
+                kind = TEE_SINK_NO;
+            } else if (mRecordTeeSink == 0) {
+                kind = TEE_SINK_NEW;
+            } else if (mRecordTeeSink->getStrongCount() != 1) {
+                kind = TEE_SINK_NO;
+            } else if (Format_isEqual(format, mRecordTeeSink->format())) {
+                kind = TEE_SINK_OLD;
+            } else {
+                kind = TEE_SINK_NEW;
+            }
+            switch (kind) {
+            case TEE_SINK_NEW: {
+                Pipe *pipe = new Pipe(mTeeSinkInputFrames, format);
+                size_t numCounterOffers = 0;
+                const NBAIO_Format offers[1] = {format};
+                ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers);
+                ALOG_ASSERT(index == 0);
+                PipeReader *pipeReader = new PipeReader(*pipe);
+                numCounterOffers = 0;
+                index = pipeReader->negotiate(offers, 1, NULL, numCounterOffers);
+                ALOG_ASSERT(index == 0);
+                mRecordTeeSink = pipe;
+                mRecordTeeSource = pipeReader;
+                teeSink = pipe;
+                }
+                break;
+            case TEE_SINK_OLD:
+                teeSink = mRecordTeeSink;
+                break;
+            case TEE_SINK_NO:
+            default:
+                break;
+            }
 #endif
-                                  );
-        mRecordThreads.add(*input, thread);
-        ALOGV("openInput_l() created record thread: ID %d thread %p", *input, thread.get());
-        return thread;
+
+            // Start record thread
+            // RecordThread requires both input and output device indication to forward to audio
+            // pre processing modules
+            sp<RecordThread> thread = new RecordThread(this,
+                                      inputStream,
+                                      *input,
+                                      primaryOutputDevice_l(),
+                                      devices,
+                                      mSystemReady
+#ifdef TEE_SINK
+                                      , teeSink
+#endif
+                                      );
+            mRecordThreads.add(*input, thread);
+            ALOGV("openInput_l() created record thread: ID %d thread %p", *input, thread.get());
+            return thread;
+        }
     }
 
     *input = AUDIO_IO_HANDLE_NONE;
@@ -2204,60 +2339,73 @@
 {
     // keep strong reference on the record thread so that
     // it is not destroyed while exit() is executed
-    sp<RecordThread> thread;
+    sp<RecordThread> recordThread;
+    sp<MmapCaptureThread> mmapThread;
     {
         Mutex::Autolock _l(mLock);
-        thread = checkRecordThread_l(input);
-        if (thread == 0) {
-            return BAD_VALUE;
-        }
+        recordThread = checkRecordThread_l(input);
+        if (recordThread != 0) {
+            ALOGV("closeInput() %d", input);
 
-        ALOGV("closeInput() %d", input);
-
-        // If we still have effect chains, it means that a client still holds a handle
-        // on at least one effect. We must either move the chain to an existing thread with the
-        // same session ID or put it aside in case a new record thread is opened for a
-        // new capture on the same session
-        sp<EffectChain> chain;
-        {
-            Mutex::Autolock _sl(thread->mLock);
-            Vector< sp<EffectChain> > effectChains = thread->getEffectChains_l();
-            // Note: maximum one chain per record thread
-            if (effectChains.size() != 0) {
-                chain = effectChains[0];
-            }
-        }
-        if (chain != 0) {
-            // first check if a record thread is already opened with a client on the same session.
-            // This should only happen in case of overlap between one thread tear down and the
-            // creation of its replacement
-            size_t i;
-            for (i = 0; i < mRecordThreads.size(); i++) {
-                sp<RecordThread> t = mRecordThreads.valueAt(i);
-                if (t == thread) {
-                    continue;
-                }
-                if (t->hasAudioSession(chain->sessionId()) != 0) {
-                    Mutex::Autolock _l(t->mLock);
-                    ALOGV("closeInput() found thread %d for effect session %d",
-                          t->id(), chain->sessionId());
-                    t->addEffectChain_l(chain);
-                    break;
+            // If we still have effect chains, it means that a client still holds a handle
+            // on at least one effect. We must either move the chain to an existing thread with the
+            // same session ID or put it aside in case a new record thread is opened for a
+            // new capture on the same session
+            sp<EffectChain> chain;
+            {
+                Mutex::Autolock _sl(recordThread->mLock);
+                Vector< sp<EffectChain> > effectChains = recordThread->getEffectChains_l();
+                // Note: maximum one chain per record thread
+                if (effectChains.size() != 0) {
+                    chain = effectChains[0];
                 }
             }
-            // put the chain aside if we could not find a record thread with the same session id.
-            if (i == mRecordThreads.size()) {
-                putOrphanEffectChain_l(chain);
+            if (chain != 0) {
+                // first check if a record thread is already opened with a client on the same session.
+                // This should only happen in case of overlap between one thread tear down and the
+                // creation of its replacement
+                size_t i;
+                for (i = 0; i < mRecordThreads.size(); i++) {
+                    sp<RecordThread> t = mRecordThreads.valueAt(i);
+                    if (t == recordThread) {
+                        continue;
+                    }
+                    if (t->hasAudioSession(chain->sessionId()) != 0) {
+                        Mutex::Autolock _l(t->mLock);
+                        ALOGV("closeInput() found thread %d for effect session %d",
+                              t->id(), chain->sessionId());
+                        t->addEffectChain_l(chain);
+                        break;
+                    }
+                }
+                // put the chain aside if we could not find a record thread with the same session id.
+                if (i == mRecordThreads.size()) {
+                    putOrphanEffectChain_l(chain);
+                }
             }
+            mRecordThreads.removeItem(input);
+        } else {
+            mmapThread = (MmapCaptureThread *)checkMmapThread_l(input);
+            if (mmapThread == 0) {
+                return BAD_VALUE;
+            }
+            mMmapThreads.removeItem(input);
         }
         const sp<AudioIoDescriptor> ioDesc = new AudioIoDescriptor();
         ioDesc->mIoHandle = input;
         ioConfigChanged(AUDIO_INPUT_CLOSED, ioDesc);
-        mRecordThreads.removeItem(input);
     }
     // FIXME: calling thread->exit() without mLock held should not be needed anymore now that
     // we have a different lock for notification client
-    closeInputFinish(thread);
+    if (recordThread != 0) {
+        closeInputFinish(recordThread);
+    } else if (mmapThread != 0) {
+        mmapThread->exit();
+        AudioStreamIn *in = mmapThread->clearInput();
+        ALOG_ASSERT(in != NULL, "in shouldn't be NULL");
+        // from now on thread->mInput is NULL
+        delete in;
+    }
     return NO_ERROR;
 }
 
@@ -2285,7 +2433,9 @@
         PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
         thread->invalidateTracks(stream);
     }
-
+    for (size_t i = 0; i < mMmapThreads.size(); i++) {
+        mMmapThreads[i]->invalidateTracks(stream);
+    }
     return NO_ERROR;
 }
 
@@ -2435,16 +2585,18 @@
 // checkThread_l() must be called with AudioFlinger::mLock held
 AudioFlinger::ThreadBase *AudioFlinger::checkThread_l(audio_io_handle_t ioHandle) const
 {
-    ThreadBase *thread = NULL;
-    switch (audio_unique_id_get_use(ioHandle)) {
-    case AUDIO_UNIQUE_ID_USE_OUTPUT:
-        thread = checkPlaybackThread_l(ioHandle);
-        break;
-    case AUDIO_UNIQUE_ID_USE_INPUT:
-        thread = checkRecordThread_l(ioHandle);
-        break;
-    default:
-        break;
+    ThreadBase *thread = checkMmapThread_l(ioHandle);
+    if (thread == 0) {
+        switch (audio_unique_id_get_use(ioHandle)) {
+        case AUDIO_UNIQUE_ID_USE_OUTPUT:
+            thread = checkPlaybackThread_l(ioHandle);
+            break;
+        case AUDIO_UNIQUE_ID_USE_INPUT:
+            thread = checkRecordThread_l(ioHandle);
+            break;
+        default:
+            break;
+        }
     }
     return thread;
 }
@@ -2468,6 +2620,42 @@
     return mRecordThreads.valueFor(input).get();
 }
 
+// checkMmapThread_l() must be called with AudioFlinger::mLock held
+AudioFlinger::MmapThread *AudioFlinger::checkMmapThread_l(audio_io_handle_t io) const
+{
+    return mMmapThreads.valueFor(io).get();
+}
+
+
+// checkPlaybackThread_l() must be called with AudioFlinger::mLock held
+AudioFlinger::VolumeInterface *AudioFlinger::getVolumeInterface_l(audio_io_handle_t output) const
+{
+    VolumeInterface *volumeInterface = (VolumeInterface *)mPlaybackThreads.valueFor(output).get();
+    if (volumeInterface == nullptr) {
+        MmapThread *mmapThread = mMmapThreads.valueFor(output).get();
+        if (mmapThread != nullptr) {
+            if (mmapThread->isOutput()) {
+                volumeInterface = (VolumeInterface *)mmapThread;
+            }
+        }
+    }
+    return volumeInterface;
+}
+
+Vector <AudioFlinger::VolumeInterface *> AudioFlinger::getAllVolumeInterfaces_l() const
+{
+    Vector <VolumeInterface *> volumeInterfaces;
+    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+        volumeInterfaces.add((VolumeInterface *)mPlaybackThreads.valueAt(i).get());
+    }
+    for (size_t i = 0; i < mMmapThreads.size(); i++) {
+        if (mMmapThreads.valueAt(i)->isOutput()) {
+            volumeInterfaces.add((VolumeInterface *)mMmapThreads.valueAt(i).get());
+        }
+    }
+    return volumeInterfaces;
+}
+
 audio_unique_id_t AudioFlinger::nextUniqueId(audio_unique_id_use_t use)
 {
     // This is the internal API, so it is OK to assert on bad parameter.
@@ -2759,7 +2947,7 @@
                     break;
                 }
             }
-            if (io == 0) {
+            if (io == AUDIO_IO_HANDLE_NONE) {
                 for (size_t i = 0; i < mRecordThreads.size(); i++) {
                     if (mRecordThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
                         io = mRecordThreads.keyAt(i);
@@ -2767,6 +2955,14 @@
                     }
                 }
             }
+            if (io == AUDIO_IO_HANDLE_NONE) {
+                for (size_t i = 0; i < mMmapThreads.size(); i++) {
+                    if (mMmapThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
+                        io = mMmapThreads.keyAt(i);
+                        break;
+                    }
+                }
+            }
             // If no output thread contains the requested session ID, default to
             // first output. The effect chain will be moved to the correct output
             // thread when a track with the same session ID is created
@@ -2779,9 +2975,12 @@
         if (thread == NULL) {
             thread = checkPlaybackThread_l(io);
             if (thread == NULL) {
-                ALOGE("createEffect() unknown output thread");
-                lStatus = BAD_VALUE;
-                goto Exit;
+                thread = checkMmapThread_l(io);
+                if (thread == NULL) {
+                    ALOGE("createEffect() unknown output thread");
+                    lStatus = BAD_VALUE;
+                    goto Exit;
+                }
             }
         } else {
             // Check if one effect chain was awaiting for an effect to be created on this
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index e97d1ed..44fd512 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -34,6 +34,8 @@
 #include <media/IAudioRecord.h>
 #include <media/AudioSystem.h>
 #include <media/AudioTrack.h>
+#include <media/MmapStreamInterface.h>
+#include <media/MmapStreamCallback.h>
 
 #include <utils/Atomic.h>
 #include <utils/Errors.h>
@@ -54,6 +56,7 @@
 #include <media/AudioMixer.h>
 #include <media/ExtendedAudioBufferProvider.h>
 #include <media/LinearMap.h>
+#include <media/VolumeShaper.h>
 
 #include "FastCapture.h"
 #include "FastMixer.h"
@@ -100,6 +103,7 @@
     public BnAudioFlinger
 {
     friend class BinderService<AudioFlinger>;   // for AudioFlinger()
+
 public:
     static const char* getServiceName() ANDROID_API { return "media.audio_flinger"; }
 
@@ -283,6 +287,14 @@
     sp<NBLog::Writer>   newWriter_l(size_t size, const char *name);
     void                unregisterWriter(const sp<NBLog::Writer>& writer);
     sp<EffectsFactoryHalInterface> getEffectsFactory();
+
+    status_t openMmapStream(MmapStreamInterface::stream_direction_t direction,
+                            const audio_attributes_t *attr,
+                            audio_config_base_t *config,
+                            const MmapStreamInterface::Client& client,
+                            audio_port_handle_t *deviceId,
+                            const sp<MmapStreamCallback>& callback,
+                            sp<MmapStreamInterface>& interface);
 private:
     static const size_t kLogMemorySize = 40 * 1024;
     sp<MemoryDealer>    mLogMemoryDealer;   // == 0 when NBLog is disabled
@@ -290,6 +302,7 @@
     // for as long as possible.  The memory is only freed when it is needed for another log writer.
     Vector< sp<NBLog::Writer> > mUnregisteredWriters;
     Mutex               mUnregisteredWritersLock;
+
 public:
 
     class SyncEvent;
@@ -506,6 +519,10 @@
         virtual void        pause();
         virtual status_t    attachAuxEffect(int effectId);
         virtual status_t    setParameters(const String8& keyValuePairs);
+        virtual VolumeShaper::Status applyVolumeShaper(
+                const sp<VolumeShaper::Configuration>& configuration,
+                const sp<VolumeShaper::Operation>& operation) override;
+        virtual sp<VolumeShaper::State> getVolumeShaperState(int id) override;
         virtual status_t    getTimestamp(AudioTimestamp& timestamp);
         virtual void        signal(); // signal playback thread for a change in control block
 
@@ -533,19 +550,40 @@
         void                stop_nonvirtual();
     };
 
+    // Mmap stream control interface implementation. Each MmapThreadHandle controls one
+    // MmapPlaybackThread or MmapCaptureThread instance.
+    class MmapThreadHandle : public MmapStreamInterface {
+    public:
+        explicit            MmapThreadHandle(const sp<MmapThread>& thread);
+        virtual             ~MmapThreadHandle();
+
+        // MmapStreamInterface virtuals
+        virtual status_t createMmapBuffer(int32_t minSizeFrames,
+                                          struct audio_mmap_buffer_info *info);
+        virtual status_t getMmapPosition(struct audio_mmap_position *position);
+        virtual status_t start(const MmapStreamInterface::Client& client, audio_port_handle_t *handle);
+        virtual status_t stop(audio_port_handle_t handle);
+
+    private:
+        sp<MmapThread> mThread;
+    };
 
               ThreadBase *checkThread_l(audio_io_handle_t ioHandle) const;
               PlaybackThread *checkPlaybackThread_l(audio_io_handle_t output) const;
               MixerThread *checkMixerThread_l(audio_io_handle_t output) const;
               RecordThread *checkRecordThread_l(audio_io_handle_t input) const;
-              sp<RecordThread> openInput_l(audio_module_handle_t module,
+              MmapThread *checkMmapThread_l(audio_io_handle_t io) const;
+              VolumeInterface *getVolumeInterface_l(audio_io_handle_t output) const;
+              Vector <VolumeInterface *> getAllVolumeInterfaces_l() const;
+
+              sp<ThreadBase> openInput_l(audio_module_handle_t module,
                                            audio_io_handle_t *input,
                                            audio_config_t *config,
                                            audio_devices_t device,
                                            const String8& address,
                                            audio_source_t source,
                                            audio_input_flags_t flags);
-              sp<PlaybackThread> openOutput_l(audio_module_handle_t module,
+              sp<ThreadBase> openOutput_l(audio_module_handle_t module,
                                               audio_io_handle_t *output,
                                               audio_config_t *config,
                                               audio_devices_t devices,
@@ -722,6 +760,12 @@
 
                 // list of sessions for which a valid HW A/V sync ID was retrieved from the HAL
                 DefaultKeyedVector< audio_session_t , audio_hw_sync_t >mHwAvSyncIds;
+
+                // list of MMAP stream control threads. Those threads allow for wake lock, routing
+                // and volume control for activity on the associated MMAP stream at the HAL.
+                // Audio data transfer is directly handled by the client creating the MMAP stream
+                DefaultKeyedVector< audio_io_handle_t, sp<MmapThread> >  mMmapThreads;
+
 private:
     sp<Client>  registerPid(pid_t pid);    // always returns non-0
 
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 70929e4..b4029c7 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1225,10 +1225,9 @@
         mEnabled = false;
     } else {
         if (thread != 0) {
-            if (thread->type() == ThreadBase::OFFLOAD) {
-                PlaybackThread *t = (PlaybackThread *)thread.get();
-                Mutex::Autolock _l(t->mLock);
-                t->broadcast_l();
+            if (thread->type() == ThreadBase::OFFLOAD || thread->type() == ThreadBase::MMAP) {
+                Mutex::Autolock _l(thread->mLock);
+                thread->broadcast_l();
             }
             if (!effect->isOffloadable()) {
                 if (thread->type() == ThreadBase::OFFLOAD) {
@@ -1270,10 +1269,9 @@
     sp<ThreadBase> thread = effect->thread().promote();
     if (thread != 0) {
         thread->checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
-        if (thread->type() == ThreadBase::OFFLOAD) {
-            PlaybackThread *t = (PlaybackThread *)thread.get();
-            Mutex::Autolock _l(t->mLock);
-            t->broadcast_l();
+        if (thread->type() == ThreadBase::OFFLOAD || thread->type() == ThreadBase::MMAP) {
+            Mutex::Autolock _l(thread->mLock);
+            thread->broadcast_l();
         }
     }
 
@@ -1581,6 +1579,9 @@
 // Must be called with EffectChain::mLock locked
 void AudioFlinger::EffectChain::clearInputBuffer_l(const sp<ThreadBase>& thread)
 {
+    if (mInBuffer == NULL) {
+        return;
+    }
     // TODO: This will change in the future, depending on multichannel
     // and sample format changes for effects.
     // Currently effects processing is only available for stereo, AUDIO_FORMAT_PCM_16_BIT
@@ -1604,7 +1605,8 @@
     // never process effects when:
     // - on an OFFLOAD thread
     // - no more tracks are on the session and the effect tail has been rendered
-    bool doProcess = (thread->type() != ThreadBase::OFFLOAD);
+    bool doProcess = (thread->type() != ThreadBase::OFFLOAD)
+                  && (thread->type() != ThreadBase::MMAP);
     if (!isGlobalSession) {
         bool tracksOnSession = (trackCnt() != 0);
 
diff --git a/services/audioflinger/MmapTracks.h b/services/audioflinger/MmapTracks.h
new file mode 100644
index 0000000..e4fe8ac
--- /dev/null
+++ b/services/audioflinger/MmapTracks.h
@@ -0,0 +1,60 @@
+/*
+**
+** Copyright 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 INCLUDING_FROM_AUDIOFLINGER_H
+    #error This header file should only be included from AudioFlinger.h
+#endif
+
+// playback track
+class MmapTrack : public TrackBase {
+public:
+                MmapTrack(ThreadBase *thread,
+                            uint32_t sampleRate,
+                            audio_format_t format,
+                            audio_channel_mask_t channelMask,
+                            audio_session_t sessionId,
+                            uid_t uid,
+                            audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE);
+    virtual             ~MmapTrack();
+
+                        // TrackBase virtual
+    virtual status_t    initCheck() const;
+    virtual status_t    start(AudioSystem::sync_event_t event,
+                              audio_session_t triggerSession);
+    virtual void        stop();
+    virtual bool        isFastTrack() const { return false; }
+
+     static void        appendDumpHeader(String8& result);
+            void        dump(char* buffer, size_t size);
+
+protected:
+    friend class MmapThread;
+
+                MmapTrack(const MmapTrack&);
+                MmapTrack& operator = (const MmapTrack&);
+
+    // AudioBufferProvider interface
+    virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+    // releaseBuffer() not overridden
+
+    // ExtendedAudioBufferProvider interface
+    virtual size_t framesReady() const;
+    virtual int64_t framesReleased() const;
+    virtual void onTimestamp(const ExtendedTimestamp &timestamp);
+
+};  // end of Track
+
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 591a49e..d7c0728 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -274,13 +274,14 @@
                     audio_devices_t device = patch->sinks[0].ext.device.type;
                     String8 address = String8(patch->sinks[0].ext.device.address);
                     audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-                    newPatch->mPlaybackThread = audioflinger->openOutput_l(
-                                                             patch->sinks[0].ext.device.hw_module,
-                                                             &output,
-                                                             &config,
-                                                             device,
-                                                             address,
-                                                             AUDIO_OUTPUT_FLAG_NONE);
+                    sp<ThreadBase> thread = audioflinger->openOutput_l(
+                                                            patch->sinks[0].ext.device.hw_module,
+                                                            &output,
+                                                            &config,
+                                                            device,
+                                                            address,
+                                                            AUDIO_OUTPUT_FLAG_NONE);
+                    newPatch->mPlaybackThread = (PlaybackThread *)thread.get();
                     ALOGV("audioflinger->openOutput_l() returned %p",
                                           newPatch->mPlaybackThread.get());
                     if (newPatch->mPlaybackThread == 0) {
@@ -310,13 +311,14 @@
                     config.format = newPatch->mPlaybackThread->format();
                 }
                 audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
-                newPatch->mRecordThread = audioflinger->openInput_l(srcModule,
+                sp<ThreadBase> thread = audioflinger->openInput_l(srcModule,
                                                                     &input,
                                                                     &config,
                                                                     device,
                                                                     address,
                                                                     AUDIO_SOURCE_MIC,
                                                                     AUDIO_INPUT_FLAG_NONE);
+                newPatch->mRecordThread = (RecordThread *)thread.get();
                 ALOGV("audioflinger->openInput_l() returned %p inChannelMask %08x",
                       newPatch->mRecordThread.get(), config.channel_mask);
                 if (newPatch->mRecordThread == 0) {
@@ -332,10 +334,13 @@
                     sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
                                                               patch->sinks[0].ext.mix.handle);
                     if (thread == 0) {
-                        ALOGW("createAudioPatch() bad capture I/O handle %d",
-                                                              patch->sinks[0].ext.mix.handle);
-                        status = BAD_VALUE;
-                        goto exit;
+                        thread = audioflinger->checkMmapThread_l(patch->sinks[0].ext.mix.handle);
+                        if (thread == 0) {
+                            ALOGW("createAudioPatch() bad capture I/O handle %d",
+                                                                  patch->sinks[0].ext.mix.handle);
+                            status = BAD_VALUE;
+                            goto exit;
+                        }
                     }
                     status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
                 } else {
@@ -376,10 +381,13 @@
             sp<ThreadBase> thread =
                             audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
             if (thread == 0) {
-                ALOGW("createAudioPatch() bad playback I/O handle %d",
-                          patch->sources[0].ext.mix.handle);
-                status = BAD_VALUE;
-                goto exit;
+                thread = audioflinger->checkMmapThread_l(patch->sources[0].ext.mix.handle);
+                if (thread == 0) {
+                    ALOGW("createAudioPatch() bad playback I/O handle %d",
+                              patch->sources[0].ext.mix.handle);
+                    status = BAD_VALUE;
+                    goto exit;
+                }
             }
             if (thread == audioflinger->primaryPlaybackThread_l()) {
                 AudioParameter param = AudioParameter();
@@ -606,10 +614,13 @@
                 sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
                                                                 patch->sinks[0].ext.mix.handle);
                 if (thread == 0) {
-                    ALOGW("releaseAudioPatch() bad capture I/O handle %d",
-                                                              patch->sinks[0].ext.mix.handle);
-                    status = BAD_VALUE;
-                    break;
+                    thread = audioflinger->checkMmapThread_l(patch->sinks[0].ext.mix.handle);
+                    if (thread == 0) {
+                        ALOGW("releaseAudioPatch() bad capture I/O handle %d",
+                                                                  patch->sinks[0].ext.mix.handle);
+                        status = BAD_VALUE;
+                        break;
+                    }
                 }
                 status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle);
             } else {
@@ -629,10 +640,13 @@
             sp<ThreadBase> thread =
                             audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
             if (thread == 0) {
-                ALOGW("releaseAudioPatch() bad playback I/O handle %d",
-                                                              patch->sources[0].ext.mix.handle);
-                status = BAD_VALUE;
-                break;
+                thread = audioflinger->checkMmapThread_l(patch->sources[0].ext.mix.handle);
+                if (thread == 0) {
+                    ALOGW("releaseAudioPatch() bad playback I/O handle %d",
+                                                                  patch->sources[0].ext.mix.handle);
+                    status = BAD_VALUE;
+                    break;
+                }
             }
             status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle);
         } break;
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 27e4627..f84ba08 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -59,6 +59,10 @@
             bool        isOffloaded() const
                                 { return (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0; }
             bool        isDirect() const { return (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0; }
+            bool        isOffloadedOrDirect() const { return (mFlags
+                            & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
+                                    | AUDIO_OUTPUT_FLAG_DIRECT)) != 0; }
+
             status_t    setParameters(const String8& keyValuePairs);
             status_t    attachAuxEffect(int EffectId);
             void        setAuxBuffer(int EffectId, int32_t *buffer);
@@ -76,6 +80,13 @@
 
     virtual bool        isFastTrack() const { return (mFlags & AUDIO_OUTPUT_FLAG_FAST) != 0; }
 
+// implement volume handling.
+   VolumeShaper::Status applyVolumeShaper(
+                                const sp<VolumeShaper::Configuration>& configuration,
+                                const sp<VolumeShaper::Operation>& operation);
+sp<VolumeShaper::State> getVolumeShaperState(int id);
+    sp<VolumeHandler>   getVolumeHandler() { return mVolumeHandler; }
+
 protected:
     // for numerous
     friend class PlaybackThread;
@@ -118,10 +129,9 @@
 
 public:
     void triggerEvents(AudioSystem::sync_event_t type);
-    void invalidate();
+    virtual void invalidate();
     void disable();
 
-    bool isInvalid() const { return mIsInvalid; }
     int fastIndex() const { return mFastIndex; }
 
 protected:
@@ -153,6 +163,8 @@
 
     ExtendedTimestamp  mSinkTimestamp;
 
+    sp<VolumeHandler>  mVolumeHandler; // handles multiple VolumeShaper configs and operations
+
 private:
     // The following fields are only for fast tracks, and should be in a subclass
     int                 mFastIndex; // index within FastMixerState::mFastTracks[];
@@ -166,7 +178,6 @@
     volatile float      mCachedVolume;  // combined master volume and stream type volume;
                                         // 'volatile' means accessed without lock or
                                         // barrier, but is read/written atomically
-    bool                mIsInvalid; // non-resettable latch, set by invalidate()
     sp<AudioTrackServerProxy>  mAudioTrackServerProxy;
     bool                mResumeToStopping; // track was paused in stopping state.
     bool                mFlushHwPending; // track requests for thread flush
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 848e531..72ebc93 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -42,7 +42,7 @@
 
             void        destroy();
 
-            void        invalidate();
+    virtual void        invalidate();
             // clear the buffer overflow flag
             void        clearOverflow() { mOverflow = false; }
             // set the buffer overflow flag and return previous value
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index a1d81f9..b10e42c 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -510,7 +510,8 @@
         mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
         // mName will be set by concrete (non-virtual) subclass
         mDeathRecipient(new PMDeathRecipient(this)),
-        mSystemReady(systemReady)
+        mSystemReady(systemReady),
+        mSignalPending(false)
 {
     memset(&mPatch, 0, sizeof(struct audio_patch));
 }
@@ -613,16 +614,17 @@
     sendConfigEvent_l(configEvent);
 }
 
-void AudioFlinger::ThreadBase::sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio)
+void AudioFlinger::ThreadBase::sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio, bool forApp)
 {
     Mutex::Autolock _l(mLock);
-    sendPrioConfigEvent_l(pid, tid, prio);
+    sendPrioConfigEvent_l(pid, tid, prio, forApp);
 }
 
 // sendPrioConfigEvent_l() must be called with ThreadBase::mLock held
-void AudioFlinger::ThreadBase::sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio)
+void AudioFlinger::ThreadBase::sendPrioConfigEvent_l(
+        pid_t pid, pid_t tid, int32_t prio, bool forApp)
 {
-    sp<ConfigEvent> configEvent = (ConfigEvent *)new PrioConfigEvent(pid, tid, prio);
+    sp<ConfigEvent> configEvent = (ConfigEvent *)new PrioConfigEvent(pid, tid, prio, forApp);
     sendConfigEvent_l(configEvent);
 }
 
@@ -682,7 +684,7 @@
         case CFG_EVENT_PRIO: {
             PrioConfigEventData *data = (PrioConfigEventData *)event->mData.get();
             // FIXME Need to understand why this has to be done asynchronously
-            int err = requestPriority(data->mPid, data->mTid, data->mPrio,
+            int err = requestPriority(data->mPid, data->mTid, data->mPrio, data->mForApp,
                     true /*asynchronous*/);
             if (err != 0) {
                 ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
@@ -870,6 +872,8 @@
         return String16("AudioIn");
     case OFFLOAD:
         return String16("AudioOffload");
+    case MMAP:
+        return String16("Mmap");
     default:
         ALOG_ASSERT(false);
         return String16("AudioUnknown");
@@ -1594,6 +1598,16 @@
     }
 }
 
+void AudioFlinger::ThreadBase::broadcast_l()
+{
+    // Thread could be blocked waiting for async
+    // so signal it to handle state changes immediately
+    // If threadLoop is currently unlocked a signal of mWaitWorkCV will
+    // be lost so we also flag to prevent it blocking on mWaitWorkCV
+    mSignalPending = true;
+    mWaitWorkCV.broadcast();
+}
+
 // ----------------------------------------------------------------------------
 //      Playback
 // ----------------------------------------------------------------------------
@@ -1630,7 +1644,6 @@
         mUseAsyncWrite(false),
         mWriteAckSequence(0),
         mDrainSequence(0),
-        mSignalPending(false),
         mScreenState(AudioFlinger::mScreenState),
         // index 0 is reserved for normal mixer's submix
         mFastTrackAvailMask(((1 << FastMixerState::sMaxFastTracks) - 1) & ~1),
@@ -2017,7 +2030,7 @@
             pid_t callingPid = IPCThreadState::self()->getCallingPid();
             // we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful,
             // so ask activity manager to do this on our behalf
-            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp);
+            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true /*isForApp*/);
         }
     }
 
@@ -2061,6 +2074,9 @@
 
 void AudioFlinger::PlaybackThread::setMasterMute(bool muted)
 {
+    if (isDuplicating()) {
+        return;
+    }
     Mutex::Autolock _l(mLock);
     // Don't apply master mute in SW if our HAL can do it for us.
     if (mOutput && mOutput->audioHwDev &&
@@ -2202,16 +2218,6 @@
     }
 }
 
-void AudioFlinger::PlaybackThread::broadcast_l()
-{
-    // Thread could be blocked waiting for async
-    // so signal it to handle state changes immediately
-    // If threadLoop is currently unlocked a signal of mWaitWorkCV will
-    // be lost so we also flag to prevent it blocking on mWaitWorkCV
-    mSignalPending = true;
-    mWaitWorkCV.broadcast();
-}
-
 String8 AudioFlinger::PlaybackThread::getParameters(const String8& keys)
 {
     Mutex::Autolock _l(mLock);
@@ -3035,12 +3041,12 @@
             }
 #if 0
             // logFormat example
-            if (!(z % 100)) {
+            if (z % 100 == 0) {
                 timespec ts;
                 clock_gettime(CLOCK_MONOTONIC, &ts);
-                LOGF("This is an integer %d, this is a float %f, this is my "
+                LOGT("This is an integer %d, this is a float %f, this is my "
                     "pid %p %% %s %t", 42, 3.14, "and this is a timestamp", ts);
-                LOGF("A deceptive null-terminated string %\0");
+                LOGT("A deceptive null-terminated string %\0");
             }
             ++z;
 #endif
@@ -3057,8 +3063,13 @@
                     releaseWakeLock_l();
                     released = true;
                 }
-                ALOGV("wait async completion");
-                mWaitWorkCV.wait(mLock);
+
+                const int64_t waitNs = computeWaitTimeNs_l();
+                ALOGV("wait async completion (wait time: %lld)", (long long)waitNs);
+                status_t status = mWaitWorkCV.waitRelative(mLock, waitNs);
+                if (status == TIMED_OUT) {
+                    mSignalPending = true; // if timeout recheck everything
+                }
                 ALOGV("async completion/wake");
                 if (released) {
                     acquireWakeLock_l();
@@ -3572,9 +3583,17 @@
         break;
     case FastMixer_Static:
     case FastMixer_Dynamic:
-        initFastMixer = mFrameCount < mNormalFrameCount;
+        // FastMixer was designed to operate with a HAL that pulls at a regular rate,
+        // where the period is less than an experimentally determined threshold that can be
+        // scheduled reliably with CFS. However, the BT A2DP HAL is
+        // bursty (does not pull at a regular rate) and so cannot operate with FastMixer.
+        initFastMixer = mFrameCount < mNormalFrameCount
+                && (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) == 0;
         break;
     }
+    ALOGW_IF(initFastMixer == false && mFrameCount < mNormalFrameCount,
+            "FastMixer is preferred for this sink as frameCount %zu is less than threshold %zu",
+            mFrameCount, mNormalFrameCount);
     if (initFastMixer) {
         audio_format_t fastMixerFormat;
         if (mMixerBufferEnabled && mEffectBufferEnabled) {
@@ -3673,7 +3692,7 @@
         // start the fast mixer
         mFastMixer->run("FastMixer", PRIORITY_URGENT_AUDIO);
         pid_t tid = mFastMixer->getTid();
-        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer);
+        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer, false);
         stream()->setHalThreadPriority(kPriorityFastMixer);
 
 #ifdef AUDIO_WATCHDOG
@@ -3967,9 +3986,11 @@
     FastMixerState *state = NULL;
     bool didModify = false;
     FastMixerStateQueue::block_t block = FastMixerStateQueue::BLOCK_UNTIL_PUSHED;
+    bool coldIdle = false;
     if (mFastMixer != 0) {
         sq = mFastMixer->sq();
         state = sq->begin();
+        coldIdle = state->mCommand == FastMixerState::COLD_IDLE;
     }
 
     mMixerBufferValid = false;  // mMixerBuffer has no valid data until appropriate tracks found.
@@ -4114,7 +4135,11 @@
                 }
                 // cache the combined master volume and stream type volume for fast mixer; this
                 // lacks any synchronization or barrier so VolumeProvider may read a stale value
-                track->mCachedVolume = masterVolume * mStreamTypes[track->streamType()].volume;
+                const float vh = track->getVolumeHandler()->getVolume(
+                        track->mAudioTrackServerProxy->framesReleased()).first;
+                track->mCachedVolume = masterVolume
+                        * mStreamTypes[track->streamType()].volume
+                        * vh;
                 ++fastTracks;
             } else {
                 // was it previously active?
@@ -4256,9 +4281,11 @@
                     ALOGV("Track right volume out of range: %.3g", vrf);
                     vrf = GAIN_FLOAT_UNITY;
                 }
-                // now apply the master volume and stream type volume
-                vlf *= v;
-                vrf *= v;
+                const float vh = track->getVolumeHandler()->getVolume(
+                        track->mAudioTrackServerProxy->framesReleased()).first;
+                // now apply the master volume and stream type volume and shaper volume
+                vlf *= v * vh;
+                vrf *= v * vh;
                 // assuming master volume and stream type volume each go up to 1.0,
                 // then derive vl and vr as U8.24 versions for the effect chain
                 const float scaleto8_24 = MAX_GAIN_INT * MAX_GAIN_INT;
@@ -4459,7 +4486,15 @@
     }
     if (sq != NULL) {
         sq->end(didModify);
-        sq->push(block);
+        // No need to block if the FastMixer is in COLD_IDLE as the FastThread
+        // is not active. (We BLOCK_UNTIL_ACKED when entering COLD_IDLE
+        // when bringing the output sink into standby.)
+        //
+        // We will get the latest FastMixer state when we come out of COLD_IDLE.
+        //
+        // This occurs with BT suspend when we idle the FastMixer with
+        // active tracks, which may be added or removed.
+        sq->push(coldIdle ? FastMixerStateQueue::BLOCK_NEVER : block);
     }
 #ifdef AUDIO_WATCHDOG
     if (pauseAudioWatchdog && mAudioWatchdog != 0) {
@@ -4726,6 +4761,7 @@
         ThreadBase::type_t type, bool systemReady)
     :   PlaybackThread(audioFlinger, output, id, device, type, systemReady)
         // mLeftVolFloat, mRightVolFloat
+        , mVolumeShaperActive(false)
 {
 }
 
@@ -4743,6 +4779,14 @@
         float typeVolume = mStreamTypes[track->streamType()].volume;
         float v = mMasterVolume * typeVolume;
         sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
+
+        // Get volumeshaper scaling
+        std::pair<float /* volume */, bool /* active */>
+            vh = track->getVolumeHandler()->getVolume(
+                    track->mAudioTrackServerProxy->framesReleased());
+        v *= vh.first;
+        mVolumeShaperActive = vh.second;
+
         gain_minifloat_packed_t vlr = proxy->getVolumeLR();
         left = float_from_gain(gain_minifloat_unpack_left(vlr));
         if (left > GAIN_FLOAT_UNITY) {
@@ -5199,6 +5243,13 @@
     mFlushPending = false;
 }
 
+int64_t AudioFlinger::DirectOutputThread::computeWaitTimeNs_l() const {
+    // If a VolumeShaper is active, we must wake up periodically to update volume.
+    const int64_t NS_PER_MS = 1000000;
+    return mVolumeShaperActive ?
+            kMinNormalSinkBufferSizeMs * NS_PER_MS : PlaybackThread::computeWaitTimeNs_l();
+}
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::AsyncCallbackThread::AsyncCallbackThread(
@@ -5810,6 +5861,7 @@
     MixerThread::cacheParameters_l();
 }
 
+
 // ----------------------------------------------------------------------------
 //      Record
 // ----------------------------------------------------------------------------
@@ -5936,7 +5988,7 @@
         // start the fast capture
         mFastCapture->run("FastCapture", ANDROID_PRIORITY_URGENT_AUDIO);
         pid_t tid = mFastCapture->getTid();
-        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastCapture);
+        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastCapture, false);
         stream()->setHalThreadPriority(kPriorityFastCapture);
 #ifdef AUDIO_WATCHDOG
         // FIXME
@@ -5976,6 +6028,18 @@
     run(mThreadName, PRIORITY_URGENT_AUDIO);
 }
 
+void AudioFlinger::RecordThread::preExit()
+{
+    ALOGV("  preExit()");
+    Mutex::Autolock _l(mLock);
+    for (size_t i = 0; i < mTracks.size(); i++) {
+        sp<RecordTrack> track = mTracks[i];
+        track->invalidate();
+    }
+    mActiveTracks.clear();
+    mStartStopCond.broadcast();
+}
+
 bool AudioFlinger::RecordThread::threadLoop()
 {
     nsecs_t lastWarning = 0;
@@ -6596,7 +6660,7 @@
             pid_t callingPid = IPCThreadState::self()->getCallingPid();
             // we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful,
             // so ask activity manager to do this on our behalf
-            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp);
+            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true);
         }
     }
 
@@ -7357,4 +7421,889 @@
     config->ext.mix.usecase.source = mAudioSource;
 }
 
+// ----------------------------------------------------------------------------
+//      Mmap
+// ----------------------------------------------------------------------------
+
+AudioFlinger::MmapThreadHandle::MmapThreadHandle(const sp<MmapThread>& thread)
+    : mThread(thread)
+{
+}
+
+AudioFlinger::MmapThreadHandle::~MmapThreadHandle()
+{
+    MmapThread *thread = mThread.get();
+    // clear our strong reference before disconnecting the thread: the last strong reference
+    // will be removed when closeInput/closeOutput is executed upono call from audio policy manager
+    // and the thread removed from mMMapThreads list causing the thread destruction.
+    mThread.clear();
+    if (thread != nullptr) {
+        thread->disconnect();
+    }
+}
+
+status_t AudioFlinger::MmapThreadHandle::createMmapBuffer(int32_t minSizeFrames,
+                                  struct audio_mmap_buffer_info *info)
+{
+    if (mThread == 0) {
+        return NO_INIT;
+    }
+    return mThread->createMmapBuffer(minSizeFrames, info);
+}
+
+status_t AudioFlinger::MmapThreadHandle::getMmapPosition(struct audio_mmap_position *position)
+{
+    if (mThread == 0) {
+        return NO_INIT;
+    }
+    return mThread->getMmapPosition(position);
+}
+
+status_t AudioFlinger::MmapThreadHandle::start(const MmapStreamInterface::Client& client, audio_port_handle_t *handle)
+
+{
+    if (mThread == 0) {
+        return NO_INIT;
+    }
+    return mThread->start(client, handle);
+}
+
+status_t AudioFlinger::MmapThreadHandle::stop(audio_port_handle_t handle)
+{
+    if (mThread == 0) {
+        return NO_INIT;
+    }
+    return mThread->stop(handle);
+}
+
+
+AudioFlinger::MmapThread::MmapThread(
+        const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
+        AudioHwDevice *hwDev, sp<StreamHalInterface> stream,
+        audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady)
+    : ThreadBase(audioFlinger, id, outDevice, inDevice, MMAP, systemReady),
+      mHalStream(stream), mHalDevice(hwDev->hwDevice()), mAudioHwDev(hwDev)
+{
+    readHalParameters_l();
+}
+
+AudioFlinger::MmapThread::~MmapThread()
+{
+}
+
+void AudioFlinger::MmapThread::onFirstRef()
+{
+    run(mThreadName, ANDROID_PRIORITY_URGENT_AUDIO);
+}
+
+void AudioFlinger::MmapThread::disconnect()
+{
+    for (const sp<MmapTrack> &t : mActiveTracks) {
+        stop(t->portId());
+    }
+    // this will cause the destruction of this thread.
+    if (isOutput()) {
+        AudioSystem::releaseOutput(mId, streamType(), mSessionId);
+    } else {
+        AudioSystem::releaseInput(mId, mSessionId);
+    }
+}
+
+
+void AudioFlinger::MmapThread::configure(const audio_attributes_t *attr,
+                                                audio_stream_type_t streamType __unused,
+                                                audio_session_t sessionId,
+                                                const sp<MmapStreamCallback>& callback,
+                                                audio_port_handle_t portId)
+{
+    mAttr = *attr;
+    mSessionId = sessionId;
+    mCallback = callback;
+    mPortId = portId;
+}
+
+status_t AudioFlinger::MmapThread::createMmapBuffer(int32_t minSizeFrames,
+                                  struct audio_mmap_buffer_info *info)
+{
+    if (mHalStream == 0) {
+        return NO_INIT;
+    }
+    return mHalStream->createMmapBuffer(minSizeFrames, info);
+}
+
+status_t AudioFlinger::MmapThread::getMmapPosition(struct audio_mmap_position *position)
+{
+    if (mHalStream == 0) {
+        return NO_INIT;
+    }
+    return mHalStream->getMmapPosition(position);
+}
+
+status_t AudioFlinger::MmapThread::start(const MmapStreamInterface::Client& client,
+                                         audio_port_handle_t *handle)
+{
+    ALOGV("%s clientUid %d", __FUNCTION__, client.clientUid);
+    if (mHalStream == 0) {
+        return NO_INIT;
+    }
+
+    status_t ret;
+    audio_session_t sessionId;
+    audio_port_handle_t portId;
+
+    if (mActiveTracks.size() == 0) {
+        // for the first track, reuse portId and session allocated when the stream was opened
+        mHalStream->start();
+        portId = mPortId;
+        sessionId = mSessionId;
+    } else {
+        // for other tracks than first one, get a new port ID from APM.
+        sessionId = (audio_session_t)mAudioFlinger->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
+        audio_io_handle_t io;
+        if (isOutput()) {
+            audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+            config.sample_rate = mSampleRate;
+            config.channel_mask = mChannelMask;
+            config.format = mFormat;
+            audio_stream_type_t stream = streamType();
+            audio_output_flags_t flags =
+                    (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
+            ret = AudioSystem::getOutputForAttr(&mAttr, &io,
+                                                sessionId,
+                                                &stream,
+                                                client.clientUid,
+                                                &config,
+                                                flags,
+                                                AUDIO_PORT_HANDLE_NONE,
+                                                &portId);
+        } else {
+            audio_config_base_t config;
+            config.sample_rate = mSampleRate;
+            config.channel_mask = mChannelMask;
+            config.format = mFormat;
+            ret = AudioSystem::getInputForAttr(&mAttr, &io,
+                                                  sessionId,
+                                                  client.clientPid,
+                                                  client.clientUid,
+                                                  &config,
+                                                  AUDIO_INPUT_FLAG_MMAP_NOIRQ,
+                                                  AUDIO_PORT_HANDLE_NONE,
+                                                  &portId);
+        }
+        // APM should not chose a different input or output stream for the same set of attributes
+        // and audo configuration
+        if (ret != NO_ERROR || io != mId) {
+            ALOGE("%s: error getting output or input from APM (error %d, io %d expected io %d)",
+                  __FUNCTION__, ret, io, mId);
+            return BAD_VALUE;
+        }
+    }
+
+    if (isOutput()) {
+        ret = AudioSystem::startOutput(mId, streamType(), sessionId);
+    } else {
+        ret = AudioSystem::startInput(mId, sessionId);
+    }
+
+    // abort if start is rejected by audio policy manager
+    if (ret != NO_ERROR) {
+        if (mActiveTracks.size() != 0) {
+            if (isOutput()) {
+                AudioSystem::releaseOutput(mId, streamType(), sessionId);
+            } else {
+                AudioSystem::releaseInput(mId, sessionId);
+            }
+        }
+        return PERMISSION_DENIED;
+    }
+
+    sp<MmapTrack> track = new MmapTrack(this, mSampleRate, mFormat, mChannelMask, sessionId,
+                                        client.clientUid, portId);
+
+    mActiveTracks.add(track);
+    sp<EffectChain> chain = getEffectChain_l(sessionId);
+    if (chain != 0) {
+        chain->setStrategy(AudioSystem::getStrategyForStream(streamType()));
+        chain->incTrackCnt();
+        chain->incActiveTrackCnt();
+    }
+
+    *handle = portId;
+
+    broadcast_l();
+
+    ALOGV("%s DONE handle %d", __FUNCTION__, portId);
+
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MmapThread::stop(audio_port_handle_t handle)
+{
+
+    ALOGV("%s handle %d", __FUNCTION__, handle);
+
+    if (mHalStream == 0) {
+        return NO_INIT;
+    }
+
+    sp<MmapTrack> track;
+    for (const sp<MmapTrack> &t : mActiveTracks) {
+        if (handle == t->portId()) {
+            track = t;
+            break;
+        }
+    }
+    if (track == 0) {
+        return BAD_VALUE;
+    }
+
+    mActiveTracks.remove(track);
+
+    if (isOutput()) {
+        AudioSystem::stopOutput(mId, streamType(), track->sessionId());
+        if (mActiveTracks.size() != 0) {
+            AudioSystem::releaseOutput(mId, streamType(), track->sessionId());
+        }
+    } else {
+        AudioSystem::stopInput(mId, track->sessionId());
+        if (mActiveTracks.size() != 0) {
+            AudioSystem::releaseInput(mId, track->sessionId());
+        }
+    }
+
+    sp<EffectChain> chain = getEffectChain_l(track->sessionId());
+    if (chain != 0) {
+        chain->decActiveTrackCnt();
+        chain->decTrackCnt();
+    }
+
+    broadcast_l();
+
+    if (mActiveTracks.size() == 0) {
+        mHalStream->stop();
+    }
+    return NO_ERROR;
+}
+
+
+void AudioFlinger::MmapThread::readHalParameters_l()
+{
+    status_t result = mHalStream->getAudioProperties(&mSampleRate, &mChannelMask, &mHALFormat);
+    LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving audio properties from HAL: %d", result);
+    mFormat = mHALFormat;
+    LOG_ALWAYS_FATAL_IF(!audio_is_linear_pcm(mFormat), "HAL format %#x is not linear pcm", mFormat);
+    result = mHalStream->getFrameSize(&mFrameSize);
+    LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving frame size from HAL: %d", result);
+    result = mHalStream->getBufferSize(&mBufferSize);
+    LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving buffer size from HAL: %d", result);
+    mFrameCount = mBufferSize / mFrameSize;
+}
+
+bool AudioFlinger::MmapThread::threadLoop()
+{
+    acquireWakeLock();
+
+    checkSilentMode_l();
+
+    const String8 myName(String8::format("thread %p type %d TID %d", this, mType, gettid()));
+
+    while (!exitPending())
+    {
+        Mutex::Autolock _l(mLock);
+        Vector< sp<EffectChain> > effectChains;
+
+        if (mSignalPending) {
+            // A signal was raised while we were unlocked
+            mSignalPending = false;
+        } else {
+            if (mConfigEvents.isEmpty()) {
+                // we're about to wait, flush the binder command buffer
+                IPCThreadState::self()->flushCommands();
+
+                if (exitPending()) {
+                    break;
+                }
+
+                bool wakelockReleased = false;
+                if (mActiveTracks.size() == 0) {
+                    releaseWakeLock_l();
+                    wakelockReleased = true;
+                }
+                // wait until we have something to do...
+                ALOGV("%s going to sleep", myName.string());
+                mWaitWorkCV.wait(mLock);
+                ALOGV("%s waking up", myName.string());
+                if (wakelockReleased) {
+                    acquireWakeLock_l();
+                }
+
+                checkSilentMode_l();
+
+                continue;
+            }
+        }
+
+        processConfigEvents_l();
+
+        processVolume_l();
+
+        checkInvalidTracks_l();
+
+        mActiveTracks.updatePowerState(this);
+
+        lockEffectChains_l(effectChains);
+        for (size_t i = 0; i < effectChains.size(); i ++) {
+            effectChains[i]->process_l();
+        }
+        // enable changes in effect chain
+        unlockEffectChains(effectChains);
+        // Effect chains will be actually deleted here if they were removed from
+        // mEffectChains list during mixing or effects processing
+    }
+
+    threadLoop_exit();
+
+    if (!mStandby) {
+        threadLoop_standby();
+        mStandby = true;
+    }
+
+    releaseWakeLock();
+
+    ALOGV("Thread %p type %d exiting", this, mType);
+    return false;
+}
+
+// checkForNewParameter_l() must be called with ThreadBase::mLock held
+bool AudioFlinger::MmapThread::checkForNewParameter_l(const String8& keyValuePair,
+                                                              status_t& status)
+{
+    AudioParameter param = AudioParameter(keyValuePair);
+    int value;
+    if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
+        // forward device change to effects that have requested to be
+        // aware of attached audio device.
+        if (value != AUDIO_DEVICE_NONE) {
+            mOutDevice = value;
+            for (size_t i = 0; i < mEffectChains.size(); i++) {
+                mEffectChains[i]->setDevice_l(mOutDevice);
+            }
+        }
+    }
+    status = mHalStream->setParameters(keyValuePair);
+
+    return false;
+}
+
+String8 AudioFlinger::MmapThread::getParameters(const String8& keys)
+{
+    Mutex::Autolock _l(mLock);
+    String8 out_s8;
+    if (initCheck() == NO_ERROR && mHalStream->getParameters(keys, &out_s8) == OK) {
+        return out_s8;
+    }
+    return String8();
+}
+
+void AudioFlinger::MmapThread::ioConfigChanged(audio_io_config_event event, pid_t pid) {
+    sp<AudioIoDescriptor> desc = new AudioIoDescriptor();
+
+    desc->mIoHandle = mId;
+
+    switch (event) {
+    case AUDIO_INPUT_OPENED:
+    case AUDIO_INPUT_CONFIG_CHANGED:
+    case AUDIO_OUTPUT_OPENED:
+    case AUDIO_OUTPUT_CONFIG_CHANGED:
+        desc->mPatch = mPatch;
+        desc->mChannelMask = mChannelMask;
+        desc->mSamplingRate = mSampleRate;
+        desc->mFormat = mFormat;
+        desc->mFrameCount = mFrameCount;
+        desc->mFrameCountHAL = mFrameCount;
+        desc->mLatency = 0;
+        break;
+
+    case AUDIO_INPUT_CLOSED:
+    case AUDIO_OUTPUT_CLOSED:
+    default:
+        break;
+    }
+    mAudioFlinger->ioConfigChanged(event, desc, pid);
+}
+
+status_t AudioFlinger::MmapThread::createAudioPatch_l(const struct audio_patch *patch,
+                                                          audio_patch_handle_t *handle)
+{
+    status_t status = NO_ERROR;
+
+    // store new device and send to effects
+    audio_devices_t type = AUDIO_DEVICE_NONE;
+    audio_port_handle_t deviceId;
+    if (isOutput()) {
+        for (unsigned int i = 0; i < patch->num_sinks; i++) {
+            type |= patch->sinks[i].ext.device.type;
+        }
+        deviceId = patch->sinks[0].id;
+    } else {
+        type = patch->sources[0].ext.device.type;
+        deviceId = patch->sources[0].id;
+    }
+
+    for (size_t i = 0; i < mEffectChains.size(); i++) {
+        mEffectChains[i]->setDevice_l(type);
+    }
+
+    if (isOutput()) {
+        mOutDevice = type;
+    } else {
+        mInDevice = type;
+        // store new source and send to effects
+        if (mAudioSource != patch->sinks[0].ext.mix.usecase.source) {
+            mAudioSource = patch->sinks[0].ext.mix.usecase.source;
+            for (size_t i = 0; i < mEffectChains.size(); i++) {
+                mEffectChains[i]->setAudioSource_l(mAudioSource);
+            }
+        }
+    }
+
+    if (mAudioHwDev->supportsAudioPatches()) {
+        status = mHalDevice->createAudioPatch(patch->num_sources,
+                                            patch->sources,
+                                            patch->num_sinks,
+                                            patch->sinks,
+                                            handle);
+    } else {
+        char *address;
+        if (strcmp(patch->sinks[0].ext.device.address, "") != 0) {
+            //FIXME: we only support address on first sink with HAL version < 3.0
+            address = audio_device_address_to_parameter(
+                                                        patch->sinks[0].ext.device.type,
+                                                        patch->sinks[0].ext.device.address);
+        } else {
+            address = (char *)calloc(1, 1);
+        }
+        AudioParameter param = AudioParameter(String8(address));
+        free(address);
+        param.addInt(String8(AudioParameter::keyRouting), (int)type);
+        if (!isOutput()) {
+            param.addInt(String8(AudioParameter::keyInputSource),
+                                         (int)patch->sinks[0].ext.mix.usecase.source);
+        }
+        status = mHalStream->setParameters(param.toString());
+        *handle = AUDIO_PATCH_HANDLE_NONE;
+    }
+
+    if (isOutput() && mPrevOutDevice != mOutDevice) {
+        mPrevOutDevice = type;
+        sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
+        if (mCallback != 0) {
+            mCallback->onRoutingChanged(deviceId);
+        }
+    }
+    if (!isOutput() && mPrevInDevice != mInDevice) {
+        mPrevInDevice = type;
+        sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
+        if (mCallback != 0) {
+            mCallback->onRoutingChanged(deviceId);
+        }
+    }
+    return status;
+}
+
+status_t AudioFlinger::MmapThread::releaseAudioPatch_l(const audio_patch_handle_t handle)
+{
+    status_t status = NO_ERROR;
+
+    mInDevice = AUDIO_DEVICE_NONE;
+
+    bool supportsAudioPatches = mHalDevice->supportsAudioPatches(&supportsAudioPatches) == OK ?
+                                        supportsAudioPatches : false;
+
+    if (supportsAudioPatches) {
+        status = mHalDevice->releaseAudioPatch(handle);
+    } else {
+        AudioParameter param;
+        param.addInt(String8(AudioParameter::keyRouting), 0);
+        status = mHalStream->setParameters(param.toString());
+    }
+    return status;
+}
+
+void AudioFlinger::MmapThread::getAudioPortConfig(struct audio_port_config *config)
+{
+    ThreadBase::getAudioPortConfig(config);
+    if (isOutput()) {
+        config->role = AUDIO_PORT_ROLE_SOURCE;
+        config->ext.mix.hw_module = mAudioHwDev->handle();
+        config->ext.mix.usecase.stream = AUDIO_STREAM_DEFAULT;
+    } else {
+        config->role = AUDIO_PORT_ROLE_SINK;
+        config->ext.mix.hw_module = mAudioHwDev->handle();
+        config->ext.mix.usecase.source = mAudioSource;
+    }
+}
+
+status_t AudioFlinger::MmapThread::addEffectChain_l(const sp<EffectChain>& chain)
+{
+    audio_session_t session = chain->sessionId();
+
+    ALOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
+    // Attach all tracks with same session ID to this chain.
+    // indicate all active tracks in the chain
+    for (const sp<MmapTrack> &track : mActiveTracks) {
+        if (session == track->sessionId()) {
+            chain->incTrackCnt();
+            chain->incActiveTrackCnt();
+        }
+    }
+
+    chain->setThread(this);
+    chain->setInBuffer(nullptr);
+    chain->setOutBuffer(nullptr);
+    chain->syncHalEffectsState();
+
+    mEffectChains.add(chain);
+    checkSuspendOnAddEffectChain_l(chain);
+    return NO_ERROR;
+}
+
+size_t AudioFlinger::MmapThread::removeEffectChain_l(const sp<EffectChain>& chain)
+{
+    audio_session_t session = chain->sessionId();
+
+    ALOGV("removeEffectChain_l() %p from thread %p for session %d", chain.get(), this, session);
+
+    for (size_t i = 0; i < mEffectChains.size(); i++) {
+        if (chain == mEffectChains[i]) {
+            mEffectChains.removeAt(i);
+            // detach all active tracks from the chain
+            // detach all tracks with same session ID from this chain
+            for (const sp<MmapTrack> &track : mActiveTracks) {
+                if (session == track->sessionId()) {
+                    chain->decActiveTrackCnt();
+                    chain->decTrackCnt();
+                }
+            }
+            break;
+        }
+    }
+    return mEffectChains.size();
+}
+
+// hasAudioSession_l() must be called with ThreadBase::mLock held
+uint32_t AudioFlinger::MmapThread::hasAudioSession_l(audio_session_t sessionId) const
+{
+    uint32_t result = 0;
+    if (getEffectChain_l(sessionId) != 0) {
+        result = EFFECT_SESSION;
+    }
+
+    for (size_t i = 0; i < mActiveTracks.size(); i++) {
+        sp<MmapTrack> track = mActiveTracks[i];
+        if (sessionId == track->sessionId()) {
+            result |= TRACK_SESSION;
+            if (track->isFastTrack()) {
+                result |= FAST_SESSION;
+            }
+            break;
+        }
+    }
+
+    return result;
+}
+
+void AudioFlinger::MmapThread::threadLoop_standby()
+{
+    mHalStream->standby();
+}
+
+void AudioFlinger::MmapThread::threadLoop_exit()
+{
+    if (mCallback != 0) {
+        mCallback->onTearDown();
+    }
+}
+
+status_t AudioFlinger::MmapThread::setSyncEvent(const sp<SyncEvent>& event __unused)
+{
+    return BAD_VALUE;
+}
+
+bool AudioFlinger::MmapThread::isValidSyncEvent(const sp<SyncEvent>& event __unused) const
+{
+    return false;
+}
+
+status_t AudioFlinger::MmapThread::checkEffectCompatibility_l(
+        const effect_descriptor_t *desc, audio_session_t sessionId)
+{
+    // No global effect sessions on mmap threads
+    if (sessionId == AUDIO_SESSION_OUTPUT_MIX || sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
+        ALOGW("checkEffectCompatibility_l(): global effect %s on record thread %s",
+                desc->name, mThreadName);
+        return BAD_VALUE;
+    }
+
+    if (!isOutput() && ((desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC)) {
+        ALOGW("checkEffectCompatibility_l(): non pre processing effect %s on capture mmap thread",
+                desc->name);
+        return BAD_VALUE;
+    }
+    if (isOutput() && ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC)) {
+        ALOGW("checkEffectCompatibility_l(): pre processing effect %s created on playback mmap thread",
+              desc->name);
+        return BAD_VALUE;
+    }
+
+    // Only allow effects without processing load or latency
+    if ((desc->flags & EFFECT_FLAG_NO_PROCESS_MASK) != EFFECT_FLAG_NO_PROCESS) {
+        return BAD_VALUE;
+    }
+
+    return NO_ERROR;
+
+}
+
+void AudioFlinger::MmapThread::checkInvalidTracks_l()
+{
+    for (const sp<MmapTrack> &track : mActiveTracks) {
+        if (track->isInvalid()) {
+            if (mCallback != 0) {
+                mCallback->onTearDown();
+            }
+            break;
+        }
+    }
+}
+
+void AudioFlinger::MmapThread::dump(int fd, const Vector<String16>& args)
+{
+    dumpInternals(fd, args);
+    dumpTracks(fd, args);
+    dumpEffectChains(fd, args);
+}
+
+void AudioFlinger::MmapThread::dumpInternals(int fd, const Vector<String16>& args)
+{
+    dprintf(fd, "\nMmap thread %p:\n", this);
+
+    dumpBase(fd, args);
+
+    dprintf(fd, "  Attributes: content type %d usage %d source %d\n",
+            mAttr.content_type, mAttr.usage, mAttr.source);
+    dprintf(fd, "  Session: %d port Id: %d\n", mSessionId, mPortId);
+    if (mActiveTracks.size() == 0) {
+        dprintf(fd, "  No active clients\n");
+    }
+}
+
+void AudioFlinger::MmapThread::dumpTracks(int fd, const Vector<String16>& args __unused)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    size_t numtracks = mActiveTracks.size();
+    dprintf(fd, "  %zu Tracks", numtracks);
+    if (numtracks) {
+        MmapTrack::appendDumpHeader(result);
+        for (size_t i = 0; i < numtracks ; ++i) {
+            sp<MmapTrack> track = mActiveTracks[i];
+            track->dump(buffer, SIZE);
+            result.append(buffer);
+        }
+    } else {
+        dprintf(fd, "\n");
+    }
+    write(fd, result.string(), result.size());
+}
+
+AudioFlinger::MmapPlaybackThread::MmapPlaybackThread(
+        const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
+        AudioHwDevice *hwDev,  AudioStreamOut *output,
+        audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady)
+    : MmapThread(audioFlinger, id, hwDev, output->stream, outDevice, inDevice, systemReady),
+      mStreamType(AUDIO_STREAM_MUSIC),
+      mStreamVolume(1.0), mStreamMute(false), mOutput(output)
+{
+    snprintf(mThreadName, kThreadNameLength, "AudioMmapOut_%X", id);
+    mChannelCount = audio_channel_count_from_out_mask(mChannelMask);
+    mMasterVolume = audioFlinger->masterVolume_l();
+    mMasterMute = audioFlinger->masterMute_l();
+    if (mAudioHwDev) {
+        if (mAudioHwDev->canSetMasterVolume()) {
+            mMasterVolume = 1.0;
+        }
+
+        if (mAudioHwDev->canSetMasterMute()) {
+            mMasterMute = false;
+        }
+    }
+}
+
+void AudioFlinger::MmapPlaybackThread::configure(const audio_attributes_t *attr,
+                                                audio_stream_type_t streamType,
+                                                audio_session_t sessionId,
+                                                const sp<MmapStreamCallback>& callback,
+                                                audio_port_handle_t portId)
+{
+    MmapThread::configure(attr, streamType, sessionId, callback, portId);
+    mStreamType = streamType;
+}
+
+AudioStreamOut* AudioFlinger::MmapPlaybackThread::clearOutput()
+{
+    Mutex::Autolock _l(mLock);
+    AudioStreamOut *output = mOutput;
+    mOutput = NULL;
+    return output;
+}
+
+void AudioFlinger::MmapPlaybackThread::setMasterVolume(float value)
+{
+    Mutex::Autolock _l(mLock);
+    // Don't apply master volume in SW if our HAL can do it for us.
+    if (mAudioHwDev &&
+            mAudioHwDev->canSetMasterVolume()) {
+        mMasterVolume = 1.0;
+    } else {
+        mMasterVolume = value;
+    }
+}
+
+void AudioFlinger::MmapPlaybackThread::setMasterMute(bool muted)
+{
+    Mutex::Autolock _l(mLock);
+    // Don't apply master mute in SW if our HAL can do it for us.
+    if (mAudioHwDev && mAudioHwDev->canSetMasterMute()) {
+        mMasterMute = false;
+    } else {
+        mMasterMute = muted;
+    }
+}
+
+void AudioFlinger::MmapPlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
+{
+    Mutex::Autolock _l(mLock);
+    if (stream == mStreamType) {
+        mStreamVolume = value;
+        broadcast_l();
+    }
+}
+
+float AudioFlinger::MmapPlaybackThread::streamVolume(audio_stream_type_t stream) const
+{
+    Mutex::Autolock _l(mLock);
+    if (stream == mStreamType) {
+        return mStreamVolume;
+    }
+    return 0.0f;
+}
+
+void AudioFlinger::MmapPlaybackThread::setStreamMute(audio_stream_type_t stream, bool muted)
+{
+    Mutex::Autolock _l(mLock);
+    if (stream == mStreamType) {
+        mStreamMute= muted;
+        broadcast_l();
+    }
+}
+
+void AudioFlinger::MmapPlaybackThread::invalidateTracks(audio_stream_type_t streamType)
+{
+    Mutex::Autolock _l(mLock);
+    if (streamType == mStreamType) {
+        for (const sp<MmapTrack> &track : mActiveTracks) {
+            track->invalidate();
+        }
+        broadcast_l();
+    }
+}
+
+void AudioFlinger::MmapPlaybackThread::processVolume_l()
+{
+    float volume;
+
+    if (mMasterMute || mStreamMute) {
+        volume = 0;
+    } else {
+        volume = mMasterVolume * mStreamVolume;
+    }
+
+    if (volume != mHalVolFloat) {
+        mHalVolFloat = volume;
+
+        // Convert volumes from float to 8.24
+        uint32_t vol = (uint32_t)(volume * (1 << 24));
+
+        // Delegate volume control to effect in track effect chain if needed
+        // only one effect chain can be present on DirectOutputThread, so if
+        // there is one, the track is connected to it
+        if (!mEffectChains.isEmpty()) {
+            mEffectChains[0]->setVolume_l(&vol, &vol);
+            volume = (float)vol / (1 << 24);
+        }
+
+        mOutput->stream->setVolume(volume, volume);
+
+        if (mCallback != 0) {
+            int channelCount;
+            if (isOutput()) {
+                channelCount = audio_channel_count_from_out_mask(mChannelMask);
+            } else {
+                channelCount = audio_channel_count_from_in_mask(mChannelMask);
+            }
+            Vector<float> values;
+            for (int i = 0; i < channelCount; i++) {
+                values.add(volume);
+            }
+            mCallback->onVolumeChanged(mChannelMask, values);
+        }
+    }
+}
+
+void AudioFlinger::MmapPlaybackThread::checkSilentMode_l()
+{
+    if (!mMasterMute) {
+        char value[PROPERTY_VALUE_MAX];
+        if (property_get("ro.audio.silent", value, "0") > 0) {
+            char *endptr;
+            unsigned long ul = strtoul(value, &endptr, 0);
+            if (*endptr == '\0' && ul != 0) {
+                ALOGD("Silence is golden");
+                // The setprop command will not allow a property to be changed after
+                // the first time it is set, so we don't have to worry about un-muting.
+                setMasterMute_l(true);
+            }
+        }
+    }
+}
+
+void AudioFlinger::MmapPlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
+{
+    MmapThread::dumpInternals(fd, args);
+
+    dprintf(fd, "  Stream type: %d Stream volume: %f HAL volume: %f Stream mute %d\n", mStreamType, mStreamVolume, mHalVolFloat, mStreamMute);
+    dprintf(fd, "  Master volume: %f Master mute %d\n", mMasterVolume, mMasterMute);
+}
+
+AudioFlinger::MmapCaptureThread::MmapCaptureThread(
+        const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
+        AudioHwDevice *hwDev,  AudioStreamIn *input,
+        audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady)
+    : MmapThread(audioFlinger, id, hwDev, input->stream, outDevice, inDevice, systemReady),
+      mInput(input)
+{
+    snprintf(mThreadName, kThreadNameLength, "AudioMmapIn_%X", id);
+    mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
+}
+
+AudioFlinger::AudioStreamIn* AudioFlinger::MmapCaptureThread::clearInput()
+{
+    Mutex::Autolock _l(mLock);
+    AudioStreamIn *input = mInput;
+    mInput = NULL;
+    return input;
+}
 } // namespace android
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 3fb0b07..0a17a8e 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -29,7 +29,8 @@
         DIRECT,             // Thread class is DirectOutputThread
         DUPLICATING,        // Thread class is DuplicatingThread
         RECORD,             // Thread class is RecordThread
-        OFFLOAD             // Thread class is OffloadThread
+        OFFLOAD,            // Thread class is OffloadThread
+        MMAP                // control thread for MMAP stream
     };
 
     static const char *threadTypeToString(type_t type);
@@ -126,23 +127,25 @@
 
     class PrioConfigEventData : public ConfigEventData {
     public:
-        PrioConfigEventData(pid_t pid, pid_t tid, int32_t prio) :
-            mPid(pid), mTid(tid), mPrio(prio) {}
+        PrioConfigEventData(pid_t pid, pid_t tid, int32_t prio, bool forApp) :
+            mPid(pid), mTid(tid), mPrio(prio), mForApp(forApp) {}
 
         virtual  void dump(char *buffer, size_t size) {
-            snprintf(buffer, size, "Prio event: pid %d, tid %d, prio %d\n", mPid, mTid, mPrio);
+            snprintf(buffer, size, "Prio event: pid %d, tid %d, prio %d, for app? %d\n",
+                    mPid, mTid, mPrio, mForApp);
         }
 
         const pid_t mPid;
         const pid_t mTid;
         const int32_t mPrio;
+        const bool mForApp;
     };
 
     class PrioConfigEvent : public ConfigEvent {
     public:
-        PrioConfigEvent(pid_t pid, pid_t tid, int32_t prio) :
+        PrioConfigEvent(pid_t pid, pid_t tid, int32_t prio, bool forApp) :
             ConfigEvent(CFG_EVENT_PRIO, true) {
-            mData = new PrioConfigEventData(pid, tid, prio);
+            mData = new PrioConfigEventData(pid, tid, prio, forApp);
         }
         virtual ~PrioConfigEvent() {}
     };
@@ -267,8 +270,8 @@
                 status_t    sendConfigEvent_l(sp<ConfigEvent>& event);
                 void        sendIoConfigEvent(audio_io_config_event event, pid_t pid = 0);
                 void        sendIoConfigEvent_l(audio_io_config_event event, pid_t pid = 0);
-                void        sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio);
-                void        sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);
+                void        sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio, bool forApp);
+                void        sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio, bool forApp);
                 status_t    sendSetParameterConfigEvent_l(const String8& keyValuePair);
                 status_t    sendCreateAudioPatchConfigEvent(const struct audio_patch *patch,
                                                             audio_patch_handle_t *handle);
@@ -390,6 +393,8 @@
                 virtual status_t    checkEffectCompatibility_l(const effect_descriptor_t *desc,
                                                                audio_session_t sessionId) = 0;
 
+                        void        broadcast_l();
+
     mutable     Mutex                   mLock;
 
 protected:
@@ -482,6 +487,9 @@
                 sp<NBLog::Writer>       mNBLogWriter;
                 bool                    mSystemReady;
                 ExtendedTimestamp       mTimestamp;
+                // A condition that must be evaluated by the thread loop has changed and
+                // we must not wait for async write callback in the thread loop before evaluating it
+                bool                    mSignalPending;
 
                 // ActiveTracks is a sorted vector of track type T representing the
                 // active tracks of threadLoop() to be considered by the locked prepare portion.
@@ -569,8 +577,22 @@
                 };
 };
 
+class VolumeInterface {
+ public:
+
+    virtual ~VolumeInterface() {}
+
+    virtual void        setMasterVolume(float value) = 0;
+    virtual void        setMasterMute(bool muted) = 0;
+    virtual void        setStreamVolume(audio_stream_type_t stream, float value) = 0;
+    virtual void        setStreamMute(audio_stream_type_t stream, bool muted) = 0;
+    virtual float       streamVolume(audio_stream_type_t stream) const = 0;
+
+};
+
 // --- PlaybackThread ---
-class PlaybackThread : public ThreadBase, public StreamOutHalInterfaceCallback {
+class PlaybackThread : public ThreadBase, public StreamOutHalInterfaceCallback,
+    public VolumeInterface {
 public:
 
 #include "PlaybackTracks.h"
@@ -659,13 +681,12 @@
                 // same, but lock must already be held
                 uint32_t    latency_l() const;
 
-                void        setMasterVolume(float value);
-                void        setMasterMute(bool muted);
-
-                void        setStreamVolume(audio_stream_type_t stream, float value);
-                void        setStreamMute(audio_stream_type_t stream, bool muted);
-
-                float       streamVolume(audio_stream_type_t stream) const;
+                // VolumeInterface
+    virtual     void        setMasterVolume(float value);
+    virtual     void        setMasterMute(bool muted);
+    virtual     void        setStreamVolume(audio_stream_type_t stream, float value);
+    virtual     void        setStreamMute(audio_stream_type_t stream, bool muted);
+    virtual     float       streamVolume(audio_stream_type_t stream) const;
 
                 sp<Track>   createTrack_l(
                                 const sp<AudioFlinger::Client>& client,
@@ -736,6 +757,9 @@
 
     virtual     void        getAudioPortConfig(struct audio_port_config *config);
 
+                // Return the asynchronous signal wait time.
+    virtual     int64_t     computeWaitTimeNs_l() const { return INT64_MAX; }
+
 protected:
     // updated by readOutputParameters_l()
     size_t                          mNormalFrameCount;  // normal mixer and effects
@@ -868,7 +892,6 @@
     status_t    addTrack_l(const sp<Track>& track);
     bool        destroyTrack_l(const sp<Track>& track);
     void        removeTrack_l(const sp<Track>& track);
-    void        broadcast_l();
 
     void        readOutputParameters_l();
 
@@ -930,9 +953,6 @@
     // Bit 0 is reset by the async callback thread calling resetDraining(). Out of sequence
     // callbacks are ignored.
     uint32_t                        mDrainSequence;
-    // A condition that must be evaluated by prepareTrack_l() has changed and we must not wait
-    // for async write callback in the thread loop before evaluating it
-    bool                            mSignalPending;
     sp<AsyncCallbackThread>         mCallbackThread;
 
 private:
@@ -1157,6 +1177,7 @@
     // volumes last sent to audio HAL with stream->set_volume()
     float mLeftVolFloat;
     float mRightVolFloat;
+    bool mVolumeShaperActive;
 
     DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
                         audio_io_handle_t id, uint32_t device, ThreadBase::type_t type,
@@ -1170,6 +1191,8 @@
 
 public:
     virtual     bool        hasFastMixer() const { return false; }
+
+    virtual     int64_t     computeWaitTimeNs_l() const override;
 };
 
 class OffloadThread : public DirectOutputThread {
@@ -1274,7 +1297,6 @@
     virtual     bool        hasFastMixer() const { return false; }
 };
 
-
 // record thread
 class RecordThread : public ThreadBase
 {
@@ -1346,6 +1368,7 @@
 
     // Thread virtuals
     virtual bool        threadLoop();
+    virtual void        preExit();
 
     // RefBase
     virtual void        onFirstRef();
@@ -1491,3 +1514,153 @@
 
             bool                                mFastTrackAvail;    // true if fast track available
 };
+
+class MmapThread : public ThreadBase
+{
+ public:
+
+#include "MmapTracks.h"
+
+    MmapThread(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
+                      AudioHwDevice *hwDev, sp<StreamHalInterface> stream,
+                      audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady);
+    virtual     ~MmapThread();
+
+    virtual     void        configure(const audio_attributes_t *attr,
+                                      audio_stream_type_t streamType,
+                                      audio_session_t sessionId,
+                                      const sp<MmapStreamCallback>& callback,
+                                      audio_port_handle_t portId);
+
+                void        disconnect();
+
+    // MmapStreamInterface
+    status_t createMmapBuffer(int32_t minSizeFrames,
+                                      struct audio_mmap_buffer_info *info);
+    status_t getMmapPosition(struct audio_mmap_position *position);
+    status_t start(const MmapStreamInterface::Client& client, audio_port_handle_t *handle);
+    status_t stop(audio_port_handle_t handle);
+
+    // RefBase
+    virtual     void        onFirstRef();
+
+    // Thread virtuals
+    virtual     bool        threadLoop();
+
+    virtual     void        threadLoop_exit();
+    virtual     void        threadLoop_standby();
+
+    virtual     status_t    initCheck() const { return (mHalStream == 0) ? NO_INIT : NO_ERROR; }
+    virtual     size_t      frameCount() const { return mFrameCount; }
+    virtual     bool        checkForNewParameter_l(const String8& keyValuePair,
+                                                    status_t& status);
+    virtual     String8     getParameters(const String8& keys);
+    virtual     void        ioConfigChanged(audio_io_config_event event, pid_t pid = 0);
+                void        readHalParameters_l();
+    virtual     void        cacheParameters_l() {}
+    virtual     status_t    createAudioPatch_l(const struct audio_patch *patch,
+                                               audio_patch_handle_t *handle);
+    virtual     status_t    releaseAudioPatch_l(const audio_patch_handle_t handle);
+    virtual     void        getAudioPortConfig(struct audio_port_config *config);
+
+    virtual     sp<StreamHalInterface> stream() const { return mHalStream; }
+    virtual     status_t    addEffectChain_l(const sp<EffectChain>& chain);
+    virtual     size_t      removeEffectChain_l(const sp<EffectChain>& chain);
+    virtual     status_t    checkEffectCompatibility_l(const effect_descriptor_t *desc,
+                                                               audio_session_t sessionId);
+
+    virtual     uint32_t    hasAudioSession_l(audio_session_t sessionId) const;
+    virtual     status_t    setSyncEvent(const sp<SyncEvent>& event);
+    virtual     bool        isValidSyncEvent(const sp<SyncEvent>& event) const;
+
+    virtual     void        checkSilentMode_l() {}
+    virtual     void        processVolume_l() {}
+                void        checkInvalidTracks_l();
+
+    virtual     audio_stream_type_t streamType() { return AUDIO_STREAM_DEFAULT; }
+
+    virtual     void        invalidateTracks(audio_stream_type_t streamType __unused) {}
+
+                void        dump(int fd, const Vector<String16>& args);
+    virtual     void        dumpInternals(int fd, const Vector<String16>& args);
+                void        dumpTracks(int fd, const Vector<String16>& args);
+
+    virtual     bool        isOutput() const = 0;
+
+ protected:
+
+                audio_attributes_t      mAttr;
+                audio_session_t         mSessionId;
+                audio_port_handle_t     mPortId;
+
+                sp<MmapStreamCallback>  mCallback;
+                sp<StreamHalInterface>  mHalStream;
+                sp<DeviceHalInterface>  mHalDevice;
+                AudioHwDevice* const    mAudioHwDev;
+                ActiveTracks<MmapTrack> mActiveTracks;
+};
+
+class MmapPlaybackThread : public MmapThread, public VolumeInterface
+{
+
+public:
+    MmapPlaybackThread(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
+                      AudioHwDevice *hwDev, AudioStreamOut *output,
+                      audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady);
+    virtual     ~MmapPlaybackThread() {}
+
+    virtual     void        configure(const audio_attributes_t *attr,
+                                      audio_stream_type_t streamType,
+                                      audio_session_t sessionId,
+                                      const sp<MmapStreamCallback>& callback,
+                                      audio_port_handle_t portId);
+
+                AudioStreamOut* clearOutput();
+
+                // VolumeInterface
+    virtual     void        setMasterVolume(float value);
+    virtual     void        setMasterMute(bool muted);
+    virtual     void        setStreamVolume(audio_stream_type_t stream, float value);
+    virtual     void        setStreamMute(audio_stream_type_t stream, bool muted);
+    virtual     float       streamVolume(audio_stream_type_t stream) const;
+
+                void        setMasterMute_l(bool muted) { mMasterMute = muted; }
+
+    virtual     void        invalidateTracks(audio_stream_type_t streamType);
+
+    virtual     audio_stream_type_t streamType() { return mStreamType; }
+    virtual     void        checkSilentMode_l();
+    virtual     void        processVolume_l();
+
+    virtual     void        dumpInternals(int fd, const Vector<String16>& args);
+
+    virtual     bool        isOutput() const { return true; }
+
+protected:
+
+                audio_stream_type_t         mStreamType;
+                float                       mMasterVolume;
+                float                       mStreamVolume;
+                bool                        mMasterMute;
+                bool                        mStreamMute;
+                float                       mHalVolFloat;
+                AudioStreamOut*             mOutput;
+};
+
+class MmapCaptureThread : public MmapThread
+{
+
+public:
+    MmapCaptureThread(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
+                      AudioHwDevice *hwDev, AudioStreamIn *input,
+                      audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady);
+    virtual     ~MmapCaptureThread() {}
+
+                AudioStreamIn* clearInput();
+
+    virtual     bool           isOutput() const { return false; }
+
+protected:
+
+                AudioStreamIn*  mInput;
+};
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 9ca2d63..e0c09f7 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -77,6 +77,7 @@
             audio_track_cblk_t* cblk() const { return mCblk; }
             audio_session_t sessionId() const { return mSessionId; }
             uid_t       uid() const { return mUid; }
+            audio_port_handle_t portId() const { return mPortId; }
     virtual status_t    setSyncEvent(const sp<SyncEvent>& event);
 
             sp<IMemory> getBuffers() const { return mBufferMemory; }
@@ -86,6 +87,10 @@
             bool        isPatchTrack() const { return (mType == TYPE_PATCH); }
             bool        isExternalTrack() const { return !isOutputTrack() && !isPatchTrack(); }
 
+    virtual void        invalidate() { mIsInvalid = true; }
+            bool        isInvalid() const { return mIsInvalid; }
+
+
 protected:
                         TrackBase(const TrackBase&);
                         TrackBase& operator = (const TrackBase&);
@@ -165,6 +170,7 @@
     track_type          mType;      // must be one of TYPE_DEFAULT, TYPE_OUTPUT, TYPE_PATCH ...
     audio_io_handle_t   mThreadIoHandle; // I/O handle of the thread the track is attached to
     audio_port_handle_t mPortId; // unique ID for this track used by audio policy
+    bool                mIsInvalid; // non-resettable latch, set by invalidate()
 };
 
 // PatchProxyBufferProvider interface is implemented by PatchTrack and PatchRecord.
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index f2dd884..5e07e3b 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -98,7 +98,8 @@
         mTerminated(false),
         mType(type),
         mThreadIoHandle(thread->id()),
-        mPortId(portId)
+        mPortId(portId),
+        mIsInvalid(false)
 {
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
     if (!isTrustedCallingUid(callingUid) || clientUid == AUDIO_UID_INVALID) {
@@ -111,9 +112,24 @@
     mUid = clientUid;
 
     // ALOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
+
+    size_t bufferSize = buffer == NULL ? roundup(frameCount) : frameCount;
+    // check overflow when computing bufferSize due to multiplication by mFrameSize.
+    if (bufferSize < frameCount  // roundup rounds down for values above UINT_MAX / 2
+            || mFrameSize == 0   // format needs to be correct
+            || bufferSize > SIZE_MAX / mFrameSize) {
+        android_errorWriteLog(0x534e4554, "34749571");
+        return;
+    }
+    bufferSize *= mFrameSize;
+
     size_t size = sizeof(audio_track_cblk_t);
-    size_t bufferSize = (buffer == NULL ? roundup(frameCount) : frameCount) * mFrameSize;
     if (buffer == NULL && alloc == ALLOC_CBLK) {
+        // check overflow when computing allocation size for streaming tracks.
+        if (size > SIZE_MAX - bufferSize) {
+            android_errorWriteLog(0x534e4554, "34749571");
+            return;
+        }
         size += bufferSize;
     }
 
@@ -127,9 +143,11 @@
             return;
         }
     } else {
-        // this syntax avoids calling the audio_track_cblk_t constructor twice
-        mCblk = (audio_track_cblk_t *) new uint8_t[size];
-        // assume mCblk != NULL
+        mCblk = (audio_track_cblk_t *) malloc(size);
+        if (mCblk == NULL) {
+            ALOGE("not enough memory for AudioTrack size=%zu", size);
+            return;
+        }
     }
 
     // construct the shared structure in-place.
@@ -221,10 +239,9 @@
     // delete the proxy before deleting the shared memory it refers to, to avoid dangling reference
     mServerProxy.clear();
     if (mCblk != NULL) {
+        mCblk->~audio_track_cblk_t();   // destroy our shared-structure.
         if (mClient == 0) {
-            delete mCblk;
-        } else {
-            mCblk->~audio_track_cblk_t();   // destroy our shared-structure.
+            free(mCblk);
         }
     }
     mCblkMemory.clear();    // free the shared memory before releasing the heap it belongs to
@@ -312,6 +329,16 @@
     return mTrack->setParameters(keyValuePairs);
 }
 
+VolumeShaper::Status AudioFlinger::TrackHandle::applyVolumeShaper(
+        const sp<VolumeShaper::Configuration>& configuration,
+        const sp<VolumeShaper::Operation>& operation) {
+    return mTrack->applyVolumeShaper(configuration, operation);
+}
+
+sp<VolumeShaper::State> AudioFlinger::TrackHandle::getVolumeShaperState(int id) {
+    return mTrack->getVolumeShaperState(id);
+}
+
 status_t AudioFlinger::TrackHandle::getTimestamp(AudioTimestamp& timestamp)
 {
     return mTrack->getTimestamp(timestamp);
@@ -362,10 +389,10 @@
     mAuxEffectId(0), mHasVolumeController(false),
     mPresentationCompleteFrames(0),
     mFrameMap(16 /* sink-frame-to-track-frame map memory */),
+    mVolumeHandler(new VolumeHandler(sampleRate)),
     // mSinkTimestamp
     mFastIndex(-1),
     mCachedVolume(1.0),
-    mIsInvalid(false),
     mResumeToStopping(false),
     mFlushHwPending(false),
     mFlags(flags)
@@ -874,6 +901,47 @@
     }
 }
 
+VolumeShaper::Status AudioFlinger::PlaybackThread::Track::applyVolumeShaper(
+        const sp<VolumeShaper::Configuration>& configuration,
+        const sp<VolumeShaper::Operation>& operation)
+{
+    sp<VolumeShaper::Configuration> newConfiguration;
+
+    if (isOffloadedOrDirect()) {
+        const VolumeShaper::Configuration::OptionFlag optionFlag
+            = configuration->getOptionFlags();
+        if ((optionFlag & VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME) == 0) {
+            ALOGW("%s tracks do not support frame counted VolumeShaper,"
+                    " using clock time instead", isOffloaded() ? "Offload" : "Direct");
+            newConfiguration = new VolumeShaper::Configuration(*configuration);
+            newConfiguration->setOptionFlags(
+                VolumeShaper::Configuration::OptionFlag(optionFlag
+                        | VolumeShaper::Configuration::OPTION_FLAG_CLOCK_TIME));
+        }
+    }
+
+    VolumeShaper::Status status = mVolumeHandler->applyVolumeShaper(
+            (newConfiguration.get() != nullptr ? newConfiguration : configuration), operation);
+
+    if (isOffloadedOrDirect()) {
+        // Signal thread to fetch new volume.
+        sp<ThreadBase> thread = mThread.promote();
+        if (thread != 0) {
+             Mutex::Autolock _l(thread->mLock);
+            thread->broadcast_l();
+        }
+    }
+    return status;
+}
+
+sp<VolumeShaper::State> AudioFlinger::PlaybackThread::Track::getVolumeShaperState(int id)
+{
+    // Note: We don't check if Thread exists.
+
+    // mVolumeHandler is thread safe.
+    return mVolumeHandler->getVolumeShaperState(id);
+}
+
 status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& timestamp)
 {
     if (!isOffloaded() && !isDirect()) {
@@ -1042,8 +1110,8 @@
 
 void AudioFlinger::PlaybackThread::Track::invalidate()
 {
+    TrackBase::invalidate();
     signalClientFlag(CBLK_INVALID);
-    mIsInvalid = true;
 }
 
 void AudioFlinger::PlaybackThread::Track::disable()
@@ -1599,6 +1667,7 @@
 
 void AudioFlinger::RecordThread::RecordTrack::invalidate()
 {
+    TrackBase::invalidate();
     // FIXME should use proxy, and needs work
     audio_track_cblk_t* cblk = mCblk;
     android_atomic_or(CBLK_INVALID, &cblk->mFlags);
@@ -1735,4 +1804,76 @@
     mProxy->releaseBuffer(buffer);
 }
 
+
+
+AudioFlinger::MmapThread::MmapTrack::MmapTrack(ThreadBase *thread,
+        uint32_t sampleRate,
+        audio_format_t format,
+        audio_channel_mask_t channelMask,
+        audio_session_t sessionId,
+        uid_t uid,
+        audio_port_handle_t portId)
+    :   TrackBase(thread, NULL, sampleRate, format,
+                  channelMask, 0, NULL, sessionId, uid, false,
+                  ALLOC_NONE,
+                  TYPE_DEFAULT, portId)
+{
+}
+
+AudioFlinger::MmapThread::MmapTrack::~MmapTrack()
+{
+}
+
+status_t AudioFlinger::MmapThread::MmapTrack::initCheck() const
+{
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::MmapThread::MmapTrack::start(AudioSystem::sync_event_t event __unused,
+                                                        audio_session_t triggerSession __unused)
+{
+    return NO_ERROR;
+}
+
+void AudioFlinger::MmapThread::MmapTrack::stop()
+{
+}
+
+// AudioBufferProvider interface
+status_t AudioFlinger::MmapThread::MmapTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+{
+    buffer->frameCount = 0;
+    buffer->raw = nullptr;
+    return INVALID_OPERATION;
+}
+
+// ExtendedAudioBufferProvider interface
+size_t AudioFlinger::MmapThread::MmapTrack::framesReady() const {
+    return 0;
+}
+
+int64_t AudioFlinger::MmapThread::MmapTrack::framesReleased() const
+{
+    return 0;
+}
+
+void AudioFlinger::MmapThread::MmapTrack::onTimestamp(const ExtendedTimestamp &timestamp __unused)
+{
+}
+
+/*static*/ void AudioFlinger::MmapThread::MmapTrack::appendDumpHeader(String8& result)
+{
+    result.append("    Client Fmt Chn mask  SRate\n");
+}
+
+void AudioFlinger::MmapThread::MmapTrack::dump(char* buffer, size_t size)
+{
+    snprintf(buffer, size, "            %6u %3u    %08X %5u\n",
+            mUid,
+            mFormat,
+            mChannelMask,
+            mSampleRate);
+
+}
+
 } // namespace android
diff --git a/services/audioflinger/TypedLogger.cpp b/services/audioflinger/TypedLogger.cpp
index b5b1bc5..e08f6f6 100644
--- a/services/audioflinger/TypedLogger.cpp
+++ b/services/audioflinger/TypedLogger.cpp
@@ -1,19 +1,19 @@
 /*
-*
-* Copyright 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.
-*/
+ *
+ * Copyright 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 "AudioFlinger"
 //#define LOG_NDEBUG 0
@@ -22,4 +22,6 @@
 #include <pthread.h>
 #include "TypedLogger.h"
 
-thread_local android::NBLog::Writer *logWriterTLS;
+namespace android {
+thread_local NBLog::Writer *logWriterTLS;
+}
diff --git a/services/audioflinger/TypedLogger.h b/services/audioflinger/TypedLogger.h
index 2d71ab4..0b23c7c 100644
--- a/services/audioflinger/TypedLogger.h
+++ b/services/audioflinger/TypedLogger.h
@@ -1,29 +1,30 @@
 /*
-*
-* Copyright 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.
-*/
+ *
+ * Copyright 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 TYPED_LOGGER_H
-#define TYPED_LOGGER_H
+#ifndef ANDROID_TYPED_LOGGER_H
+#define ANDROID_TYPED_LOGGER_H
 
 #include <media/nbaio/NBLog.h>
+#define LOGT(fmt, ...) logWriterTLS->logFormat(fmt, ##__VA_ARGS__) // TODO: check null pointer
 
+namespace android {
 extern "C" {
-    extern thread_local android::NBLog::Writer *logWriterTLS;
+extern thread_local NBLog::Writer *logWriterTLS;
 }
+} // namespace android
 
-#define LOGF(fmt, ...) logWriterTLS->logFormat(fmt, ##__VA_ARGS__)
-
-#endif
\ No newline at end of file
+#endif // ANDROID_TYPED_LOGGER_H
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 35bb021..16fed70 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include <sys/types.h>
+
 #include "AudioPort.h"
 #include <RoutingStrategy.h>
 #include <utils/Errors.h>
@@ -128,6 +130,7 @@
     sp<SwAudioOutputDescriptor> mOutput1;    // used by duplicated outputs: first output
     sp<SwAudioOutputDescriptor> mOutput2;    // used by duplicated outputs: second output
     uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only)
+    uid_t mDirectClientUid; // uid of the direct output client
     uint32_t mGlobalRefCount;  // non-stream-specific ref count
 };
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 93b7f47..5643335 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -223,7 +223,7 @@
     : AudioOutputDescriptor(profile, clientInterface),
     mProfile(profile), mIoHandle(0), mLatency(0),
     mFlags((audio_output_flags_t)0), mPolicyMix(NULL),
-    mOutput1(0), mOutput2(0), mDirectOpenCount(0), mGlobalRefCount(0)
+    mOutput1(0), mOutput2(0), mDirectOpenCount(0), mDirectClientUid(0), mGlobalRefCount(0)
 {
     if (profile != NULL) {
         mFlags = (audio_output_flags_t)profile->getFlags();
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 54c406c..31c145e 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -24,7 +24,8 @@
 #define ALOGVV(a...) do { } while(0)
 #endif
 
-#define AUDIO_POLICY_XML_CONFIG_FILE "/system/etc/audio_policy_configuration.xml"
+#define AUDIO_POLICY_XML_CONFIG_FILE_PATH_MAX_LENGTH 128
+#define AUDIO_POLICY_XML_CONFIG_FILE_NAME "audio_policy_configuration.xml"
 
 #include <inttypes.h>
 #include <math.h>
@@ -752,7 +753,7 @@
     ALOGV("getOutput() device %d, stream %d, samplingRate %d, format %x, channelMask %x, flags %x",
           device, stream, samplingRate, format, channelMask, flags);
 
-    return getOutputForDevice(device, AUDIO_SESSION_ALLOCATE,
+    return getOutputForDevice(device, AUDIO_SESSION_ALLOCATE, uid_t{0} /*Invalid uid*/,
                               stream, samplingRate,format, channelMask,
                               flags, offloadInfo);
 }
@@ -832,7 +833,7 @@
     ALOGV("getOutputForAttr() device 0x%x, samplingRate %d, format %x, channelMask %x, flags %x",
           device, config->sample_rate, config->format, config->channel_mask, flags);
 
-    *output = getOutputForDevice(device, session, *stream,
+    *output = getOutputForDevice(device, session, uid, *stream,
                                  config->sample_rate, config->format, config->channel_mask,
                                  flags, &config->offload_info);
     if (*output == AUDIO_IO_HANDLE_NONE) {
@@ -846,6 +847,7 @@
 audio_io_handle_t AudioPolicyManager::getOutputForDevice(
         audio_devices_t device,
         audio_session_t session __unused,
+        uid_t clientUid,
         audio_stream_type_t stream,
         uint32_t samplingRate,
         audio_format_t format,
@@ -954,13 +956,21 @@
             sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
             if (!desc->isDuplicated() && (profile == desc->mProfile)) {
                 outputDesc = desc;
-                // reuse direct output if currently open and configured with same parameters
+                // reuse direct output if currently open by the same client
+                // and configured with same parameters
                 if ((samplingRate == outputDesc->mSamplingRate) &&
-                        audio_formats_match(format, outputDesc->mFormat) &&
-                        (channelMask == outputDesc->mChannelMask)) {
-                    outputDesc->mDirectOpenCount++;
-                    ALOGV("getOutput() reusing direct output %d", mOutputs.keyAt(i));
-                    return mOutputs.keyAt(i);
+                    audio_formats_match(format, outputDesc->mFormat) &&
+                    (channelMask == outputDesc->mChannelMask)) {
+                  if (clientUid == outputDesc->mDirectClientUid) {
+                      outputDesc->mDirectOpenCount++;
+                      ALOGV("getOutput() reusing direct output %d", mOutputs.keyAt(i));
+                      return mOutputs.keyAt(i);
+                  } else {
+                      ALOGV("getOutput() do not reuse direct output because current client (%ld) "
+                            "is not the same as requesting client (%ld)",
+                            (long)outputDesc->mDirectClientUid, (long)clientUid);
+                      goto non_direct_output;
+                  }
                 }
             }
         }
@@ -1028,6 +1038,7 @@
         outputDesc->mRefCount[stream] = 0;
         outputDesc->mStopTime[stream] = 0;
         outputDesc->mDirectOpenCount = 1;
+        outputDesc->mDirectClientUid = clientUid;
 
         audio_io_handle_t srcOutput = getOutputForEffect();
         addOutput(output, outputDesc);
@@ -1621,8 +1632,8 @@
                                                               isSoundTrigger,
                                                               policyMix, mpClientInterface);
 
-
     // reuse an open input if possible
+    sp<AudioInputDescriptor> reusedInputDesc;
     for (size_t i = 0; i < mInputs.size(); i++) {
         sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
         // reuse input if:
@@ -1646,28 +1657,27 @@
                 } else {
                     ALOGW("getInputForDevice() record with different attributes"
                           " exists for session %d", session);
-                    break;
+                    continue;
                 }
             } else if (isSoundTrigger) {
-                break;
+                continue;
             }
 
-            // force close input if current source is now the highest priority request on this input
-            // and current input properties are not exactly as requested.
-            if (!isConcurrentSource(inputSource) && !isConcurrentSource(desc->inputSource()) &&
+            // Reuse the already opened input stream on this profile if:
+            // - the new capture source is background OR
+            // - the path requested configurations match OR
+            // - the new source priority is less than the highest source priority on this input
+            // If the input stream cannot be reused, close it before opening a new stream
+            // on the same profile for the new client so that the requested path configuration
+            // can be selected.
+            if (!isConcurrentSource(inputSource) &&
                     ((desc->mSamplingRate != samplingRate ||
                     desc->mChannelMask != channelMask ||
                     !audio_formats_match(desc->mFormat, format)) &&
                     (source_priority(desc->getHighestPrioritySource(false /*activeOnly*/)) <
                      source_priority(inputSource)))) {
-                ALOGV("%s: ", __FUNCTION__);
-                AudioSessionCollection sessions = desc->getAudioSessions(false /*activeOnly*/);
-                for (size_t j = 0; j < sessions.size(); j++) {
-                    audio_session_t currentSession = sessions.keyAt(j);
-                    stopInput(desc->mIoHandle, currentSession);
-                    releaseInput(desc->mIoHandle, currentSession);
-                }
-                break;
+                reusedInputDesc = desc;
+                continue;
             } else {
                 desc->addAudioSession(session, audioSession);
                 ALOGV("%s: reusing input %d", __FUNCTION__, mInputs.keyAt(i));
@@ -1676,6 +1686,15 @@
         }
     }
 
+    if (reusedInputDesc != 0) {
+        AudioSessionCollection sessions = reusedInputDesc->getAudioSessions(false /*activeOnly*/);
+        for (size_t j = 0; j < sessions.size(); j++) {
+            audio_session_t currentSession = sessions.keyAt(j);
+            stopInput(reusedInputDesc->mIoHandle, currentSession);
+            releaseInput(reusedInputDesc->mIoHandle, currentSession);
+        }
+    }
+
     audio_config_t config = AUDIO_CONFIG_INITIALIZER;
     config.sample_rate = profileSamplingRate;
     config.channel_mask = profileChannelMask;
@@ -3309,6 +3328,33 @@
     return android_atomic_inc(&mAudioPortGeneration);
 }
 
+#ifdef USE_XML_AUDIO_POLICY_CONF
+// Treblized audio policy xml config will be located in /odm/etc or /vendor/etc.
+static const char *kConfigLocationList[] =
+        {"/odm/etc", "/vendor/etc", "/system/etc"};
+static const int kConfigLocationListSize =
+        (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
+
+static status_t deserializeAudioPolicyXmlConfig(AudioPolicyConfig &config) {
+    char audioPolicyXmlConfigFile[AUDIO_POLICY_XML_CONFIG_FILE_PATH_MAX_LENGTH];
+    status_t ret;
+
+    for (int i = 0; i < kConfigLocationListSize; i++) {
+        PolicySerializer serializer;
+        snprintf(audioPolicyXmlConfigFile,
+                 sizeof(audioPolicyXmlConfigFile),
+                 "%s/%s",
+                 kConfigLocationList[i],
+                 AUDIO_POLICY_XML_CONFIG_FILE_NAME);
+        ret = serializer.deserialize(audioPolicyXmlConfigFile, config);
+        if (ret == NO_ERROR) {
+            break;
+        }
+    }
+    return ret;
+}
+#endif
+
 AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
     :
 #ifdef AUDIO_POLICY_TEST
@@ -3336,8 +3382,7 @@
     AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
                              mDefaultOutputDevice, speakerDrcEnabled,
                              static_cast<VolumeCurvesCollection *>(mVolumeCurves));
-    PolicySerializer serializer;
-    if (serializer.deserialize(AUDIO_POLICY_XML_CONFIG_FILE, config) != NO_ERROR) {
+    if (deserializeAudioPolicyXmlConfig(config) != NO_ERROR) {
 #else
     mVolumeCurves = new StreamDescriptorCollection();
     AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index cea3f54..3dfcde6 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -625,6 +625,7 @@
         audio_io_handle_t getOutputForDevice(
                 audio_devices_t device,
                 audio_session_t session,
+                uid_t client,
                 audio_stream_type_t stream,
                 uint32_t samplingRate,
                 audio_format_t format,
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 9328d65..0401796 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -46,7 +46,6 @@
     device3/Camera3IOStreamBase.cpp \
     device3/Camera3InputStream.cpp \
     device3/Camera3OutputStream.cpp \
-    device3/Camera3ZslStream.cpp \
     device3/Camera3DummyStream.cpp \
     device3/Camera3SharedOutputStream.cpp \
     device3/StatusTracker.cpp \
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index f429df8..7133709 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -58,9 +58,6 @@
 
 #include <system/camera.h>
 
-#include <android/hidl/manager/1.0/IServiceManager.h>
-#include <hidl/ServiceManagement.h>
-
 #include "CameraService.h"
 #include "api1/CameraClient.h"
 #include "api1/Camera2Client.h"
@@ -651,22 +648,6 @@
     return String8(formattedTime);
 }
 
-int CameraService::getCameraPriorityFromProcState(int procState) {
-    // Find the priority for the camera usage based on the process state.  Higher priority clients
-    // win for evictions.
-    if (procState < 0) {
-        ALOGE("%s: Received invalid process state %d from ActivityManagerService!", __FUNCTION__,
-                procState);
-        return -1;
-    }
-    // Treat sleeping TOP processes the same as regular TOP processes, for
-    // access priority.  This is important for lock-screen camera launch scenarios
-    if (procState == PROCESS_STATE_TOP_SLEEPING) {
-        procState = PROCESS_STATE_TOP;
-    }
-    return INT_MAX - procState;
-}
-
 Status CameraService::getCameraVendorTagDescriptor(
         /*out*/
         hardware::camera2::params::VendorTagDescriptor* desc) {
@@ -1212,20 +1193,24 @@
         std::vector<int> ownerPids(mActiveClientManager.getAllOwners());
         ownerPids.push_back(clientPid);
 
-        // Use the value +PROCESS_STATE_NONEXISTENT, to avoid taking
-        // address of PROCESS_STATE_NONEXISTENT as a reference argument
-        // for the vector constructor. PROCESS_STATE_NONEXISTENT does
-        // not have an out-of-class definition.
-        std::vector<int> priorities(ownerPids.size(), +PROCESS_STATE_NONEXISTENT);
+        std::vector<int> priorityScores(ownerPids.size());
+        std::vector<int> states(ownerPids.size());
 
-        // Get priorites of all active PIDs
-        ProcessInfoService::getProcessStatesFromPids(ownerPids.size(), &ownerPids[0],
-                /*out*/&priorities[0]);
+        // Get priority scores of all active PIDs
+        status_t err = ProcessInfoService::getProcessStatesScoresFromPids(
+                ownerPids.size(), &ownerPids[0], /*out*/&states[0],
+                /*out*/&priorityScores[0]);
+        if (err != OK) {
+            ALOGE("%s: Priority score query failed: %d",
+                  __FUNCTION__, err);
+            return err;
+        }
 
         // Update all active clients' priorities
-        std::map<int,int> pidToPriorityMap;
+        std::map<int,resource_policy::ClientPriority> pidToPriorityMap;
         for (size_t i = 0; i < ownerPids.size() - 1; i++) {
-            pidToPriorityMap.emplace(ownerPids[i], getCameraPriorityFromProcState(priorities[i]));
+            pidToPriorityMap.emplace(ownerPids[i],
+                    resource_policy::ClientPriority(priorityScores[i], states[i]));
         }
         mActiveClientManager.updatePriorities(pidToPriorityMap);
 
@@ -1242,7 +1227,9 @@
         clientDescriptor = CameraClientManager::makeClientDescriptor(cameraId,
                 sp<BasicClient>{nullptr}, static_cast<int32_t>(state->getCost()),
                 state->getConflicting(),
-                getCameraPriorityFromProcState(priorities[priorities.size() - 1]), clientPid);
+                priorityScores[priorityScores.size() - 1],
+                clientPid,
+                states[states.size() - 1]);
 
         // Find clients that would be evicted
         auto evicted = mActiveClientManager.wouldEvict(clientDescriptor);
@@ -1259,19 +1246,22 @@
                     mActiveClientManager.getIncompatibleClients(clientDescriptor);
 
             String8 msg = String8::format("%s : DENIED connect device %s client for package %s "
-                    "(PID %d, priority %d) due to eviction policy", curTime.string(),
+                    "(PID %d, score %d state %d) due to eviction policy", curTime.string(),
                     cameraId.string(), packageName.string(), clientPid,
-                    getCameraPriorityFromProcState(priorities[priorities.size() - 1]));
+                    priorityScores[priorityScores.size() - 1],
+                    states[states.size() - 1]);
 
             for (auto& i : incompatibleClients) {
                 msg.appendFormat("\n   - Blocked by existing device %s client for package %s"
-                        "(PID %" PRId32 ", priority %" PRId32 ")", i->getKey().string(),
-                        String8{i->getValue()->getPackageName()}.string(), i->getOwnerId(),
-                        i->getPriority());
+                        "(PID %" PRId32 ", score %" PRId32 ", state %" PRId32 ")",
+                        i->getKey().string(),
+                        String8{i->getValue()->getPackageName()}.string(),
+                        i->getOwnerId(), i->getPriority().getScore(),
+                        i->getPriority().getState());
                 ALOGE("   Conflicts with: Device %s, client package %s (PID %"
-                        PRId32 ", priority %" PRId32 ")", i->getKey().string(),
+                        PRId32 ", score %" PRId32 ", state %" PRId32 ")", i->getKey().string(),
                         String8{i->getValue()->getPackageName()}.string(), i->getOwnerId(),
-                        i->getPriority());
+                        i->getPriority().getScore(), i->getPriority().getState());
             }
 
             // Log the client's attempt
@@ -1299,12 +1289,14 @@
 
             // Log the clients evicted
             logEvent(String8::format("EVICT device %s client held by package %s (PID"
-                    " %" PRId32 ", priority %" PRId32 ")\n   - Evicted by device %s client for"
-                    " package %s (PID %d, priority %" PRId32 ")",
+                    " %" PRId32 ", score %" PRId32 ", state %" PRId32 ")\n - Evicted by device %s client for"
+                    " package %s (PID %d, score %" PRId32 ", state %" PRId32 ")",
                     i->getKey().string(), String8{clientSp->getPackageName()}.string(),
-                    i->getOwnerId(), i->getPriority(), cameraId.string(),
+                    i->getOwnerId(), i->getPriority().getScore(),
+                    i->getPriority().getState(), cameraId.string(),
                     packageName.string(), clientPid,
-                    getCameraPriorityFromProcState(priorities[priorities.size() - 1])));
+                    priorityScores[priorityScores.size() - 1],
+                    states[states.size() - 1]));
 
             // Notify the client of disconnection
             clientSp->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
@@ -1883,14 +1875,7 @@
             return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.string());
     }
 
-    int facing = -1;
-    int deviceVersion = getDeviceVersion(id, /*out*/ &facing);
-    if (facing == -1) {
-        String8 msg = String8::format("Unable to get facing for camera device %s",
-                id.string());
-        ALOGE("%s: %s", __FUNCTION__, msg.string());
-        return STATUS_ERROR(ERROR_INVALID_OPERATION, msg.string());
-    }
+    int deviceVersion = getDeviceVersion(id);
     switch(deviceVersion) {
         case CAMERA_DEVICE_API_VERSION_1_0:
         case CAMERA_DEVICE_API_VERSION_3_0:
@@ -2142,9 +2127,11 @@
 
         // Log the clients evicted
         logEvent(String8::format("EVICT device %s client held by package %s (PID %"
-                PRId32 ", priority %" PRId32 ")\n   - Evicted due to user switch.",
-                i->getKey().string(), String8{clientSp->getPackageName()}.string(),
-                i->getOwnerId(), i->getPriority()));
+                PRId32 ", score %" PRId32 ", state %" PRId32 ")\n   - Evicted due"
+                " to user switch.", i->getKey().string(),
+                String8{clientSp->getPackageName()}.string(),
+                i->getOwnerId(), i->getPriority().getScore(),
+                i->getPriority().getState()));
 
     }
 
@@ -2680,7 +2667,8 @@
         String8 key = i->getKey();
         int32_t cost = i->getCost();
         int32_t pid = i->getOwnerId();
-        int32_t priority = i->getPriority();
+        int32_t score = i->getPriority().getScore();
+        int32_t state = i->getPriority().getState();
         auto conflicting = i->getConflicting();
         auto clientSp = i->getValue();
         String8 packageName;
@@ -2690,8 +2678,8 @@
             uid_t clientUid = clientSp->getClientUid();
             clientUserId = multiuser_get_user_id(clientUid);
         }
-        ret.appendFormat("\n(Camera ID: %s, Cost: %" PRId32 ", PID: %" PRId32 ", Priority: %"
-                PRId32 ", ", key.string(), cost, pid, priority);
+        ret.appendFormat("\n(Camera ID: %s, Cost: %" PRId32 ", PID: %" PRId32 ", Score: %"
+                PRId32 ", State: %" PRId32, key.string(), cost, pid, score, state);
 
         if (clientSp.get() != nullptr) {
             ret.appendFormat("User Id: %d, ", clientUserId);
@@ -2713,16 +2701,18 @@
 
 CameraService::DescriptorPtr CameraService::CameraClientManager::makeClientDescriptor(
         const String8& key, const sp<BasicClient>& value, int32_t cost,
-        const std::set<String8>& conflictingKeys, int32_t priority, int32_t ownerId) {
+        const std::set<String8>& conflictingKeys, int32_t score, int32_t ownerId,
+        int32_t state) {
 
     return std::make_shared<resource_policy::ClientDescriptor<String8, sp<BasicClient>>>(
-            key, value, cost, conflictingKeys, priority, ownerId);
+            key, value, cost, conflictingKeys, score, ownerId, state);
 }
 
 CameraService::DescriptorPtr CameraService::CameraClientManager::makeClientDescriptor(
         const sp<BasicClient>& value, const CameraService::DescriptorPtr& partial) {
     return makeClientDescriptor(partial->getKey(), value, partial->getCost(),
-            partial->getConflicting(), partial->getPriority(), partial->getOwnerId());
+            partial->getConflicting(), partial->getPriority().getScore(),
+            partial->getOwnerId(), partial->getPriority().getState());
 }
 
 // ----------------------------------------------------------------------------
@@ -2793,21 +2783,23 @@
         }
 
         auto clientDescriptor = mActiveClientManager.get(cameraId);
-        if (clientDescriptor == nullptr) {
+        if (clientDescriptor != nullptr) {
+            dprintf(fd, "  Device %s is open. Client instance dump:\n",
+                    cameraId.string());
+            dprintf(fd, "    Client priority score: %d state: %d\n",
+                    clientDescriptor->getPriority().getScore(),
+                    clientDescriptor->getPriority().getState());
+            dprintf(fd, "    Client PID: %d\n", clientDescriptor->getOwnerId());
+
+            auto client = clientDescriptor->getValue();
+            dprintf(fd, "    Client package: %s\n",
+                    String8(client->getPackageName()).string());
+
+            client->dumpClient(fd, args);
+        } else {
             dprintf(fd, "  Device %s is closed, no client instance\n",
                     cameraId.string());
-            continue;
         }
-        dprintf(fd, "  Device %s is open. Client instance dump:\n",
-                cameraId.string());
-        dprintf(fd, "    Client priority level: %d\n", clientDescriptor->getPriority());
-        dprintf(fd, "    Client PID: %d\n", clientDescriptor->getOwnerId());
-
-        auto client = clientDescriptor->getValue();
-        dprintf(fd, "    Client package: %s\n",
-                String8(client->getPackageName()).string());
-
-        client->dumpClient(fd, args);
 
         if (mModule != nullptr) {
             dprintf(fd, "== Camera HAL device %s static information: ==\n", cameraId.string());
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index d463b59..c7acdc9 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -75,11 +75,6 @@
         API_2 = 2
     };
 
-    // Process state (mirrors frameworks/base/core/java/android/app/ActivityManager.java)
-    static const int PROCESS_STATE_NONEXISTENT = -1;
-    static const int PROCESS_STATE_TOP = 2;
-    static const int PROCESS_STATE_TOP_SLEEPING = 5;
-
     // 3 second busy timeout when other clients are connecting
     static const nsecs_t DEFAULT_CONNECT_TIMEOUT_NS = 3000000000;
 
@@ -402,8 +397,8 @@
          * Make a ClientDescriptor object wrapping the given BasicClient strong pointer.
          */
         static DescriptorPtr makeClientDescriptor(const String8& key, const sp<BasicClient>& value,
-                int32_t cost, const std::set<String8>& conflictingKeys, int32_t priority,
-                int32_t ownerId);
+                int32_t cost, const std::set<String8>& conflictingKeys, int32_t score,
+                int32_t ownerId, int32_t state);
 
         /**
          * Make a ClientDescriptor object wrapping the given BasicClient strong pointer with
@@ -775,11 +770,6 @@
      */
     static String8 getFormattedCurrentTime();
 
-    /**
-     * Get the camera eviction priority from the current process state given by ActivityManager.
-     */
-    static int getCameraPriorityFromProcState(int procState);
-
     static binder::Status makeClient(const sp<CameraService>& cameraService,
             const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
             int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode,
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 6efe4e3..83c84af 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -911,14 +911,26 @@
             CameraParameters::FALSE);
     }
 
+    bool isZslReprocessPresent = false;
+    camera_metadata_ro_entry_t availableCapabilities =
+        staticInfo(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+    if (0 < availableCapabilities.count) {
+        const uint8_t *caps = availableCapabilities.data.u8;
+        for (size_t i = 0; i < availableCapabilities.count; i++) {
+            if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING ==
+                caps[i]) {
+                isZslReprocessPresent = true;
+                break;
+            }
+        }
+    }
+
     if (slowJpegMode || property_get_bool("camera.disable_zsl_mode", false)) {
         ALOGI("Camera %d: Disabling ZSL mode", cameraId);
         allowZslMode = false;
     } else {
-        allowZslMode = true;
+        allowZslMode = isZslReprocessPresent;
     }
-    // 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/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index b127472..e03ec66 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -37,9 +37,91 @@
 #include "api1/client2/ZslProcessor.h"
 #include "device3/Camera3Device.h"
 
+typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem;
+
 namespace android {
 namespace camera2 {
 
+namespace {
+struct TimestampFinder : public RingBufferConsumer::RingBufferComparator {
+    typedef RingBufferConsumer::BufferInfo BufferInfo;
+
+    enum {
+        SELECT_I1 = -1,
+        SELECT_I2 = 1,
+        SELECT_NEITHER = 0,
+    };
+
+    explicit TimestampFinder(nsecs_t timestamp) : mTimestamp(timestamp) {}
+    ~TimestampFinder() {}
+
+    template <typename T>
+    static void swap(T& a, T& b) {
+        T tmp = a;
+        a = b;
+        b = tmp;
+    }
+
+    /**
+     * Try to find the best candidate for a ZSL buffer.
+     * Match priority from best to worst:
+     *  1) Timestamps match.
+     *  2) Timestamp is closest to the needle (and lower).
+     *  3) Timestamp is closest to the needle (and higher).
+     *
+     */
+    virtual int compare(const BufferInfo *i1,
+                        const BufferInfo *i2) const {
+        // Try to select non-null object first.
+        if (i1 == NULL) {
+            return SELECT_I2;
+        } else if (i2 == NULL) {
+            return SELECT_I1;
+        }
+
+        // Best result: timestamp is identical
+        if (i1->mTimestamp == mTimestamp) {
+            return SELECT_I1;
+        } else if (i2->mTimestamp == mTimestamp) {
+            return SELECT_I2;
+        }
+
+        const BufferInfo* infoPtrs[2] = {
+            i1,
+            i2
+        };
+        int infoSelectors[2] = {
+            SELECT_I1,
+            SELECT_I2
+        };
+
+        // Order i1,i2 so that always i1.timestamp < i2.timestamp
+        if (i1->mTimestamp > i2->mTimestamp) {
+            swap(infoPtrs[0], infoPtrs[1]);
+            swap(infoSelectors[0], infoSelectors[1]);
+        }
+
+        // Second best: closest (lower) timestamp
+        if (infoPtrs[1]->mTimestamp < mTimestamp) {
+            return infoSelectors[1];
+        } else if (infoPtrs[0]->mTimestamp < mTimestamp) {
+            return infoSelectors[0];
+        }
+
+        // Worst: closest (higher) timestamp
+        return infoSelectors[0];
+
+        /**
+         * The above cases should cover all the possibilities,
+         * and we get an 'empty' result only if the ring buffer
+         * was empty itself
+         */
+    }
+
+    const nsecs_t mTimestamp;
+}; // struct TimestampFinder
+} // namespace anonymous
+
 ZslProcessor::ZslProcessor(
     sp<Camera2Client> client,
     wp<CaptureSequencer> sequencer):
@@ -50,8 +132,13 @@
         mSequencer(sequencer),
         mId(client->getCameraId()),
         mZslStreamId(NO_STREAM),
+        mInputStreamId(NO_STREAM),
         mFrameListHead(0),
-        mHasFocuser(false) {
+        mHasFocuser(false),
+        mInputBuffer(nullptr),
+        mProducer(nullptr),
+        mInputProducer(nullptr),
+        mInputProducerSlot(-1) {
     // Initialize buffer queue and frame list based on pipeline max depth.
     size_t pipelineMaxDepth = kDefaultMaxPipelineDepth;
     if (client != 0) {
@@ -83,7 +170,6 @@
     mFrameListDepth = pipelineMaxDepth;
     mBufferQueueDepth = mFrameListDepth + 1;
 
-
     mZslQueue.insertAt(0, mBufferQueueDepth);
     mFrameList.insertAt(0, mFrameListDepth);
     sp<CaptureSequencer> captureSequencer = mSequencer.promote();
@@ -144,7 +230,7 @@
         return INVALID_OPERATION;
     }
 
-    if (mZslStreamId != NO_STREAM) {
+    if ((mZslStreamId != NO_STREAM) || (mInputStreamId != NO_STREAM)) {
         // Check if stream parameters have to change
         uint32_t currentWidth, currentHeight;
         res = device->getStreamInfo(mZslStreamId,
@@ -157,21 +243,57 @@
         }
         if (currentWidth != (uint32_t)params.fastInfo.arrayWidth ||
                 currentHeight != (uint32_t)params.fastInfo.arrayHeight) {
-            ALOGV("%s: Camera %d: Deleting stream %d since the buffer "
-                  "dimensions changed",
-                __FUNCTION__, client->getCameraId(), mZslStreamId);
-            res = device->deleteStream(mZslStreamId);
-            if (res == -EBUSY) {
-                ALOGV("%s: Camera %d: Device is busy, call updateStream again "
-                      " after it becomes idle", __FUNCTION__, mId);
-                return res;
-            } else if(res != OK) {
-                ALOGE("%s: Camera %d: Unable to delete old output stream "
-                        "for ZSL: %s (%d)", __FUNCTION__,
-                        client->getCameraId(), strerror(-res), res);
-                return res;
+            if (mZslStreamId != NO_STREAM) {
+                ALOGV("%s: Camera %d: Deleting stream %d since the buffer "
+                      "dimensions changed",
+                    __FUNCTION__, client->getCameraId(), mZslStreamId);
+                res = device->deleteStream(mZslStreamId);
+                if (res == -EBUSY) {
+                    ALOGV("%s: Camera %d: Device is busy, call updateStream again "
+                          " after it becomes idle", __FUNCTION__, mId);
+                    return res;
+                } else if(res != OK) {
+                    ALOGE("%s: Camera %d: Unable to delete old output stream "
+                            "for ZSL: %s (%d)", __FUNCTION__,
+                            client->getCameraId(), strerror(-res), res);
+                    return res;
+                }
+                mZslStreamId = NO_STREAM;
             }
-            mZslStreamId = NO_STREAM;
+
+            if (mInputStreamId != NO_STREAM) {
+                ALOGV("%s: Camera %d: Deleting stream %d since the buffer "
+                      "dimensions changed",
+                    __FUNCTION__, client->getCameraId(), mInputStreamId);
+                res = device->deleteStream(mInputStreamId);
+                if (res == -EBUSY) {
+                    ALOGV("%s: Camera %d: Device is busy, call updateStream again "
+                          " after it becomes idle", __FUNCTION__, mId);
+                    return res;
+                } else if(res != OK) {
+                    ALOGE("%s: Camera %d: Unable to delete old output stream "
+                            "for ZSL: %s (%d)", __FUNCTION__,
+                            client->getCameraId(), strerror(-res), res);
+                    return res;
+                }
+                mInputStreamId = NO_STREAM;
+            }
+            if (nullptr != mInputProducer.get()) {
+                mInputProducer->disconnect(NATIVE_WINDOW_API_CPU);
+                mInputProducer.clear();
+            }
+        }
+    }
+
+    if (mInputStreamId == NO_STREAM) {
+        res = device->createInputStream(params.fastInfo.arrayWidth,
+            params.fastInfo.arrayHeight, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+            &mInputStreamId);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Can't create input stream: "
+                    "%s (%d)", __FUNCTION__, client->getCameraId(),
+                    strerror(-res), res);
+            return res;
         }
     }
 
@@ -179,21 +301,23 @@
         // Create stream for HAL production
         // TODO: Sort out better way to select resolution for ZSL
 
-        // Note that format specified internally in Camera3ZslStream
-        res = device->createZslStream(
-                params.fastInfo.arrayWidth, params.fastInfo.arrayHeight,
-                mBufferQueueDepth,
-                &mZslStreamId,
-                &mZslStream);
+        sp<IGraphicBufferProducer> producer;
+        sp<IGraphicBufferConsumer> consumer;
+        BufferQueue::createBufferQueue(&producer, &consumer);
+        mProducer = new RingBufferConsumer(consumer, GRALLOC_USAGE_HW_CAMERA_ZSL,
+            mBufferQueueDepth);
+        mProducer->setName(String8("Camera2-ZslRingBufferConsumer"));
+        sp<Surface> outSurface = new Surface(producer);
+
+        res = device->createStream(outSurface, params.fastInfo.arrayWidth,
+            params.fastInfo.arrayHeight, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+            HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0, &mZslStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Can't create ZSL stream: "
                     "%s (%d)", __FUNCTION__, client->getCameraId(),
                     strerror(-res), res);
             return res;
         }
-
-        // Only add the camera3 buffer listener when the stream is created.
-        mZslStream->addBufferListener(this);
     }
 
     client->registerFrameListener(Camera2Client::kPreviewRequestIdStart,
@@ -207,23 +331,27 @@
 status_t ZslProcessor::deleteStream() {
     ATRACE_CALL();
     status_t res;
+    sp<Camera3Device> device = nullptr;
+    sp<Camera2Client> client = nullptr;
 
     Mutex::Autolock l(mInputMutex);
 
-    if (mZslStreamId != NO_STREAM) {
-        sp<Camera2Client> client = mClient.promote();
+    if ((mZslStreamId != NO_STREAM) || (mInputStreamId != NO_STREAM)) {
+        client = mClient.promote();
         if (client == 0) {
             ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
             return INVALID_OPERATION;
         }
 
-        sp<Camera3Device> device =
+        device =
             reinterpret_cast<Camera3Device*>(client->getCameraDevice().get());
         if (device == 0) {
             ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
             return INVALID_OPERATION;
         }
+    }
 
+    if (mZslStreamId != NO_STREAM) {
         res = device->deleteStream(mZslStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Cannot delete ZSL output stream %d: "
@@ -234,6 +362,23 @@
 
         mZslStreamId = NO_STREAM;
     }
+    if (mInputStreamId != NO_STREAM) {
+        res = device->deleteStream(mInputStreamId);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Cannot delete input stream %d: "
+                    "%s (%d)", __FUNCTION__, client->getCameraId(),
+                    mInputStreamId, strerror(-res), res);
+            return res;
+        }
+
+        mInputStreamId = NO_STREAM;
+    }
+
+    if (nullptr != mInputProducer.get()) {
+        mInputProducer->disconnect(NATIVE_WINDOW_API_CPU);
+        mInputProducer.clear();
+    }
+
     return OK;
 }
 
@@ -282,6 +427,45 @@
     return OK;
 }
 
+void ZslProcessor::notifyInputReleased() {
+    Mutex::Autolock l(mInputMutex);
+
+    assert(nullptr != mInputBuffer.get());
+    assert(nullptr != mInputProducer.get());
+
+    sp<GraphicBuffer> gb;
+    sp<Fence> fence;
+    auto rc = mInputProducer->detachNextBuffer(&gb, &fence);
+    if (NO_ERROR != rc) {
+        ALOGE("%s: Failed to detach buffer from input producer: %d",
+            __FUNCTION__, rc);
+        return;
+    }
+
+    BufferItem &item = mInputBuffer->getBufferItem();
+    sp<GraphicBuffer> inputBuffer = item.mGraphicBuffer;
+    if (gb->handle != inputBuffer->handle) {
+        ALOGE("%s: Input mismatch, expected buffer %p received %p", __FUNCTION__,
+            inputBuffer->handle, gb->handle);
+        return;
+    }
+
+    mInputBuffer.clear();
+    ALOGV("%s: Memory optimization, clearing ZSL queue",
+          __FUNCTION__);
+    clearZslResultQueueLocked();
+
+    // Required so we accept more ZSL requests
+    mState = RUNNING;
+}
+
+void ZslProcessor::InputProducerListener::onBufferReleased() {
+    sp<ZslProcessor> parent = mParent.promote();
+    if (nullptr != parent.get()) {
+        parent->notifyInputReleased();
+    }
+}
+
 status_t ZslProcessor::pushToReprocess(int32_t requestId) {
     ALOGV("%s: Send in reprocess request with id %d",
             __FUNCTION__, requestId);
@@ -302,15 +486,38 @@
     nsecs_t candidateTimestamp = getCandidateTimestampLocked(&metadataIdx);
 
     if (candidateTimestamp == -1) {
-        ALOGE("%s: Could not find good candidate for ZSL reprocessing",
+        ALOGV("%s: Could not find good candidate for ZSL reprocessing",
               __FUNCTION__);
         return NOT_ENOUGH_DATA;
+    } else {
+        ALOGV("%s: Found good ZSL candidate idx: %u",
+            __FUNCTION__, (unsigned int) metadataIdx);
     }
 
-    res = mZslStream->enqueueInputBufferByTimestamp(candidateTimestamp,
-                                                    /*actualTimestamp*/NULL);
+    if (nullptr == mInputProducer.get()) {
+        res = client->getCameraDevice()->getInputBufferProducer(
+            &mInputProducer);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Unable to retrieve input producer: "
+                    "%s (%d)", __FUNCTION__, client->getCameraId(),
+                    strerror(-res), res);
+            return res;
+        }
 
-    if (res == mZslStream->NO_BUFFER_AVAILABLE) {
+        IGraphicBufferProducer::QueueBufferOutput output;
+        res = mInputProducer->connect(new InputProducerListener(this),
+            NATIVE_WINDOW_API_CPU, false, &output);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Unable to connect to input producer: "
+                    "%s (%d)", __FUNCTION__, client->getCameraId(),
+                    strerror(-res), res);
+            return res;
+        }
+    }
+
+    res = enqueueInputBufferByTimestamp(candidateTimestamp,
+        /*actualTimestamp*/NULL);
+    if (res == NO_BUFFER_AVAILABLE) {
         ALOGV("%s: No ZSL buffers yet", __FUNCTION__);
         return NOT_ENOUGH_DATA;
     } else if (res != OK) {
@@ -348,7 +555,7 @@
         }
 
         int32_t inputStreams[1] =
-                { mZslStreamId };
+                { mInputStreamId };
         res = request.update(ANDROID_REQUEST_INPUT_STREAMS,
                 inputStreams, 1);
         if (res != OK) {
@@ -428,6 +635,70 @@
     return OK;
 }
 
+status_t ZslProcessor::enqueueInputBufferByTimestamp(
+        nsecs_t timestamp,
+        nsecs_t* actualTimestamp) {
+
+    TimestampFinder timestampFinder = TimestampFinder(timestamp);
+
+    mInputBuffer = mProducer->pinSelectedBuffer(timestampFinder,
+        /*waitForFence*/false);
+
+    if (nullptr == mInputBuffer.get()) {
+        ALOGE("%s: No ZSL buffers were available yet", __FUNCTION__);
+        return NO_BUFFER_AVAILABLE;
+    }
+
+    nsecs_t actual = mInputBuffer->getBufferItem().mTimestamp;
+
+    if (actual != timestamp) {
+        // TODO: This is problematic, the metadata queue timestamp should
+        //       usually have a corresponding ZSL buffer with the same timestamp.
+        //       If this is not the case, then it is possible that we will use
+        //       a ZSL buffer from a different request, which can result in
+        //       side effects during the reprocess pass.
+        ALOGW("%s: ZSL buffer candidate search didn't find an exact match --"
+              " requested timestamp = %" PRId64 ", actual timestamp = %" PRId64,
+              __FUNCTION__, timestamp, actual);
+    }
+
+    if (nullptr != actualTimestamp) {
+        *actualTimestamp = actual;
+    }
+
+    BufferItem &item = mInputBuffer->getBufferItem();
+    auto rc = mInputProducer->attachBuffer(&mInputProducerSlot,
+        item.mGraphicBuffer);
+    if (OK != rc) {
+        ALOGE("%s: Failed to attach input ZSL buffer to producer: %d",
+            __FUNCTION__, rc);
+        return rc;
+    }
+
+    IGraphicBufferProducer::QueueBufferOutput output;
+    IGraphicBufferProducer::QueueBufferInput input(item.mTimestamp,
+            item.mIsAutoTimestamp, item.mDataSpace, item.mCrop,
+            item.mScalingMode, item.mTransform, item.mFence);
+    rc = mInputProducer->queueBuffer(mInputProducerSlot, input, &output);
+    if (OK != rc) {
+        ALOGE("%s: Failed to queue ZSL buffer to producer: %d",
+            __FUNCTION__, rc);
+        return rc;
+    }
+
+    return rc;
+}
+
+status_t ZslProcessor::clearInputRingBufferLocked(nsecs_t* latestTimestamp) {
+
+    if (nullptr != latestTimestamp) {
+        *latestTimestamp = mProducer->getLatestTimestamp();
+    }
+    mInputBuffer.clear();
+
+    return mProducer->clear();
+}
+
 status_t ZslProcessor::clearZslQueue() {
     Mutex::Autolock l(mInputMutex);
     // If in middle of capture, can't clear out queue
@@ -437,10 +708,10 @@
 }
 
 status_t ZslProcessor::clearZslQueueLocked() {
-    if (mZslStream != 0) {
+    if (NO_STREAM != mZslStreamId) {
         // clear result metadata list first.
         clearZslResultQueueLocked();
-        return mZslStream->clearInputRingBuffer(&mLatestClearedBufferTimestamp);
+        return clearInputRingBufferLocked(&mLatestClearedBufferTimestamp);
     }
     return OK;
 }
@@ -630,46 +901,5 @@
     return minTimestamp;
 }
 
-void ZslProcessor::onBufferAcquired(const BufferInfo& /*bufferInfo*/) {
-    // Intentionally left empty
-    // Although theoretically we could use this to get better dump info
-}
-
-void ZslProcessor::onBufferReleased(const BufferInfo& bufferInfo) {
-
-    // ignore output buffers
-    if (bufferInfo.mOutput) {
-        return;
-    }
-
-    // Lock mutex only once we know this is an input buffer returned to avoid
-    // potential deadlock
-    Mutex::Autolock l(mInputMutex);
-    // TODO: Verify that the buffer is in our queue by looking at timestamp
-    // theoretically unnecessary unless we change the following assumptions:
-    // -- only 1 buffer reprocessed at a time (which is the case now)
-
-    // Erase entire ZSL queue since we've now completed the capture and preview
-    // is stopped.
-    //
-    // We need to guarantee that if we do two back-to-back captures,
-    // the second won't use a buffer that's older/the same as the first, which
-    // is theoretically possible if we don't clear out the queue and the
-    // selection criteria is something like 'newest'. Clearing out the result
-    // metadata queue on a completed capture ensures we'll only use new timestamp.
-    // Calling clearZslQueueLocked is a guaranteed deadlock because this callback
-    // holds the Camera3Stream internal lock (mLock), and clearZslQueueLocked requires
-    // to hold the same lock.
-    // TODO: need figure out a way to clear the Zsl buffer queue properly. Right now
-    // it is safe not to do so, as back to back ZSL capture requires stop and start
-    // preview, which will flush ZSL queue automatically.
-    ALOGV("%s: Memory optimization, clearing ZSL queue",
-          __FUNCTION__);
-    clearZslResultQueueLocked();
-
-    // Required so we accept more ZSL requests
-    mState = RUNNING;
-}
-
 }; // namespace camera2
 }; // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.h b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
index 86c06c6..6113d58 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
@@ -24,10 +24,11 @@
 #include <utils/Condition.h>
 #include <gui/BufferItem.h>
 #include <gui/BufferItemConsumer.h>
+#include <gui/RingBufferConsumer.h>
+#include <gui/IProducerListener.h>
 #include <camera/CameraMetadata.h>
 
 #include "api1/client2/FrameProcessor.h"
-#include "device3/Camera3ZslStream.h"
 
 namespace android {
 
@@ -42,7 +43,6 @@
  * ZSL queue processing for HALv3.0 or newer
  */
 class ZslProcessor :
-                    public camera3::Camera3StreamBufferListener,
             virtual public Thread,
             virtual public FrameProcessor::FilteredListener {
   public:
@@ -81,19 +81,18 @@
 
     void dump(int fd, const Vector<String16>& args) const;
 
-  protected:
-    /**
-     **********************************************
-     * Camera3StreamBufferListener implementation *
-     **********************************************
-     */
-    typedef camera3::Camera3StreamBufferListener::BufferInfo BufferInfo;
-    // Buffer was acquired by the HAL
-    virtual void onBufferAcquired(const BufferInfo& bufferInfo);
-    // Buffer was released by the HAL
-    virtual void onBufferReleased(const BufferInfo& bufferInfo);
-
   private:
+
+    class InputProducerListener : public BnProducerListener {
+    public:
+        InputProducerListener(wp<ZslProcessor> parent) : mParent(parent) {}
+        virtual void onBufferReleased();
+        virtual bool needsReleaseNotify() { return true; }
+
+    private:
+        wp<ZslProcessor> mParent;
+    };
+
     static const nsecs_t kWaitDuration = 10000000; // 10 ms
     nsecs_t mLatestClearedBufferTimestamp;
 
@@ -102,6 +101,8 @@
         LOCKED
     } mState;
 
+    enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE };
+
     wp<Camera2Client> mClient;
     wp<CaptureSequencer> mSequencer;
 
@@ -114,7 +115,7 @@
     };
 
     int mZslStreamId;
-    sp<camera3::Camera3ZslStream> mZslStream;
+    int mInputStreamId;
 
     struct ZslPair {
         BufferItem buffer;
@@ -135,6 +136,12 @@
 
     bool mHasFocuser;
 
+    // Input buffer queued into HAL
+    sp<RingBufferConsumer::PinnedBufferItem> mInputBuffer;
+    sp<RingBufferConsumer>                   mProducer;
+    sp<IGraphicBufferProducer>               mInputProducer;
+    int                                      mInputProducerSlot;
+
     virtual bool threadLoop();
 
     status_t clearZslQueueLocked();
@@ -145,6 +152,11 @@
 
     nsecs_t getCandidateTimestampLocked(size_t* metadataIdx) const;
 
+    status_t enqueueInputBufferByTimestamp( nsecs_t timestamp,
+        nsecs_t* actualTimestamp);
+    status_t clearInputRingBufferLocked(nsecs_t* latestTimestamp);
+    void notifyInputReleased();
+
     bool isFixedFocusMode(uint8_t afMode) const;
 
     // Update the post-processing metadata with the default still capture request template
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 2618838..79e7ff0 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -507,6 +507,14 @@
             return res;
 
         if (!isStreamInfoValid) {
+            // Streaming sharing is only supported for IMPLEMENTATION_DEFINED
+            // formats.
+            if (isShared && streamInfo.format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+                String8 msg = String8::format("Camera %s: Stream sharing is only supported for "
+                        "IMPLEMENTATION_DEFINED format", mCameraIdStr.string());
+                ALOGW("%s: %s", __FUNCTION__, msg.string());
+                return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+            }
             isStreamInfoValid = true;
         }
 
@@ -1217,6 +1225,13 @@
         return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
     }
 
+    if (mStreamInfoMap[streamId].finalized) {
+        String8 msg = String8::format("Camera %s: finalizeOutputConfigurations has been called"
+                " on stream ID %d", mCameraIdStr.string(), streamId);
+        ALOGW("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+    }
+
     if (!mDevice.get()) {
         return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
     }
@@ -1246,13 +1261,6 @@
         surfaceId++;
     }
 
-    if (consumerSurfaces.size() == 0) {
-        String8 msg = String8::format("Camera %s: New OutputConfiguration has the same surfaces"
-                " for stream (ID %d)", mCameraIdStr.string(), streamId);
-        ALOGW("%s: %s", __FUNCTION__, msg.string());
-        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
-    }
-
     // Finish the deferred stream configuration with the surface.
     status_t err;
     err = mDevice->setConsumerSurfaces(streamId, consumerSurfaces);
@@ -1267,6 +1275,7 @@
         if (deferredStreamIndex != NAME_NOT_FOUND) {
             mDeferredStreams.removeItemsAt(deferredStreamIndex);
         }
+        mStreamInfoMap[streamId].finalized = true;
     } else if (err == NO_INIT) {
         res = STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
                 "Camera %s: Deferred surface is invalid: %s (%d)",
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 2f6d414..012beb4 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -215,6 +215,7 @@
         int format;
         android_dataspace dataSpace;
         int32_t consumerUsage;
+        bool finalized = false;
         OutputStreamInfo() :
                 width(-1), height(-1), format(-1), dataSpace(HAL_DATASPACE_UNKNOWN),
                 consumerUsage(0) {}
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index f44fd08..f6ad7d7 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -21,7 +21,6 @@
 #include "CameraProviderManager.h"
 
 #include <chrono>
-#include <android/hidl/manager/1.0/IServiceManager.h>
 #include <hidl/ServiceManagement.h>
 
 namespace android {
@@ -64,8 +63,10 @@
                 "about camera providers", __FUNCTION__);
         return INVALID_OPERATION;
     }
+
     // See if there's a passthrough HAL, but let's not complain if there's not
     addProvider(kLegacyProviderName, /*expected*/ false);
+
     return OK;
 }
 
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.cpp b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
index 5a5d7b7..d45891f 100644
--- a/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
@@ -19,6 +19,7 @@
 #define ATRACE_TAG ATRACE_TAG_CAMERA
 
 #include <gui/ISurfaceComposer.h>
+#include <gui/IGraphicBufferAlloc.h>
 #include <private/gui/ComposerService.h>
 #include <utils/Log.h>
 #include <utils/Trace.h>
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.h b/services/camera/libcameraservice/device3/Camera3BufferManager.h
index b5b86a3..f44c4a3 100644
--- a/services/camera/libcameraservice/device3/Camera3BufferManager.h
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.h
@@ -26,6 +26,8 @@
 
 namespace android {
 
+class IGraphicBufferAlloc;
+
 namespace camera3 {
 
 struct StreamInfo;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 208dcb6..f20556d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -51,7 +51,6 @@
 #include "device3/Camera3Device.h"
 #include "device3/Camera3OutputStream.h"
 #include "device3/Camera3InputStream.h"
-#include "device3/Camera3ZslStream.h"
 #include "device3/Camera3DummyStream.h"
 #include "device3/Camera3SharedOutputStream.h"
 #include "CameraService.h"
@@ -1209,86 +1208,6 @@
     return OK;
 }
 
-
-status_t Camera3Device::createZslStream(
-            uint32_t width, uint32_t height,
-            int depth,
-            /*out*/
-            int *id,
-            sp<Camera3ZslStream>* zslStream) {
-    ATRACE_CALL();
-    Mutex::Autolock il(mInterfaceLock);
-    Mutex::Autolock l(mLock);
-    ALOGV("Camera %s: Creating ZSL stream %d: %d x %d, depth %d",
-            mId.string(), mNextStreamId, width, height, depth);
-
-    status_t res;
-    bool wasActive = false;
-
-    switch (mStatus) {
-        case STATUS_ERROR:
-            ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
-            return INVALID_OPERATION;
-        case STATUS_UNINITIALIZED:
-            ALOGE("%s: Device not initialized", __FUNCTION__);
-            return INVALID_OPERATION;
-        case STATUS_UNCONFIGURED:
-        case STATUS_CONFIGURED:
-            // OK
-            break;
-        case STATUS_ACTIVE:
-            ALOGV("%s: Stopping activity to reconfigure streams", __FUNCTION__);
-            res = internalPauseAndWaitLocked();
-            if (res != OK) {
-                SET_ERR_L("Can't pause captures to reconfigure streams!");
-                return res;
-            }
-            wasActive = true;
-            break;
-        default:
-            SET_ERR_L("Unexpected status: %d", mStatus);
-            return INVALID_OPERATION;
-    }
-    assert(mStatus != STATUS_ACTIVE);
-
-    if (mInputStream != 0) {
-        ALOGE("%s: Cannot create more than 1 input stream", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-
-    sp<Camera3ZslStream> newStream = new Camera3ZslStream(mNextStreamId,
-                width, height, depth);
-    newStream->setStatusTracker(mStatusTracker);
-
-    res = mOutputStreams.add(mNextStreamId, newStream);
-    if (res < 0) {
-        ALOGE("%s: Can't add new stream to set: %s (%d)",
-                __FUNCTION__, strerror(-res), res);
-        return res;
-    }
-    mInputStream = newStream;
-
-    mNeedConfig = true;
-
-    *id = mNextStreamId++;
-    *zslStream = newStream;
-
-    // Continue captures if active at start
-    if (wasActive) {
-        ALOGV("%s: Restarting activity to reconfigure streams", __FUNCTION__);
-        res = configureStreamsLocked();
-        if (res != OK) {
-            ALOGE("%s: Can't reconfigure device for new stream %d: %s (%d)",
-                    __FUNCTION__, mNextStreamId, strerror(-res), res);
-            return res;
-        }
-        internalResumeLocked();
-    }
-
-    ALOGV("Camera %s: Created ZSL stream", mId.string());
-    return OK;
-}
-
 status_t Camera3Device::createStream(sp<Surface> consumer,
             uint32_t width, uint32_t height, int format,
             android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
@@ -2368,7 +2287,7 @@
         // Boost priority of request thread to SCHED_FIFO.
         pid_t requestThreadTid = mRequestThread->getTid();
         res = requestPriority(getpid(), requestThreadTid,
-                kRequestThreadPriority, /*asynchronous*/ false);
+                kRequestThreadPriority, /*isForApp*/ false, /*asynchronous*/ false);
         if (res != OK) {
             ALOGW("Can't set realtime priority for request processing thread: %s (%d)",
                     strerror(-res), res);
@@ -4037,7 +3956,8 @@
                 }
             }
 
-            res = outputStream->getBuffer(&outputBuffers->editItemAt(i));
+            res = outputStream->getBuffer(&outputBuffers->editItemAt(i),
+                    captureRequest->mOutputSurfaces[i]);
             if (res != OK) {
                 // Can't get output buffer from gralloc queue - this could be due to
                 // abandoned queue or other consumer misbehavior, so not a fatal
@@ -4049,13 +3969,6 @@
             }
             halRequest->num_output_buffers++;
 
-            res = outputStream->notifyRequestedSurfaces(halRequest->frame_number,
-                    captureRequest->mOutputSurfaces[i]);
-            if (res != OK) {
-                ALOGE("RequestThread: Cannot register output surfaces: %s (%d)",
-                      strerror(-res), res);
-                return INVALID_OPERATION;
-            }
         }
         totalNumBuffers += halRequest->num_output_buffers;
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 91d682e..e19b62e 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -125,12 +125,6 @@
     status_t createInputStream(
             uint32_t width, uint32_t height, int format,
             int *id) override;
-    status_t createZslStream(
-            uint32_t width, uint32_t height,
-            int depth,
-            /*out*/
-            int *id,
-            sp<camera3::Camera3ZslStream>* zslStream);
     status_t createReprocessStreamFromStream(int outputId, int *id) override;
 
     status_t getStreamInfo(int id,
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
index 1a730d6..9c951b7 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -36,7 +36,8 @@
 
 }
 
-status_t Camera3DummyStream::getBufferLocked(camera3_stream_buffer *) {
+status_t Camera3DummyStream::getBufferLocked(camera3_stream_buffer *,
+        const std::vector<size_t>&) {
     ATRACE_CALL();
     ALOGE("%s: Stream %d: Dummy stream cannot produce buffers!", __FUNCTION__, mId);
     return INVALID_OPERATION;
@@ -83,14 +84,6 @@
     return OK;
 }
 
-status_t Camera3DummyStream::notifyRequestedSurfaces(uint32_t frame_number,
-        const std::vector<size_t>& surface_ids) {
-    (void) frame_number;
-    (void) surface_ids;
-    // Do nothing
-    return OK;
-}
-
 status_t Camera3DummyStream::configureQueueLocked() {
     // Do nothing
     return OK;
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h
index b6ec99c..35a6a18 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.h
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h
@@ -56,9 +56,6 @@
 
     virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd);
 
-    virtual status_t notifyRequestedSurfaces(uint32_t frame_number,
-            const std::vector<size_t>& surface_ids);
-
     /**
      * Return if this output stream is for video encoding.
      */
@@ -102,7 +99,8 @@
     /**
      * Internal Camera3Stream interface
      */
-    virtual status_t getBufferLocked(camera3_stream_buffer *buffer);
+    virtual status_t getBufferLocked(camera3_stream_buffer *buffer,
+            const std::vector<size_t>& surface_ids = std::vector<size_t>());
     virtual status_t returnBufferLocked(
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index f971116..51dc20a 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -148,73 +148,17 @@
     disconnectLocked();
 }
 
-status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer) {
+status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer,
+        const std::vector<size_t>&) {
     ATRACE_CALL();
-    status_t res;
-
-    if ((res = getBufferPreconditionCheckLocked()) != OK) {
-        return res;
-    }
 
     ANativeWindowBuffer* anb;
     int fenceFd = -1;
-    bool gotBufferFromManager = false;
 
-    if (mUseBufferManager) {
-        sp<GraphicBuffer> gb;
-        res = mBufferManager->getBufferForStream(getId(), getStreamSetId(), &gb, &fenceFd);
-        if (res == OK) {
-            // Attach this buffer to the bufferQueue: the buffer will be in dequeue state after a
-            // successful return.
-            anb = gb.get();
-            res = mConsumer->attachBuffer(anb);
-            if (res != OK) {
-                ALOGE("%s: Stream %d: Can't attach the output buffer to this surface: %s (%d)",
-                        __FUNCTION__, mId, strerror(-res), res);
-                return res;
-            }
-            gotBufferFromManager = true;
-            ALOGV("Stream %d: Attached new buffer", getId());
-        } else if (res == ALREADY_EXISTS) {
-            // Have sufficient free buffers already attached, can just
-            // dequeue from buffer queue
-            ALOGV("Stream %d: Reusing attached buffer", getId());
-            gotBufferFromManager = false;
-        } else if (res != OK) {
-            ALOGE("%s: Stream %d: Can't get next output buffer from buffer manager: %s (%d)",
-                    __FUNCTION__, mId, strerror(-res), res);
-            return res;
-        }
-    }
-    if (!gotBufferFromManager) {
-        /**
-         * Release the lock briefly to avoid deadlock for below scenario:
-         * Thread 1: StreamingProcessor::startStream -> Camera3Stream::isConfiguring().
-         * This thread acquired StreamingProcessor lock and try to lock Camera3Stream lock.
-         * Thread 2: Camera3Stream::returnBuffer->StreamingProcessor::onFrameAvailable().
-         * This thread acquired Camera3Stream lock and bufferQueue lock, and try to lock
-         * StreamingProcessor lock.
-         * Thread 3: Camera3Stream::getBuffer(). This thread acquired Camera3Stream lock
-         * and try to lock bufferQueue lock.
-         * Then there is circular locking dependency.
-         */
-        sp<ANativeWindow> currentConsumer = mConsumer;
-        mLock.unlock();
-
-        res = currentConsumer->dequeueBuffer(currentConsumer.get(), &anb, &fenceFd);
-        mLock.lock();
-        if (res != OK) {
-            ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)",
-                    __FUNCTION__, mId, strerror(-res), res);
-
-            // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is STATE_PREPARING,
-            // let prepareNextBuffer handle the error.)
-            if (res == NO_INIT && mState == STATE_CONFIGURED) {
-                mState = STATE_ABANDONED;
-            }
-
-            return res;
-        }
+    status_t res;
+    res = getBufferLockedCommon(&anb, &fenceFd);
+    if (res != OK) {
+        return res;
     }
 
     /**
@@ -227,6 +171,11 @@
     return OK;
 }
 
+status_t Camera3OutputStream::queueBufferToConsumer(sp<ANativeWindow>& consumer,
+            ANativeWindowBuffer* buffer, int anwReleaseFence) {
+    return consumer->queueBuffer(consumer.get(), buffer, anwReleaseFence);
+}
+
 status_t Camera3OutputStream::returnBufferLocked(
         const camera3_stream_buffer &buffer,
         nsecs_t timestamp) {
@@ -269,6 +218,7 @@
     sp<ANativeWindow> currentConsumer = mConsumer;
     mLock.unlock();
 
+    ANativeWindowBuffer *anwBuffer = container_of(buffer.buffer, ANativeWindowBuffer, handle);
     /**
      * Return buffer back to ANativeWindow
      */
@@ -276,13 +226,14 @@
         // Cancel buffer
         ALOGW("A frame is dropped for stream %d", mId);
         res = currentConsumer->cancelBuffer(currentConsumer.get(),
-                container_of(buffer.buffer, ANativeWindowBuffer, handle),
+                anwBuffer,
                 anwReleaseFence);
         if (res != OK) {
             ALOGE("%s: Stream %d: Error cancelling buffer to native window:"
                   " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
         }
 
+        notifyBufferReleased(anwBuffer);
         if (mUseBufferManager) {
             // Return this buffer back to buffer manager.
             mBufferReleasedListener->onBufferReleased();
@@ -308,9 +259,7 @@
             return res;
         }
 
-        res = currentConsumer->queueBuffer(currentConsumer.get(),
-                container_of(buffer.buffer, ANativeWindowBuffer, handle),
-                anwReleaseFence);
+        res = queueBufferToConsumer(currentConsumer, anwBuffer, anwReleaseFence);
         if (res != OK) {
             ALOGE("%s: Stream %d: Error queueing buffer to native window: "
                   "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
@@ -527,6 +476,76 @@
     return OK;
 }
 
+status_t Camera3OutputStream::getBufferLockedCommon(ANativeWindowBuffer** anb, int* fenceFd) {
+    ATRACE_CALL();
+    status_t res;
+
+    if ((res = getBufferPreconditionCheckLocked()) != OK) {
+        return res;
+    }
+
+    bool gotBufferFromManager = false;
+
+    if (mUseBufferManager) {
+        sp<GraphicBuffer> gb;
+        res = mBufferManager->getBufferForStream(getId(), getStreamSetId(), &gb, fenceFd);
+        if (res == OK) {
+            // Attach this buffer to the bufferQueue: the buffer will be in dequeue state after a
+            // successful return.
+            *anb = gb.get();
+            res = mConsumer->attachBuffer(*anb);
+            if (res != OK) {
+                ALOGE("%s: Stream %d: Can't attach the output buffer to this surface: %s (%d)",
+                        __FUNCTION__, mId, strerror(-res), res);
+                return res;
+            }
+            gotBufferFromManager = true;
+            ALOGV("Stream %d: Attached new buffer", getId());
+        } else if (res == ALREADY_EXISTS) {
+            // Have sufficient free buffers already attached, can just
+            // dequeue from buffer queue
+            ALOGV("Stream %d: Reusing attached buffer", getId());
+            gotBufferFromManager = false;
+        } else if (res != OK) {
+            ALOGE("%s: Stream %d: Can't get next output buffer from buffer manager: %s (%d)",
+                    __FUNCTION__, mId, strerror(-res), res);
+            return res;
+        }
+    }
+    if (!gotBufferFromManager) {
+        /**
+         * Release the lock briefly to avoid deadlock for below scenario:
+         * Thread 1: StreamingProcessor::startStream -> Camera3Stream::isConfiguring().
+         * This thread acquired StreamingProcessor lock and try to lock Camera3Stream lock.
+         * Thread 2: Camera3Stream::returnBuffer->StreamingProcessor::onFrameAvailable().
+         * This thread acquired Camera3Stream lock and bufferQueue lock, and try to lock
+         * StreamingProcessor lock.
+         * Thread 3: Camera3Stream::getBuffer(). This thread acquired Camera3Stream lock
+         * and try to lock bufferQueue lock.
+         * Then there is circular locking dependency.
+         */
+        sp<ANativeWindow> currentConsumer = mConsumer;
+        mLock.unlock();
+
+        res = currentConsumer->dequeueBuffer(currentConsumer.get(), anb, fenceFd);
+        mLock.lock();
+        if (res != OK) {
+            ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)",
+                    __FUNCTION__, mId, strerror(-res), res);
+
+            // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is STATE_PREPARING,
+            // let prepareNextBuffer handle the error.)
+            if (res == NO_INIT && mState == STATE_CONFIGURED) {
+                mState = STATE_ABANDONED;
+            }
+
+            return res;
+        }
+    }
+
+    return res;
+}
+
 status_t Camera3OutputStream::disconnectLocked() {
     status_t res;
 
@@ -702,8 +721,7 @@
     return OK;
 }
 
-status_t Camera3OutputStream::notifyRequestedSurfaces(uint32_t /*frame_number*/,
-        const std::vector<size_t>& /*surface_ids*/) {
+status_t Camera3OutputStream::notifyBufferReleased(ANativeWindowBuffer* /*anwBuffer*/) {
     return OK;
 }
 
@@ -717,6 +735,7 @@
 }
 
 status_t Camera3OutputStream::setConsumers(const std::vector<sp<Surface>>& consumers) {
+    Mutex::Autolock l(mLock);
     if (consumers.size() != 1) {
         ALOGE("%s: it's illegal to set %zu consumer surfaces!",
                   __FUNCTION__, consumers.size());
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 080c721..24e4e05 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -158,8 +158,11 @@
 
     virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd);
 
-    virtual status_t notifyRequestedSurfaces(uint32_t frame_number,
-            const std::vector<size_t>& surface_ids);
+    /**
+     * Notify that the buffer is being released to the buffer queue instead of
+     * being queued to the consumer.
+     */
+    virtual status_t notifyBufferReleased(ANativeWindowBuffer *anwBuffer);
 
     /**
      * Set the graphic buffer manager to get/return the stream buffers.
@@ -198,6 +201,9 @@
 
     static const nsecs_t       kDequeueBufferTimeout   = 1000000000; // 1 sec
 
+    status_t getBufferLockedCommon(ANativeWindowBuffer** anb, int* fenceFd);
+
+
   private:
 
     int               mTransform;
@@ -243,11 +249,16 @@
     /**
      * Internal Camera3Stream interface
      */
-    virtual status_t getBufferLocked(camera3_stream_buffer *buffer);
+    virtual status_t getBufferLocked(camera3_stream_buffer *buffer,
+            const std::vector<size_t>& surface_ids);
+
     virtual status_t returnBufferLocked(
             const camera3_stream_buffer &buffer,
             nsecs_t timestamp);
 
+    virtual status_t queueBufferToConsumer(sp<ANativeWindow>& consumer,
+            ANativeWindowBuffer* buffer, int anwReleaseFence);
+
     virtual status_t configureQueueLocked();
 
     virtual status_t getEndpointUsage(uint32_t *usage) const;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index 11868e7..8107dd0 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -59,20 +59,6 @@
      *
      */
     virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd) = 0;
-
-    /**
-     * Notify which surfaces are requested for a particular frame number.
-     *
-     * Mulitple surfaces could share the same output stream, but a request may
-     * be only for a subset of surfaces. In this case, the
-     * Camera3OutputStreamInterface object needs to manage the output surfaces on
-     * a per request basis.
-     *
-     * If there is only one surface for this output stream, calling this
-     * function is a no-op.
-     */
-    virtual status_t notifyRequestedSurfaces(uint32_t frame_number,
-            const std::vector<size_t>& surface_ids) = 0;
 };
 
 } // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index 0d6a96c..2ae5660 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -44,7 +44,7 @@
     uint32_t usage;
     getEndpointUsage(&usage);
 
-    res = mStreamSplitter->connect(mSurfaces, usage, camera3_stream::max_buffers, mConsumer);
+    res = mStreamSplitter->connect(mSurfaces, usage, camera3_stream::max_buffers, &mConsumer);
     if (res != OK) {
         ALOGE("%s: Failed to connect to stream splitter: %s(%d)",
                 __FUNCTION__, strerror(-res), res);
@@ -54,13 +54,13 @@
     return res;
 }
 
-status_t Camera3SharedOutputStream::notifyRequestedSurfaces(uint32_t /*frame_number*/,
-        const std::vector<size_t>& surface_ids) {
+status_t Camera3SharedOutputStream::notifyBufferReleased(ANativeWindowBuffer *anwBuffer) {
     Mutex::Autolock l(mLock);
     status_t res = OK;
+    const sp<GraphicBuffer> buffer(static_cast<GraphicBuffer*>(anwBuffer));
 
     if (mStreamSplitter != nullptr) {
-        res = mStreamSplitter->notifyRequestedSurfaces(surface_ids);
+        res = mStreamSplitter->notifyBufferReleased(buffer);
     }
 
     return res;
@@ -72,6 +72,7 @@
 }
 
 status_t Camera3SharedOutputStream::setConsumers(const std::vector<sp<Surface>>& surfaces) {
+    Mutex::Autolock l(mLock);
     if (surfaces.size() == 0) {
         ALOGE("%s: it's illegal to set zero consumer surfaces!", __FUNCTION__);
         return INVALID_OPERATION;
@@ -88,7 +89,7 @@
 
         // Only call addOutput if the splitter has been connected.
         if (mStreamSplitter != nullptr) {
-            ret = mStreamSplitter->addOutput(surface, camera3_stream::max_buffers);
+            ret = mStreamSplitter->addOutput(surface);
             if (ret != OK) {
                 ALOGE("%s: addOutput failed with error code %d", __FUNCTION__, ret);
                 return ret;
@@ -99,6 +100,64 @@
     return ret;
 }
 
+status_t Camera3SharedOutputStream::getBufferLocked(camera3_stream_buffer *buffer,
+        const std::vector<size_t>& surface_ids) {
+    ANativeWindowBuffer* anb;
+    int fenceFd = -1;
+
+    status_t res;
+    res = getBufferLockedCommon(&anb, &fenceFd);
+    if (res != OK) {
+        return res;
+    }
+
+    // Attach the buffer to the splitter output queues. This could block if
+    // the output queue doesn't have any empty slot. So unlock during the course
+    // of attachBufferToOutputs.
+    sp<Camera3StreamSplitter> splitter = mStreamSplitter;
+    mLock.unlock();
+    res = splitter->attachBufferToOutputs(anb, surface_ids);
+    mLock.lock();
+    if (res != OK) {
+        ALOGE("%s: Stream %d: Cannot attach stream splitter buffer to outputs: %s (%d)",
+                __FUNCTION__, mId, strerror(-res), res);
+        // Only transition to STATE_ABANDONED from STATE_CONFIGURED. (If it is STATE_PREPARING,
+        // let prepareNextBuffer handle the error.)
+        if (res == NO_INIT && mState == STATE_CONFIGURED) {
+            mState = STATE_ABANDONED;
+        }
+
+        return res;
+    }
+
+    /**
+     * FenceFD now owned by HAL except in case of error,
+     * in which case we reassign it to acquire_fence
+     */
+    handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
+                        /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/true);
+
+    return OK;
+}
+
+status_t Camera3SharedOutputStream::queueBufferToConsumer(sp<ANativeWindow>& consumer,
+            ANativeWindowBuffer* buffer, int anwReleaseFence) {
+    status_t res = consumer->queueBuffer(consumer.get(), buffer, anwReleaseFence);
+
+    // After queuing buffer to the internal consumer queue, check whether the buffer is
+    // successfully queued to the output queues.
+    if (res == OK) {
+        res = mStreamSplitter->getOnFrameAvailableResult();
+        if (res != OK) {
+            ALOGE("%s: getOnFrameAvailable returns %d", __FUNCTION__, res);
+        }
+    } else {
+        ALOGE("%s: queueBufer failed %d", __FUNCTION__, res);
+    }
+
+    return res;
+}
+
 status_t Camera3SharedOutputStream::configureQueueLocked() {
     status_t res;
 
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index cc96076..7be0940 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -40,8 +40,7 @@
 
     virtual ~Camera3SharedOutputStream();
 
-    virtual status_t notifyRequestedSurfaces(uint32_t frame_number,
-            const std::vector<size_t>& surface_ids);
+    virtual status_t notifyBufferReleased(ANativeWindowBuffer *buffer);
 
     virtual bool isConsumerConfigurationDeferred(size_t surface_id) const;
 
@@ -62,6 +61,15 @@
      */
     status_t connectStreamSplitterLocked();
 
+    /**
+     * Internal Camera3Stream interface
+     */
+    virtual status_t getBufferLocked(camera3_stream_buffer *buffer,
+            const std::vector<size_t>& surface_ids);
+
+    virtual status_t queueBufferToConsumer(sp<ANativeWindow>& consumer,
+            ANativeWindowBuffer* buffer, int anwReleaseFence);
+
     virtual status_t configureQueueLocked();
 
     virtual status_t disconnectLocked();
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index c3b7565..53a3168 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -443,7 +443,8 @@
     return OK;
 }
 
-status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer) {
+status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer,
+        const std::vector<size_t>& surface_ids) {
     ATRACE_CALL();
     Mutex::Autolock l(mLock);
     status_t res = OK;
@@ -470,7 +471,7 @@
         }
     }
 
-    res = getBufferLocked(buffer);
+    res = getBufferLocked(buffer, surface_ids);
     if (res == OK) {
         fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/true);
         if (buffer->buffer) {
@@ -745,7 +746,8 @@
     return res;
 }
 
-status_t Camera3Stream::getBufferLocked(camera3_stream_buffer *) {
+status_t Camera3Stream::getBufferLocked(camera3_stream_buffer *,
+        const std::vector<size_t>&) {
     ALOGE("%s: This type of stream does not support output", __FUNCTION__);
     return INVALID_OPERATION;
 }
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 471b393..56cb827 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -277,12 +277,18 @@
      * Fill in the camera3_stream_buffer with the next valid buffer for this
      * stream, to hand over to the HAL.
      *
+     * Multiple surfaces could share the same HAL stream, but a request may
+     * be only for a subset of surfaces. In this case, the
+     * Camera3StreamInterface object needs the surface ID information to acquire
+     * buffers for those surfaces.
+     *
      * This method may only be called once finishConfiguration has been called.
      * For bidirectional streams, this method applies to the output-side
      * buffers.
      *
      */
-    status_t         getBuffer(camera3_stream_buffer *buffer);
+    status_t         getBuffer(camera3_stream_buffer *buffer,
+            const std::vector<size_t>& surface_ids = std::vector<size_t>());
 
     /**
      * Return a buffer to the stream after use by the HAL.
@@ -412,7 +418,8 @@
     // cast to camera3_stream*, implementations must increment the
     // refcount of the stream manually in getBufferLocked, and decrement it in
     // returnBufferLocked.
-    virtual status_t getBufferLocked(camera3_stream_buffer *buffer);
+    virtual status_t getBufferLocked(camera3_stream_buffer *buffer,
+            const std::vector<size_t>& surface_ids = std::vector<size_t>());
     virtual status_t returnBufferLocked(const camera3_stream_buffer &buffer,
             nsecs_t timestamp);
     virtual status_t getInputBufferLocked(camera3_stream_buffer *buffer);
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index ceea08a..f7b092f 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -200,12 +200,19 @@
      * Fill in the camera3_stream_buffer with the next valid buffer for this
      * stream, to hand over to the HAL.
      *
+     * Multiple surfaces could share the same HAL stream, but a request may
+     * be only for a subset of surfaces. In this case, the
+     * Camera3StreamInterface object needs the surface ID information to acquire
+     * buffers for those surfaces. For the case of single surface for a HAL
+     * stream, surface_ids parameter has no effect.
+     *
      * This method may only be called once finishConfiguration has been called.
      * For bidirectional streams, this method applies to the output-side
      * buffers.
      *
      */
-    virtual status_t getBuffer(camera3_stream_buffer *buffer) = 0;
+    virtual status_t getBuffer(camera3_stream_buffer *buffer,
+            const std::vector<size_t>& surface_ids = std::vector<size_t>()) = 0;
 
     /**
      * Return a buffer to the stream after use by the HAL.
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index c9f43aa..deb6735 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -37,10 +37,10 @@
 namespace android {
 
 status_t Camera3StreamSplitter::connect(const std::vector<sp<Surface> >& surfaces,
-                                           uint32_t consumerUsage, size_t hal_max_buffers,
-                                           sp<Surface>& consumer) {
-    if (consumer != nullptr) {
-        ALOGE("%s: output Surface is not NULL", __FUNCTION__);
+        uint32_t consumerUsage, size_t halMaxBuffers, sp<Surface>* consumer) {
+    ATRACE_CALL();
+    if (consumer == nullptr) {
+        SP_LOGE("%s: consumer pointer is NULL", __FUNCTION__);
         return BAD_VALUE;
     }
 
@@ -48,129 +48,147 @@
     status_t res = OK;
 
     if (mOutputs.size() > 0 || mConsumer != nullptr) {
-        ALOGE("%s: StreamSplitter already connected", __FUNCTION__);
+        SP_LOGE("%s: already connected", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    if (mBuffers.size() > 0) {
+        SP_LOGE("%s: still has %zu pending buffers", __FUNCTION__, mBuffers.size());
         return BAD_VALUE;
     }
 
+    mMaxHalBuffers = halMaxBuffers;
+    mConsumerName = getUniqueConsumerName();
     // Add output surfaces. This has to be before creating internal buffer queue
     // in order to get max consumer side buffers.
     for (size_t i = 0; i < surfaces.size(); i++) {
         if (surfaces[i] == nullptr) {
-            ALOGE("%s: Fatal: surface is NULL", __FUNCTION__);
+            SP_LOGE("%s: Fatal: surface is NULL", __FUNCTION__);
             return BAD_VALUE;
         }
-        res = addOutputLocked(surfaces[i], hal_max_buffers, OutputType::NonDeferred);
+        res = addOutputLocked(surfaces[i]);
         if (res != OK) {
-            ALOGE("%s: Failed to add output surface: %s(%d)",
+            SP_LOGE("%s: Failed to add output surface: %s(%d)",
                     __FUNCTION__, strerror(-res), res);
             return res;
         }
     }
 
-    // Create buffer queue for input
+    // Create BufferQueue for input
     BufferQueue::createBufferQueue(&mProducer, &mConsumer);
 
+    // Allocate 1 extra buffer to handle the case where all buffers are detached
+    // from input, and attached to the outputs. In this case, the input queue's
+    // dequeueBuffer can still allocate 1 extra buffer before being blocked by
+    // the output's attachBuffer().
     mBufferItemConsumer = new BufferItemConsumer(mConsumer, consumerUsage,
-                                                 mMaxConsumerBuffers);
+                                                 mMaxConsumerBuffers+1);
     if (mBufferItemConsumer == nullptr) {
         return NO_MEMORY;
     }
-    mConsumer->setConsumerName(getUniqueConsumerName());
+    mConsumer->setConsumerName(mConsumerName);
 
-    mSurface = new Surface(mProducer);
-    if (mSurface == nullptr) {
+    *consumer = new Surface(mProducer);
+    if (*consumer == nullptr) {
         return NO_MEMORY;
     }
-    consumer = mSurface;
 
     res = mConsumer->consumerConnect(this, /* controlledByApp */ false);
 
+    SP_LOGV("%s: connected", __FUNCTION__);
     return res;
 }
 
+status_t Camera3StreamSplitter::getOnFrameAvailableResult() {
+    ATRACE_CALL();
+    return mOnFrameAvailableRes.load();
+}
+
 void Camera3StreamSplitter::disconnect() {
+    ATRACE_CALL();
     Mutex::Autolock lock(mMutex);
 
+    for (auto& notifier : mNotifiers) {
+        sp<IGraphicBufferProducer> producer = notifier.first;
+        sp<OutputListener> listener = notifier.second;
+        IInterface::asBinder(producer)->unlinkToDeath(listener);
+    }
+    mNotifiers.clear();
+
     for (auto& output : mOutputs) {
         output->disconnect(NATIVE_WINDOW_API_CAMERA);
     }
     mOutputs.clear();
+    mOutputSlots.clear();
 
-    if (mConsumer != nullptr) {
-        mConsumer->consumerDisconnect();
-        mConsumer.clear();
-    }
+    mConsumer->consumerDisconnect();
 
     if (mBuffers.size() > 0) {
-        ALOGI("%zu buffers still being tracked", mBuffers.size());
+        SP_LOGW("%zu buffers still being tracked", mBuffers.size());
+        mBuffers.clear();
     }
+
+    mMaxHalBuffers = 0;
+    mMaxConsumerBuffers = 0;
+    SP_LOGV("%s: Disconnected", __FUNCTION__);
 }
 
+
 Camera3StreamSplitter::~Camera3StreamSplitter() {
     disconnect();
 }
 
-status_t Camera3StreamSplitter::addOutput(
-        const sp<Surface>& outputQueue, size_t hal_max_buffers) {
+status_t Camera3StreamSplitter::addOutput(const sp<Surface>& outputQueue) {
+    ATRACE_CALL();
     Mutex::Autolock lock(mMutex);
-    return addOutputLocked(outputQueue, hal_max_buffers, OutputType::Deferred);
+    status_t res = addOutputLocked(outputQueue);
+
+    if (res != OK) {
+        SP_LOGE("%s: addOutputLocked failed %d", __FUNCTION__, res);
+        return res;
+    }
+
+    res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers+1);
+
+    return res;
 }
 
-status_t Camera3StreamSplitter::addOutputLocked(
-        const sp<Surface>& outputQueue, size_t hal_max_buffers,
-        OutputType outputType) {
+status_t Camera3StreamSplitter::addOutputLocked(const sp<Surface>& outputQueue) {
+    ATRACE_CALL();
     if (outputQueue == nullptr) {
-        ALOGE("addOutput: outputQueue must not be NULL");
-        return BAD_VALUE;
-    }
-    if (hal_max_buffers < 1) {
-        ALOGE("%s: Camera HAL requested max_buffer count: %zu, requires at least 1",
-                __FUNCTION__, hal_max_buffers);
+        SP_LOGE("addOutput: outputQueue must not be NULL");
         return BAD_VALUE;
     }
 
     sp<IGraphicBufferProducer> gbp = outputQueue->getIGraphicBufferProducer();
     // Connect to the buffer producer
-    IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
     sp<OutputListener> listener(new OutputListener(this, gbp));
     IInterface::asBinder(gbp)->linkToDeath(listener);
-    status_t status = gbp->connect(listener, NATIVE_WINDOW_API_CAMERA,
-            /* producerControlledByApp */ true, &queueBufferOutput);
-    if (status != NO_ERROR) {
-        ALOGE("addOutput: failed to connect (%d)", status);
-       return status;
+    status_t res = outputQueue->connect(NATIVE_WINDOW_API_CAMERA, listener);
+    if (res != NO_ERROR) {
+        SP_LOGE("addOutput: failed to connect (%d)", res);
+        return res;
     }
 
     // Query consumer side buffer count, and update overall buffer count
     int maxConsumerBuffers = 0;
-    status = static_cast<ANativeWindow*>(outputQueue.get())->query(
+    res = static_cast<ANativeWindow*>(outputQueue.get())->query(
             outputQueue.get(),
             NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
-    if (status != OK) {
-        ALOGE("%s: Unable to query consumer undequeued buffer count"
+    if (res != OK) {
+        SP_LOGE("%s: Unable to query consumer undequeued buffer count"
               " for surface", __FUNCTION__);
-        return status;
+        return res;
     }
 
-    if (maxConsumerBuffers > mMaxConsumerBuffers) {
-        if (outputType == OutputType::Deferred) {
-            ALOGE("%s: Fatal: Deferred surface has higher consumer buffer count"
-                  " %d than what's already configured %d", __FUNCTION__,
-                  maxConsumerBuffers, mMaxConsumerBuffers);
-            return BAD_VALUE;
-        }
-        mMaxConsumerBuffers = maxConsumerBuffers;
-    }
-
-    ALOGV("%s: Consumer wants %d buffers, HAL wants %zu", __FUNCTION__,
-            maxConsumerBuffers, hal_max_buffers);
-    size_t totalBufferCount = maxConsumerBuffers + hal_max_buffers;
-    status = native_window_set_buffer_count(outputQueue.get(),
+    SP_LOGV("%s: Consumer wants %d buffers, Producer wants %zu", __FUNCTION__,
+            maxConsumerBuffers, mMaxHalBuffers);
+    size_t totalBufferCount = maxConsumerBuffers + mMaxHalBuffers;
+    res = native_window_set_buffer_count(outputQueue.get(),
             totalBufferCount);
-    if (status != OK) {
-        ALOGE("%s: Unable to set buffer count for surface %p",
+    if (res != OK) {
+        SP_LOGE("%s: Unable to set buffer count for surface %p",
                 __FUNCTION__, outputQueue.get());
-        return status;
+        return res;
     }
 
     // Set dequeueBuffer/attachBuffer timeout if the consumer is not hw composer or hw texture.
@@ -183,157 +201,239 @@
         outputQueue->setDequeueTimeout(kDequeueBufferTimeout);
     }
 
-    status = gbp->allowAllocation(false);
-    if (status != OK) {
-        ALOGE("%s: Failed to turn off allocation for outputQueue", __FUNCTION__);
-        return status;
+    res = gbp->allowAllocation(false);
+    if (res != OK) {
+        SP_LOGE("%s: Failed to turn off allocation for outputQueue", __FUNCTION__);
+        return res;
     }
 
     // Add new entry into mOutputs
     mOutputs.push_back(gbp);
+    mNotifiers[gbp] = listener;
+    mOutputSlots[gbp] = std::make_unique<OutputSlots>(totalBufferCount);
+
+    mMaxConsumerBuffers += maxConsumerBuffers;
     return NO_ERROR;
 }
 
+status_t Camera3StreamSplitter::outputBufferLocked(const sp<IGraphicBufferProducer>& output,
+        const BufferItem& bufferItem) {
+    ATRACE_CALL();
+    status_t res;
+    IGraphicBufferProducer::QueueBufferInput queueInput(
+            bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp,
+            bufferItem.mDataSpace, bufferItem.mCrop,
+            static_cast<int32_t>(bufferItem.mScalingMode),
+            bufferItem.mTransform, bufferItem.mFence);
+
+    IGraphicBufferProducer::QueueBufferOutput queueOutput;
+
+    uint64_t bufferId = bufferItem.mGraphicBuffer->getId();
+    const BufferTracker& tracker = *(mBuffers[bufferId]);
+    int slot = getSlotForOutputLocked(output, tracker.getBuffer());
+
+    // In case the output BufferQueue has its own lock, if we hold splitter lock while calling
+    // queueBuffer (which will try to acquire the output lock), the output could be holding its
+    // own lock calling releaseBuffer (which  will try to acquire the splitter lock), running into
+    // circular lock situation.
+    mMutex.unlock();
+    res = output->queueBuffer(slot, queueInput, &queueOutput);
+    mMutex.lock();
+
+    SP_LOGV("%s: Queuing buffer to buffer queue %p slot %d returns %d",
+            __FUNCTION__, output.get(), slot, res);
+    if (res != OK) {
+        if (res != NO_INIT && res != DEAD_OBJECT) {
+            SP_LOGE("Queuing buffer to output failed (%d)", res);
+        }
+        // If we just discovered that this output has been abandoned, note
+        // that, increment the release count so that we still release this
+        // buffer eventually, and move on to the next output
+        onAbandonedLocked();
+        decrementBufRefCountLocked(bufferItem.mGraphicBuffer->getId(), output);
+        return res;
+    }
+
+    // If the queued buffer replaces a pending buffer in the async
+    // queue, no onBufferReleased is called by the buffer queue.
+    // Proactively trigger the callback to avoid buffer loss.
+    if (queueOutput.bufferReplaced) {
+        onBufferReleasedByOutputLocked(output);
+    }
+
+    return res;
+}
+
 String8 Camera3StreamSplitter::getUniqueConsumerName() {
     static volatile int32_t counter = 0;
     return String8::format("Camera3StreamSplitter-%d", android_atomic_inc(&counter));
 }
 
-status_t Camera3StreamSplitter::notifyRequestedSurfaces(
-        const std::vector<size_t>& surfaces) {
+status_t Camera3StreamSplitter::notifyBufferReleased(const sp<GraphicBuffer>& buffer) {
     ATRACE_CALL();
+    status_t res = OK;
+
     Mutex::Autolock lock(mMutex);
 
-    mRequestedSurfaces.push_back(surfaces);
-    return OK;
-}
+    uint64_t bufferId = buffer->getId();
+    std::unique_ptr<BufferTracker> tracker_ptr = std::move(mBuffers[bufferId]);
+    mBuffers.erase(bufferId);
 
-
-void Camera3StreamSplitter::onFrameAvailable(const BufferItem& /* item */) {
-    ATRACE_CALL();
-    Mutex::Autolock lock(mMutex);
-
-    // The current policy is that if any one consumer is consuming buffers too
-    // slowly, the splitter will stall the rest of the outputs by not acquiring
-    // any more buffers from the input. This will cause back pressure on the
-    // input queue, slowing down its producer.
-
-    // If there are too many outstanding buffers, we block until a buffer is
-    // released back to the input in onBufferReleased
-    while (mOutstandingBuffers >= mMaxConsumerBuffers) {
-        mReleaseCondition.wait(mMutex);
-
-        // If the splitter is abandoned while we are waiting, the release
-        // condition variable will be broadcast, and we should just return
-        // without attempting to do anything more (since the input queue will
-        // also be abandoned).
-        if (mIsAbandoned) {
-            return;
+    for (const auto surface : tracker_ptr->requestedSurfaces()) {
+        sp<IGraphicBufferProducer>& gbp = mOutputs[surface];
+        OutputSlots& outputSlots = *(mOutputSlots[gbp]);
+        int slot = getSlotForOutputLocked(gbp, buffer);
+        if (slot != BufferItem::INVALID_BUFFER_SLOT) {
+             gbp->detachBuffer(slot);
+             outputSlots[slot].clear();
         }
     }
-    // If the splitter is abandoned without reaching mMaxConsumerBuffers, just
-    // return without attempting to do anything more.
-    if (mIsAbandoned) {
-        return;
+
+    return res;
+}
+
+status_t Camera3StreamSplitter::attachBufferToOutputs(ANativeWindowBuffer* anb,
+        const std::vector<size_t>& surface_ids) {
+    ATRACE_CALL();
+    status_t res = OK;
+
+    Mutex::Autolock lock(mMutex);
+
+    sp<GraphicBuffer> gb(static_cast<GraphicBuffer*>(anb));
+    uint64_t bufferId = gb->getId();
+
+    // Initialize buffer tracker for this input buffer
+    auto tracker = std::make_unique<BufferTracker>(gb, surface_ids);
+
+    for (auto& surface_id : surface_ids) {
+        sp<IGraphicBufferProducer>& gbp = mOutputs[surface_id];
+        int slot = BufferItem::INVALID_BUFFER_SLOT;
+        //Temporarly Unlock the mutex when trying to attachBuffer to the output
+        //queue, because attachBuffer could block in case of a slow consumer. If
+        //we block while holding the lock, onFrameAvailable and onBufferReleased
+        //will block as well because they need to acquire the same lock.
+        mMutex.unlock();
+        res = gbp->attachBuffer(&slot, gb);
+        mMutex.lock();
+        if (res != OK) {
+            SP_LOGE("%s: Cannot acquireBuffer from GraphicBufferProducer %p: %s (%d)",
+                    __FUNCTION__, gbp.get(), strerror(-res), res);
+            return res;
+        }
+        auto& outputSlots = *mOutputSlots[gbp];
+        if (outputSlots[slot] != nullptr) {
+            // If the buffer is attached to a slot which already contains a buffer,
+            // the previous buffer will be removed from the output queue. Decrement
+            // the reference count accordingly.
+            decrementBufRefCountLocked(outputSlots[slot]->getId(), gbp);
+        }
+        SP_LOGV("%s: Attached buffer %p to slot %d on output %p.",__FUNCTION__, gb.get(),
+                slot, gbp.get());
+        outputSlots[slot] = gb;
     }
 
-    ++mOutstandingBuffers;
+    mBuffers[bufferId] = std::move(tracker);
+
+    return res;
+}
+
+void Camera3StreamSplitter::onFrameAvailable(const BufferItem& /*item*/) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
 
     // Acquire and detach the buffer from the input
     BufferItem bufferItem;
-    status_t status = mConsumer->acquireBuffer(&bufferItem, /* presentWhen */ 0);
-    LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-            "acquiring buffer from input failed (%d)", status);
+    status_t res = mConsumer->acquireBuffer(&bufferItem, /* presentWhen */ 0);
+    if (res != NO_ERROR) {
+        SP_LOGE("%s: Acquiring buffer from input failed (%d)", __FUNCTION__, res);
+        mOnFrameAvailableRes.store(res);
+        return;
+    }
+    if (mBuffers.find(bufferItem.mGraphicBuffer->getId()) == mBuffers.end()) {
+        SP_LOGE("%s: Acquired buffer doesn't exist in attached buffer map",
+                __FUNCTION__);
+        mOnFrameAvailableRes.store(INVALID_OPERATION);
+        return;
+    }
 
-    ALOGV("acquired buffer %#" PRIx64 " from input",
-            bufferItem.mGraphicBuffer->getId());
+    SP_LOGV("acquired buffer %" PRId64 " from input at slot %d",
+            bufferItem.mGraphicBuffer->getId(), bufferItem.mSlot);
 
-    status = mConsumer->detachBuffer(bufferItem.mSlot);
-    LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-            "detaching buffer from input failed (%d)", status);
-
-    IGraphicBufferProducer::QueueBufferInput queueInput(
-            bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp,
-            bufferItem.mDataSpace, bufferItem.mCrop,
-            static_cast<int32_t>(bufferItem.mScalingMode),
-            bufferItem.mTransform, bufferItem.mFence);
+    res = mConsumer->detachBuffer(bufferItem.mSlot);
+    if (res != NO_ERROR) {
+        SP_LOGE("%s: detaching buffer from input failed (%d)", __FUNCTION__, res);
+        mOnFrameAvailableRes.store(res);
+        return;
+    }
 
     // Attach and queue the buffer to each of the outputs
-    std::vector<std::vector<size_t> >::iterator surfaces = mRequestedSurfaces.begin();
-    if (surfaces != mRequestedSurfaces.end()) {
+    BufferTracker& tracker = *(mBuffers[bufferItem.mGraphicBuffer->getId()]);
 
-        LOG_ALWAYS_FATAL_IF(surfaces->size() == 0,
-                "requested surface ids shouldn't be empty");
+    SP_LOGV("%s: BufferTracker for buffer %" PRId64 ", number of requests %zu",
+           __FUNCTION__, bufferItem.mGraphicBuffer->getId(), tracker.requestedSurfaces().size());
+    for (const auto id : tracker.requestedSurfaces()) {
 
-        // Initialize our reference count for this buffer
-        mBuffers[bufferItem.mGraphicBuffer->getId()] =
-                std::unique_ptr<BufferTracker>(
-                new BufferTracker(bufferItem.mGraphicBuffer, surfaces->size()));
+        LOG_ALWAYS_FATAL_IF(id >= mOutputs.size(),
+                "requested surface id exceeding max registered ids");
 
-        for (auto id : *surfaces) {
-
-            LOG_ALWAYS_FATAL_IF(id >= mOutputs.size(),
-                    "requested surface id exceeding max registered ids");
-
-            int slot = BufferItem::INVALID_BUFFER_SLOT;
-            status = mOutputs[id]->attachBuffer(&slot, bufferItem.mGraphicBuffer);
-            if (status == NO_INIT) {
-                // If we just discovered that this output has been abandoned, note
-                // that, decrement the reference count so that we still release this
-                // buffer eventually, and move on to the next output
-                onAbandonedLocked();
-                mBuffers[bufferItem.mGraphicBuffer->getId()]->
-                        decrementReferenceCountLocked();
-                continue;
-            } else if (status == WOULD_BLOCK) {
-                // If the output is async, attachBuffer may return WOULD_BLOCK
-                // indicating number of dequeued buffers has reached limit. In
-                // this case, simply decrement the reference count, and move on
-                // to the next output.
-                // TODO: Do we need to report BUFFER_ERROR for this result?
-                mBuffers[bufferItem.mGraphicBuffer->getId()]->
-                        decrementReferenceCountLocked();
-                continue;
-            } else if (status == TIMED_OUT) {
-                // If attachBuffer times out due to the value set by
-                // setDequeueTimeout, simply decrement the reference count, and
-                // move on to the next output.
-                // TODO: Do we need to report BUFFER_ERROR for this result?
-                mBuffers[bufferItem.mGraphicBuffer->getId()]->
-                        decrementReferenceCountLocked();
-                continue;
-            } else {
-                LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-                        "attaching buffer to output failed (%d)", status);
-            }
-
-            IGraphicBufferProducer::QueueBufferOutput queueOutput;
-            status = mOutputs[id]->queueBuffer(slot, queueInput, &queueOutput);
-            if (status == NO_INIT) {
-                // If we just discovered that this output has been abandoned, note
-                // that, increment the release count so that we still release this
-                // buffer eventually, and move on to the next output
-                onAbandonedLocked();
-                mBuffers[bufferItem.mGraphicBuffer->getId()]->
-                        decrementReferenceCountLocked();
-                continue;
-            } else {
-                LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-                        "queueing buffer to output failed (%d)", status);
-            }
-
-            // If the queued buffer replaces a pending buffer in the async
-            // queue, no onBufferReleased is called by the buffer queue.
-            // Proactively trigger the callback to avoid buffer loss.
-            if (queueOutput.bufferReplaced) {
-                onBufferReleasedByOutputLocked(mOutputs[id]);
-            }
-
-            ALOGV("queued buffer %#" PRIx64 " to output %p",
-                    bufferItem.mGraphicBuffer->getId(), mOutputs[id].get());
+        res = outputBufferLocked(mOutputs[id], bufferItem);
+        if (res != OK) {
+            SP_LOGE("%s: outputBufferLocked failed %d", __FUNCTION__, res);
+            mOnFrameAvailableRes.store(res);
+            // If we fail to send buffer to certain output, keep sending to
+            // other outputs.
+            continue;
         }
+    }
 
-        mRequestedSurfaces.erase(surfaces);
+    mOnFrameAvailableRes.store(res);
+}
+
+void Camera3StreamSplitter::decrementBufRefCountLocked(uint64_t id,
+        const sp<IGraphicBufferProducer>& from) {
+    ATRACE_CALL();
+    size_t referenceCount = mBuffers[id]->decrementReferenceCountLocked();
+
+    removeSlotForOutputLocked(from, mBuffers[id]->getBuffer());
+    if (referenceCount > 0) {
+        return;
+    }
+
+    // We no longer need to track the buffer now that it is being returned to the
+    // input. Note that this should happen before we unlock the mutex and call
+    // releaseBuffer, to avoid the case where the same bufferId is acquired in
+    // attachBufferToOutputs resulting in a new BufferTracker with same bufferId
+    // overwrites the current one.
+    std::unique_ptr<BufferTracker> tracker_ptr = std::move(mBuffers[id]);
+    mBuffers.erase(id);
+
+    // Attach and release the buffer back to the input
+    int consumerSlot = BufferItem::INVALID_BUFFER_SLOT;
+    status_t res = mConsumer->attachBuffer(&consumerSlot, tracker_ptr->getBuffer());
+    if (res != NO_ERROR) {
+        SP_LOGE("%s: attaching buffer to input failed (%d)", __FUNCTION__, res);
+        return;
+    }
+
+    // Temporarily unlock mutex to avoid circular lock:
+    // 1. This function holds splitter lock, calls releaseBuffer which triggers
+    // onBufferReleased in Camera3OutputStream. onBufferReleased waits on the
+    // OutputStream lock
+    // 2. Camera3SharedOutputStream::getBufferLocked calls
+    // attachBufferToOutputs, which holds the stream lock, and waits for the
+    // splitter lock.
+    sp<IGraphicBufferConsumer> consumer(mConsumer);
+    mMutex.unlock();
+    if (consumer != nullptr) {
+        res = consumer->releaseBuffer(consumerSlot, /* frameNumber */ 0,
+                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, tracker_ptr->getMergedFence());
+    } else {
+        SP_LOGE("%s: consumer has become null!", __FUNCTION__);
+    }
+    mMutex.lock();
+    // If the producer of this queue is disconnected, -22 error will occur
+    if (res != NO_ERROR) {
+        SP_LOGE("%s: releaseBuffer returns %d", __FUNCTION__, res);
     }
 }
 
@@ -347,73 +447,79 @@
 
 void Camera3StreamSplitter::onBufferReleasedByOutputLocked(
         const sp<IGraphicBufferProducer>& from) {
-
+    ATRACE_CALL();
     sp<GraphicBuffer> buffer;
     sp<Fence> fence;
-    status_t status = from->detachNextBuffer(&buffer, &fence);
-    if (status == NO_INIT) {
+    status_t res = from->detachNextBuffer(&buffer, &fence);
+    if (res == NO_INIT) {
         // If we just discovered that this output has been abandoned, note that,
         // but we can't do anything else, since buffer is invalid
         onAbandonedLocked();
         return;
+    } else if (res == NO_MEMORY) {
+        SP_LOGV("%s: No free buffers", __FUNCTION__);
+        return;
     } else {
-        LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-                "detaching buffer from output failed (%d)", status);
+        LOG_ALWAYS_FATAL_IF(res != NO_ERROR,
+                "detaching buffer from output failed (%d)", res);
     }
 
-    ALOGV("detached buffer %#" PRIx64 " from output %p",
-          buffer->getId(), from.get());
-
     BufferTracker& tracker = *(mBuffers[buffer->getId()]);
-
     // Merge the release fence of the incoming buffer so that the fence we send
     // back to the input includes all of the outputs' fences
-    tracker.mergeFence(fence);
+    if (fence != nullptr && fence->isValid()) {
+        tracker.mergeFence(fence);
+    }
+    SP_LOGV("detached buffer %" PRId64 " %p from output %p",
+            buffer->getId(), buffer.get(), from.get());
 
     // Check to see if this is the last outstanding reference to this buffer
-    size_t referenceCount = tracker.decrementReferenceCountLocked();
-    ALOGV("buffer %#" PRIx64 " reference count %zu", buffer->getId(),
-            referenceCount);
-    if (referenceCount > 0) {
-        return;
-    }
-
-    // If we've been abandoned, we can't return the buffer to the input, so just
-    // stop tracking it and move on
-    if (mIsAbandoned) {
-        mBuffers.erase(buffer->getId());
-        return;
-    }
-
-    // Attach and release the buffer back to the input
-    int consumerSlot = BufferItem::INVALID_BUFFER_SLOT;
-    status = mConsumer->attachBuffer(&consumerSlot, tracker.getBuffer());
-    LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-            "attaching buffer to input failed (%d)", status);
-
-    status = mConsumer->releaseBuffer(consumerSlot, /* frameNumber */ 0,
-            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, tracker.getMergedFence());
-    LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
-            "releasing buffer to input failed (%d)", status);
-
-    ALOGV("released buffer %#" PRIx64 " to input", buffer->getId());
-
-    // We no longer need to track the buffer once it has been returned to the
-    // input
-    mBuffers.erase(buffer->getId());
-
-    // Notify any waiting onFrameAvailable calls
-    --mOutstandingBuffers;
-    mReleaseCondition.signal();
+    decrementBufRefCountLocked(buffer->getId(), from);
 }
 
 void Camera3StreamSplitter::onAbandonedLocked() {
-    ALOGE("one of my outputs has abandoned me");
-    if (!mIsAbandoned && mConsumer != nullptr) {
-        mConsumer->consumerDisconnect();
+    // If this is called from binderDied callback, it means the app process
+    // holding the binder has died. CameraService will be notified of the binder
+    // death, and camera device will be closed, which in turn calls
+    // disconnect().
+    //
+    // If this is called from onBufferReleasedByOutput or onFrameAvailable, one
+    // consumer being abanoned shouldn't impact the other consumer. So we won't
+    // stop the buffer flow.
+    //
+    // In both cases, we don't need to do anything here.
+    SP_LOGV("One of my outputs has abandoned me");
+}
+
+int Camera3StreamSplitter::getSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
+        const sp<GraphicBuffer>& gb) {
+    auto& outputSlots = *mOutputSlots[gbp];
+
+    for (size_t i = 0; i < outputSlots.size(); i++) {
+        if (outputSlots[i] == gb) {
+            return (int)i;
+        }
     }
-    mIsAbandoned = true;
-    mReleaseCondition.broadcast();
+
+    SP_LOGE("%s: Cannot find slot for gb %p on output %p", __FUNCTION__, gb.get(),
+            gbp.get());
+    return BufferItem::INVALID_BUFFER_SLOT;
+}
+
+status_t Camera3StreamSplitter::removeSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
+        const sp<GraphicBuffer>& gb) {
+    auto& outputSlots = *mOutputSlots[gbp];
+
+    for (size_t i = 0; i < outputSlots.size(); i++) {
+        if (outputSlots[i] == gb) {
+           outputSlots[i].clear();
+           return NO_ERROR;
+        }
+    }
+
+    SP_LOGE("%s: Cannot find slot for gb %p on output %p", __FUNCTION__, gb.get(),
+            gbp.get());
+    return BAD_VALUE;
 }
 
 Camera3StreamSplitter::OutputListener::OutputListener(
@@ -422,6 +528,7 @@
       : mSplitter(splitter), mOutput(output) {}
 
 void Camera3StreamSplitter::OutputListener::onBufferReleased() {
+    ATRACE_CALL();
     sp<Camera3StreamSplitter> splitter = mSplitter.promote();
     sp<IGraphicBufferProducer> output = mOutput.promote();
     if (splitter != nullptr && output != nullptr) {
@@ -438,9 +545,9 @@
 }
 
 Camera3StreamSplitter::BufferTracker::BufferTracker(
-        const sp<GraphicBuffer>& buffer, size_t referenceCount)
-      : mBuffer(buffer), mMergedFence(Fence::NO_FENCE),
-        mReferenceCount(referenceCount) {}
+        const sp<GraphicBuffer>& buffer, const std::vector<size_t>& requestedSurfaces)
+      : mBuffer(buffer), mMergedFence(Fence::NO_FENCE), mRequestedSurfaces(requestedSurfaces),
+        mReferenceCount(requestedSurfaces.size()) {}
 
 void Camera3StreamSplitter::BufferTracker::mergeFence(const sp<Fence>& with) {
     mMergedFence = Fence::merge(String8("Camera3StreamSplitter"), mMergedFence, with);
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index 92371ff..cc623e0 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -26,6 +26,11 @@
 #include <utils/StrongPointer.h>
 #include <utils/Timers.h>
 
+#define SP_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
+#define SP_LOGI(x, ...) ALOGI("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
+#define SP_LOGW(x, ...) ALOGW("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
+#define SP_LOGE(x, ...) ALOGE("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
+
 namespace android {
 
 class GraphicBuffer;
@@ -47,8 +52,8 @@
     // Connect to the stream splitter by creating buffer queue and connecting it
     // with output surfaces.
     status_t connect(const std::vector<sp<Surface> >& surfaces,
-            uint32_t consumerUsage, size_t hal_max_buffers,
-            sp<Surface>& consumer);
+            uint32_t consumerUsage, size_t halMaxBuffers,
+            sp<Surface>* consumer);
 
     // addOutput adds an output BufferQueue to the splitter. The splitter
     // connects to outputQueue as a CPU producer, and any buffers queued
@@ -61,13 +66,22 @@
     // outputQueue has not been added to the splitter. BAD_VALUE is returned if
     // outputQueue is NULL. See IGraphicBufferProducer::connect for explanations
     // of other error codes.
-    status_t addOutput(const sp<Surface>& outputQueue, size_t hal_max_buffers);
+    status_t addOutput(const sp<Surface>& outputQueue);
 
-    // Request surfaces for a particular frame number. The requested surfaces
-    // are stored in a FIFO queue. And when the buffer becomes available from the
-    // input queue, the registered surfaces are used to decide which output is
-    // the buffer sent to.
-    status_t notifyRequestedSurfaces(const std::vector<size_t>& surfaces);
+    // Notification that the graphic buffer has been released to the input
+    // BufferQueue. The buffer should be reused by the camera device instead of
+    // queuing to the outputs.
+    status_t notifyBufferReleased(const sp<GraphicBuffer>& buffer);
+
+    // Attach a buffer to the specified outputs. This call reserves a buffer
+    // slot in the output queue.
+    status_t attachBufferToOutputs(ANativeWindowBuffer* anb,
+            const std::vector<size_t>& surface_ids);
+
+    // Get return value of onFrameAvailable to work around problem that
+    // onFrameAvailable is void. This function should be called by the producer
+    // right after calling queueBuffer().
+    status_t getOnFrameAvailableResult();
 
     // Disconnect the buffer queue from output surfaces.
     void disconnect();
@@ -115,6 +129,10 @@
     // acquire. This must be called with mMutex locked.
     void onAbandonedLocked();
 
+    // Decrement the buffer's reference count. Once the reference count becomes
+    // 0, return the buffer back to the input BufferQueue.
+    void decrementBufRefCountLocked(uint64_t id, const sp<IGraphicBufferProducer>& from);
+
     // This is a thin wrapper class that lets us determine which BufferQueue
     // the IProducerListener::onBufferReleased callback is associated with. We
     // create one of these per output BufferQueue, and then pass the producer
@@ -139,7 +157,8 @@
 
     class BufferTracker {
     public:
-        BufferTracker(const sp<GraphicBuffer>& buffer, size_t referenceCount);
+        BufferTracker(const sp<GraphicBuffer>& buffer,
+                const std::vector<size_t>& requestedSurfaces);
         ~BufferTracker() = default;
 
         const sp<GraphicBuffer>& getBuffer() const { return mBuffer; }
@@ -151,6 +170,8 @@
         // Only called while mMutex is held
         size_t decrementReferenceCountLocked();
 
+        const std::vector<size_t> requestedSurfaces() const { return mRequestedSurfaces; }
+
     private:
 
         // Disallow copying
@@ -159,39 +180,43 @@
 
         sp<GraphicBuffer> mBuffer; // One instance that holds this native handle
         sp<Fence> mMergedFence;
+
+        // Request surfaces for a particular buffer. And when the buffer becomes
+        // available from the input queue, the registered surfaces are used to decide
+        // which output is the buffer sent to.
+        std::vector<size_t> mRequestedSurfaces;
         size_t mReferenceCount;
     };
 
-    // A deferred output is an output being added to the splitter after
-    // connect() call, whereas a non deferred output is added within connect()
-    // call.
-    enum class OutputType { NonDeferred, Deferred };
-
     // Must be accessed through RefBase
     virtual ~Camera3StreamSplitter();
 
-    status_t addOutputLocked(const sp<Surface>& outputQueue,
-                             size_t hal_max_buffers, OutputType outputType);
+    status_t addOutputLocked(const sp<Surface>& outputQueue);
+
+    // Send a buffer to particular output, and increment the reference count
+    // of the buffer. If this output is abandoned, the buffer's reference count
+    // won't be incremented.
+    status_t outputBufferLocked(const sp<IGraphicBufferProducer>& output,
+            const BufferItem& bufferItem);
 
     // Get unique name for the buffer queue consumer
-    static String8 getUniqueConsumerName();
+    String8 getUniqueConsumerName();
 
-    // Max consumer side buffers for deferred surface. This will be used as a
-    // lower bound for overall consumer side max buffers.
-    static const int MAX_BUFFERS_DEFERRED_OUTPUT = 2;
-    int mMaxConsumerBuffers = MAX_BUFFERS_DEFERRED_OUTPUT;
+    // Helper function to get the BufferQueue slot where a particular buffer is attached to.
+    int getSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
+            const sp<GraphicBuffer>& gb);
+    // Helper function to remove the buffer from the BufferQueue slot
+    status_t removeSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
+            const sp<GraphicBuffer>& gb);
+
+
+    // Sum of max consumer buffers for all outputs
+    size_t mMaxConsumerBuffers = 0;
+    size_t mMaxHalBuffers = 0;
 
     static const nsecs_t kDequeueBufferTimeout   = s2ns(1); // 1 sec
 
-    // mIsAbandoned is set to true when an output dies. Once the Camera3StreamSplitter
-    // has been abandoned, it will continue to detach buffers from other
-    // outputs, but it will disconnect from the input and not attempt to
-    // communicate with it further.
-    bool mIsAbandoned = false;
-
     Mutex mMutex;
-    Condition mReleaseCondition;
-    int mOutstandingBuffers = 0;
 
     sp<IGraphicBufferProducer> mProducer;
     sp<IGraphicBufferConsumer> mConsumer;
@@ -199,14 +224,28 @@
     sp<Surface> mSurface;
 
     std::vector<sp<IGraphicBufferProducer> > mOutputs;
-    // Tracking which outputs should the buffer be attached and queued
-    // to for each input buffer.
-    std::vector<std::vector<size_t> > mRequestedSurfaces;
-
     // Map of GraphicBuffer IDs (GraphicBuffer::getId()) to buffer tracking
     // objects (which are mostly for counting how many outputs have released the
     // buffer, but also contain merged release fences).
     std::unordered_map<uint64_t, std::unique_ptr<BufferTracker> > mBuffers;
+
+    struct GBPHash {
+        std::size_t operator()(const sp<IGraphicBufferProducer>& producer) const {
+            return std::hash<IGraphicBufferProducer *>{}(producer.get());
+        }
+    };
+
+    std::unordered_map<sp<IGraphicBufferProducer>, sp<OutputListener>,
+            GBPHash> mNotifiers;
+
+    typedef std::vector<sp<GraphicBuffer>> OutputSlots;
+    std::unordered_map<sp<IGraphicBufferProducer>, std::unique_ptr<OutputSlots>,
+            GBPHash> mOutputSlots;
+
+    // Latest onFrameAvailable return value
+    std::atomic<status_t> mOnFrameAvailableRes{0};
+
+    String8 mConsumerName;
 };
 
 } // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
deleted file mode 100644
index ea138b7..0000000
--- a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Camera3-ZslStream"
-#define ATRACE_TAG ATRACE_TAG_CAMERA
-//#define LOG_NDEBUG 0
-
-#include <inttypes.h>
-
-#include <utils/Log.h>
-#include <utils/Trace.h>
-#include "Camera3ZslStream.h"
-
-typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem;
-
-namespace android {
-
-namespace camera3 {
-
-namespace {
-struct TimestampFinder : public RingBufferConsumer::RingBufferComparator {
-    typedef RingBufferConsumer::BufferInfo BufferInfo;
-
-    enum {
-        SELECT_I1 = -1,
-        SELECT_I2 = 1,
-        SELECT_NEITHER = 0,
-    };
-
-    explicit TimestampFinder(nsecs_t timestamp) : mTimestamp(timestamp) {}
-    ~TimestampFinder() {}
-
-    template <typename T>
-    static void swap(T& a, T& b) {
-        T tmp = a;
-        a = b;
-        b = tmp;
-    }
-
-    /**
-     * Try to find the best candidate for a ZSL buffer.
-     * Match priority from best to worst:
-     *  1) Timestamps match.
-     *  2) Timestamp is closest to the needle (and lower).
-     *  3) Timestamp is closest to the needle (and higher).
-     *
-     */
-    virtual int compare(const BufferInfo *i1,
-                        const BufferInfo *i2) const {
-        // Try to select non-null object first.
-        if (i1 == NULL) {
-            return SELECT_I2;
-        } else if (i2 == NULL) {
-            return SELECT_I1;
-        }
-
-        // Best result: timestamp is identical
-        if (i1->mTimestamp == mTimestamp) {
-            return SELECT_I1;
-        } else if (i2->mTimestamp == mTimestamp) {
-            return SELECT_I2;
-        }
-
-        const BufferInfo* infoPtrs[2] = {
-            i1,
-            i2
-        };
-        int infoSelectors[2] = {
-            SELECT_I1,
-            SELECT_I2
-        };
-
-        // Order i1,i2 so that always i1.timestamp < i2.timestamp
-        if (i1->mTimestamp > i2->mTimestamp) {
-            swap(infoPtrs[0], infoPtrs[1]);
-            swap(infoSelectors[0], infoSelectors[1]);
-        }
-
-        // Second best: closest (lower) timestamp
-        if (infoPtrs[1]->mTimestamp < mTimestamp) {
-            return infoSelectors[1];
-        } else if (infoPtrs[0]->mTimestamp < mTimestamp) {
-            return infoSelectors[0];
-        }
-
-        // Worst: closest (higher) timestamp
-        return infoSelectors[0];
-
-        /**
-         * The above cases should cover all the possibilities,
-         * and we get an 'empty' result only if the ring buffer
-         * was empty itself
-         */
-    }
-
-    const nsecs_t mTimestamp;
-}; // struct TimestampFinder
-} // namespace anonymous
-
-Camera3ZslStream::Camera3ZslStream(int id, uint32_t width, uint32_t height,
-        int bufferCount) :
-        Camera3OutputStream(id, CAMERA3_STREAM_BIDIRECTIONAL,
-                            width, height,
-                            HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
-                            HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0) {
-
-    sp<IGraphicBufferProducer> producer;
-    sp<IGraphicBufferConsumer> consumer;
-    BufferQueue::createBufferQueue(&producer, &consumer);
-    mProducer = new RingBufferConsumer(consumer, GRALLOC_USAGE_HW_CAMERA_ZSL, bufferCount);
-    mProducer->setName(String8("Camera2-ZslRingBufferConsumer"));
-    mConsumer = new Surface(producer);
-}
-
-Camera3ZslStream::~Camera3ZslStream() {
-}
-
-status_t Camera3ZslStream::getInputBufferLocked(camera3_stream_buffer *buffer) {
-    ATRACE_CALL();
-
-    status_t res;
-
-    // TODO: potentially register from inputBufferLocked
-    // this should be ok, registerBuffersLocked only calls getBuffer for now
-    // register in output mode instead of input mode for ZSL streams.
-    if (mState == STATE_IN_CONFIG || mState == STATE_IN_RECONFIG) {
-        ALOGE("%s: Stream %d: Buffer registration for input streams"
-              " not implemented (state %d)",
-              __FUNCTION__, mId, mState);
-        return INVALID_OPERATION;
-    }
-
-    if ((res = getBufferPreconditionCheckLocked()) != OK) {
-        return res;
-    }
-
-    ANativeWindowBuffer* anb;
-    int fenceFd;
-
-    assert(mProducer != 0);
-
-    sp<PinnedBufferItem> bufferItem;
-    {
-        List<sp<RingBufferConsumer::PinnedBufferItem> >::iterator it, end;
-        it = mInputBufferQueue.begin();
-        end = mInputBufferQueue.end();
-
-        // Need to call enqueueInputBufferByTimestamp as a prerequisite
-        if (it == end) {
-            ALOGE("%s: Stream %d: No input buffer was queued",
-                    __FUNCTION__, mId);
-            return INVALID_OPERATION;
-        }
-        bufferItem = *it;
-        mInputBufferQueue.erase(it);
-    }
-
-    anb = bufferItem->getBufferItem().mGraphicBuffer->getNativeBuffer();
-    assert(anb != NULL);
-    fenceFd = bufferItem->getBufferItem().mFence->dup();
-
-    /**
-     * FenceFD now owned by HAL except in case of error,
-     * in which case we reassign it to acquire_fence
-     */
-    handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
-                         /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/false);
-
-    mBuffersInFlight.push_back(bufferItem);
-
-    return OK;
-}
-
-status_t Camera3ZslStream::returnBufferCheckedLocked(
-            const camera3_stream_buffer &buffer,
-            nsecs_t timestamp,
-            bool output,
-            /*out*/
-            sp<Fence> *releaseFenceOut) {
-
-    if (output) {
-        // Output stream path
-        return Camera3OutputStream::returnBufferCheckedLocked(buffer,
-                                                              timestamp,
-                                                              output,
-                                                              releaseFenceOut);
-    }
-
-    /**
-     * Input stream path
-     */
-    bool bufferFound = false;
-    sp<PinnedBufferItem> bufferItem;
-    {
-        // Find the buffer we are returning
-        Vector<sp<PinnedBufferItem> >::iterator it, end;
-        for (it = mBuffersInFlight.begin(), end = mBuffersInFlight.end();
-             it != end;
-             ++it) {
-
-            const sp<PinnedBufferItem>& tmp = *it;
-            ANativeWindowBuffer *anb =
-                    tmp->getBufferItem().mGraphicBuffer->getNativeBuffer();
-            if (anb != NULL && &(anb->handle) == buffer.buffer) {
-                bufferFound = true;
-                bufferItem = tmp;
-                mBuffersInFlight.erase(it);
-                break;
-            }
-        }
-    }
-    if (!bufferFound) {
-        ALOGE("%s: Stream %d: Can't return buffer that wasn't sent to HAL",
-              __FUNCTION__, mId);
-        return INVALID_OPERATION;
-    }
-
-    int releaseFenceFd = buffer.release_fence;
-
-    if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR) {
-        if (buffer.release_fence != -1) {
-            ALOGE("%s: Stream %d: HAL should not set release_fence(%d) when "
-                  "there is an error", __FUNCTION__, mId, buffer.release_fence);
-            close(buffer.release_fence);
-        }
-
-        /**
-         * Reassign release fence as the acquire fence incase of error
-         */
-        releaseFenceFd = buffer.acquire_fence;
-    }
-
-    /**
-     * Unconditionally return buffer to the buffer queue.
-     * - Fwk takes over the release_fence ownership
-     */
-    sp<Fence> releaseFence = new Fence(releaseFenceFd);
-    bufferItem->getBufferItem().mFence = releaseFence;
-    bufferItem.clear(); // dropping last reference unpins buffer
-
-    *releaseFenceOut = releaseFence;
-
-    return OK;
-}
-
-status_t Camera3ZslStream::returnInputBufferLocked(
-        const camera3_stream_buffer &buffer) {
-    ATRACE_CALL();
-
-    status_t res = returnAnyBufferLocked(buffer, /*timestamp*/0,
-                                         /*output*/false);
-
-    return res;
-}
-
-void Camera3ZslStream::dump(int fd, const Vector<String16> &args) const {
-    (void) args;
-
-    String8 lines;
-    lines.appendFormat("    Stream[%d]: ZSL\n", mId);
-    write(fd, lines.string(), lines.size());
-
-    Camera3IOStreamBase::dump(fd, args);
-
-    lines = String8();
-    lines.appendFormat("      Input buffers pending: %zu, in flight %zu\n",
-            mInputBufferQueue.size(), mBuffersInFlight.size());
-    write(fd, lines.string(), lines.size());
-}
-
-status_t Camera3ZslStream::enqueueInputBufferByTimestamp(
-        nsecs_t timestamp,
-        nsecs_t* actualTimestamp) {
-
-    Mutex::Autolock l(mLock);
-
-    TimestampFinder timestampFinder = TimestampFinder(timestamp);
-
-    sp<RingBufferConsumer::PinnedBufferItem> pinnedBuffer =
-            mProducer->pinSelectedBuffer(timestampFinder,
-                                        /*waitForFence*/false);
-
-    if (pinnedBuffer == 0) {
-        ALOGE("%s: No ZSL buffers were available yet", __FUNCTION__);
-        return NO_BUFFER_AVAILABLE;
-    }
-
-    nsecs_t actual = pinnedBuffer->getBufferItem().mTimestamp;
-
-    if (actual != timestamp) {
-        // TODO: this is problematic, we'll end up with using wrong result for this pinned buffer.
-        ALOGW("%s: ZSL buffer candidate search didn't find an exact match --"
-              " requested timestamp = %" PRId64 ", actual timestamp = %" PRId64,
-              __FUNCTION__, timestamp, actual);
-    }
-
-    mInputBufferQueue.push_back(pinnedBuffer);
-
-    if (actualTimestamp != NULL) {
-        *actualTimestamp = actual;
-    }
-
-    return OK;
-}
-
-status_t Camera3ZslStream::clearInputRingBuffer(nsecs_t* latestTimestamp) {
-    Mutex::Autolock l(mLock);
-
-    return clearInputRingBufferLocked(latestTimestamp);
-}
-
-status_t Camera3ZslStream::clearInputRingBufferLocked(nsecs_t* latestTimestamp) {
-
-    if (latestTimestamp) {
-        *latestTimestamp = mProducer->getLatestTimestamp();
-    }
-    mInputBufferQueue.clear();
-
-    return mProducer->clear();
-}
-
-status_t Camera3ZslStream::disconnectLocked() {
-    clearInputRingBufferLocked(NULL);
-
-    return Camera3OutputStream::disconnectLocked();
-}
-
-status_t Camera3ZslStream::setTransform(int /*transform*/) {
-    ALOGV("%s: Not implemented", __FUNCTION__);
-    return INVALID_OPERATION;
-}
-
-}; // namespace camera3
-
-}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.h b/services/camera/libcameraservice/device3/Camera3ZslStream.h
deleted file mode 100644
index 12369cf..0000000
--- a/services/camera/libcameraservice/device3/Camera3ZslStream.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SERVERS_CAMERA3_ZSL_STREAM_H
-#define ANDROID_SERVERS_CAMERA3_ZSL_STREAM_H
-
-#include <utils/RefBase.h>
-#include <gui/Surface.h>
-#include <gui/RingBufferConsumer.h>
-
-#include "Camera3OutputStream.h"
-
-namespace android {
-
-namespace camera3 {
-
-/**
- * A class for managing a single opaque ZSL stream to/from the camera device.
- * This acts as a bidirectional stream at the HAL layer, caching and discarding
- * most output buffers, and when directed, pushes a buffer back to the HAL for
- * processing.
- */
-class Camera3ZslStream :
-        public Camera3OutputStream {
-  public:
-    /**
-     * Set up a ZSL stream of a given resolution. bufferCount is the number of buffers
-     * cached within the stream that can be retrieved for input.
-     */
-    Camera3ZslStream(int id, uint32_t width, uint32_t height, int bufferCount);
-    ~Camera3ZslStream();
-
-    virtual void     dump(int fd, const Vector<String16> &args) const;
-
-    enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE };
-
-    /**
-     * Locate a buffer matching this timestamp in the RingBufferConsumer,
-     * and mark it to be queued at the next getInputBufferLocked invocation.
-     *
-     * Errors: Returns NO_BUFFER_AVAILABLE if we could not find a match.
-     *
-     */
-    status_t enqueueInputBufferByTimestamp(nsecs_t timestamp,
-                                           nsecs_t* actualTimestamp);
-
-    /**
-     * Clears the buffers that can be used by enqueueInputBufferByTimestamp
-     * latestTimestamp will be filled with the largest timestamp of buffers
-     * being cleared, 0 if there is no buffer being clear.
-     */
-    status_t clearInputRingBuffer(nsecs_t* latestTimestamp);
-
-  protected:
-
-    /**
-     * Camera3OutputStreamInterface implementation
-     */
-    status_t setTransform(int transform);
-
-  private:
-
-    // Input buffers pending to be queued into HAL
-    List<sp<RingBufferConsumer::PinnedBufferItem> > mInputBufferQueue;
-    sp<RingBufferConsumer>                          mProducer;
-
-    // Input buffers in flight to HAL
-    Vector<sp<RingBufferConsumer::PinnedBufferItem> > mBuffersInFlight;
-
-    /**
-     * Camera3Stream interface
-     */
-
-    // getInputBuffer/returnInputBuffer operate the input stream side of the
-    // ZslStream.
-    virtual status_t getInputBufferLocked(camera3_stream_buffer *buffer);
-    virtual status_t returnInputBufferLocked(
-            const camera3_stream_buffer &buffer);
-
-    // Actual body to return either input or output buffers
-    virtual status_t returnBufferCheckedLocked(
-            const camera3_stream_buffer &buffer,
-            nsecs_t timestamp,
-            bool output,
-            /*out*/
-            sp<Fence> *releaseFenceOut);
-
-    // Disconnet the Camera3ZslStream specific bufferQueues.
-    virtual status_t disconnectLocked();
-
-    status_t clearInputRingBufferLocked(nsecs_t* latestTimestamp);
-
-}; // class Camera3ZslStream
-
-}; // namespace camera3
-
-}; // namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.h b/services/camera/libcameraservice/gui/RingBufferConsumer.h
index 28dc5d5..2bafe4a 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.h
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.h
@@ -19,18 +19,16 @@
 
 #include <gui/BufferItem.h>
 #include <gui/ConsumerBase.h>
+#include <gui/BufferQueue.h>
 
-#include <ui/GraphicBuffer.h>
-
-#include <utils/String8.h>
-#include <utils/Vector.h>
-#include <utils/threads.h>
 #include <utils/List.h>
 
 #define ANDROID_GRAPHICS_RINGBUFFERCONSUMER_JNI_ID "mRingBufferConsumer"
 
 namespace android {
 
+class String8;
+
 /**
  * The RingBufferConsumer maintains a ring buffer of BufferItem objects,
  * (which are 'acquired' as long as they are part of the ring buffer, and
diff --git a/services/camera/libcameraservice/utils/ClientManager.h b/services/camera/libcameraservice/utils/ClientManager.h
index 830c50b..d7135f1 100644
--- a/services/camera/libcameraservice/utils/ClientManager.h
+++ b/services/camera/libcameraservice/utils/ClientManager.h
@@ -31,6 +31,43 @@
 namespace android {
 namespace resource_policy {
 
+class ClientPriority {
+public:
+    ClientPriority(int32_t score, int32_t state) :
+        mScore(score), mState(state) {}
+
+    int32_t getScore() const { return mScore; }
+    int32_t getState() const { return mState; }
+
+    bool operator==(const ClientPriority& rhs) const {
+        return (this->mScore == rhs.mScore) && (this->mState == rhs.mState);
+    }
+
+    bool operator< (const ClientPriority& rhs)  const {
+        if (this->mScore == rhs.mScore) {
+            return this->mState < rhs.mState;
+        } else {
+            return this->mScore < rhs.mScore;
+        }
+    }
+
+    bool operator> (const ClientPriority& rhs) const {
+        return rhs < *this;
+    }
+
+    bool operator<=(const ClientPriority& rhs) const {
+        return !(*this > rhs);
+    }
+
+    bool operator>=(const ClientPriority& rhs) const {
+        return !(*this < rhs);
+    }
+
+private:
+        int32_t mScore;
+        int32_t mState;
+};
+
 // --------------------------------------------------------------------------------
 
 /**
@@ -45,9 +82,9 @@
 class ClientDescriptor final {
 public:
     ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost,
-            const std::set<KEY>& conflictingKeys, int32_t priority, int32_t ownerId);
+            const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state);
     ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost, std::set<KEY>&& conflictingKeys,
-            int32_t priority, int32_t ownerId);
+            int32_t score, int32_t ownerId, int32_t state);
 
     ~ClientDescriptor();
 
@@ -69,7 +106,7 @@
     /**
      * Return the priority for this descriptor.
      */
-    int32_t getPriority() const;
+    const ClientPriority &getPriority() const;
 
     /**
      * Return the owner ID for this descriptor.
@@ -89,7 +126,7 @@
     /**
      * Set the proirity for this descriptor.
      */
-    void setPriority(int32_t priority);
+    void setPriority(const ClientPriority& priority);
 
     // This class is ordered by key
     template<class K, class V>
@@ -100,7 +137,7 @@
     VALUE mValue;
     int32_t mCost;
     std::set<KEY> mConflicting;
-    int32_t mPriority;
+    ClientPriority mPriority;
     int32_t mOwnerId;
 }; // class ClientDescriptor
 
@@ -111,16 +148,17 @@
 
 template<class KEY, class VALUE>
 ClientDescriptor<KEY, VALUE>::ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost,
-        const std::set<KEY>& conflictingKeys, int32_t priority, int32_t ownerId) : mKey{key},
-        mValue{value}, mCost{cost}, mConflicting{conflictingKeys}, mPriority{priority},
+        const std::set<KEY>& conflictingKeys, int32_t score, int32_t ownerId, int32_t state) :
+        mKey{key}, mValue{value}, mCost{cost}, mConflicting{conflictingKeys},
+        mPriority(score, state),
         mOwnerId{ownerId} {}
 
 template<class KEY, class VALUE>
 ClientDescriptor<KEY, VALUE>::ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost,
-        std::set<KEY>&& conflictingKeys, int32_t priority, int32_t ownerId) :
+        std::set<KEY>&& conflictingKeys, int32_t score, int32_t ownerId, int32_t state) :
         mKey{std::forward<KEY>(key)}, mValue{std::forward<VALUE>(value)}, mCost{cost},
-        mConflicting{std::forward<std::set<KEY>>(conflictingKeys)}, mPriority{priority},
-        mOwnerId{ownerId} {}
+        mConflicting{std::forward<std::set<KEY>>(conflictingKeys)},
+        mPriority(score, state), mOwnerId{ownerId} {}
 
 template<class KEY, class VALUE>
 ClientDescriptor<KEY, VALUE>::~ClientDescriptor() {}
@@ -141,7 +179,7 @@
 }
 
 template<class KEY, class VALUE>
-int32_t ClientDescriptor<KEY, VALUE>::getPriority() const {
+const ClientPriority& ClientDescriptor<KEY, VALUE>::getPriority() const {
     return mPriority;
 }
 
@@ -165,7 +203,7 @@
 }
 
 template<class KEY, class VALUE>
-void ClientDescriptor<KEY, VALUE>::setPriority(int32_t priority) {
+void ClientDescriptor<KEY, VALUE>::setPriority(const ClientPriority& priority) {
     mPriority = priority;
 }
 
@@ -231,7 +269,7 @@
      * Given a map containing owner (pid) -> priority mappings, update the priority of each
      * ClientDescriptor with an owner in this mapping.
      */
-    void updatePriorities(const std::map<int32_t,int32_t>& ownerPriorityList);
+    void updatePriorities(const std::map<int32_t,ClientPriority>& ownerPriorityList);
 
     /**
      * Remove all ClientDescriptors.
@@ -383,17 +421,17 @@
 
     const KEY& key = client->getKey();
     int32_t cost = client->getCost();
-    int32_t priority = client->getPriority();
+    ClientPriority priority = client->getPriority();
     int32_t owner = client->getOwnerId();
 
     int64_t totalCost = getCurrentCostLocked() + cost;
 
     // Determine the MRU of the owners tied for having the highest priority
     int32_t highestPriorityOwner = owner;
-    int32_t highestPriority = priority;
+    ClientPriority highestPriority = priority;
     for (const auto& i : mClients) {
-        int32_t curPriority = i->getPriority();
-        if (curPriority >= highestPriority) {
+        ClientPriority curPriority = i->getPriority();
+        if (curPriority <= highestPriority) {
             highestPriority = curPriority;
             highestPriorityOwner = i->getOwnerId();
         }
@@ -408,7 +446,7 @@
     for (const auto& i : mClients) {
         const KEY& curKey = i->getKey();
         int32_t curCost = i->getCost();
-        int32_t curPriority = i->getPriority();
+        ClientPriority curPriority = i->getPriority();
         int32_t curOwner = i->getOwnerId();
 
         bool conflicting = (curKey == key || i->isConflicting(key) ||
@@ -417,13 +455,13 @@
         if (!returnIncompatibleClients) {
             // Find evicted clients
 
-            if (conflicting && curPriority > priority) {
+            if (conflicting && curPriority < priority) {
                 // Pre-existing conflicting client with higher priority exists
                 evictList.clear();
                 evictList.push_back(client);
                 return evictList;
             } else if (conflicting || ((totalCost > mMaxCost && curCost > 0) &&
-                    (curPriority <= priority) &&
+                    (curPriority >= priority) &&
                     !(highestPriorityOwner == owner && owner == curOwner))) {
                 // Add a pre-existing client to the eviction list if:
                 // - We are adding a client with higher priority that conflicts with this one.
@@ -437,7 +475,7 @@
         } else {
             // Find clients preventing the incoming client from being added
 
-            if (curPriority > priority && (conflicting || (totalCost > mMaxCost && curCost > 0))) {
+            if (curPriority < priority && (conflicting || (totalCost > mMaxCost && curCost > 0))) {
                 // Pre-existing conflicting client with higher priority exists
                 evictList.push_back(i);
             }
@@ -524,7 +562,7 @@
 
 template<class KEY, class VALUE, class LISTENER>
 void ClientManager<KEY, VALUE, LISTENER>::updatePriorities(
-        const std::map<int32_t,int32_t>& ownerPriorityList) {
+        const std::map<int32_t,ClientPriority>& ownerPriorityList) {
     Mutex::Autolock lock(mLock);
     for (auto& i : mClients) {
         auto j = ownerPriorityList.find(i->getOwnerId());
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index 4cbf737..8814cf2 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -3,7 +3,13 @@
 # service library
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := MediaCodecService.cpp
-LOCAL_SHARED_LIBRARIES := libmedia libbinder libutils liblog libstagefright_omx
+LOCAL_SHARED_LIBRARIES := \
+    libmedia \
+    libbinder \
+    libgui \
+    libutils \
+    liblog \
+    libstagefright_omx
 LOCAL_C_INCLUDES := \
     $(TOP)/frameworks/av/media/libstagefright \
     $(TOP)/frameworks/native/include/media/openmax
@@ -14,18 +20,46 @@
 
 # service executable
 include $(CLEAR_VARS)
-LOCAL_REQUIRED_MODULES_arm := mediacodec-seccomp.policy
-LOCAL_SRC_FILES := main_codecservice.cpp minijail/minijail.cpp
-LOCAL_SHARED_LIBRARIES := libmedia libmediacodecservice libbinder libutils \
-    liblog libminijail libcutils \
-    android.hardware.media.omx@1.0
+LOCAL_REQUIRED_MODULES_arm := mediacodec.policy
+LOCAL_SRC_FILES := main_codecservice.cpp
+LOCAL_SHARED_LIBRARIES := \
+    libmedia \
+    libmediacodecservice \
+    libbinder \
+    libutils \
+    libgui \
+    liblog \
+    libbase \
+    libavservices_minijail \
+    libcutils \
+    libhwbinder \
+    libhidltransport \
+    android.hardware.media.omx@1.0 \
+    android.hardware.media.omx@1.0-impl \
+    android.hidl.memory@1.0
 LOCAL_C_INCLUDES := \
     $(TOP)/frameworks/av/media/libstagefright \
+    $(TOP)/frameworks/av/media/libstagefright/include \
     $(TOP)/frameworks/native/include/media/openmax
-LOCAL_MODULE:= mediacodec
+LOCAL_MODULE := mediacodec
 LOCAL_32_BIT_ONLY := true
 LOCAL_INIT_RC := mediacodec.rc
 include $(BUILD_EXECUTABLE)
 
-include $(call all-makefiles-under, $(LOCAL_PATH))
+# service seccomp policy
+ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64))
+include $(CLEAR_VARS)
+LOCAL_MODULE := mediacodec.policy
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
+# mediacodec runs in 32-bit combatibility mode. For 64 bit architectures,
+# use the 32 bit policy
+ifdef TARGET_2ND_ARCH
+    LOCAL_SRC_FILES := seccomp_policy/mediacodec-$(TARGET_2ND_ARCH).policy
+else
+    LOCAL_SRC_FILES := seccomp_policy/mediacodec-$(TARGET_ARCH).policy
+endif
+include $(BUILD_PREBUILT)
+endif
 
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index f6cde85..ef305b4 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -15,49 +15,60 @@
 ** limitations under the License.
 */
 
-#define LOG_TAG "mediacodec"
-//#define LOG_NDEBUG 0
-
 #include <fcntl.h>
 #include <sys/prctl.h>
 #include <sys/wait.h>
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
-#include <utils/Log.h>
 #include <cutils/properties.h>
 
+#include <string>
+
+#include <android-base/logging.h>
+
 // from LOCAL_C_INCLUDES
 #include "MediaCodecService.h"
-#include "minijail/minijail.h"
+#include "minijail.h"
 
 #include <android/hardware/media/omx/1.0/IOmx.h>
+#include <hidl/HidlTransportSupport.h>
+#include <omx/hal/1.0/impl/Omx.h>
 
 using namespace android;
 
+// Must match location in Android.mk.
+static const char kSystemSeccompPolicyPath[] =
+        "/system/etc/seccomp_policy/mediacodec.policy";
+static const char kVendorSeccompPolicyPath[] =
+        "/vendor/etc/seccomp_policy/mediacodec.policy";
+
 int main(int argc __unused, char** argv)
 {
-    ALOGI("@@@ mediacodecservice starting");
+    LOG(INFO) << "mediacodecservice starting";
     signal(SIGPIPE, SIG_IGN);
-    MiniJail();
+    SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
 
     strcpy(argv[0], "media.codec");
-    sp<ProcessState> proc(ProcessState::self());
-    sp<IServiceManager> sm = defaultServiceManager();
-    MediaCodecService::instantiate();
 
-    // Treble
-    bool useTrebleOmx = bool(property_get_bool("debug.treble_omx", 0));
-    if (useTrebleOmx) {
+    ::android::hardware::configureRpcThreadpool(64, false);
+    sp<ProcessState> proc(ProcessState::self());
+
+    int32_t trebleOmx = property_get_int32("persist.media.treble_omx", -1);
+    if ((trebleOmx == 1) || ((trebleOmx == -1) &&
+            property_get_bool("persist.hal.binderization", 0))) {
         using namespace ::android::hardware::media::omx::V1_0;
-        sp<IOmx> omx = IOmx::getService(true);
+        sp<IOmx> omx = new implementation::Omx();
         if (omx == nullptr) {
-            ALOGE("Cannot create a Treble IOmx service.");
-        } else if (omx->registerAsService("default") != OK) {
-            ALOGE("Cannot register a Treble IOmx service.");
+            LOG(ERROR) << "Cannot create a Treble IOmx service.";
+        } else if (omx->registerAsService() != OK) {
+            LOG(ERROR) << "Cannot register a Treble IOmx service.";
         } else {
-            ALOGV("Treble IOmx service created.");
+            LOG(INFO) << "Treble IOmx service created.";
         }
+    } else {
+        MediaCodecService::instantiate();
+        LOG(INFO) << "Non-Treble IOMX service created.";
     }
 
     ProcessState::self()->startThreadPool();
diff --git a/services/mediacodec/minijail/Android.mk b/services/mediacodec/minijail/Android.mk
deleted file mode 100644
index de05bc3..0000000
--- a/services/mediacodec/minijail/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64))
-include $(CLEAR_VARS)
-LOCAL_MODULE := mediacodec-seccomp.policy
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
-
-# mediacodec runs in 32-bit combatibility mode. For 64 bit architectures,
-# use the 32 bit policy
-ifdef TARGET_2ND_ARCH
-    LOCAL_SRC_FILES := $(LOCAL_PATH)/seccomp_policy/mediacodec-seccomp-$(TARGET_2ND_ARCH).policy
-else
-    LOCAL_SRC_FILES := $(LOCAL_PATH)/seccomp_policy/mediacodec-seccomp-$(TARGET_ARCH).policy
-endif
-
-# allow device specific additions to the syscall whitelist
-LOCAL_SRC_FILES += $(wildcard $(foreach dir, $(BOARD_SECCOMP_POLICY), \
-                     $(dir)/mediacodec-seccomp.policy))
-
-include $(BUILD_SYSTEM)/base_rules.mk
-
-$(LOCAL_BUILT_MODULE): $(LOCAL_SRC_FILES)
-	@mkdir -p $(dir $@)
-	$(hide) cat > $@ $^
-
-endif
diff --git a/services/mediacodec/minijail/minijail.cpp b/services/mediacodec/minijail/minijail.cpp
deleted file mode 100644
index 463f161..0000000
--- a/services/mediacodec/minijail/minijail.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-**
-** 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_TAG "minijail"
-
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include <libminijail.h>
-
-#include "minijail.h"
-
-namespace android {
-
-/* Must match location in Android.mk */
-static const char kSeccompFilePath[] = "/system/etc/seccomp_policy/mediacodec-seccomp.policy";
-
-int MiniJail()
-{
-    /* no seccomp policy for this architecture */
-    if (access(kSeccompFilePath, R_OK) == -1) {
-        ALOGW("No seccomp filter defined for this architecture.");
-        return 0;
-    }
-
-    struct minijail *jail = minijail_new();
-    if (jail == NULL) {
-        ALOGW("Failed to create minijail.");
-        return -1;
-    }
-
-    minijail_no_new_privs(jail);
-    minijail_log_seccomp_filter_failures(jail);
-    minijail_use_seccomp_filter(jail);
-    minijail_parse_seccomp_filters(jail, kSeccompFilePath);
-    minijail_enter(jail);
-    minijail_destroy(jail);
-    return 0;
-}
-}
diff --git a/services/mediacodec/minijail/minijail.h b/services/mediacodec/minijail/minijail.h
deleted file mode 100644
index ae01470..0000000
--- a/services/mediacodec/minijail/minijail.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-**
-** 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.
-*/
-
-namespace android {
-int MiniJail();
-}
diff --git a/services/mediacodec/minijail/seccomp_policy/mediacodec-seccomp-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
similarity index 98%
rename from services/mediacodec/minijail/seccomp_policy/mediacodec-seccomp-arm.policy
rename to services/mediacodec/seccomp_policy/mediacodec-arm.policy
index b7603bc..a8f2ca9 100644
--- a/services/mediacodec/minijail/seccomp_policy/mediacodec-seccomp-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
@@ -50,6 +50,7 @@
 sched_setscheduler: 1
 fstatat64: 1
 ugetrlimit: 1
+getdents64: 1
 
 # for attaching to debuggerd on process crash
 sigaction: 1
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
index 2bf2201..87fddd4 100644
--- a/services/mediadrm/Android.mk
+++ b/services/mediadrm/Android.mk
@@ -17,6 +17,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
+    MediaCasService.cpp \
     MediaDrmService.cpp \
     main_mediadrmserver.cpp
 
@@ -25,7 +26,7 @@
     liblog \
     libmediadrm \
     libutils
-ifeq ($(ENABLE_TREBLE), true)
+ifneq ($(DISABLE_TREBLE_DRM), true)
 LOCAL_SHARED_LIBRARIES += \
     libhidlbase \
     libhidlmemory \
@@ -34,8 +35,8 @@
 endif
 
 LOCAL_CFLAGS += -Wall -Wextra -Werror
-ifeq ($(ENABLE_TREBLE), true)
-LOCAL_CFLAGS += -DENABLE_TREBLE=1
+ifeq ($(DISABLE_TREBLE_DRM), true)
+LOCAL_CFLAGS += -DDISABLE_TREBLE_DRM=1
 endif
 
 LOCAL_MODULE:= mediadrmserver
diff --git a/services/mediadrm/FactoryLoader.h b/services/mediadrm/FactoryLoader.h
new file mode 100644
index 0000000..1e03e9b
--- /dev/null
+++ b/services/mediadrm/FactoryLoader.h
@@ -0,0 +1,220 @@
+/*
+ * 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 MEDIA_CAS_LOADER_H_
+#define MEDIA_CAS_LOADER_H_
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <media/SharedLibrary.h>
+#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
+
+namespace android {
+using namespace std;
+using namespace media;
+using namespace MediaCas;
+
+template <class T>
+class FactoryLoader {
+public:
+    FactoryLoader(const char *name) :
+        mFactory(NULL), mCreateFactoryFuncName(name) {}
+
+    virtual ~FactoryLoader() { closeFactory(); }
+
+    bool findFactoryForScheme(
+            int32_t CA_system_id,
+            sp<SharedLibrary> *library = NULL,
+            T** factory = NULL);
+
+    bool enumeratePlugins(vector<ParcelableCasPluginDescriptor>* results);
+
+private:
+    typedef T*(*CreateFactoryFunc)();
+
+    Mutex mMapLock;
+    T* mFactory;
+    const char *mCreateFactoryFuncName;
+    sp<SharedLibrary> mLibrary;
+    KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
+    KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
+
+    bool loadFactoryForSchemeFromPath(
+            const String8 &path,
+            int32_t CA_system_id,
+            sp<SharedLibrary> *library,
+            T** factory);
+
+    bool queryPluginsFromPath(
+            const String8 &path,
+            vector<ParcelableCasPluginDescriptor>* results);
+
+    bool openFactory(const String8 &path);
+    void closeFactory();
+};
+
+template <class T>
+bool FactoryLoader<T>::findFactoryForScheme(
+        int32_t CA_system_id, sp<SharedLibrary> *library, T** factory) {
+    if (library != NULL) {
+        library->clear();
+    }
+    if (factory != NULL) {
+        *factory = NULL;
+    }
+
+    Mutex::Autolock autoLock(mMapLock);
+
+    // first check cache
+    ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
+    if (index >= 0) {
+        return loadFactoryForSchemeFromPath(
+                mCASystemIdToLibraryPathMap[index],
+                CA_system_id, library, factory);
+    }
+
+    // no luck, have to search
+    String8 dirPath("/vendor/lib/mediacas");
+    DIR* pDir = opendir(dirPath.string());
+
+    if (pDir == NULL) {
+        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        return false;
+    }
+
+    struct dirent* pEntry;
+    while ((pEntry = readdir(pDir))) {
+        String8 pluginPath = dirPath + "/" + pEntry->d_name;
+        if (pluginPath.getPathExtension() == ".so") {
+            if (loadFactoryForSchemeFromPath(
+                    pluginPath, CA_system_id, library, factory)) {
+                mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
+                closedir(pDir);
+
+                return true;
+            }
+        }
+    }
+
+    closedir(pDir);
+
+    ALOGE("Failed to find plugin");
+    return false;
+}
+
+template <class T>
+bool FactoryLoader<T>::enumeratePlugins(
+        vector<ParcelableCasPluginDescriptor>* results) {
+    ALOGI("enumeratePlugins");
+
+    results->clear();
+
+    String8 dirPath("/vendor/lib/mediacas");
+    DIR* pDir = opendir(dirPath.string());
+
+    if (pDir == NULL) {
+        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        return false;
+    }
+
+    Mutex::Autolock autoLock(mMapLock);
+
+    struct dirent* pEntry;
+    while ((pEntry = readdir(pDir))) {
+        String8 pluginPath = dirPath + "/" + pEntry->d_name;
+        if (pluginPath.getPathExtension() == ".so") {
+            queryPluginsFromPath(pluginPath, results);
+        }
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::loadFactoryForSchemeFromPath(
+        const String8 &path, int32_t CA_system_id,
+        sp<SharedLibrary> *library, T** factory) {
+    closeFactory();
+
+    if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
+        closeFactory();
+        return false;
+    }
+
+    if (library != NULL) {
+        *library = mLibrary;
+    }
+    if (factory != NULL) {
+        *factory = mFactory;
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::queryPluginsFromPath(
+        const String8 &path, vector<ParcelableCasPluginDescriptor>* results) {
+    closeFactory();
+
+    vector<CasPluginDescriptor> descriptors;
+    if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
+        closeFactory();
+        return false;
+    }
+
+    for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
+        results->push_back(ParcelableCasPluginDescriptor(
+                it->CA_system_id, it->name));
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::openFactory(const String8 &path) {
+    // get strong pointer to open shared library
+    ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
+    if (index >= 0) {
+        mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
+    } else {
+        index = mLibraryPathToOpenLibraryMap.add(path, NULL);
+    }
+
+    if (!mLibrary.get()) {
+        mLibrary = new SharedLibrary(path);
+        if (!*mLibrary) {
+            return false;
+        }
+
+        mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
+    }
+
+    CreateFactoryFunc createFactory =
+        (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
+    if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
+        return false;
+    }
+    return true;
+}
+
+template <class T>
+void FactoryLoader<T>::closeFactory() {
+    delete mFactory;
+    mFactory = NULL;
+    mLibrary.clear();
+}
+
+} // namespace android
+
+#endif // MEDIA_CAS_LOADER_H_
diff --git a/services/mediadrm/MediaCasService.cpp b/services/mediadrm/MediaCasService.cpp
new file mode 100644
index 0000000..c111283
--- /dev/null
+++ b/services/mediadrm/MediaCasService.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "MediaCasService"
+
+#include <binder/IServiceManager.h>
+#include <media/cas/CasAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <media/CasImpl.h>
+#include <media/DescramblerImpl.h>
+#include <utils/Log.h>
+#include <utils/List.h>
+#include "MediaCasService.h"
+#include <android/media/ICasListener.h>
+
+namespace android {
+
+//static
+void MediaCasService::instantiate() {
+    defaultServiceManager()->addService(
+            String16("media.cas"), new MediaCasService());
+}
+
+MediaCasService::MediaCasService() :
+    mCasLoader(new FactoryLoader<CasFactory>("createCasFactory")),
+    mDescramblerLoader(new FactoryLoader<DescramblerFactory>(
+            "createDescramblerFactory")) {
+}
+
+MediaCasService::~MediaCasService() {
+    delete mCasLoader;
+    delete mDescramblerLoader;
+}
+
+Status MediaCasService::enumeratePlugins(
+        vector<ParcelableCasPluginDescriptor>* results) {
+    ALOGV("enumeratePlugins");
+
+    mCasLoader->enumeratePlugins(results);
+
+    return Status::ok();
+}
+
+Status MediaCasService::isSystemIdSupported(
+        int32_t CA_system_id, bool* result) {
+    ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id);
+
+    *result = mCasLoader->findFactoryForScheme(CA_system_id);
+
+    return Status::ok();
+}
+
+Status MediaCasService::createPlugin(
+        int32_t CA_system_id,
+        const sp<ICasListener> &listener,
+        sp<ICas>* result) {
+    ALOGV("createPlugin: CA_system_id=%d", CA_system_id);
+
+    result->clear();
+
+    CasFactory *factory;
+    sp<SharedLibrary> library;
+    if (mCasLoader->findFactoryForScheme(CA_system_id, &library, &factory)) {
+        CasPlugin *plugin = NULL;
+        sp<CasImpl> casImpl = new CasImpl(listener);
+        if (factory->createPlugin(CA_system_id, (uint64_t)casImpl.get(),
+                &CasImpl::OnEvent, &plugin) == OK && plugin != NULL) {
+            casImpl->init(library, plugin);
+            *result = casImpl;
+        }
+    }
+
+    return Status::ok();
+}
+
+Status MediaCasService::isDescramblerSupported(
+        int32_t CA_system_id, bool* result) {
+    ALOGV("isDescramblerSupported: CA_system_id=%d", CA_system_id);
+
+    *result = mDescramblerLoader->findFactoryForScheme(CA_system_id);
+
+    return Status::ok();
+}
+
+Status MediaCasService::createDescrambler(
+        int32_t CA_system_id, sp<IDescrambler>* result) {
+    ALOGV("createDescrambler: CA_system_id=%d", CA_system_id);
+
+    result->clear();
+
+    DescramblerFactory *factory;
+    sp<SharedLibrary> library;
+    if (mDescramblerLoader->findFactoryForScheme(
+            CA_system_id, &library, &factory)) {
+        DescramblerPlugin *plugin = NULL;
+        if (factory->createPlugin(CA_system_id, &plugin) == OK
+                && plugin != NULL) {
+            *result = new DescramblerImpl(library, plugin);
+        }
+    }
+
+    return Status::ok();
+}
+
+} // namespace android
diff --git a/services/mediadrm/MediaCasService.h b/services/mediadrm/MediaCasService.h
new file mode 100644
index 0000000..cb828f2
--- /dev/null
+++ b/services/mediadrm/MediaCasService.h
@@ -0,0 +1,60 @@
+/*
+ * 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 MEDIA_CAS_SERVICE_H_
+#define MEDIA_CAS_SERVICE_H_
+
+#include <android/media/BnMediaCasService.h>
+
+#include "FactoryLoader.h"
+
+namespace android {
+using binder::Status;
+struct CasFactory;
+struct DescramblerFactory;
+
+class MediaCasService : public BnMediaCasService {
+public:
+    static void instantiate();
+
+    virtual Status enumeratePlugins(
+            vector<ParcelableCasPluginDescriptor>* results) override;
+
+    virtual Status isSystemIdSupported(
+            int32_t CA_system_id, bool* result) override;
+
+    virtual Status createPlugin(
+            int32_t CA_system_id,
+            const sp<ICasListener> &listener,
+            sp<ICas>* result) override;
+
+    virtual Status isDescramblerSupported(
+            int32_t CA_system_id, bool* result) override;
+
+    virtual Status createDescrambler(
+            int32_t CA_system_id, sp<IDescrambler>* result) override;
+
+private:
+    FactoryLoader<CasFactory> *mCasLoader;
+    FactoryLoader<DescramblerFactory> *mDescramblerLoader;
+
+    MediaCasService();
+    virtual ~MediaCasService();
+};
+
+} // namespace android
+
+#endif // MEDIA_CAS_SERVICE_H_
diff --git a/services/mediadrm/MediaDrmService.cpp b/services/mediadrm/MediaDrmService.cpp
index e579dd8..b9ec347 100644
--- a/services/mediadrm/MediaDrmService.cpp
+++ b/services/mediadrm/MediaDrmService.cpp
@@ -24,12 +24,12 @@
 #include <binder/IServiceManager.h>
 #include <utils/Log.h>
 
-#ifdef ENABLE_TREBLE
-#include <media/CryptoHal.h>
-#include <media/DrmHal.h>
-#else
+#ifdef DISABLE_TREBLE_DRM
 #include <media/Crypto.h>
 #include <media/Drm.h>
+#else
+#include <media/CryptoHal.h>
+#include <media/DrmHal.h>
 #endif
 
 namespace android {
@@ -40,18 +40,18 @@
 }
 
 sp<ICrypto> MediaDrmService::makeCrypto() {
-#ifdef ENABLE_TREBLE
-    return new CryptoHal;
-#else
+#ifdef DISABLE_TREBLE_DRM
     return new Crypto;
+#else
+    return new CryptoHal;
 #endif
 }
 
 sp<IDrm> MediaDrmService::makeDrm() {
-#ifdef ENABLE_TREBLE
-    return new DrmHal;
-#else
+#ifdef DISABLE_TREBLE_DRM
     return new Drm;
+#else
+    return new DrmHal;
 #endif
 }
 
diff --git a/services/mediadrm/main_mediadrmserver.cpp b/services/mediadrm/main_mediadrmserver.cpp
index b767b8c..b685ae0 100644
--- a/services/mediadrm/main_mediadrmserver.cpp
+++ b/services/mediadrm/main_mediadrmserver.cpp
@@ -27,6 +27,7 @@
 #include <cutils/properties.h>
 #include <utils/Log.h>
 #include "MediaDrmService.h"
+#include "MediaCasService.h"
 
 using namespace android;
 
@@ -38,6 +39,7 @@
     sp<IServiceManager> sm = defaultServiceManager();
     ALOGI("ServiceManager: %p", sm.get());
     MediaDrmService::instantiate();
+    MediaCasService::instantiate();
     ProcessState::self()->startThreadPool();
     IPCThreadState::self()->joinThreadPool();
 }
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
index 4e337a0..1ebb7ff 100644
--- a/services/mediaextractor/Android.mk
+++ b/services/mediaextractor/Android.mk
@@ -11,16 +11,24 @@
 # service executable
 include $(CLEAR_VARS)
 # seccomp filters are defined for the following architectures:
-LOCAL_REQUIRED_MODULES_arm := mediaextractor-seccomp.policy
-LOCAL_REQUIRED_MODULES_arm64 := mediaextractor-seccomp.policy
-LOCAL_REQUIRED_MODULES_x86 := mediaextractor-seccomp.policy
-# TODO add seccomp filter for x86_64.
-LOCAL_SRC_FILES := main_extractorservice.cpp minijail/minijail.cpp
-LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libbinder libutils liblog libicuuc libminijail
+LOCAL_REQUIRED_MODULES_arm := mediaextractor.policy
+LOCAL_REQUIRED_MODULES_arm64 := mediaextractor.policy
+LOCAL_REQUIRED_MODULES_x86 := mediaextractor.policy
+LOCAL_SRC_FILES := main_extractorservice.cpp
+LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libbinder libutils \
+    liblog libbase libicuuc libavservices_minijail
 LOCAL_STATIC_LIBRARIES := libicuandroid_utils
 LOCAL_MODULE:= mediaextractor
 LOCAL_INIT_RC := mediaextractor.rc
 LOCAL_C_INCLUDES := frameworks/av/media/libmedia
 include $(BUILD_EXECUTABLE)
 
-include $(call all-makefiles-under, $(LOCAL_PATH))
+# service seccomp filter
+ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64 x86))
+include $(CLEAR_VARS)
+LOCAL_MODULE := mediaextractor.policy
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
+LOCAL_SRC_FILES := seccomp_policy/mediaextractor-$(TARGET_ARCH).policy
+include $(BUILD_PREBUILT)
+endif
diff --git a/services/mediaextractor/main_extractorservice.cpp b/services/mediaextractor/main_extractorservice.cpp
index 245489e..9bc69c4 100644
--- a/services/mediaextractor/main_extractorservice.cpp
+++ b/services/mediaextractor/main_extractorservice.cpp
@@ -15,25 +15,30 @@
 ** limitations under the License.
 */
 
-#define LOG_TAG "mediaextractor"
-//#define LOG_NDEBUG 0
-
 #include <fcntl.h>
 #include <sys/prctl.h>
 #include <sys/wait.h>
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
-#include <utils/Log.h>
+
+#include <string>
+
+#include <android-base/logging.h>
 
 // from LOCAL_C_INCLUDES
 #include "IcuUtils.h"
 #include "MediaExtractorService.h"
 #include "MediaUtils.h"
-#include "minijail/minijail.h"
+#include "minijail.h"
 
 using namespace android;
 
+static const char kSystemSeccompPolicyPath[] =
+        "/system/etc/seccomp_policy/mediaextractor.policy";
+static const char kVendorSeccompPolicyPath[] =
+        "/vendor/etc/seccomp_policy/mediaextractor.policy";
+
 int main(int argc __unused, char** argv)
 {
     limitProcessMemory(
@@ -42,7 +47,7 @@
         20 /* upper limit as percentage of physical RAM */);
 
     signal(SIGPIPE, SIG_IGN);
-    MiniJail();
+    SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
 
     InitializeIcuOrDie();
 
diff --git a/services/mediaextractor/minijail/Android.mk b/services/mediaextractor/minijail/Android.mk
deleted file mode 100644
index 6b01e77..0000000
--- a/services/mediaextractor/minijail/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# TODO add filter for x86_64
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64 x86))
-include $(CLEAR_VARS)
-LOCAL_MODULE := mediaextractor-seccomp.policy
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
-LOCAL_SRC_FILES := $(LOCAL_PATH)/seccomp_policy/mediaextractor-seccomp-$(TARGET_ARCH).policy
-
-# allow device specific additions to the syscall whitelist
-LOCAL_SRC_FILES += $(wildcard $(foreach dir, $(BOARD_SECCOMP_POLICY), \
-                     $(dir)/mediaextractor-seccomp.policy))
-
-include $(BUILD_SYSTEM)/base_rules.mk
-
-$(LOCAL_BUILT_MODULE): $(LOCAL_SRC_FILES)
-	@mkdir -p $(dir $@)
-	$(hide) cat > $@ $^
-
-endif
diff --git a/services/mediaextractor/minijail/minijail.cpp b/services/mediaextractor/minijail/minijail.cpp
deleted file mode 100644
index c44d00d..0000000
--- a/services/mediaextractor/minijail/minijail.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-**
-** Copyright 2015, 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 "minijail"
-
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include <libminijail.h>
-
-#include "minijail.h"
-
-namespace android {
-
-/* Must match location in Android.mk */
-static const char kSeccompFilePath[] = "/system/etc/seccomp_policy/mediaextractor-seccomp.policy";
-
-int MiniJail()
-{
-    /* no seccomp policy for this architecture */
-    if (access(kSeccompFilePath, R_OK) == -1) {
-        ALOGW("No seccomp filter defined for this architecture.");
-        return 0;
-    }
-
-    struct minijail *jail = minijail_new();
-    if (jail == NULL) {
-        ALOGW("Failed to create minijail.");
-        return -1;
-    }
-
-    minijail_no_new_privs(jail);
-    minijail_log_seccomp_filter_failures(jail);
-    minijail_use_seccomp_filter(jail);
-    minijail_parse_seccomp_filters(jail, kSeccompFilePath);
-    minijail_enter(jail);
-    minijail_destroy(jail);
-    return 0;
-}
-}
diff --git a/services/mediaextractor/minijail/minijail.h b/services/mediaextractor/minijail/minijail.h
deleted file mode 100644
index 6ea4487..0000000
--- a/services/mediaextractor/minijail/minijail.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-**
-** Copyright 2015, 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.
-*/
-
-namespace android {
-int MiniJail();
-}
diff --git a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
similarity index 100%
rename from services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy
rename to services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
diff --git a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
similarity index 100%
rename from services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm64.policy
rename to services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
diff --git a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
similarity index 100%
rename from services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy
rename to services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index ab2f925..4c81436 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -26,7 +26,7 @@
 
 namespace android {
 
-static const char kDeadlockedString[] = "MediaLogService may be deadlocked\n";
+// static const char kDeadlockedString[] = "MediaLogService may be deadlocked\n";
 
 void MediaLogService::registerWriter(const sp<IMemory>& shared, size_t size, const char *name)
 {
@@ -36,9 +36,10 @@
         return;
     }
     sp<NBLog::Reader> reader(new NBLog::Reader(shared, size));
-    NamedReader namedReader(reader, name);
+    NBLog::NamedReader namedReader(reader, name);
     Mutex::Autolock _l(mLock);
     mNamedReaders.add(namedReader);
+    mMerger.addReader(namedReader);
 }
 
 void MediaLogService::unregisterWriter(const sp<IMemory>& shared)
@@ -81,7 +82,8 @@
         return NO_ERROR;
     }
 
-    Vector<NamedReader> namedReaders;
+#if 0
+    Vector<NBLog::NamedReader> namedReaders;
     {
         bool locked = dumpTryLock(mLock);
 
@@ -95,19 +97,23 @@
             }
             return NO_ERROR;
         }
-        namedReaders = mNamedReaders;
+            // namedReaders = mNamedReaders;
+            // for (size_t i = 0; i < namedReaders.size(); i++) {
+            //     const NBLog::NamedReader& namedReader = namedReaders[i];
+            //     if (fd >= 0) {
+            //         dprintf(fd, "\n%s:\n", namedReader.name());
+            //     } else {
+            //         ALOGI("%s:", namedReader.name());
+            //     }
+            //     namedReader.reader()->dump(fd, 0 /*indent*/);
+            // }
+
         mLock.unlock();
     }
+#endif
 
-    for (size_t i = 0; i < namedReaders.size(); i++) {
-        const NamedReader& namedReader = namedReaders[i];
-        if (fd >= 0) {
-            dprintf(fd, "\n%s:\n", namedReader.name());
-        } else {
-            ALOGI("%s:", namedReader.name());
-        }
-        namedReader.reader()->dump(fd, 0 /*indent*/);
-    }
+    mMerger.merge();
+    mMergeReader.dump(fd);
     return NO_ERROR;
 }
 
diff --git a/services/medialog/MediaLogService.h b/services/medialog/MediaLogService.h
index c9bf2eb..e934844 100644
--- a/services/medialog/MediaLogService.h
+++ b/services/medialog/MediaLogService.h
@@ -27,8 +27,13 @@
 {
     friend class BinderService<MediaLogService>;    // for MediaLogService()
 public:
-    MediaLogService() : BnMediaLogService() { }
-    virtual ~MediaLogService() { }
+    MediaLogService() :
+        BnMediaLogService(),
+        mMergerShared((NBLog::Shared*) malloc(NBLog::Timeline::sharedSize(kMergeBufferSize))),
+        mMerger(mMergerShared, kMergeBufferSize),
+        mMergeReader(mMergerShared, kMergeBufferSize, mMerger)
+    {ALOGI("Nico creating MergeReader");}
+    virtual ~MediaLogService() { free(mMergerShared); }
     virtual void onFirstRef() { }
 
     static const char*  getServiceName() { return "media.log"; }
@@ -47,23 +52,16 @@
     // Internal dump
     static const int kDumpLockRetries = 50;
     static const int kDumpLockSleepUs = 20000;
+    static const size_t kMergeBufferSize = 16 * 1024; // TODO determine good value for this
     static bool dumpTryLock(Mutex& mutex);
 
     Mutex               mLock;
-    class NamedReader {
-    public:
-        NamedReader() : mReader(0) { mName[0] = '\0'; } // for Vector
-        NamedReader(const sp<NBLog::Reader>& reader, const char *name) : mReader(reader)
-            { strlcpy(mName, name, sizeof(mName)); }
-        ~NamedReader() { }
-        const sp<NBLog::Reader>&  reader() const { return mReader; }
-        const char*               name() const { return mName; }
-    private:
-        sp<NBLog::Reader>   mReader;
-        static const size_t kMaxName = 32;
-        char                mName[kMaxName];
-    };
-    Vector<NamedReader> mNamedReaders;
+
+    Vector<NBLog::NamedReader> mNamedReaders;
+
+    NBLog::Shared *mMergerShared;
+    NBLog::Merger mMerger;
+    NBLog::MergeReader mMergeReader;
 };
 
 }   // namespace android
diff --git a/services/minijail/Android.mk b/services/minijail/Android.mk
new file mode 100644
index 0000000..3e63f97
--- /dev/null
+++ b/services/minijail/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH := $(call my-dir)
+
+# Small library for media.extractor and media.codec sandboxing.
+include $(CLEAR_VARS)
+LOCAL_MODULE := libavservices_minijail
+LOCAL_SRC_FILES := minijail.cpp
+LOCAL_SHARED_LIBRARIES := libbase libminijail
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_SHARED_LIBRARY)
+
+
+# Unit tests.
+include $(CLEAR_VARS)
+LOCAL_MODULE := libavservices_minijail_unittest
+LOCAL_SRC_FILES := minijail.cpp av_services_minijail_unittest.cpp
+LOCAL_SHARED_LIBRARIES := libbase libminijail
+include $(BUILD_NATIVE_TEST)
diff --git a/services/minijail/av_services_minijail_unittest.cpp b/services/minijail/av_services_minijail_unittest.cpp
new file mode 100644
index 0000000..31313f8
--- /dev/null
+++ b/services/minijail/av_services_minijail_unittest.cpp
@@ -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.
+
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/unique_fd.h>
+
+#include <gtest/gtest.h>
+
+#include "minijail.h"
+
+class WritePolicyTest : public ::testing::Test
+{
+  protected:
+    const std::string base_policy_ =
+        "read: 1\n"
+        "write: 1\n"
+        "rt_sigreturn: 1\n"
+        "exit: 1\n";
+
+    const std::string additional_policy_ =
+        "mmap: 1\n"
+        "munmap: 1\n";
+
+    const std::string full_policy_ = base_policy_ + std::string("\n") + additional_policy_;
+};
+
+TEST_F(WritePolicyTest, OneFile)
+{
+    std::string final_string;
+    android::base::unique_fd fd(android::WritePolicyToPipe(base_policy_, std::string()));
+    EXPECT_LE(0, fd.get());
+    bool success = android::base::ReadFdToString(fd.get(), &final_string);
+    EXPECT_TRUE(success);
+    EXPECT_EQ(final_string, base_policy_);
+}
+
+TEST_F(WritePolicyTest, TwoFiles)
+{
+    std::string final_string;
+    android::base::unique_fd fd(android::WritePolicyToPipe(base_policy_, additional_policy_));
+    EXPECT_LE(0, fd.get());
+    bool success = android::base::ReadFdToString(fd.get(), &final_string);
+    EXPECT_TRUE(success);
+    EXPECT_EQ(final_string, full_policy_);
+}
diff --git a/services/minijail/minijail.cpp b/services/minijail/minijail.cpp
new file mode 100644
index 0000000..f213287
--- /dev/null
+++ b/services/minijail/minijail.cpp
@@ -0,0 +1,95 @@
+// Copyright 2015, 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 <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+#include <libminijail.h>
+#include <scoped_minijail.h>
+
+#include "minijail.h"
+
+namespace android {
+
+int WritePolicyToPipe(const std::string& base_policy_content,
+                      const std::string& additional_policy_content)
+{
+    int pipefd[2];
+    if (pipe(pipefd) == -1) {
+        PLOG(ERROR) << "pipe() failed";
+        return -1;
+    }
+
+    base::unique_fd write_end(pipefd[1]);
+    std::string content = base_policy_content;
+
+    if (additional_policy_content.length() > 0) {
+        content += "\n";
+        content += additional_policy_content;
+    }
+
+    if (!base::WriteStringToFd(content, write_end.get())) {
+        LOG(ERROR) << "Could not write policy to fd";
+        return -1;
+    }
+
+    return pipefd[0];
+}
+
+void SetUpMinijail(const std::string& base_policy_path, const std::string& additional_policy_path)
+{
+    // No seccomp policy defined for this architecture.
+    if (access(base_policy_path.c_str(), R_OK) == -1) {
+        LOG(WARNING) << "No seccomp policy defined for this architecture.";
+        return;
+    }
+
+    std::string base_policy_content;
+    std::string additional_policy_content;
+    if (!base::ReadFileToString(base_policy_path, &base_policy_content,
+                                false /* follow_symlinks */)) {
+        LOG(FATAL) << "Could not read base policy file '" << base_policy_path << "'";
+    }
+
+    if (additional_policy_path.length() > 0 &&
+        !base::ReadFileToString(additional_policy_path, &additional_policy_content,
+                                false /* follow_symlinks */)) {
+        LOG(WARNING) << "Could not read additional policy file '" << additional_policy_path << "'";
+        additional_policy_content = std::string();
+    }
+
+    base::unique_fd policy_fd(WritePolicyToPipe(base_policy_content, additional_policy_content));
+    if (policy_fd.get() == -1) {
+        LOG(FATAL) << "Could not write seccomp policy to fd";
+    }
+
+    ScopedMinijail jail{minijail_new()};
+    if (!jail) {
+        LOG(FATAL) << "Failed to create minijail.";
+    }
+
+    minijail_no_new_privs(jail.get());
+    minijail_log_seccomp_filter_failures(jail.get());
+    minijail_use_seccomp_filter(jail.get());
+    // Transfer ownership of |policy_fd|.
+    minijail_parse_seccomp_filters_from_fd(jail.get(), policy_fd.release());
+    minijail_enter(jail.get());
+}
+}
diff --git a/services/minijail/minijail.h b/services/minijail/minijail.h
new file mode 100644
index 0000000..c8a2149
--- /dev/null
+++ b/services/minijail/minijail.h
@@ -0,0 +1,26 @@
+// Copyright 2015, 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 AV_SERVICES_MINIJAIL_MINIJAIL
+#define AV_SERVICES_MINIJAIL_MINIJAIL
+
+#include <string>
+
+namespace android {
+int WritePolicyToPipe(const std::string& base_policy_content,
+                      const std::string& additional_policy_content);
+void SetUpMinijail(const std::string& base_policy_path, const std::string& additional_policy_path);
+}
+
+#endif  // AV_SERVICES_MINIJAIL_MINIJAIL
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index dfa9753..99b0b4d 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -57,7 +57,7 @@
         ALOGE("AAudioService::openStream(): open returned %d", result);
         return result;
     } else {
-        AAudioStream handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream);
+        aaudio_handle_t handle = mHandleTracker.put(AAUDIO_HANDLE_TYPE_STREAM, serviceStream);
         ALOGD("AAudioService::openStream(): handle = 0x%08X", handle);
         if (handle < 0) {
             delete serviceStream;
@@ -127,7 +127,7 @@
 
 aaudio_result_t AAudioService::registerAudioThread(aaudio_handle_t streamHandle,
                                                          pid_t clientThreadId,
-                                                         aaudio_nanoseconds_t periodNanoseconds) {
+                                                         int64_t periodNanoseconds) {
     AAudioServiceStreamBase *serviceStream = convertHandleToServiceStream(streamHandle);
     ALOGD("AAudioService::registerAudioThread(), serviceStream = %p", serviceStream);
     if (serviceStream == nullptr) {
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index e9625b2..a520d7a 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef AAUDIO_AAUDIO_AUDIO_SERVICE_H
-#define AAUDIO_AAUDIO_AUDIO_SERVICE_H
+#ifndef AAUDIO_AAUDIO_SERVICE_H
+#define AAUDIO_AAUDIO_SERVICE_H
 
 #include <time.h>
 #include <pthread.h>
@@ -58,7 +58,7 @@
     virtual aaudio_result_t flushStream(aaudio_handle_t streamHandle);
 
     virtual aaudio_result_t registerAudioThread(aaudio_handle_t streamHandle,
-                                              pid_t pid, aaudio_nanoseconds_t periodNanoseconds) ;
+                                              pid_t pid, int64_t periodNanoseconds) ;
 
     virtual aaudio_result_t unregisterAudioThread(aaudio_handle_t streamHandle, pid_t pid);
 
@@ -72,4 +72,4 @@
 
 } /* namespace android */
 
-#endif //AAUDIO_AAUDIO_AUDIO_SERVICE_H
+#endif //AAUDIO_AAUDIO_SERVICE_H
diff --git a/services/oboeservice/AAudioServiceDefinitions.h b/services/oboeservice/AAudioServiceDefinitions.h
index ee9aaa7..f98acbf 100644
--- a/services/oboeservice/AAudioServiceDefinitions.h
+++ b/services/oboeservice/AAudioServiceDefinitions.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef AAUDIO_AAUDIO_SERVICE_H
-#define AAUDIO_AAUDIO_SERVICE_H
+#ifndef AAUDIO_AAUDIO_SERVICE_DEFINITIONS_H
+#define AAUDIO_AAUDIO_SERVICE_DEFINITIONS_H
 
 #include <stdint.h>
 
@@ -28,9 +28,9 @@
 // TODO move this an "include" folder for the service.
 
 struct AAudioMessageTimestamp {
-    aaudio_position_frames_t position;
+    int64_t position;
     int64_t                deviceOffset; // add to client position to get device position
-    aaudio_nanoseconds_t     timestamp;
+    int64_t     timestamp;
 };
 
 typedef enum aaudio_service_event_e : uint32_t {
@@ -61,7 +61,6 @@
     };
 } AAudioServiceMessage;
 
-
 } /* namespace aaudio */
 
-#endif //AAUDIO_AAUDIO_SERVICE_H
+#endif //AAUDIO_AAUDIO_SERVICE_DEFINITIONS_H
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 4a59253..7a812f9 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -72,7 +72,7 @@
 
     virtual void sendCurrentTimestamp() = 0;
 
-    aaudio_size_frames_t getFramesPerBurst() {
+    int32_t getFramesPerBurst() {
         return mFramesPerBurst;
     }
 
@@ -90,17 +90,17 @@
 
 protected:
 
-    pid_t                    mRegisteredClientThread = ILLEGAL_THREAD_ID;
+    pid_t              mRegisteredClientThread = ILLEGAL_THREAD_ID;
 
-    SharedRingBuffer *       mUpMessageQueue;
+    SharedRingBuffer*  mUpMessageQueue;
 
-    aaudio_sample_rate_t       mSampleRate = 0;
-    aaudio_size_bytes_t        mBytesPerFrame = 0;
-    aaudio_size_frames_t       mFramesPerBurst = 0;
-    aaudio_size_frames_t       mCapacityInFrames = 0;
-    aaudio_size_bytes_t        mCapacityInBytes = 0;
+    int32_t            mSampleRate = 0;
+    int32_t            mBytesPerFrame = 0;
+    int32_t            mFramesPerBurst = 0;
+    int32_t            mCapacityInFrames = 0;
+    int32_t            mCapacityInBytes = 0;
 
-    android::Mutex           mLockUpMessageQueue;
+    android::Mutex     mLockUpMessageQueue;
 };
 
 } /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceStreamFakeHal.cpp b/services/oboeservice/AAudioServiceStreamFakeHal.cpp
index 627a504..71d3542 100644
--- a/services/oboeservice/AAudioServiceStreamFakeHal.cpp
+++ b/services/oboeservice/AAudioServiceStreamFakeHal.cpp
@@ -53,13 +53,14 @@
 }
 
 aaudio_result_t AAudioServiceStreamFakeHal::open(aaudio::AAudioStreamRequest &request,
-                                             aaudio::AAudioStreamConfiguration &configuration) {
+                                       aaudio::AAudioStreamConfiguration &configurationOutput) {
     // Open stream on HAL and pass information about the ring buffer to the client.
     mmap_buffer_info mmapInfo;
     aaudio_result_t error;
 
     // Open HAL
-    error = fake_hal_open(CARD_ID, DEVICE_ID, &mStreamId);
+    int bufferCapacity = request.getConfiguration().getBufferCapacity();
+    error = fake_hal_open(CARD_ID, DEVICE_ID, bufferCapacity, &mStreamId);
     if(error < 0) {
         ALOGE("Could not open card %d, device %d", CARD_ID, DEVICE_ID);
         return error;
@@ -87,9 +88,9 @@
          mmapInfo.buffer_capacity_in_bytes);
 
     // Fill in AAudioStreamConfiguration
-    configuration.setSampleRate(mSampleRate);
-    configuration.setSamplesPerFrame(mmapInfo.channel_count);
-    configuration.setAudioFormat(AAUDIO_FORMAT_PCM_I16);
+    configurationOutput.setSampleRate(mSampleRate);
+    configurationOutput.setSamplesPerFrame(mmapInfo.channel_count);
+    configurationOutput.setAudioFormat(AAUDIO_FORMAT_PCM_I16);
 
     return AAUDIO_OK;
 }
@@ -190,7 +191,7 @@
     timestampScheduler.setBurstPeriod(mFramesPerBurst, mSampleRate);
     timestampScheduler.start(AudioClock::getNanoseconds());
     while(mThreadEnabled.load()) {
-        aaudio_nanoseconds_t nextTime = timestampScheduler.nextAbsoluteTime();
+        int64_t nextTime = timestampScheduler.nextAbsoluteTime();
         if (AudioClock::getNanoseconds() >= nextTime) {
             sendCurrentTimestamp();
         } else  {
diff --git a/services/oboeservice/AAudioServiceStreamFakeHal.h b/services/oboeservice/AAudioServiceStreamFakeHal.h
index 170d0ee..e9480fb 100644
--- a/services/oboeservice/AAudioServiceStreamFakeHal.h
+++ b/services/oboeservice/AAudioServiceStreamFakeHal.h
@@ -37,7 +37,7 @@
     virtual aaudio_result_t getDescription(AudioEndpointParcelable &parcelable) override;
 
     virtual aaudio_result_t open(aaudio::AAudioStreamRequest &request,
-                               aaudio::AAudioStreamConfiguration &configuration) override;
+                                 aaudio::AAudioStreamConfiguration &configurationOutput) override;
 
     /**
      * Start the flow of data.
diff --git a/services/oboeservice/AAudioThread.h b/services/oboeservice/AAudioThread.h
index 1f676dc..a5d43a4 100644
--- a/services/oboeservice/AAudioThread.h
+++ b/services/oboeservice/AAudioThread.h
@@ -62,9 +62,9 @@
     void dispatch(); // called internally from 'C' thread wrapper
 
 private:
-    Runnable*                mRunnable = nullptr; // TODO make atomic with memory barrier?
-    bool                     mHasThread = false;
-    pthread_t                mThread; // initialized in constructor
+    Runnable*          mRunnable = nullptr; // TODO make atomic with memory barrier?
+    bool               mHasThread = false;
+    pthread_t          mThread; // initialized in constructor
 
 };
 
diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk
index 68e43ed..5cd9121 100644
--- a/services/oboeservice/Android.mk
+++ b/services/oboeservice/Android.mk
@@ -3,28 +3,28 @@
 # AAudio Service
 include $(CLEAR_VARS)
 
-LOCAL_MODULE := oboeservice
+LOCAL_MODULE := aaudioservice
 LOCAL_MODULE_TAGS := optional
 
-LIBAAUDIO_DIR := ../../media/liboboe
+LIBAAUDIO_DIR := ../../media/libaaudio
 LIBAAUDIO_SRC_DIR := $(LIBAAUDIO_DIR)/src
 
 LOCAL_C_INCLUDES := \
     $(call include-path-for, audio-utils) \
     frameworks/native/include \
     system/core/base/include \
-    $(TOP)/frameworks/native/media/liboboe/include/include \
-    $(TOP)/frameworks/av/media/liboboe/include \
+    $(TOP)/frameworks/native/media/libaaudio/include/include \
+    $(TOP)/frameworks/av/media/libaaudio/include \
     frameworks/native/include \
     $(TOP)/external/tinyalsa/include \
-    $(TOP)/frameworks/av/media/liboboe/src \
-    $(TOP)/frameworks/av/media/liboboe/src/binding \
-    $(TOP)/frameworks/av/media/liboboe/src/client \
-    $(TOP)/frameworks/av/media/liboboe/src/core \
-    $(TOP)/frameworks/av/media/liboboe/src/fifo \
-    $(TOP)/frameworks/av/media/liboboe/src/utility
+    $(TOP)/frameworks/av/media/libaaudio/src \
+    $(TOP)/frameworks/av/media/libaaudio/src/binding \
+    $(TOP)/frameworks/av/media/libaaudio/src/client \
+    $(TOP)/frameworks/av/media/libaaudio/src/core \
+    $(TOP)/frameworks/av/media/libaaudio/src/fifo \
+    $(TOP)/frameworks/av/media/libaaudio/src/utility
 
-# TODO These could be in a liboboe_common library
+# TODO These could be in a libaaudio_common library
 LOCAL_SRC_FILES += \
     $(LIBAAUDIO_SRC_DIR)/utility/HandleTracker.cpp \
     $(LIBAAUDIO_SRC_DIR)/utility/AAudioUtilities.cpp \
diff --git a/services/oboeservice/FakeAudioHal.cpp b/services/oboeservice/FakeAudioHal.cpp
index cf0dc86..122671e 100644
--- a/services/oboeservice/FakeAudioHal.cpp
+++ b/services/oboeservice/FakeAudioHal.cpp
@@ -23,9 +23,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#define __force
-#define __bitwise
-#define __user
 #include <sound/asound.h>
 
 #include "tinyalsa/asoundlib.h"
@@ -94,14 +91,25 @@
 #define FRAMES_PER_BURST_QUALCOMM 192
 #define FRAMES_PER_BURST_NVIDIA   128
 
-int fake_hal_open(int card_id, int device_id, fake_hal_stream_ptr *streamPP) {
+int fake_hal_open(int card_id, int device_id,
+                  int frameCapacity,
+                  fake_hal_stream_ptr *streamPP) {
     int framesPerBurst = FRAMES_PER_BURST_QUALCOMM; // TODO update as needed
+    int periodCountRequested = frameCapacity / framesPerBurst;
     int periodCount = 32;
     unsigned int offset1;
     unsigned int frames1;
     void *area = nullptr;
     int mmapAvail = 0;
 
+    // Try to match requested size with a power of 2.
+    while (periodCount < periodCountRequested && periodCount < 1024) {
+        periodCount *= 2;
+    }
+    std::cout << "fake_hal_open() requested frameCapacity = " << frameCapacity << std::endl;
+    std::cout << "fake_hal_open() periodCountRequested = " << periodCountRequested << std::endl;
+    std::cout << "fake_hal_open() periodCount = " << periodCount << std::endl;
+
     // Configuration for an ALSA stream.
     pcm_config cfg;
     memset(&cfg, 0, sizeof(cfg));
diff --git a/services/oboeservice/FakeAudioHal.h b/services/oboeservice/FakeAudioHal.h
index f47ccd9..d3aa4e8 100644
--- a/services/oboeservice/FakeAudioHal.h
+++ b/services/oboeservice/FakeAudioHal.h
@@ -39,7 +39,9 @@
 //extern "C"
 //{
 
-int fake_hal_open(int card_id, int device_id, fake_hal_stream_ptr *stream_pp);
+int fake_hal_open(int card_id, int device_id,
+                  int frameCapacity,
+                  fake_hal_stream_ptr *stream_pp);
 
 int fake_hal_get_mmap_info(fake_hal_stream_ptr stream, mmap_buffer_info *info);
 
diff --git a/services/oboeservice/TimestampScheduler.cpp b/services/oboeservice/TimestampScheduler.cpp
index 5875909..d54996f 100644
--- a/services/oboeservice/TimestampScheduler.cpp
+++ b/services/oboeservice/TimestampScheduler.cpp
@@ -21,12 +21,12 @@
 
 using namespace aaudio;
 
-void TimestampScheduler::start(aaudio_nanoseconds_t startTime) {
+void TimestampScheduler::start(int64_t startTime) {
     mStartTime = startTime;
     mLastTime = startTime;
 }
 
-aaudio_nanoseconds_t TimestampScheduler::nextAbsoluteTime() {
+int64_t TimestampScheduler::nextAbsoluteTime() {
     int64_t periodsElapsed = (mLastTime - mStartTime) / mBurstPeriod;
     // This is an arbitrary schedule that could probably be improved.
     // It starts out sending a timestamp on every period because we want to
@@ -35,10 +35,10 @@
     int64_t minPeriodsToDelay = (periodsElapsed < 10) ? 1 :
         (periodsElapsed < 100) ? 3 :
         (periodsElapsed < 1000) ? 10 : 50;
-    aaudio_nanoseconds_t sleepTime = minPeriodsToDelay * mBurstPeriod;
+    int64_t sleepTime = minPeriodsToDelay * mBurstPeriod;
     // Generate a random rectangular distribution one burst wide so that we get
     // an uncorrelated sampling of the MMAP pointer.
-    sleepTime += (aaudio_nanoseconds_t)(random() * mBurstPeriod / RAND_MAX);
+    sleepTime += (int64_t)(random() * mBurstPeriod / RAND_MAX);
     mLastTime += sleepTime;
     return mLastTime;
 }
diff --git a/services/oboeservice/TimestampScheduler.h b/services/oboeservice/TimestampScheduler.h
index efc9c5f..91a2477 100644
--- a/services/oboeservice/TimestampScheduler.h
+++ b/services/oboeservice/TimestampScheduler.h
@@ -17,7 +17,7 @@
 #ifndef AAUDIO_TIMESTAMP_SCHEDULER_H
 #define AAUDIO_TIMESTAMP_SCHEDULER_H
 
-//#include <stdlib.h> // random()
+
 
 #include "IAAudioService.h"
 #include "AAudioServiceDefinitions.h"
@@ -25,6 +25,7 @@
 #include "fifo/FifoBuffer.h"
 #include "SharedRingBuffer.h"
 #include "AudioEndpointParcelable.h"
+#include "utility/AudioClock.h"
 
 namespace aaudio {
 
@@ -43,32 +44,32 @@
     /**
      * Start the schedule at the given time.
      */
-    void start(aaudio_nanoseconds_t startTime);
+    void start(int64_t startTime);
 
     /**
      * Calculate the next time that the read position should be
      * measured.
      */
-    aaudio_nanoseconds_t nextAbsoluteTime();
+    int64_t nextAbsoluteTime();
 
-    void setBurstPeriod(aaudio_nanoseconds_t burstPeriod) {
+    void setBurstPeriod(int64_t burstPeriod) {
         mBurstPeriod = burstPeriod;
     }
 
-    void setBurstPeriod(aaudio_size_frames_t framesPerBurst,
-                        aaudio_sample_rate_t sampleRate) {
+    void setBurstPeriod(int32_t framesPerBurst,
+                        int32_t sampleRate) {
         mBurstPeriod = AAUDIO_NANOS_PER_SECOND * framesPerBurst / sampleRate;
     }
 
-    aaudio_nanoseconds_t getBurstPeriod() {
+    int64_t getBurstPeriod() {
         return mBurstPeriod;
     }
 
 private:
     // Start with an arbitrary default so we do not divide by zero.
-    aaudio_nanoseconds_t mBurstPeriod = AAUDIO_NANOS_PER_MILLISECOND;
-    aaudio_nanoseconds_t mStartTime;
-    aaudio_nanoseconds_t mLastTime;
+    int64_t mBurstPeriod = AAUDIO_NANOS_PER_MILLISECOND;
+    int64_t mStartTime;
+    int64_t mLastTime;
 };
 
 } /* namespace aaudio */
diff --git a/services/radio/HidlUtils.cpp b/services/radio/HidlUtils.cpp
index 3b33386..6895377 100644
--- a/services/radio/HidlUtils.cpp
+++ b/services/radio/HidlUtils.cpp
@@ -134,14 +134,18 @@
                            halInfo->channel, halInfo->subChannel);
 }
 
+// TODO(twasilczyk): drop unnecessary channel info
 //static
 void HidlUtils::convertMetaDataFromHal(radio_metadata_t **metadata,
                                        const hidl_vec<MetaData>& halMetadata,
-                                       uint32_t channel,
-                                       uint32_t subChannel)
+                                       uint32_t channel __unused,
+                                       uint32_t subChannel __unused)
 {
 
-    radio_metadata_allocate(metadata, channel, subChannel);
+    if (metadata == nullptr || *metadata == nullptr) {
+        ALOGE("destination metadata buffer is a nullptr");
+        return;
+    }
     for (size_t i = 0; i < halMetadata.size(); i++) {
         radio_metadata_key_t key = static_cast<radio_metadata_key_t>(halMetadata[i].key);
         radio_metadata_type_t type = static_cast<radio_metadata_key_t>(halMetadata[i].type);
diff --git a/services/radio/RadioHalHidl.cpp b/services/radio/RadioHalHidl.cpp
index 032d3fd..bfc5500 100644
--- a/services/radio/RadioHalHidl.cpp
+++ b/services/radio/RadioHalHidl.cpp
@@ -20,7 +20,7 @@
 #include <media/audiohal/hidl/HalDeathHandler.h>
 #include <utils/Log.h>
 #include <utils/misc.h>
-#include <system/radio_metadata.h>
+#include <system/RadioMetadataWrapper.h>
 #include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
 
 #include "RadioHalHidl.h"
@@ -116,7 +116,7 @@
 sp<IBroadcastRadio> RadioHalHidl::getService()
 {
     if (mHalModule == 0) {
-        sp<IBroadcastRadioFactory> factory = IBroadcastRadioFactory::getService("broadcastradio");
+        sp<IBroadcastRadioFactory> factory = IBroadcastRadioFactory::getService();
         if (factory != 0) {
             factory->connectModule(static_cast<Class>(mClassId),
                                [&](Result retval, const ::android::sp<IBroadcastRadio>& result) {
@@ -261,27 +261,25 @@
 Return<void> RadioHalHidl::Tuner::tuneComplete(Result result, const ProgramInfo& info)
 {
     ALOGV("%s IN", __FUNCTION__);
-    radio_hal_event_t event;
-    memset(&event, 0, sizeof(radio_hal_event_t));
+    radio_hal_event_t event = {};
+    RadioMetadataWrapper metadataWrapper(&event.info.metadata);
+
     event.type = RADIO_EVENT_TUNED;
     event.status = HidlUtils::convertHalResult(result);
     HidlUtils::convertProgramInfoFromHal(&event.info, &info);
     onCallback(&event);
-    radio_metadata_deallocate(event.info.metadata);
     return Return<void>();
 }
 
 Return<void> RadioHalHidl::Tuner::afSwitch(const ProgramInfo& info)
 {
     ALOGV("%s IN", __FUNCTION__);
-    radio_hal_event_t event;
-    memset(&event, 0, sizeof(radio_hal_event_t));
+    radio_hal_event_t event = {};
+    RadioMetadataWrapper metadataWrapper(&event.info.metadata);
+
     event.type = RADIO_EVENT_AF_SWITCH;
     HidlUtils::convertProgramInfoFromHal(&event.info, &info);
     onCallback(&event);
-    if (event.info.metadata != NULL) {
-        radio_metadata_deallocate(event.info.metadata);
-    }
     return Return<void>();
 }
 
@@ -319,14 +317,12 @@
                                           const ::android::hardware::hidl_vec<MetaData>& metadata)
 {
     ALOGV("%s IN", __FUNCTION__);
-    radio_hal_event_t event;
-    memset(&event, 0, sizeof(radio_hal_event_t));
+    radio_hal_event_t event = {};
+    RadioMetadataWrapper metadataWrapper(&event.info.metadata);
+
     event.type = RADIO_EVENT_METADATA;
     HidlUtils::convertMetaDataFromHal(&event.metadata, metadata, channel, subChannel);
     onCallback(&event);
-    if (event.metadata != NULL) {
-        radio_metadata_deallocate(event.info.metadata);
-    }
     return Return<void>();
 }
 
diff --git a/services/radio/RadioService.cpp b/services/radio/RadioService.cpp
index a73ed8f..f7a73c3 100644
--- a/services/radio/RadioService.cpp
+++ b/services/radio/RadioService.cpp
@@ -68,10 +68,11 @@
     radio_properties_t properties;
     properties.handle =
             (radio_handle_t)android_atomic_inc(&mNextUniqueId);
-
-    ALOGI("loaded default module %s, handle %d", properties.product, properties.handle);
-
     convertProperties(&properties, &halProperties);
+
+    ALOGI("loaded default module %s, ver %s, handle %d", properties.product,
+        properties.version, properties.handle);
+
     sp<Module> module = new Module(dev, properties);
     mModules.add(properties.handle, module);
 }
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 54f9b95..78845b7 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -923,7 +923,10 @@
 
 void SoundTriggerHwService::ModuleClient::onFirstRef()
 {
-    IInterface::asBinder(mClient)->linkToDeath(this);
+    sp<IBinder> binder = IInterface::asBinder(mClient);
+    if (binder != 0) {
+        binder->linkToDeath(this);
+    }
 }
 
 SoundTriggerHwService::ModuleClient::~ModuleClient()