resolve merge conflicts of c25621f0e5 to nyc-dev-plus-aosp

Change-Id: I36983f261e91f9fc1b41ff54ba604fa616ada0ff
diff --git a/camera/Android.mk b/camera/Android.mk
index 471cb0d..de23953 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -52,6 +52,7 @@
 LOCAL_C_INCLUDES += \
 	system/media/camera/include \
 	system/media/private/camera/include \
+	frameworks/native/include/media/openmax \
 
 LOCAL_MODULE:= libcamera_client
 
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index 9bf3134..1289348 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -72,9 +72,9 @@
 }
 
 sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
-        int clientUid)
+        int clientUid, int clientPid)
 {
-    return CameraBaseT::connect(cameraId, clientPackageName, clientUid);
+    return CameraBaseT::connect(cameraId, clientPackageName, clientUid, clientPid);
 }
 
 status_t Camera::connectLegacy(int cameraId, int halVersion,
@@ -136,6 +136,15 @@
     return c->setPreviewTarget(bufferProducer);
 }
 
+status_t Camera::setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer)
+{
+    ALOGV("setVideoTarget(%p)", bufferProducer.get());
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    ALOGD_IF(bufferProducer == 0, "app passed NULL video surface");
+    return c->setVideoTarget(bufferProducer);
+}
+
 // start preview mode
 status_t Camera::startPreview()
 {
@@ -145,13 +154,12 @@
     return c->startPreview();
 }
 
-status_t Camera::storeMetaDataInBuffers(bool enabled)
+status_t Camera::setVideoBufferMode(int32_t videoBufferMode)
 {
-    ALOGV("storeMetaDataInBuffers: %s",
-            enabled? "true": "false");
+    ALOGV("setVideoBufferMode: %d", videoBufferMode);
     sp <ICamera> c = mCamera;
     if (c == 0) return NO_INIT;
-    return c->storeMetaDataInBuffers(enabled);
+    return c->setVideoBufferMode(videoBufferMode);
 }
 
 // start recording mode, must call setPreviewTarget first
diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp
index 5d50aa8..9ee7ae5 100644
--- a/camera/CameraBase.cpp
+++ b/camera/CameraBase.cpp
@@ -92,7 +92,7 @@
 template <typename TCam, typename TCamTraits>
 sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
                                                const String16& clientPackageName,
-                                               int clientUid)
+                                               int clientUid, int clientPid)
 {
     ALOGV("%s: connect", __FUNCTION__);
     sp<TCam> c = new TCam(cameraId);
@@ -103,7 +103,7 @@
     if (cs != 0) {
         TCamConnectService fnConnectService = TCamTraits::fnConnectService;
         status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
-                                             /*out*/ c->mCamera);
+                                               clientPid, /*out*/ c->mCamera);
     }
     if (status == OK && c->mCamera != 0) {
         IInterface::asBinder(c->mCamera)->linkToDeath(c);
diff --git a/camera/CameraUtils.cpp b/camera/CameraUtils.cpp
index 04244ac..26eebe3 100644
--- a/camera/CameraUtils.cpp
+++ b/camera/CameraUtils.cpp
@@ -18,6 +18,7 @@
 //#define LOG_NDEBUG 0
 
 #include <camera/CameraUtils.h>
+#include <media/hardware/HardwareAPI.h>
 
 #include <system/window.h>
 #include <system/graphics.h>
@@ -121,5 +122,19 @@
     return OK;
 }
 
+// Return whether the image data contains a native handle.
+bool CameraUtils::isNativeHandleMetadata(const sp<IMemory>& imageData) {
+    if (imageData == nullptr) {
+        return false;
+    }
+
+    if (imageData->size() == sizeof(VideoNativeHandleMetadata)) {
+        VideoNativeHandleMetadata *metadata =
+                (VideoNativeHandleMetadata*)(imageData->pointer());
+        return metadata->eType == kMetadataBufferTypeNativeHandleSource;
+    }
+
+    return false;
+}
 
 } /* namespace android */
diff --git a/camera/ICamera.cpp b/camera/ICamera.cpp
index 9943be6..1dd8912 100644
--- a/camera/ICamera.cpp
+++ b/camera/ICamera.cpp
@@ -21,9 +21,11 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <binder/Parcel.h>
+#include <camera/CameraUtils.h>
 #include <camera/ICamera.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/Surface.h>
+#include <media/hardware/HardwareAPI.h>
 
 namespace android {
 
@@ -48,7 +50,8 @@
     STOP_RECORDING,
     RECORDING_ENABLED,
     RELEASE_RECORDING_FRAME,
-    STORE_META_DATA_IN_BUFFERS,
+    SET_VIDEO_BUFFER_MODE,
+    SET_VIDEO_BUFFER_TARGET,
 };
 
 class BpCamera: public BpInterface<ICamera>
@@ -148,16 +151,31 @@
         Parcel data, reply;
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
         data.writeStrongBinder(IInterface::asBinder(mem));
+
+        native_handle_t *nh = nullptr;
+        if (CameraUtils::isNativeHandleMetadata(mem)) {
+            VideoNativeHandleMetadata *metadata =
+                        (VideoNativeHandleMetadata*)(mem->pointer());
+            nh = metadata->pHandle;
+            data.writeNativeHandle(nh);
+        }
+
         remote()->transact(RELEASE_RECORDING_FRAME, data, &reply);
+
+        if (nh) {
+            // Close the native handle because camera received a dup copy.
+            native_handle_close(nh);
+            native_handle_delete(nh);
+        }
     }
 
-    status_t storeMetaDataInBuffers(bool enabled)
+    status_t setVideoBufferMode(int32_t videoBufferMode)
     {
-        ALOGV("storeMetaDataInBuffers: %s", enabled? "true": "false");
+        ALOGV("setVideoBufferMode: %d", videoBufferMode);
         Parcel data, reply;
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
-        data.writeInt32(enabled);
-        remote()->transact(STORE_META_DATA_IN_BUFFERS, data, &reply);
+        data.writeInt32(videoBufferMode);
+        remote()->transact(SET_VIDEO_BUFFER_MODE, data, &reply);
         return reply.readInt32();
     }
 
@@ -268,6 +286,17 @@
         remote()->transact(UNLOCK, data, &reply);
         return reply.readInt32();
     }
+
+    status_t setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer)
+    {
+        ALOGV("setVideoTarget");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        sp<IBinder> b(IInterface::asBinder(bufferProducer));
+        data.writeStrongBinder(b);
+        remote()->transact(SET_VIDEO_BUFFER_TARGET, data, &reply);
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(Camera, "android.hardware.ICamera");
@@ -336,14 +365,22 @@
             ALOGV("RELEASE_RECORDING_FRAME");
             CHECK_INTERFACE(ICamera, data, reply);
             sp<IMemory> mem = interface_cast<IMemory>(data.readStrongBinder());
+
+            if (CameraUtils::isNativeHandleMetadata(mem)) {
+                VideoNativeHandleMetadata *metadata =
+                        (VideoNativeHandleMetadata*)(mem->pointer());
+                metadata->pHandle = data.readNativeHandle();
+                // releaseRecordingFrame will be responsble to close the native handle.
+            }
+
             releaseRecordingFrame(mem);
             return NO_ERROR;
         } break;
-        case STORE_META_DATA_IN_BUFFERS: {
-            ALOGV("STORE_META_DATA_IN_BUFFERS");
+        case SET_VIDEO_BUFFER_MODE: {
+            ALOGV("SET_VIDEO_BUFFER_MODE");
             CHECK_INTERFACE(ICamera, data, reply);
-            bool enabled = data.readInt32();
-            reply->writeInt32(storeMetaDataInBuffers(enabled));
+            int32_t mode = data.readInt32();
+            reply->writeInt32(setVideoBufferMode(mode));
             return NO_ERROR;
         } break;
         case PREVIEW_ENABLED: {
@@ -415,6 +452,14 @@
             reply->writeInt32(unlock());
             return NO_ERROR;
         } break;
+        case SET_VIDEO_BUFFER_TARGET: {
+            ALOGV("SET_VIDEO_BUFFER_TARGET");
+            CHECK_INTERFACE(ICamera, data, reply);
+            sp<IGraphicBufferProducer> st =
+                interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
+            reply->writeInt32(setVideoTarget(st));
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp
index 179a341..4282f9a 100644
--- a/camera/ICameraClient.cpp
+++ b/camera/ICameraClient.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2008, 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -20,7 +20,9 @@
 #include <utils/Log.h>
 #include <stdint.h>
 #include <sys/types.h>
+#include <camera/CameraUtils.h>
 #include <camera/ICameraClient.h>
+#include <media/hardware/HardwareAPI.h>
 
 namespace android {
 
@@ -75,6 +77,13 @@
         data.writeInt64(timestamp);
         data.writeInt32(msgType);
         data.writeStrongBinder(IInterface::asBinder(imageData));
+        // If imageData is metadata and it contains a native handle, write the native handle to
+        // parcel.
+        if (CameraUtils::isNativeHandleMetadata(imageData)) {
+            VideoNativeHandleMetadata *metadata =
+                    (VideoNativeHandleMetadata*)(imageData->pointer());
+            data.writeNativeHandle(metadata->pHandle);
+        }
         remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, IBinder::FLAG_ONEWAY);
     }
 };
@@ -118,6 +127,19 @@
             nsecs_t timestamp = data.readInt64();
             int32_t msgType = data.readInt32();
             sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());
+
+            // If the image data contains a native handle, read the native handle from the parcel
+            // and replace the native handle in the image data. (The native handle in image data is
+            // not serielized/deserialized so it's not valid in the process.)
+            if (CameraUtils::isNativeHandleMetadata(imageData)) {
+                VideoNativeHandleMetadata *metadata =
+                        (VideoNativeHandleMetadata*)(imageData->pointer());
+                metadata->pHandle = data.readNativeHandle();
+
+                // The native handle will be freed in
+                // BpCameraRecordingProxyListener::releaseRecordingFrame.
+            }
+
             dataCallbackTimestamp(timestamp, msgType, imageData);
             return NO_ERROR;
         } break;
diff --git a/camera/ICameraRecordingProxy.cpp b/camera/ICameraRecordingProxy.cpp
index 3dc0ffb..d128f5b 100644
--- a/camera/ICameraRecordingProxy.cpp
+++ b/camera/ICameraRecordingProxy.cpp
@@ -16,10 +16,12 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "ICameraRecordingProxy"
+#include <camera/CameraUtils.h>
 #include <camera/ICameraRecordingProxy.h>
 #include <camera/ICameraRecordingProxyListener.h>
 #include <binder/IMemory.h>
 #include <binder/Parcel.h>
+#include <media/hardware/HardwareAPI.h>
 #include <stdint.h>
 #include <utils/Log.h>
 
@@ -64,7 +66,22 @@
         Parcel data, reply;
         data.writeInterfaceToken(ICameraRecordingProxy::getInterfaceDescriptor());
         data.writeStrongBinder(IInterface::asBinder(mem));
+
+        native_handle_t *nh = nullptr;
+        if (CameraUtils::isNativeHandleMetadata(mem)) {
+            VideoNativeHandleMetadata *metadata =
+                        (VideoNativeHandleMetadata*)(mem->pointer());
+            nh = metadata->pHandle;
+            data.writeNativeHandle(nh);
+        }
+
         remote()->transact(RELEASE_RECORDING_FRAME, data, &reply);
+
+        if (nh) {
+            // Close the native handle because camera received a dup copy.
+            native_handle_close(nh);
+            native_handle_delete(nh);
+        }
     }
 };
 
@@ -94,7 +111,16 @@
             ALOGV("RELEASE_RECORDING_FRAME");
             CHECK_INTERFACE(ICameraRecordingProxy, data, reply);
             sp<IMemory> mem = interface_cast<IMemory>(data.readStrongBinder());
+
+            if (CameraUtils::isNativeHandleMetadata(mem)) {
+                VideoNativeHandleMetadata *metadata =
+                        (VideoNativeHandleMetadata*)(mem->pointer());
+                metadata->pHandle = data.readNativeHandle();
+
+                // releaseRecordingFrame will be responsble to close the native handle.
+            }
             releaseRecordingFrame(mem);
+
             return NO_ERROR;
         } break;
 
diff --git a/camera/ICameraRecordingProxyListener.cpp b/camera/ICameraRecordingProxyListener.cpp
index cf848fc..447174e 100644
--- a/camera/ICameraRecordingProxyListener.cpp
+++ b/camera/ICameraRecordingProxyListener.cpp
@@ -16,9 +16,11 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "ICameraRecordingProxyListener"
+#include <camera/CameraUtils.h>
 #include <camera/ICameraRecordingProxyListener.h>
 #include <binder/IMemory.h>
 #include <binder/Parcel.h>
+#include <media/hardware/HardwareAPI.h>
 #include <utils/Log.h>
 
 namespace android {
@@ -43,7 +45,22 @@
         data.writeInt64(timestamp);
         data.writeInt32(msgType);
         data.writeStrongBinder(IInterface::asBinder(imageData));
+        native_handle_t* nh = nullptr;
+
+        if (CameraUtils::isNativeHandleMetadata(imageData)) {
+            VideoNativeHandleMetadata *metadata =
+                    (VideoNativeHandleMetadata*)(imageData->pointer());
+            nh = metadata->pHandle;
+            data.writeNativeHandle(nh);
+        }
+
         remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, IBinder::FLAG_ONEWAY);
+
+        // The native handle is dupped in ICameraClient so we need to free it here.
+        if (nh) {
+            native_handle_close(nh);
+            native_handle_delete(nh);
+        }
     }
 };
 
@@ -61,6 +78,15 @@
             nsecs_t timestamp = data.readInt64();
             int32_t msgType = data.readInt32();
             sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());
+
+            if (CameraUtils::isNativeHandleMetadata(imageData)) {
+                VideoNativeHandleMetadata *meta = (VideoNativeHandleMetadata*)(imageData->pointer());
+                meta->pHandle = data.readNativeHandle();
+
+                // The native handle will be freed in
+                // BpCameraRecordingProxyListener::releaseRecordingFrame.
+            }
+
             dataCallbackTimestamp(timestamp, msgType, imageData);
             return NO_ERROR;
         } break;
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index b359f57..4a042a6 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -172,7 +172,7 @@
 
     // connect to camera service (android.hardware.Camera)
     virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
-                             const String16 &clientPackageName, int clientUid,
+                             const String16 &clientPackageName, int clientUid, int clientPid,
                              /*out*/
                              sp<ICamera>& device)
     {
@@ -182,6 +182,7 @@
         data.writeInt32(cameraId);
         data.writeString16(clientPackageName);
         data.writeInt32(clientUid);
+        data.writeInt32(clientPid);
 
         status_t status;
         status = remote()->transact(BnCameraService::CONNECT, data, &reply);
@@ -396,9 +397,10 @@
             int32_t cameraId = data.readInt32();
             const String16 clientName = data.readString16();
             int32_t clientUid = data.readInt32();
+            int32_t clientPid = data.readInt32();
             sp<ICamera> camera;
             status_t status = connect(cameraClient, cameraId,
-                    clientName, clientUid, /*out*/camera);
+                    clientName, clientUid, clientPid, /*out*/camera);
             reply->writeNoException();
             reply->writeInt32(status);
             if (camera != NULL) {
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index 20a23e0..3505154 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -25,6 +25,7 @@
 
 
 const int OutputConfiguration::INVALID_ROTATION = -1;
+const int OutputConfiguration::INVALID_SET_ID = -1;
 
 // Read empty strings without printing a false error message.
 String16 OutputConfiguration::readMaybeEmptyString16(const Parcel& parcel) {
@@ -45,6 +46,10 @@
     return mRotation;
 }
 
+int OutputConfiguration::getSurfaceSetID() const {
+    return mSurfaceSetID;
+}
+
 OutputConfiguration::OutputConfiguration(const Parcel& parcel) {
     status_t err;
     int rotation = 0;
@@ -55,24 +60,36 @@
         return;
     }
 
+    int setID = INVALID_SET_ID;
+    if ((err = parcel.readInt32(&setID)) != OK) {
+        ALOGE("%s: Failed to read surface set ID from parcel", __FUNCTION__);
+        mGbp = NULL;
+        mSurfaceSetID = INVALID_SET_ID;
+        return;
+    }
+
     String16 name = readMaybeEmptyString16(parcel);
     const sp<IGraphicBufferProducer>& gbp =
             interface_cast<IGraphicBufferProducer>(parcel.readStrongBinder());
     mGbp = gbp;
     mRotation = rotation;
+    mSurfaceSetID = setID;
 
     ALOGV("%s: OutputConfiguration: bp = %p, name = %s", __FUNCTION__,
           gbp.get(), String8(name).string());
 }
 
-OutputConfiguration::OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation) {
+OutputConfiguration::OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
+        int surfaceSetID) {
     mGbp = gbp;
     mRotation = rotation;
+    mSurfaceSetID = surfaceSetID;
 }
 
 status_t OutputConfiguration::writeToParcel(Parcel& parcel) const {
 
     parcel.writeInt32(mRotation);
+    parcel.writeInt32(mSurfaceSetID);
     parcel.writeString16(String16("unknown_name")); // name of surface
     sp<IBinder> b(IInterface::asBinder(mGbp));
     parcel.writeStrongBinder(b);
diff --git a/camera/cameraserver/Android.mk b/camera/cameraserver/Android.mk
new file mode 100644
index 0000000..4d8339c
--- /dev/null
+++ b/camera/cameraserver/Android.mk
@@ -0,0 +1,37 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	main_cameraserver.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcameraservice \
+	libcutils \
+	libutils \
+	libbinder
+
+LOCAL_C_INCLUDES := \
+    frameworks/av/services/camera/libcameraservice \
+    system/media/camera/include
+
+LOCAL_MODULE:= cameraserver
+LOCAL_32_BIT_ONLY := true
+
+LOCAL_INIT_RC := cameraserver.rc
+
+include $(BUILD_EXECUTABLE)
diff --git a/camera/cameraserver/cameraserver.rc b/camera/cameraserver/cameraserver.rc
new file mode 100644
index 0000000..37e2688
--- /dev/null
+++ b/camera/cameraserver/cameraserver.rc
@@ -0,0 +1,5 @@
+service cameraserver /system/bin/cameraserver
+    class main
+    user cameraserver
+    group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
+    ioprio rt 4
diff --git a/camera/cameraserver/main_cameraserver.cpp b/camera/cameraserver/main_cameraserver.cpp
new file mode 100644
index 0000000..f4be468
--- /dev/null
+++ b/camera/cameraserver/main_cameraserver.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 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 "cameraserver"
+//#define LOG_NDEBUG 0
+
+// from LOCAL_C_INCLUDES
+#include "CameraService.h"
+
+using namespace android;
+
+int main(int argc __unused, char** argv __unused)
+{
+    signal(SIGPIPE, SIG_IGN);
+
+    sp<ProcessState> proc(ProcessState::self());
+    sp<IServiceManager> sm = defaultServiceManager();
+    ALOGI("ServiceManager: %p", sm.get());
+    CameraService::instantiate();
+    ProcessState::self()->startThreadPool();
+    IPCThreadState::self()->joinThreadPool();
+}
diff --git a/camera/ndk/Android.mk b/camera/ndk/Android.mk
new file mode 100644
index 0000000..8e84e40
--- /dev/null
+++ b/camera/ndk/Android.mk
@@ -0,0 +1,57 @@
+#
+# Copyright (C) 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+ifneq ($(TARGET_BUILD_PDK), true)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=                  \
+    NdkCameraManager.cpp           \
+    NdkCameraMetadata.cpp          \
+    NdkCameraDevice.cpp            \
+    NdkCaptureRequest.cpp          \
+    NdkCameraCaptureSession.cpp    \
+    impl/ACameraManager.cpp        \
+    impl/ACameraMetadata.cpp       \
+    impl/ACameraDevice.cpp         \
+    impl/ACameraCaptureSession.cpp
+
+LOCAL_MODULE:= libcamera2ndk
+
+LOCAL_C_INCLUDES := \
+    system/media/camera/include \
+    frameworks/av/include/camera/ndk \
+    frameworks/av/include/ndk \
+
+LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
+
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    liblog \
+    libgui \
+    libutils \
+    libandroid_runtime \
+    libcamera_client \
+    libstagefright_foundation \
+    libcutils \
+
+LOCAL_CLANG := true
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
new file mode 100644
index 0000000..ab93bd6
--- /dev/null
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 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_NDEBUG 0
+#define LOG_TAG "NdkCameraCaptureSession"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+#include <utils/StrongPointer.h>
+#include <utils/Trace.h>
+
+#include "NdkCameraDevice.h"
+#include <NdkCaptureRequest.h>
+#include <NdkCameraCaptureSession.h>
+#include "impl/ACameraCaptureSession.h"
+
+using namespace android;
+
+EXPORT
+void ACameraCaptureSession_close(ACameraCaptureSession* session) {
+    ATRACE_CALL();
+    if (session != nullptr) {
+        session->closeByApp();
+    }
+    return;
+}
+
+EXPORT
+camera_status_t ACameraCaptureSession_getDevice(
+        ACameraCaptureSession* session, ACameraDevice **device) {
+    ATRACE_CALL();
+    if (session == nullptr || device == nullptr) {
+        ALOGE("%s: Error: invalid input: session %p, device %p",
+                __FUNCTION__, session, device);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+
+    if (session->isClosed()) {
+        ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+        *device = nullptr;
+        return ACAMERA_ERROR_SESSION_CLOSED;
+    }
+
+    *device = session->getDevice();
+    if (*device == nullptr) {
+        // Should not reach here
+        ALOGE("%s: unknown failure: device is null", __FUNCTION__);
+        return ACAMERA_ERROR_UNKNOWN;
+    }
+    return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraCaptureSession_capture(
+        ACameraCaptureSession* session, /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+        int numRequests, ACaptureRequest** requests,
+        /*optional*/int* captureSequenceId) {
+    ATRACE_CALL();
+    if (session == nullptr || requests == nullptr || numRequests < 1) {
+        ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
+                __FUNCTION__, session, numRequests, requests);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+
+    if (session->isClosed()) {
+        ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+        *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+        return ACAMERA_ERROR_SESSION_CLOSED;
+    }
+
+    return session->capture(cbs, numRequests, requests, captureSequenceId);
+}
+
+EXPORT
+camera_status_t ACameraCaptureSession_setRepeatingRequest(
+        ACameraCaptureSession* session, /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+        int numRequests, ACaptureRequest** requests,
+        /*optional*/int* captureSequenceId) {
+    ATRACE_CALL();
+    if (session == nullptr || requests == nullptr || numRequests < 1) {
+        ALOGE("%s: Error: invalid input: session %p, numRequest %d, requests %p",
+                __FUNCTION__, session, numRequests, requests);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+
+    if (session->isClosed()) {
+        ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+        *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+        return ACAMERA_ERROR_SESSION_CLOSED;
+    }
+
+    return session->setRepeatingRequest(cbs, numRequests, requests, captureSequenceId);
+}
+
+EXPORT
+camera_status_t ACameraCaptureSession_stopRepeating(ACameraCaptureSession* session) {
+    ATRACE_CALL();
+    if (session == nullptr) {
+        ALOGE("%s: Error: session is null", __FUNCTION__);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+
+    if (session->isClosed()) {
+        ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+        return ACAMERA_ERROR_SESSION_CLOSED;
+    }
+    return session->stopRepeating();
+}
+
+EXPORT
+camera_status_t ACameraCaptureSession_abortCaptures(ACameraCaptureSession*) {
+    ATRACE_CALL();
+    return ACAMERA_OK;
+}
diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp
new file mode 100644
index 0000000..281d3e7
--- /dev/null
+++ b/camera/ndk/NdkCameraDevice.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 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_NDEBUG 0
+#define LOG_TAG "NdkCameraDevice"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include <NdkCameraDevice.h>
+#include "impl/ACameraCaptureSession.h"
+
+using namespace android;
+
+EXPORT
+camera_status_t ACameraDevice_close(ACameraDevice* device) {
+    ATRACE_CALL();
+    if (device == nullptr) {
+        ALOGE("%s: invalid argument! device is null", __FUNCTION__);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    delete device;
+    return ACAMERA_OK;
+}
+
+EXPORT
+const char* ACameraDevice_getId(const ACameraDevice* device) {
+    ATRACE_CALL();
+    if (device == nullptr) {
+        ALOGE("%s: invalid argument! device is null", __FUNCTION__);
+        return nullptr;
+    }
+    return device->getId();
+}
+
+EXPORT
+camera_status_t ACameraDevice_createCaptureRequest(
+        const ACameraDevice* device,
+        ACameraDevice_request_template templateId,
+        ACaptureRequest** request) {
+    ATRACE_CALL();
+    if (device == nullptr || request == nullptr) {
+        ALOGE("%s: invalid argument! device %p request %p",
+                __FUNCTION__, device, request);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    switch (templateId) {
+        case TEMPLATE_PREVIEW:
+        case TEMPLATE_STILL_CAPTURE:
+        case TEMPLATE_RECORD:
+        case TEMPLATE_VIDEO_SNAPSHOT:
+        case TEMPLATE_ZERO_SHUTTER_LAG:
+        case TEMPLATE_MANUAL:
+            break;
+        default:
+            ALOGE("%s: unknown template ID %d", __FUNCTION__, templateId);
+            return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    return device->createCaptureRequest(templateId, request);
+}
+
+EXPORT
+camera_status_t ACaptureSessionOutputContainer_create(
+        /*out*/ACaptureSessionOutputContainer** out) {
+    ATRACE_CALL();
+    if (out == nullptr) {
+        ALOGE("%s: Error: out null", __FUNCTION__);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    *out = new ACaptureSessionOutputContainer();
+    return ACAMERA_OK;
+}
+
+EXPORT
+void ACaptureSessionOutputContainer_free(ACaptureSessionOutputContainer* container) {
+    ATRACE_CALL();
+    if (container != nullptr) {
+        delete container;
+    }
+    return;
+}
+
+EXPORT
+camera_status_t ACaptureSessionOutput_create(
+        ANativeWindow* window, /*out*/ACaptureSessionOutput** out) {
+    ATRACE_CALL();
+    if (window == nullptr || out == nullptr) {
+        ALOGE("%s: Error: bad argument. window %p, out %p",
+                __FUNCTION__, window, out);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    *out = new ACaptureSessionOutput(window);
+    return ACAMERA_OK;
+}
+
+EXPORT
+void ACaptureSessionOutput_free(ACaptureSessionOutput* output) {
+    ATRACE_CALL();
+    if (output != nullptr) {
+        delete output;
+    }
+    return;
+}
+
+EXPORT
+camera_status_t ACaptureSessionOutputContainer_add(
+        ACaptureSessionOutputContainer* container, const ACaptureSessionOutput* output) {
+    ATRACE_CALL();
+    if (container == nullptr || output == nullptr) {
+        ALOGE("%s: Error: invalid input: container %p, output %p",
+                __FUNCTION__, container, output);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    auto pair = container->mOutputs.insert(*output);
+    if (!pair.second) {
+        ALOGW("%s: output %p already exists!", __FUNCTION__, output);
+    }
+    return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACaptureSessionOutputContainer_remove(
+        ACaptureSessionOutputContainer* container, const ACaptureSessionOutput* output) {
+    ATRACE_CALL();
+    if (container == nullptr || output == nullptr) {
+        ALOGE("%s: Error: invalid input: container %p, output %p",
+                __FUNCTION__, container, output);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    container->mOutputs.erase(*output);
+    return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraDevice_createCaptureSession(
+        ACameraDevice* device,
+        const ACaptureSessionOutputContainer*       outputs,
+        const ACameraCaptureSession_stateCallbacks* callbacks,
+        /*out*/ACameraCaptureSession** session) {
+    ATRACE_CALL();
+    if (device == nullptr || outputs == nullptr || callbacks == nullptr || session == nullptr) {
+        ALOGE("%s: Error: invalid input: device %p, outputs %p, callbacks %p, session %p",
+                __FUNCTION__, device, outputs, callbacks, session);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    return device->createCaptureSession(outputs, callbacks, session);
+}
diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp
new file mode 100644
index 0000000..7d9f84b
--- /dev/null
+++ b/camera/ndk/NdkCameraManager.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 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_NDEBUG 0
+#define LOG_TAG "NdkCameraManager"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include <NdkCameraManager.h>
+#include "impl/ACameraManager.h"
+
+EXPORT
+ACameraManager* ACameraManager_create() {
+    ATRACE_CALL();
+    return new ACameraManager();
+}
+
+EXPORT
+void ACameraManager_delete(ACameraManager* manager) {
+    ATRACE_CALL();
+    if (manager != nullptr) {
+        delete manager;
+    }
+}
+
+EXPORT
+camera_status_t ACameraManager_getCameraIdList(
+        ACameraManager* manager, ACameraIdList** cameraIdList) {
+    ATRACE_CALL();
+    if (manager == nullptr || cameraIdList == nullptr) {
+        ALOGE("%s: invalid argument! manager %p, cameraIdList %p",
+              __FUNCTION__, manager, cameraIdList);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    return manager->getCameraIdList(cameraIdList);
+}
+
+EXPORT
+void ACameraManager_deleteCameraIdList(ACameraIdList* cameraIdList) {
+    ATRACE_CALL();
+    if (cameraIdList != nullptr) {
+        ACameraManager::deleteCameraIdList(cameraIdList);
+    }
+}
+
+EXPORT
+camera_status_t ACameraManager_registerAvailabilityCallback(
+        ACameraManager*, const ACameraManager_AvailabilityCallbacks *callback) {
+    ATRACE_CALL();
+    if (callback == nullptr) {
+        ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    if (callback->onCameraAvailable == nullptr || callback->onCameraUnavailable == nullptr) {
+        ALOGE("%s: invalid argument! callback %p, "
+                "onCameraAvailable %p, onCameraUnavailable %p",
+               __FUNCTION__, callback,
+               callback->onCameraAvailable, callback->onCameraUnavailable);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    CameraManagerGlobal::getInstance().registerAvailabilityCallback(callback);
+    return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraManager_unregisterAvailabilityCallback(
+        ACameraManager*, const ACameraManager_AvailabilityCallbacks *callback) {
+    ATRACE_CALL();
+    if (callback == nullptr) {
+        ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    if (callback->onCameraAvailable == nullptr || callback->onCameraUnavailable == nullptr) {
+        ALOGE("%s: invalid argument! callback %p, "
+                "onCameraAvailable %p, onCameraUnavailable %p",
+               __FUNCTION__, callback,
+               callback->onCameraAvailable, callback->onCameraUnavailable);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    CameraManagerGlobal::getInstance().unregisterAvailabilityCallback(callback);
+    return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraManager_getCameraCharacteristics(
+        ACameraManager* mgr, const char* cameraId, ACameraMetadata** chars){
+    ATRACE_CALL();
+    if (mgr == nullptr || cameraId == nullptr || chars == nullptr) {
+        ALOGE("%s: invalid argument! mgr %p cameraId %p chars %p",
+                __FUNCTION__, mgr, cameraId, chars);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    return mgr->getCameraCharacteristics(cameraId, chars);
+}
+
+EXPORT
+camera_status_t ACameraManager_openCamera(
+        ACameraManager* mgr, const char* cameraId,
+        ACameraDevice_StateCallbacks* callback,
+        /*out*/ACameraDevice** device) {
+    ATRACE_CALL();
+    if (mgr == nullptr || cameraId == nullptr || callback == nullptr || device == nullptr) {
+        ALOGE("%s: invalid argument! mgr %p cameraId %p callback %p device %p",
+                __FUNCTION__, mgr, cameraId, callback, device);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    return mgr->openCamera(cameraId, callback, device);
+}
diff --git a/camera/ndk/NdkCameraMetadata.cpp b/camera/ndk/NdkCameraMetadata.cpp
new file mode 100644
index 0000000..18718d3
--- /dev/null
+++ b/camera/ndk/NdkCameraMetadata.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 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_NDEBUG 0
+#define LOG_TAG "NdkCameraMetadata"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include "NdkCameraMetadata.h"
+#include "impl/ACameraMetadata.h"
+
+using namespace android;
+
+EXPORT
+camera_status_t ACameraMetadata_getConstEntry(
+        const ACameraMetadata* acm, uint32_t tag, ACameraMetadata_const_entry* entry) {
+    ATRACE_CALL();
+    if (acm == nullptr || entry == nullptr) {
+        ALOGE("%s: invalid argument! metadata %p, tag 0x%x, entry %p",
+               __FUNCTION__, acm, tag, entry);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    return acm->getConstEntry(tag, entry);
+}
+
+EXPORT
+ACameraMetadata* ACameraMetadata_copy(const ACameraMetadata* src) {
+    ATRACE_CALL();
+    if (src == nullptr) {
+        ALOGE("%s: src is null!", __FUNCTION__);
+        return nullptr;
+    }
+    return new ACameraMetadata(*src);
+}
+
+EXPORT
+void ACameraMetadata_free(ACameraMetadata* metadata) {
+    ATRACE_CALL();
+    if (metadata != nullptr) {
+        delete metadata;
+    }
+}
diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
new file mode 100644
index 0000000..4fee09c
--- /dev/null
+++ b/camera/ndk/NdkCaptureRequest.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 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_NDEBUG 0
+#define LOG_TAG "NdkCaptureRequest"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include "NdkCaptureRequest.h"
+#include "impl/ACameraMetadata.h"
+#include "impl/ACaptureRequest.h"
+
+EXPORT
+camera_status_t ACameraOutputTarget_create(
+        ANativeWindow* window, ACameraOutputTarget** out) {
+    ATRACE_CALL();
+    if (window == nullptr) {
+        ALOGE("%s: Error: input window is null", __FUNCTION__);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    *out = new ACameraOutputTarget(window);
+    return ACAMERA_OK;
+}
+
+EXPORT
+void ACameraOutputTarget_free(ACameraOutputTarget* target) {
+    ATRACE_CALL();
+    if (target != nullptr) {
+        delete target;
+    }
+    return;
+}
+
+EXPORT
+camera_status_t ACaptureRequest_addTarget(
+        ACaptureRequest* req, const ACameraOutputTarget* target) {
+    ATRACE_CALL();
+    if (req == nullptr || req->targets == nullptr || target == nullptr) {
+        ALOGE("%s: Error: invalid input: req %p, req-targets %p, target %p",
+                __FUNCTION__, req, req->targets, target);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    auto pair = req->targets->mOutputs.insert(*target);
+    if (!pair.second) {
+        ALOGW("%s: target %p already exists!", __FUNCTION__, target);
+    }
+    return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACaptureRequest_removeTarget(
+        ACaptureRequest* req, const ACameraOutputTarget* target) {
+    ATRACE_CALL();
+    if (req == nullptr || req->targets == nullptr || target == nullptr) {
+        ALOGE("%s: Error: invalid input: req %p, req-targets %p, target %p",
+                __FUNCTION__, req, req->targets, target);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    req->targets->mOutputs.erase(*target);
+    return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACaptureRequest_getConstEntry(
+        const ACaptureRequest* req, uint32_t tag, ACameraMetadata_const_entry* entry) {
+    ATRACE_CALL();
+    if (req == nullptr || entry == nullptr) {
+        ALOGE("%s: invalid argument! req 0x%p, tag 0x%x, entry 0x%p",
+               __FUNCTION__, req, tag, entry);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    return req->settings->getConstEntry(tag, entry);
+}
+
+#define SET_ENTRY(NAME,NDK_TYPE)                                                        \
+EXPORT                                                                                  \
+camera_status_t ACaptureRequest_setEntry_##NAME(                                        \
+        ACaptureRequest* req, uint32_t tag, uint32_t count, const NDK_TYPE* data) {     \
+    ATRACE_CALL();                                                                      \
+    if (req == nullptr || (count > 0 && data == nullptr)) {                             \
+        ALOGE("%s: invalid argument! req %p, tag 0x%x, count %d, data 0x%p",            \
+               __FUNCTION__, req, tag, count, data);                                    \
+        return ACAMERA_ERROR_INVALID_PARAMETER;                                         \
+    }                                                                                   \
+    return req->settings->update(tag, count, data);                                     \
+}
+
+SET_ENTRY(u8,uint8_t)
+SET_ENTRY(i32,int32_t)
+SET_ENTRY(float,float)
+SET_ENTRY(double,double)
+SET_ENTRY(i64,int64_t)
+SET_ENTRY(rational,ACameraMetadata_rational)
+
+#undef SET_ENTRY
+
+EXPORT
+void ACaptureRequest_free(ACaptureRequest* request) {
+    ATRACE_CALL();
+    if (request == nullptr) {
+        return;
+    }
+    delete request->settings;
+    delete request->targets;
+    delete request;
+    return;
+}
diff --git a/camera/ndk/impl/ACameraCaptureSession.cpp b/camera/ndk/impl/ACameraCaptureSession.cpp
new file mode 100644
index 0000000..7f1b75d
--- /dev/null
+++ b/camera/ndk/impl/ACameraCaptureSession.cpp
@@ -0,0 +1,151 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "ACameraCaptureSession"
+
+#include "ACameraCaptureSession.h"
+
+using namespace android;
+
+ACameraCaptureSession::~ACameraCaptureSession() {
+    ALOGV("~ACameraCaptureSession: %p notify device end of life", this);
+    sp<CameraDevice> dev = getDeviceSp();
+    if (dev != nullptr && !dev->isClosed()) {
+        dev->lockDeviceForSessionOps();
+        {
+            Mutex::Autolock _l(mSessionLock);
+            dev->notifySessionEndOfLifeLocked(this);
+        }
+        dev->unlockDevice();
+    }
+    // Fire onClosed callback
+    (*mUserSessionCallback.onClosed)(mUserSessionCallback.context, this);
+    ALOGV("~ACameraCaptureSession: %p is deleted", this);
+}
+
+void
+ACameraCaptureSession::closeByApp() {
+    sp<CameraDevice> dev = getDeviceSp();
+    if (dev != nullptr) {
+        dev->lockDeviceForSessionOps();
+    }
+
+    {
+        Mutex::Autolock _l(mSessionLock);
+
+        if (!mIsClosed && dev != nullptr) {
+            camera_status_t ret = dev->stopRepeatingLocked();
+            if (ret != ACAMERA_OK) {
+                ALOGE("Stop repeating request failed while closing session %p", this);
+            }
+        }
+        mIsClosed = true;
+    }
+
+    if (dev != nullptr) {
+        dev->unlockDevice();
+    }
+    this->decStrong((void*) ACameraDevice_createCaptureSession);
+}
+
+camera_status_t
+ACameraCaptureSession::stopRepeating() {
+    sp<CameraDevice> dev = getDeviceSp();
+    if (dev == nullptr) {
+        ALOGE("Error: Device associated with session %p has been closed!", this);
+        return ACAMERA_ERROR_SESSION_CLOSED;
+    }
+
+    camera_status_t ret;
+    dev->lockDeviceForSessionOps();
+    {
+        Mutex::Autolock _l(mSessionLock);
+        ret = dev->stopRepeatingLocked();
+    }
+    dev->unlockDevice();
+    return ret;
+}
+
+camera_status_t
+ACameraCaptureSession::setRepeatingRequest(
+        /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+        int numRequests, ACaptureRequest** requests,
+        /*optional*/int* captureSequenceId) {
+    sp<CameraDevice> dev = getDeviceSp();
+    if (dev == nullptr) {
+        ALOGE("Error: Device associated with session %p has been closed!", this);
+        return ACAMERA_ERROR_SESSION_CLOSED;
+    }
+
+    camera_status_t ret;
+    dev->lockDeviceForSessionOps();
+    {
+        Mutex::Autolock _l(mSessionLock);
+        ret = dev->setRepeatingRequestsLocked(
+                this, cbs, numRequests, requests, captureSequenceId);
+    }
+    dev->unlockDevice();
+    return ret;
+}
+
+camera_status_t ACameraCaptureSession::capture(
+        /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+        int numRequests, ACaptureRequest** requests,
+        /*optional*/int* captureSequenceId) {
+    sp<CameraDevice> dev = getDeviceSp();
+    if (dev == nullptr) {
+        ALOGE("Error: Device associated with session %p has been closed!", this);
+        return ACAMERA_ERROR_SESSION_CLOSED;
+    }
+    camera_status_t ret;
+    dev->lockDeviceForSessionOps();
+    {
+        Mutex::Autolock _l(mSessionLock);
+        ret = dev->captureLocked(this, cbs, numRequests, requests, captureSequenceId);
+    }
+    dev->unlockDevice();
+    return ret;
+}
+
+ACameraDevice*
+ACameraCaptureSession::getDevice() {
+    Mutex::Autolock _l(mSessionLock);
+    sp<CameraDevice> dev = getDeviceSp();
+    if (dev == nullptr) {
+        ALOGE("Error: Device associated with session %p has been closed!", this);
+        return nullptr;
+    }
+    return dev->getWrapper();
+}
+
+void
+ACameraCaptureSession::closeByDevice() {
+    Mutex::Autolock _l(mSessionLock);
+    mIsClosed = true;
+}
+
+sp<CameraDevice>
+ACameraCaptureSession::getDeviceSp() {
+    sp<CameraDevice> device = mDevice.promote();
+    if (device == nullptr || device->isClosed()) {
+        ALOGW("Device is closed but session %d is not notified", mId);
+        return nullptr;
+    }
+    return device;
+}
+
+
diff --git a/camera/ndk/impl/ACameraCaptureSession.h b/camera/ndk/impl/ACameraCaptureSession.h
new file mode 100644
index 0000000..1db1b21
--- /dev/null
+++ b/camera/ndk/impl/ACameraCaptureSession.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 _ACAMERA_CAPTURE_SESSION_H
+#define _ACAMERA_CAPTURE_SESSION_H
+
+#include <set>
+#include <hardware/camera3.h>
+#include <NdkCameraDevice.h>
+#include "ACameraDevice.h"
+
+using namespace android;
+
+struct ACaptureSessionOutput {
+    ACaptureSessionOutput(ANativeWindow* window) : mWindow(window) {};
+
+    bool operator == (const ACaptureSessionOutput& other) const {
+        return mWindow == other.mWindow;
+    }
+    bool operator != (const ACaptureSessionOutput& other) const {
+        return mWindow != other.mWindow;
+    }
+    bool operator < (const ACaptureSessionOutput& other) const {
+        return mWindow < other.mWindow;
+    }
+    bool operator > (const ACaptureSessionOutput& other) const {
+        return mWindow > other.mWindow;
+    }
+
+    ANativeWindow* mWindow;
+    int            mRotation = CAMERA3_STREAM_ROTATION_0;
+};
+
+struct ACaptureSessionOutputContainer {
+    std::set<ACaptureSessionOutput> mOutputs;
+};
+
+/**
+ * ACameraCaptureSession opaque struct definition
+ * Leave outside of android namespace because it's NDK struct
+ */
+struct ACameraCaptureSession : public RefBase {
+  public:
+    ACameraCaptureSession(
+            int id,
+            const ACaptureSessionOutputContainer* outputs,
+            const ACameraCaptureSession_stateCallbacks* cb,
+            CameraDevice* device) :
+            mId(id), mOutput(*outputs), mUserSessionCallback(*cb),
+            mDevice(device) {}
+
+    // This can be called in app calling close() or after some app callback is finished
+    // Make sure the caller does not hold device or session lock!
+    ~ACameraCaptureSession();
+
+    // No API except Session_Close will work if device is closed
+    // A session will enter closed state when one of the following happens:
+    //     1. Explicitly closed by app
+    //     2. Replaced by a newer session
+    //     3. Device is closed
+    bool isClosed() { Mutex::Autolock _l(mSessionLock); return mIsClosed; }
+
+    // Close the session and mark app no longer need this session.
+    void closeByApp();
+
+    camera_status_t stopRepeating();
+
+    camera_status_t setRepeatingRequest(
+            /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+            int numRequests, ACaptureRequest** requests,
+            /*optional*/int* captureSequenceId);
+
+    camera_status_t capture(
+            /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+            int numRequests, ACaptureRequest** requests,
+            /*optional*/int* captureSequenceId);
+
+    ACameraDevice* getDevice();
+
+  private:
+    friend class CameraDevice;
+
+    // Close session because app close camera device, camera device got ERROR_DISCONNECTED,
+    // or a new session is replacing this session.
+    void closeByDevice();
+
+    sp<CameraDevice> getDeviceSp();
+
+    const int mId;
+    const ACaptureSessionOutputContainer mOutput;
+    const ACameraCaptureSession_stateCallbacks mUserSessionCallback;
+    const wp<CameraDevice> mDevice;
+    bool  mIsClosed = false;
+    bool  mIdle = true;
+    Mutex mSessionLock;
+};
+
+#endif // _ACAMERA_CAPTURE_SESSION_H
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
new file mode 100644
index 0000000..5f89fa3
--- /dev/null
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -0,0 +1,1212 @@
+/*
+ * Copyright (C) 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_NDEBUG 0
+#define LOG_TAG "ACameraDevice"
+
+#include <vector>
+#include <utility>
+#include <inttypes.h>
+#include <gui/Surface.h>
+#include "ACameraDevice.h"
+#include "ACameraMetadata.h"
+#include "ACaptureRequest.h"
+#include "ACameraCaptureSession.h"
+
+using namespace android;
+
+namespace android {
+// Static member definitions
+const char* CameraDevice::kContextKey        = "Context";
+const char* CameraDevice::kDeviceKey         = "Device";
+const char* CameraDevice::kErrorCodeKey      = "ErrorCode";
+const char* CameraDevice::kCallbackFpKey     = "Callback";
+const char* CameraDevice::kSessionSpKey      = "SessionSp";
+const char* CameraDevice::kCaptureRequestKey = "CaptureRequest";
+const char* CameraDevice::kTimeStampKey      = "TimeStamp";
+const char* CameraDevice::kCaptureResultKey  = "CaptureResult";
+const char* CameraDevice::kCaptureFailureKey = "CaptureFailure";
+const char* CameraDevice::kSequenceIdKey     = "SequenceId";
+const char* CameraDevice::kFrameNumberKey    = "FrameNumber";
+
+/**
+ * CameraDevice Implementation
+ */
+CameraDevice::CameraDevice(
+        const char* id,
+        ACameraDevice_StateCallbacks* cb,
+        std::unique_ptr<ACameraMetadata> chars,
+        ACameraDevice* wrapper) :
+        mCameraId(id),
+        mAppCallbacks(*cb),
+        mChars(std::move(chars)),
+        mServiceCallback(new ServiceCallback(this)),
+        mWrapper(wrapper),
+        mInError(false),
+        mError(ACAMERA_OK),
+        mIdle(true) {
+    mClosing = false;
+    // Setup looper thread to perfrom device callbacks to app
+    mCbLooper = new ALooper;
+    mCbLooper->setName("C2N-dev-looper");
+    status_t ret = mCbLooper->start(
+            /*runOnCallingThread*/false,
+            /*canCallJava*/       true,
+            PRIORITY_DEFAULT);
+    mHandler = new CallbackHandler();
+    mCbLooper->registerHandler(mHandler);
+
+    CameraMetadata metadata = mChars->mData;
+    camera_metadata_entry entry = metadata.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
+    if (entry.count != 1) {
+        ALOGW("%s: bad count %zu for partial result count", __FUNCTION__, entry.count);
+        mPartialResultCount = 1;
+    } else {
+        mPartialResultCount = entry.data.i32[0];
+    }
+
+    entry = metadata.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
+    if (entry.count != 2) {
+        ALOGW("%s: bad count %zu for shading map size", __FUNCTION__, entry.count);
+        mShadingMapSize[0] = 0;
+        mShadingMapSize[1] = 0;
+    } else {
+        mShadingMapSize[0] = entry.data.i32[0];
+        mShadingMapSize[1] = entry.data.i32[1];
+    }
+}
+
+// Device close implementaiton
+CameraDevice::~CameraDevice() {
+    Mutex::Autolock _l(mDeviceLock);
+    if (!isClosed()) {
+        disconnectLocked();
+    }
+    if (mCbLooper != nullptr) {
+        mCbLooper->unregisterHandler(mHandler->id());
+        mCbLooper->stop();
+    }
+    mCbLooper.clear();
+    mHandler.clear();
+}
+
+// TODO: cached created request?
+camera_status_t
+CameraDevice::createCaptureRequest(
+        ACameraDevice_request_template templateId,
+        ACaptureRequest** request) const {
+    Mutex::Autolock _l(mDeviceLock);
+    camera_status_t ret = checkCameraClosedOrErrorLocked();
+    if (ret != ACAMERA_OK) {
+        return ret;
+    }
+    if (mRemote == nullptr) {
+        return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+    }
+    CameraMetadata rawRequest;
+    status_t remoteRet = mRemote->createDefaultRequest(templateId, &rawRequest);
+    if (remoteRet == BAD_VALUE) {
+        ALOGW("Create capture request failed! template %d is not supported on this device",
+            templateId);
+        return ACAMERA_ERROR_UNSUPPORTED;
+    } else if (remoteRet != OK) {
+        ALOGE("Create capture request failed! error %d", remoteRet);
+        return ACAMERA_ERROR_UNKNOWN;
+    }
+    ACaptureRequest* outReq = new ACaptureRequest();
+    outReq->settings = new ACameraMetadata(rawRequest.release(), ACameraMetadata::ACM_REQUEST);
+    outReq->targets  = new ACameraOutputTargets();
+    *request = outReq;
+    return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::createCaptureSession(
+        const ACaptureSessionOutputContainer*       outputs,
+        const ACameraCaptureSession_stateCallbacks* callbacks,
+        /*out*/ACameraCaptureSession** session) {
+    Mutex::Autolock _l(mDeviceLock);
+    camera_status_t ret = checkCameraClosedOrErrorLocked();
+    if (ret != ACAMERA_OK) {
+        return ret;
+    }
+
+    if (mCurrentSession != nullptr) {
+        mCurrentSession->closeByDevice();
+        stopRepeatingLocked();
+    }
+
+    // Create new session
+    ret = configureStreamsLocked(outputs);
+    if (ret != ACAMERA_OK) {
+        ALOGE("Fail to create new session. cannot configure streams");
+        return ret;
+    }
+
+    ACameraCaptureSession* newSession = new ACameraCaptureSession(
+            mNextSessionId++, outputs, callbacks, this);
+
+    bool configureSucceeded = (ret == ACAMERA_OK);
+
+    // set new session as current session
+    newSession->incStrong((void *) ACameraDevice_createCaptureSession);
+    mCurrentSession = newSession;
+    *session = newSession;
+    return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::captureLocked(
+        sp<ACameraCaptureSession> session,
+        /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+        int numRequests, ACaptureRequest** requests,
+        /*optional*/int* captureSequenceId) {
+    return submitRequestsLocked(
+            session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/false);
+}
+
+camera_status_t
+CameraDevice::setRepeatingRequestsLocked(
+        sp<ACameraCaptureSession> session,
+        /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+        int numRequests, ACaptureRequest** requests,
+        /*optional*/int* captureSequenceId) {
+    return submitRequestsLocked(
+            session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/true);
+}
+
+camera_status_t
+CameraDevice::submitRequestsLocked(
+        sp<ACameraCaptureSession> session,
+        /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+        int numRequests, ACaptureRequest** requests,
+        /*optional*/int* captureSequenceId,
+        bool isRepeating) {
+    camera_status_t ret = checkCameraClosedOrErrorLocked();
+    if (ret != ACAMERA_OK) {
+        ALOGE("Camera %s submit capture request failed! ret %d", getId(), ret);
+        return ret;
+    }
+
+    // Form List/Vector of capture request
+    List<sp<CaptureRequest> > requestList;
+    Vector<sp<CaptureRequest> > requestsV;
+    requestsV.setCapacity(numRequests);
+    for (int i = 0; i < numRequests; i++) {
+        sp<CaptureRequest> req;
+        ret = allocateCaptureRequest(requests[i], req);
+        if (ret != ACAMERA_OK) {
+            ALOGE("Convert capture request to internal format failure! ret %d", ret);
+            return ret;
+        }
+        if (req->mSurfaceList.empty()) {
+            ALOGE("Capture request without output target cannot be submitted!");
+            return ACAMERA_ERROR_INVALID_PARAMETER;
+        }
+        requestList.push_back(req);
+        requestsV.push_back(req);
+    }
+
+    if (isRepeating) {
+        ret = stopRepeatingLocked();
+        if (ret != ACAMERA_OK) {
+            ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
+            return ret;
+        }
+    }
+
+    int sequenceId;
+    int64_t lastFrameNumber;
+
+    sequenceId = mRemote->submitRequestList(requestList, isRepeating, &lastFrameNumber);
+    if (sequenceId < 0) {
+        ALOGE("Camera %s submit request remote failure: ret %d", getId(), sequenceId);
+        return ACAMERA_ERROR_UNKNOWN;
+    }
+
+    CallbackHolder cbHolder(session, requestsV, isRepeating, cbs);
+    mSequenceCallbackMap.insert(std::make_pair(sequenceId, cbHolder));
+
+    if (isRepeating) {
+        // stopRepeating above should have cleanup repeating sequence id
+        if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+            setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+            return ACAMERA_ERROR_CAMERA_DEVICE;
+        }
+        mRepeatingSequenceId = sequenceId;
+    } else {
+        mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
+    }
+
+    if (mIdle) {
+        sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+        msg->setPointer(kContextKey, session->mUserSessionCallback.context);
+        msg->setObject(kSessionSpKey, session);
+        msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
+        msg->post();
+    }
+    mIdle = false;
+    mBusySession = session;
+
+    if (captureSequenceId) {
+        *captureSequenceId = sequenceId;
+    }
+    return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::allocateCaptureRequest(
+        const ACaptureRequest* request, /*out*/sp<CaptureRequest>& outReq) {
+    camera_status_t ret;
+    sp<CaptureRequest> req(new CaptureRequest());
+    req->mMetadata = request->settings->mData;
+    req->mIsReprocess = false; // NDK does not support reprocessing yet
+
+    for (auto outputTarget : request->targets->mOutputs) {
+        ANativeWindow* anw = outputTarget.mWindow;
+        sp<Surface> surface;
+        ret = getSurfaceFromANativeWindow(anw, surface);
+        if (ret != ACAMERA_OK) {
+            ALOGE("Bad output target in capture request! ret %d", ret);
+            return ret;
+        }
+        req->mSurfaceList.push_back(surface);
+    }
+    outReq = req;
+    return ACAMERA_OK;
+}
+
+ACaptureRequest*
+CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req) {
+    ACaptureRequest* pRequest = new ACaptureRequest();
+    CameraMetadata clone = req->mMetadata;
+    pRequest->settings = new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
+    pRequest->targets  = new ACameraOutputTargets();
+    for (size_t i = 0; i < req->mSurfaceList.size(); i++) {
+        ANativeWindow* anw = static_cast<ANativeWindow*>(req->mSurfaceList[i].get());
+        ACameraOutputTarget outputTarget(anw);
+        pRequest->targets->mOutputs.insert(outputTarget);
+    }
+    return pRequest;
+}
+
+void
+CameraDevice::freeACaptureRequest(ACaptureRequest* req) {
+    if (req == nullptr) {
+        return;
+    }
+    delete req->settings;
+    delete req->targets;
+    delete req;
+}
+
+void
+CameraDevice::notifySessionEndOfLifeLocked(ACameraCaptureSession* session) {
+    if (isClosed()) {
+        // Device is closing already. do nothing
+        return;
+    }
+
+    if (session != mCurrentSession) {
+        // Session has been replaced by other seesion or device is closed
+        return;
+    }
+    mCurrentSession = nullptr;
+
+    // Should not happen
+    if (!session->mIsClosed) {
+        ALOGE("Error: unclosed session %p reaches end of life!", session);
+        setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+        return;
+    }
+
+    // No new session, unconfigure now
+    camera_status_t ret = configureStreamsLocked(nullptr);
+    if (ret != ACAMERA_OK) {
+        ALOGE("Unconfigure stream failed. Device might still be configured! ret %d", ret);
+    }
+}
+
+void
+CameraDevice::disconnectLocked() {
+    if (mClosing.exchange(true)) {
+        // Already closing, just return
+        ALOGW("Camera device %s is already closing.", getId());
+        return;
+    }
+
+    if (mRemote != nullptr) {
+        mRemote->disconnect();
+    }
+    mRemote = nullptr;
+
+    if (mCurrentSession != nullptr) {
+        mCurrentSession->closeByDevice();
+        mCurrentSession = nullptr;
+    }
+}
+
+camera_status_t
+CameraDevice::stopRepeatingLocked() {
+    camera_status_t ret = checkCameraClosedOrErrorLocked();
+    if (ret != ACAMERA_OK) {
+        ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
+        return ret;
+    }
+    if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+        int repeatingSequenceId = mRepeatingSequenceId;
+        mRepeatingSequenceId = REQUEST_ID_NONE;
+
+        int64_t lastFrameNumber;
+        status_t remoteRet = mRemote->cancelRequest(repeatingSequenceId, &lastFrameNumber);
+        if (remoteRet != OK) {
+            ALOGE("Stop repeating request fails in remote! ret %d", remoteRet);
+            return ACAMERA_ERROR_UNKNOWN;
+        }
+        checkRepeatingSequenceCompleteLocked(repeatingSequenceId, lastFrameNumber);
+    }
+    return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::waitUntilIdleLocked() {
+    camera_status_t ret = checkCameraClosedOrErrorLocked();
+    if (ret != ACAMERA_OK) {
+        ALOGE("Wait until camera %s idle failed! ret %d", getId(), ret);
+        return ret;
+    }
+
+    if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+        ALOGE("Camera device %s won't go to idle when there is repeating request!", getId());
+        return ACAMERA_ERROR_INVALID_OPERATION;
+    }
+
+    status_t remoteRet = mRemote->waitUntilIdle();
+    if (remoteRet != OK) {
+        ALOGE("Camera device %s waitUntilIdle failed! ret %d", getId(), remoteRet);
+        // TODO: define a function to convert status_t -> camera_status_t
+        return ACAMERA_ERROR_UNKNOWN;
+    }
+
+    return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::getIGBPfromSessionOutput(
+        const ACaptureSessionOutput& config,
+        sp<IGraphicBufferProducer>& out) {
+    ANativeWindow* anw = config.mWindow;
+    if (anw == nullptr) {
+        ALOGE("Error: output ANativeWindow is null");
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    int value;
+    int err = (*anw->query)(anw, NATIVE_WINDOW_CONCRETE_TYPE, &value);
+    if (value != NATIVE_WINDOW_SURFACE) {
+        ALOGE("Error: ANativeWindow is not backed by Surface!");
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    const sp<Surface> surface(static_cast<Surface*>(anw));
+    out = surface->getIGraphicBufferProducer();
+    return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::getSurfaceFromANativeWindow(
+        ANativeWindow* anw, sp<Surface>& out) {
+    if (anw == nullptr) {
+        ALOGE("Error: output ANativeWindow is null");
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    int value;
+    int err = (*anw->query)(anw, NATIVE_WINDOW_CONCRETE_TYPE, &value);
+    if (value != NATIVE_WINDOW_SURFACE) {
+        ALOGE("Error: ANativeWindow is not backed by Surface!");
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    sp<Surface> surface(static_cast<Surface*>(anw));
+    out = surface;
+    return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::configureStreamsLocked(const ACaptureSessionOutputContainer* outputs) {
+    ACaptureSessionOutputContainer emptyOutput;
+    if (outputs == nullptr) {
+        outputs = &emptyOutput;
+    }
+
+    bool success = false;
+    camera_status_t ret = checkCameraClosedOrErrorLocked();
+    if (ret != ACAMERA_OK) {
+        return ret;
+    }
+
+    std::set<OutputConfiguration> outputSet;
+    for (auto outConfig : outputs->mOutputs) {
+        sp<IGraphicBufferProducer> iGBP(nullptr);
+        ret = getIGBPfromSessionOutput(outConfig, iGBP);
+        if (ret != ACAMERA_OK) {
+            return ret;
+        }
+        outputSet.insert(OutputConfiguration(iGBP, outConfig.mRotation));
+    }
+    std::set<OutputConfiguration> addSet = outputSet;
+    std::vector<int> deleteList;
+
+    // Determine which streams need to be created, which to be deleted
+    for (auto& kvPair : mConfiguredOutputs) {
+        int streamId = kvPair.first;
+        OutputConfiguration& outConfig = kvPair.second;
+        if (outputSet.count(outConfig) == 0) {
+            deleteList.push_back(streamId); // Need to delete a no longer needed stream
+        } else {
+            addSet.erase(outConfig);        // No need to add already existing stream
+        }
+    }
+
+    ret = stopRepeatingLocked();
+    if (ret != ACAMERA_OK) {
+        ALOGE("Camera device %s stop repeating failed, ret %d", getId(), ret);
+        return ret;
+    }
+
+    ret = waitUntilIdleLocked();
+    if (ret != ACAMERA_OK) {
+        ALOGE("Camera device %s wait until idle failed, ret %d", getId(), ret);
+        return ret;
+    }
+
+    // Send onReady to previous session
+    // CurrentSession will be updated after configureStreamLocked, so here
+    // mCurrentSession is the session to be replaced by a new session
+    if (!mIdle && mCurrentSession != nullptr) {
+        if (mBusySession != mCurrentSession) {
+            ALOGE("Current session != busy session");
+            setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+            return ACAMERA_ERROR_CAMERA_DEVICE;
+        }
+        sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+        msg->setPointer(kContextKey, mBusySession->mUserSessionCallback.context);
+        msg->setObject(kSessionSpKey, mBusySession);
+        msg->setPointer(kCallbackFpKey, (void*) mBusySession->mUserSessionCallback.onReady);
+        mBusySession.clear();
+        msg->post();
+    }
+    mIdle = true;
+
+    status_t remoteRet = mRemote->beginConfigure();
+    if (remoteRet != ACAMERA_OK) {
+        ALOGE("Camera device %s begin configure failed, ret %d", getId(), remoteRet);
+        return ACAMERA_ERROR_UNKNOWN;
+    }
+
+    // delete to-be-deleted streams
+    for (auto streamId : deleteList) {
+        remoteRet = mRemote->deleteStream(streamId);
+        if (remoteRet != ACAMERA_OK) {
+            ALOGE("Camera device %s fails to remove stream %d", getId(), streamId);
+            return ACAMERA_ERROR_UNKNOWN;
+        }
+        mConfiguredOutputs.erase(streamId);
+    }
+
+    // add new streams
+    for (auto outConfig : addSet) {
+        remoteRet = mRemote->createStream(outConfig);
+        if (remoteRet < 0) {
+            ALOGE("Camera device %s fails to create stream", getId());
+            return ACAMERA_ERROR_UNKNOWN;
+        }
+        int streamId = remoteRet; // Weird, right?
+        mConfiguredOutputs.insert(std::make_pair(streamId, outConfig));
+    }
+
+    remoteRet = mRemote->endConfigure();
+    if (remoteRet == BAD_VALUE) {
+        ALOGE("Camera device %s cannnot support app output configuration", getId());
+        return ACAMERA_ERROR_STREAM_CONFIGURE_FAIL;
+    } else if (remoteRet != ACAMERA_OK) {
+        ALOGE("Camera device %s end configure failed, ret %d", getId(), remoteRet);
+        return ACAMERA_ERROR_UNKNOWN;
+    }
+
+    return ACAMERA_OK;
+}
+
+void
+CameraDevice::setRemoteDevice(sp<ICameraDeviceUser> remote) {
+    Mutex::Autolock _l(mDeviceLock);
+    mRemote = remote;
+}
+
+camera_status_t
+CameraDevice::checkCameraClosedOrErrorLocked() const {
+    if (mRemote == nullptr) {
+        ALOGE("%s: camera device already closed", __FUNCTION__);
+        return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+    }
+    if (mInError) {// triggered by onDeviceError
+        ALOGE("%s: camera device has encountered a serious error", __FUNCTION__);
+        return mError;
+    }
+    return ACAMERA_OK;
+}
+
+void
+CameraDevice::setCameraDeviceErrorLocked(camera_status_t error) {
+    mInError = true;
+    mError = error;
+    return;
+}
+
+void
+CameraDevice::FrameNumberTracker::updateTracker(int64_t frameNumber, bool isError) {
+    ALOGV("updateTracker frame %" PRId64 " isError %d", frameNumber, isError);
+    if (isError) {
+        mFutureErrorSet.insert(frameNumber);
+    } else if (frameNumber <= mCompletedFrameNumber) {
+        ALOGE("Frame number %" PRId64 " decreased! current fn %" PRId64,
+                frameNumber, mCompletedFrameNumber);
+        return;
+    } else {
+        if (frameNumber != mCompletedFrameNumber + 1) {
+            ALOGE("Frame number out of order. Expect %" PRId64 " but get %" PRId64,
+                    mCompletedFrameNumber + 1, frameNumber);
+            // Do not assert as in java implementation
+        }
+        mCompletedFrameNumber = frameNumber;
+    }
+    update();
+}
+
+void
+CameraDevice::FrameNumberTracker::update() {
+    for (auto it = mFutureErrorSet.begin(); it != mFutureErrorSet.end();) {
+        int64_t errorFrameNumber = *it;
+        if (errorFrameNumber == mCompletedFrameNumber + 1) {
+            mCompletedFrameNumber++;
+            it = mFutureErrorSet.erase(it);
+        } else if (errorFrameNumber <= mCompletedFrameNumber) {
+            // This should not happen, but deal with it anyway
+            ALOGE("Completd frame number passed through current frame number!");
+            // erase the old error since it's no longer useful
+            it = mFutureErrorSet.erase(it);
+        } else {
+            // Normal requests hasn't catched up error frames, just break
+            break;
+        }
+    }
+    ALOGV("Update complete frame %" PRId64, mCompletedFrameNumber);
+}
+
+void
+CameraDevice::onCaptureErrorLocked(
+        ICameraDeviceCallbacks::CameraErrorCode errorCode,
+        const CaptureResultExtras& resultExtras) {
+    int sequenceId = resultExtras.requestId;
+    int64_t frameNumber = resultExtras.frameNumber;
+    int32_t burstId = resultExtras.burstId;
+
+    // No way to report buffer error now
+    if (errorCode == ICameraDeviceCallbacks::CameraErrorCode::ERROR_CAMERA_BUFFER) {
+        ALOGE("Camera %s Lost output buffer for frame %" PRId64,
+                getId(), frameNumber);
+        return;
+    }
+    // Fire capture failure callback if there is one registered
+    auto it = mSequenceCallbackMap.find(sequenceId);
+    if (it != mSequenceCallbackMap.end()) {
+        CallbackHolder cbh = (*it).second;
+        ACameraCaptureSession_captureCallback_failed onError = cbh.mCallbacks.onCaptureFailed;
+        sp<ACameraCaptureSession> session = cbh.mSession;
+        if ((size_t) burstId >= cbh.mRequests.size()) {
+            ALOGE("%s: Error: request index %d out of bound (size %zu)",
+                    __FUNCTION__, burstId, cbh.mRequests.size());
+            setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+            return;
+        }
+        sp<CaptureRequest> request = cbh.mRequests[burstId];
+        sp<CameraCaptureFailure> failure(new CameraCaptureFailure());
+        failure->frameNumber = frameNumber;
+        // TODO: refine this when implementing flush
+        failure->reason      = CAPTURE_FAILURE_REASON_ERROR;
+        failure->sequenceId  = sequenceId;
+        failure->wasImageCaptured = (errorCode ==
+                ICameraDeviceCallbacks::CameraErrorCode::ERROR_CAMERA_RESULT);
+
+        sp<AMessage> msg = new AMessage(kWhatCaptureFail, mHandler);
+        msg->setPointer(kContextKey, cbh.mCallbacks.context);
+        msg->setObject(kSessionSpKey, session);
+        msg->setPointer(kCallbackFpKey, (void*) onError);
+        msg->setObject(kCaptureRequestKey, request);
+        msg->setObject(kCaptureFailureKey, failure);
+        msg->post();
+    }
+
+    // Update tracker
+    mFrameNumberTracker.updateTracker(frameNumber, /*isError*/true);
+    checkAndFireSequenceCompleteLocked();
+}
+
+void CameraDevice::CallbackHandler::onMessageReceived(
+        const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatOnDisconnected:
+        case kWhatOnError:
+        case kWhatSessionStateCb:
+        case kWhatCaptureStart:
+        case kWhatCaptureResult:
+        case kWhatCaptureFail:
+        case kWhatCaptureSeqEnd:
+        case kWhatCaptureSeqAbort:
+            ALOGV("%s: Received msg %d", __FUNCTION__, msg->what());
+            break;
+        default:
+            ALOGE("%s:Error: unknown device callback %d", __FUNCTION__, msg->what());
+            return;
+    }
+    // Check the common part of all message
+    void* context;
+    bool found = msg->findPointer(kContextKey, &context);
+    if (!found) {
+        ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+        return;
+    }
+    switch (msg->what()) {
+        case kWhatOnDisconnected:
+        {
+            ACameraDevice* dev;
+            found = msg->findPointer(kDeviceKey, (void**) &dev);
+            if (!found || dev == nullptr) {
+                ALOGE("%s: Cannot find device pointer!", __FUNCTION__);
+                return;
+            }
+            ACameraDevice_StateCallback onDisconnected;
+            found = msg->findPointer(kCallbackFpKey, (void**) &onDisconnected);
+            if (!found) {
+                ALOGE("%s: Cannot find onDisconnected!", __FUNCTION__);
+                return;
+            }
+            if (onDisconnected == nullptr) {
+                return;
+            }
+            (*onDisconnected)(context, dev);
+            break;
+        }
+        case kWhatOnError:
+        {
+            ACameraDevice* dev;
+            found = msg->findPointer(kDeviceKey, (void**) &dev);
+            if (!found || dev == nullptr) {
+                ALOGE("%s: Cannot find device pointer!", __FUNCTION__);
+                return;
+            }
+            ACameraDevice_ErrorStateCallback onError;
+            found = msg->findPointer(kCallbackFpKey, (void**) &onError);
+            if (!found) {
+                ALOGE("%s: Cannot find onError!", __FUNCTION__);
+                return;
+            }
+            int errorCode;
+            found = msg->findInt32(kErrorCodeKey, &errorCode);
+            if (!found) {
+                ALOGE("%s: Cannot find error code!", __FUNCTION__);
+                return;
+            }
+            if (onError == nullptr) {
+                return;
+            }
+            (*onError)(context, dev, errorCode);
+            break;
+        }
+        case kWhatSessionStateCb:
+        case kWhatCaptureStart:
+        case kWhatCaptureResult:
+        case kWhatCaptureFail:
+        case kWhatCaptureSeqEnd:
+        case kWhatCaptureSeqAbort:
+        {
+            sp<RefBase> obj;
+            found = msg->findObject(kSessionSpKey, &obj);
+            if (!found || obj == nullptr) {
+                ALOGE("%s: Cannot find session pointer!", __FUNCTION__);
+                return;
+            }
+            sp<ACameraCaptureSession> session(static_cast<ACameraCaptureSession*>(obj.get()));
+            sp<CaptureRequest> requestSp = nullptr;
+            switch (msg->what()) {
+                case kWhatCaptureStart:
+                case kWhatCaptureResult:
+                case kWhatCaptureFail:
+                    found = msg->findObject(kCaptureRequestKey, &obj);
+                    if (!found) {
+                        ALOGE("%s: Cannot find capture request!", __FUNCTION__);
+                        return;
+                    }
+                    requestSp = static_cast<CaptureRequest*>(obj.get());
+                    break;
+            }
+
+            switch (msg->what()) {
+                case kWhatSessionStateCb:
+                {
+                    ACameraCaptureSession_stateCallback onState;
+                    found = msg->findPointer(kCallbackFpKey, (void**) &onState);
+                    if (!found) {
+                        ALOGE("%s: Cannot find state callback!", __FUNCTION__);
+                        return;
+                    }
+                    if (onState == nullptr) {
+                        return;
+                    }
+                    (*onState)(context, session.get());
+                    break;
+                }
+                case kWhatCaptureStart:
+                {
+                    ACameraCaptureSession_captureCallback_start onStart;
+                    found = msg->findPointer(kCallbackFpKey, (void**) &onStart);
+                    if (!found) {
+                        ALOGE("%s: Cannot find capture start callback!", __FUNCTION__);
+                        return;
+                    }
+                    if (onStart == nullptr) {
+                        return;
+                    }
+                    int64_t timestamp;
+                    found = msg->findInt64(kTimeStampKey, &timestamp);
+                    if (!found) {
+                        ALOGE("%s: Cannot find timestamp!", __FUNCTION__);
+                        return;
+                    }
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp);
+                    (*onStart)(context, session.get(), request, timestamp);
+                    freeACaptureRequest(request);
+                    break;
+                }
+                case kWhatCaptureResult:
+                {
+                    ACameraCaptureSession_captureCallback_result onResult;
+                    found = msg->findPointer(kCallbackFpKey, (void**) &onResult);
+                    if (!found) {
+                        ALOGE("%s: Cannot find capture result callback!", __FUNCTION__);
+                        return;
+                    }
+                    if (onResult == nullptr) {
+                        return;
+                    }
+
+                    found = msg->findObject(kCaptureResultKey, &obj);
+                    if (!found) {
+                        ALOGE("%s: Cannot find capture result!", __FUNCTION__);
+                        return;
+                    }
+                    sp<ACameraMetadata> result(static_cast<ACameraMetadata*>(obj.get()));
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp);
+                    (*onResult)(context, session.get(), request, result.get());
+                    freeACaptureRequest(request);
+                    break;
+                }
+                case kWhatCaptureFail:
+                {
+                    ACameraCaptureSession_captureCallback_failed onFail;
+                    found = msg->findPointer(kCallbackFpKey, (void**) &onFail);
+                    if (!found) {
+                        ALOGE("%s: Cannot find capture fail callback!", __FUNCTION__);
+                        return;
+                    }
+                    if (onFail == nullptr) {
+                        return;
+                    }
+
+                    found = msg->findObject(kCaptureFailureKey, &obj);
+                    if (!found) {
+                        ALOGE("%s: Cannot find capture failure!", __FUNCTION__);
+                        return;
+                    }
+                    sp<CameraCaptureFailure> failureSp(
+                            static_cast<CameraCaptureFailure*>(obj.get()));
+                    ACameraCaptureFailure* failure =
+                            static_cast<ACameraCaptureFailure*>(failureSp.get());
+                    ACaptureRequest* request = allocateACaptureRequest(requestSp);
+                    (*onFail)(context, session.get(), request, failure);
+                    freeACaptureRequest(request);
+                    delete failure;
+                    break;
+                }
+                case kWhatCaptureSeqEnd:
+                {
+                    ACameraCaptureSession_captureCallback_sequenceEnd onSeqEnd;
+                    found = msg->findPointer(kCallbackFpKey, (void**) &onSeqEnd);
+                    if (!found) {
+                        ALOGE("%s: Cannot find sequence end callback!", __FUNCTION__);
+                        return;
+                    }
+                    if (onSeqEnd == nullptr) {
+                        return;
+                    }
+                    int seqId;
+                    found = msg->findInt32(kSequenceIdKey, &seqId);
+                    if (!found) {
+                        ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+                        return;
+                    }
+                    int64_t frameNumber;
+                    found = msg->findInt64(kFrameNumberKey, &frameNumber);
+                    if (!found) {
+                        ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+                        return;
+                    }
+                    (*onSeqEnd)(context, session.get(), seqId, frameNumber);
+                    break;
+                }
+                case kWhatCaptureSeqAbort:
+                {
+                    ACameraCaptureSession_captureCallback_sequenceAbort onSeqAbort;
+                    found = msg->findPointer(kCallbackFpKey, (void**) &onSeqAbort);
+                    if (!found) {
+                        ALOGE("%s: Cannot find sequence end callback!", __FUNCTION__);
+                        return;
+                    }
+                    if (onSeqAbort == nullptr) {
+                        return;
+                    }
+                    int seqId;
+                    found = msg->findInt32(kSequenceIdKey, &seqId);
+                    if (!found) {
+                        ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+                        return;
+                    }
+                    (*onSeqAbort)(context, session.get(), seqId);
+                    break;
+                }
+            }
+            break;
+        }
+    }
+}
+
+CameraDevice::CallbackHolder::CallbackHolder(
+    sp<ACameraCaptureSession>          session,
+    const Vector<sp<CaptureRequest> >& requests,
+    bool                               isRepeating,
+    ACameraCaptureSession_captureCallbacks* cbs) :
+    mSession(session), mRequests(requests),
+    mIsRepeating(isRepeating), mCallbacks(fillCb(cbs)) {}
+
+void
+CameraDevice::checkRepeatingSequenceCompleteLocked(
+    const int sequenceId, const int64_t lastFrameNumber) {
+    ALOGV("Repeating seqId %d lastFrameNumer %" PRId64, sequenceId, lastFrameNumber);
+    if (lastFrameNumber == NO_FRAMES_CAPTURED) {
+        if (mSequenceCallbackMap.count(sequenceId) == 0) {
+            ALOGW("No callback found for sequenceId %d", sequenceId);
+            return;
+        }
+        // remove callback holder from callback map
+        auto cbIt = mSequenceCallbackMap.find(sequenceId);
+        CallbackHolder cbh = cbIt->second;
+        mSequenceCallbackMap.erase(cbIt);
+        // send seq aborted callback
+        sp<AMessage> msg = new AMessage(kWhatCaptureSeqAbort, mHandler);
+        msg->setPointer(kContextKey, cbh.mCallbacks.context);
+        msg->setObject(kSessionSpKey, cbh.mSession);
+        msg->setPointer(kCallbackFpKey, (void*) cbh.mCallbacks.onCaptureSequenceAborted);
+        msg->setInt32(kSequenceIdKey, sequenceId);
+        msg->post();
+    } else {
+        // Use mSequenceLastFrameNumberMap to track
+        mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
+
+        // Last frame might have arrived. Check now
+        checkAndFireSequenceCompleteLocked();
+    }
+}
+
+void
+CameraDevice::checkAndFireSequenceCompleteLocked() {
+    int64_t completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
+    //std::map<int, int64_t> mSequenceLastFrameNumberMap;
+    auto it = mSequenceLastFrameNumberMap.begin();
+    while (it != mSequenceLastFrameNumberMap.end()) {
+        int sequenceId = it->first;
+        int64_t lastFrameNumber = it->second;
+        bool seqCompleted = false;
+        bool hasCallback  = true;
+
+        if (mRemote == nullptr) {
+            ALOGW("Camera %s closed while checking sequence complete", getId());
+            return;
+        }
+
+        // Check if there is callback for this sequence
+        // This should not happen because we always register callback (with nullptr inside)
+        if (mSequenceCallbackMap.count(sequenceId) == 0) {
+            ALOGW("No callback found for sequenceId %d", sequenceId);
+            hasCallback = false;
+        }
+
+        if (lastFrameNumber <= completedFrameNumber) {
+            ALOGV("seq %d reached last frame %" PRId64 ", completed %" PRId64,
+                    sequenceId, lastFrameNumber, completedFrameNumber);
+            seqCompleted = true;
+        }
+
+        if (seqCompleted && hasCallback) {
+            // remove callback holder from callback map
+            auto cbIt = mSequenceCallbackMap.find(sequenceId);
+            CallbackHolder cbh = cbIt->second;
+            mSequenceCallbackMap.erase(cbIt);
+            // send seq complete callback
+            sp<AMessage> msg = new AMessage(kWhatCaptureSeqEnd, mHandler);
+            msg->setPointer(kContextKey, cbh.mCallbacks.context);
+            msg->setObject(kSessionSpKey, cbh.mSession);
+            msg->setPointer(kCallbackFpKey, (void*) cbh.mCallbacks.onCaptureSequenceCompleted);
+            msg->setInt32(kSequenceIdKey, sequenceId);
+            msg->setInt64(kFrameNumberKey, lastFrameNumber);
+
+            // Clear the session sp before we send out the message
+            // This will guarantee the rare case where the message is processed
+            // before cbh goes out of scope and causing we call the session
+            // destructor while holding device lock
+            cbh.mSession.clear();
+            msg->post();
+        }
+
+        // No need to track sequence complete if there is no callback registered
+        if (seqCompleted || !hasCallback) {
+            it = mSequenceLastFrameNumberMap.erase(it);
+        } else {
+            ++it;
+        }
+    }
+}
+
+/**
+  * Camera service callback implementation
+  */
+void
+CameraDevice::ServiceCallback::onDeviceError(
+        CameraErrorCode errorCode,
+        const CaptureResultExtras& resultExtras) {
+    ALOGD("Device error received, code %d, frame number %" PRId64 ", request ID %d, subseq ID %d",
+            errorCode, resultExtras.frameNumber, resultExtras.requestId, resultExtras.burstId);
+
+    sp<CameraDevice> dev = mDevice.promote();
+    if (dev == nullptr) {
+        return; // device has been closed
+    }
+
+    Mutex::Autolock _l(dev->mDeviceLock);
+    if (dev->mRemote == nullptr) {
+        return; // device has been closed
+    }
+    switch (errorCode) {
+        case ERROR_CAMERA_DISCONNECTED:
+        {
+            // Camera is disconnected, close the session and expect no more callbacks
+            if (dev->mCurrentSession != nullptr) {
+                dev->mCurrentSession->closeByDevice();
+                dev->mCurrentSession = nullptr;
+            }
+            sp<AMessage> msg = new AMessage(kWhatOnDisconnected, dev->mHandler);
+            msg->setPointer(kContextKey, dev->mAppCallbacks.context);
+            msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
+            msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onDisconnected);
+            msg->post();
+            break;
+        }
+        default:
+            ALOGE("Unknown error from camera device: %d", errorCode);
+            // no break
+        case ERROR_CAMERA_DEVICE:
+        case ERROR_CAMERA_SERVICE:
+        {
+            switch (errorCode) {
+                case ERROR_CAMERA_DEVICE:
+                    dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+                    break;
+                case ERROR_CAMERA_SERVICE:
+                    dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+                    break;
+                default:
+                    dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_UNKNOWN);
+                    break;
+            }
+            sp<AMessage> msg = new AMessage(kWhatOnError, dev->mHandler);
+            msg->setPointer(kContextKey, dev->mAppCallbacks.context);
+            msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
+            msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onError);
+            msg->setInt32(kErrorCodeKey, errorCode);
+            msg->post();
+            break;
+        }
+        case ERROR_CAMERA_REQUEST:
+        case ERROR_CAMERA_RESULT:
+        case ERROR_CAMERA_BUFFER:
+            dev->onCaptureErrorLocked(errorCode, resultExtras);
+            break;
+    }
+}
+
+void
+CameraDevice::ServiceCallback::onDeviceIdle() {
+    ALOGV("Camera is now idle");
+    sp<CameraDevice> dev = mDevice.promote();
+    if (dev == nullptr) {
+        return; // device has been closed
+    }
+
+    Mutex::Autolock _l(dev->mDeviceLock);
+    if (dev->isClosed() || dev->mRemote == nullptr) {
+        return;
+    }
+
+    if (dev->mIdle) {
+        // Already in idle state. Possibly other thread did waitUntilIdle
+        return;
+    }
+
+    if (dev->mCurrentSession != nullptr) {
+        ALOGE("onDeviceIdle sending state cb");
+        if (dev->mBusySession != dev->mCurrentSession) {
+            ALOGE("Current session != busy session");
+            dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+            return;
+        }
+        sp<AMessage> msg = new AMessage(kWhatSessionStateCb, dev->mHandler);
+        msg->setPointer(kContextKey, dev->mBusySession->mUserSessionCallback.context);
+        msg->setObject(kSessionSpKey, dev->mBusySession);
+        msg->setPointer(kCallbackFpKey, (void*) dev->mBusySession->mUserSessionCallback.onReady);
+        // Make sure we clear the sp first so the session destructor can
+        // only happen on handler thread (where we don't hold device/session lock)
+        dev->mBusySession.clear();
+        msg->post();
+    }
+    dev->mIdle = true;
+}
+
+void
+CameraDevice::ServiceCallback::onCaptureStarted(
+        const CaptureResultExtras& resultExtras,
+        int64_t timestamp) {
+    sp<CameraDevice> dev = mDevice.promote();
+    if (dev == nullptr) {
+        return; // device has been closed
+    }
+    Mutex::Autolock _l(dev->mDeviceLock);
+    if (dev->isClosed() || dev->mRemote == nullptr) {
+        return;
+    }
+
+    int sequenceId = resultExtras.requestId;
+    int64_t frameNumber = resultExtras.frameNumber;
+    int32_t burstId = resultExtras.burstId;
+
+    auto it = dev->mSequenceCallbackMap.find(sequenceId);
+    if (it != dev->mSequenceCallbackMap.end()) {
+        CallbackHolder cbh = (*it).second;
+        ACameraCaptureSession_captureCallback_start onStart = cbh.mCallbacks.onCaptureStarted;
+        sp<ACameraCaptureSession> session = cbh.mSession;
+        if ((size_t) burstId >= cbh.mRequests.size()) {
+            ALOGE("%s: Error: request index %d out of bound (size %zu)",
+                    __FUNCTION__, burstId, cbh.mRequests.size());
+            dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+        }
+        sp<CaptureRequest> request = cbh.mRequests[burstId];
+        sp<AMessage> msg = new AMessage(kWhatCaptureStart, dev->mHandler);
+        msg->setPointer(kContextKey, cbh.mCallbacks.context);
+        msg->setObject(kSessionSpKey, session);
+        msg->setPointer(kCallbackFpKey, (void*) onStart);
+        msg->setObject(kCaptureRequestKey, request);
+        msg->setInt64(kTimeStampKey, timestamp);
+        msg->post();
+    }
+}
+
+void
+CameraDevice::ServiceCallback::onResultReceived(
+        const CameraMetadata& metadata,
+        const CaptureResultExtras& resultExtras) {
+    sp<CameraDevice> dev = mDevice.promote();
+    if (dev == nullptr) {
+        return; // device has been closed
+    }
+    int sequenceId = resultExtras.requestId;
+    int64_t frameNumber = resultExtras.frameNumber;
+    int32_t burstId = resultExtras.burstId;
+    bool    isPartialResult = (resultExtras.partialResultCount < dev->mPartialResultCount);
+
+    if (!isPartialResult) {
+        ALOGV("SeqId %d frame %" PRId64 " result arrive.", sequenceId, frameNumber);
+    }
+
+    Mutex::Autolock _l(dev->mDeviceLock);
+    if (dev->mRemote == nullptr) {
+        return; // device has been disconnected
+    }
+
+    if (dev->isClosed()) {
+        if (!isPartialResult) {
+            dev->mFrameNumberTracker.updateTracker(frameNumber, /*isError*/false);
+        }
+        // early return to avoid callback sent to closed devices
+        return;
+    }
+
+    CameraMetadata metadataCopy = metadata;
+    // Copied from java implmentation. Why do we need this?
+    metadataCopy.update(ANDROID_LENS_INFO_SHADING_MAP_SIZE, dev->mShadingMapSize, /*data_count*/2);
+
+    auto it = dev->mSequenceCallbackMap.find(sequenceId);
+    if (it != dev->mSequenceCallbackMap.end()) {
+        CallbackHolder cbh = (*it).second;
+        ACameraCaptureSession_captureCallback_result onResult = isPartialResult ?
+                cbh.mCallbacks.onCaptureProgressed :
+                cbh.mCallbacks.onCaptureCompleted;
+        sp<ACameraCaptureSession> session = cbh.mSession;
+        if ((size_t) burstId >= cbh.mRequests.size()) {
+            ALOGE("%s: Error: request index %d out of bound (size %zu)",
+                    __FUNCTION__, burstId, cbh.mRequests.size());
+            dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+        }
+        sp<CaptureRequest> request = cbh.mRequests[burstId];
+        sp<ACameraMetadata> result(new ACameraMetadata(
+                metadataCopy.release(), ACameraMetadata::ACM_RESULT));
+
+        sp<AMessage> msg = new AMessage(kWhatCaptureResult, dev->mHandler);
+        msg->setPointer(kContextKey, cbh.mCallbacks.context);
+        msg->setObject(kSessionSpKey, session);
+        msg->setPointer(kCallbackFpKey, (void*) onResult);
+        msg->setObject(kCaptureRequestKey, request);
+        msg->setObject(kCaptureResultKey, result);
+        msg->post();
+    }
+
+    if (!isPartialResult) {
+        dev->mFrameNumberTracker.updateTracker(frameNumber, /*isError*/false);
+        dev->checkAndFireSequenceCompleteLocked();
+    }
+}
+
+void
+CameraDevice::ServiceCallback::onPrepared(int) {
+    // Prepare not yet implemented in NDK
+    return;
+}
+
+} // namespace android
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
new file mode 100644
index 0000000..b73e621
--- /dev/null
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 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 _ACAMERA_DEVICE_H
+#define _ACAMERA_DEVICE_H
+
+#include <memory>
+#include <map>
+#include <set>
+#include <atomic>
+#include <utils/StrongPointer.h>
+#include <utils/Mutex.h>
+#include <utils/String8.h>
+#include <utils/List.h>
+#include <utils/Vector.h>
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <camera/CaptureResult.h>
+#include <camera/camera2/ICameraDeviceCallbacks.h>
+#include <camera/camera2/ICameraDeviceUser.h>
+#include <camera/camera2/OutputConfiguration.h>
+#include <camera/camera2/CaptureRequest.h>
+
+#include <NdkCameraDevice.h>
+#include "ACameraMetadata.h"
+
+using namespace android;
+
+namespace android {
+
+// Wrap ACameraCaptureFailure so it can be ref-counter
+struct CameraCaptureFailure : public RefBase, public ACameraCaptureFailure {};
+
+class CameraDevice final : public RefBase {
+  public:
+    CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
+                  std::unique_ptr<ACameraMetadata> chars,
+                  ACameraDevice* wrapper);
+    ~CameraDevice();
+
+    inline const char* getId() const { return mCameraId.string(); }
+
+    camera_status_t createCaptureRequest(
+            ACameraDevice_request_template templateId,
+            ACaptureRequest** request) const;
+
+    camera_status_t createCaptureSession(
+            const ACaptureSessionOutputContainer*       outputs,
+            const ACameraCaptureSession_stateCallbacks* callbacks,
+            /*out*/ACameraCaptureSession** session);
+
+    // Callbacks from camera service
+    class ServiceCallback : public BnCameraDeviceCallbacks {
+      public:
+        ServiceCallback(CameraDevice* device) : mDevice(device) {}
+        void onDeviceError(CameraErrorCode errorCode,
+                           const CaptureResultExtras& resultExtras) override;
+        void onDeviceIdle() override;
+        void onCaptureStarted(const CaptureResultExtras& resultExtras,
+                              int64_t timestamp) override;
+        void onResultReceived(const CameraMetadata& metadata,
+                              const CaptureResultExtras& resultExtras) override;
+        void onPrepared(int streamId) override;
+      private:
+        const wp<CameraDevice> mDevice;
+    };
+    inline sp<ICameraDeviceCallbacks> getServiceCallback() { return mServiceCallback; };
+
+    // Camera device is only functional after remote being set
+    void setRemoteDevice(sp<ICameraDeviceUser> remote);
+
+    inline ACameraDevice* getWrapper() const { return mWrapper; };
+
+  private:
+    friend ACameraCaptureSession;
+    camera_status_t checkCameraClosedOrErrorLocked() const;
+
+    // device goes into fatal error state after this
+    void setCameraDeviceErrorLocked(camera_status_t error);
+
+    void disconnectLocked(); // disconnect from camera service
+
+    camera_status_t stopRepeatingLocked();
+
+    camera_status_t waitUntilIdleLocked();
+
+
+    camera_status_t captureLocked(sp<ACameraCaptureSession> session,
+            /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+            int numRequests, ACaptureRequest** requests,
+            /*optional*/int* captureSequenceId);
+
+    camera_status_t setRepeatingRequestsLocked(sp<ACameraCaptureSession> session,
+            /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+            int numRequests, ACaptureRequest** requests,
+            /*optional*/int* captureSequenceId);
+
+    camera_status_t submitRequestsLocked(
+            sp<ACameraCaptureSession> session,
+            /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+            int numRequests, ACaptureRequest** requests,
+            /*out*/int* captureSequenceId,
+            bool isRepeating);
+
+    static camera_status_t allocateCaptureRequest(
+            const ACaptureRequest* request, sp<CaptureRequest>& outReq);
+
+    static ACaptureRequest* allocateACaptureRequest(sp<CaptureRequest>& req);
+    static void freeACaptureRequest(ACaptureRequest*);
+
+    // only For session to hold device lock
+    // Always grab device lock before grabbing session lock
+    void lockDeviceForSessionOps() const { mDeviceLock.lock(); };
+    void unlockDevice() const { mDeviceLock.unlock(); };
+
+    // For capture session to notify its end of life
+    void notifySessionEndOfLifeLocked(ACameraCaptureSession* session);
+
+    camera_status_t configureStreamsLocked(const ACaptureSessionOutputContainer* outputs);
+
+    static camera_status_t getIGBPfromSessionOutput(
+            const ACaptureSessionOutput& config, sp<IGraphicBufferProducer>& out);
+
+    static camera_status_t getSurfaceFromANativeWindow(
+            ANativeWindow* anw, sp<Surface>& out);
+
+    mutable Mutex mDeviceLock;
+    const String8 mCameraId;                          // Camera ID
+    const ACameraDevice_StateCallbacks mAppCallbacks; // Callback to app
+    const std::unique_ptr<ACameraMetadata> mChars;    // Camera characteristics
+    const sp<ServiceCallback> mServiceCallback;
+    ACameraDevice* mWrapper;
+
+    // stream id -> OutputConfiguration map
+    std::map<int, OutputConfiguration> mConfiguredOutputs;
+
+    // TODO: maybe a bool will suffice for synchronous implementation?
+    std::atomic_bool mClosing;
+    inline bool isClosed() { return mClosing; }
+
+    bool mInError;
+    camera_status_t mError;
+    void onCaptureErrorLocked(
+            ICameraDeviceCallbacks::CameraErrorCode errorCode,
+            const CaptureResultExtras& resultExtras);
+
+    bool mIdle;
+    // This will avoid a busy session being deleted before it's back to idle state
+    sp<ACameraCaptureSession> mBusySession;
+
+    sp<ICameraDeviceUser> mRemote;
+
+    // Looper thread to handle callback to app
+    sp<ALooper> mCbLooper;
+    // definition of handler and message
+    enum {
+        // Device state callbacks
+        kWhatOnDisconnected, // onDisconnected
+        kWhatOnError,        // onError
+        // Session state callbacks
+        kWhatSessionStateCb, // onReady, onActive
+        // Capture callbacks
+        kWhatCaptureStart,   // onCaptureStarted
+        kWhatCaptureResult,  // onCaptureProgressed, onCaptureCompleted
+        kWhatCaptureFail,    // onCaptureFailed
+        kWhatCaptureSeqEnd,  // onCaptureSequenceCompleted
+        kWhatCaptureSeqAbort // onCaptureSequenceAborted
+    };
+    static const char* kContextKey;
+    static const char* kDeviceKey;
+    static const char* kErrorCodeKey;
+    static const char* kCallbackFpKey;
+    static const char* kSessionSpKey;
+    static const char* kCaptureRequestKey;
+    static const char* kTimeStampKey;
+    static const char* kCaptureResultKey;
+    static const char* kCaptureFailureKey;
+    static const char* kSequenceIdKey;
+    static const char* kFrameNumberKey;
+    class CallbackHandler : public AHandler {
+      public:
+        CallbackHandler() {}
+        void onMessageReceived(const sp<AMessage> &msg) override;
+    };
+    sp<CallbackHandler> mHandler;
+
+    /***********************************
+     * Capture session related members *
+     ***********************************/
+    // The current active session
+    ACameraCaptureSession* mCurrentSession = nullptr;
+
+    int mNextSessionId = 0;
+    // TODO: might need another looper/handler to handle callbacks from service
+
+    static const int REQUEST_ID_NONE = -1;
+    int mRepeatingSequenceId = REQUEST_ID_NONE;
+
+    // sequence id -> last frame number map
+    std::map<int, int64_t> mSequenceLastFrameNumberMap;
+
+    struct CallbackHolder {
+        CallbackHolder(sp<ACameraCaptureSession>          session,
+                       const Vector<sp<CaptureRequest> >& requests,
+                       bool                               isRepeating,
+                       ACameraCaptureSession_captureCallbacks* cbs);
+
+        static ACameraCaptureSession_captureCallbacks fillCb(
+                ACameraCaptureSession_captureCallbacks* cbs) {
+            if (cbs != nullptr) {
+                return *cbs;
+            }
+            return { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
+        }
+
+        sp<ACameraCaptureSession>   mSession;
+        Vector<sp<CaptureRequest> > mRequests;
+        const bool                  mIsRepeating;
+        ACameraCaptureSession_captureCallbacks mCallbacks;
+    };
+    // sequence id -> callbacks map
+    std::map<int, CallbackHolder> mSequenceCallbackMap;
+
+    static const int64_t NO_FRAMES_CAPTURED = -1;
+    class FrameNumberTracker {
+      public:
+        // TODO: Called in onResultReceived and onCaptureErrorLocked
+        void updateTracker(int64_t frameNumber, bool isError);
+        inline int64_t getCompletedFrameNumber() { return mCompletedFrameNumber; }
+      private:
+        void update();
+        void updateCompletedFrameNumber(int64_t frameNumber);
+
+        int64_t mCompletedFrameNumber = NO_FRAMES_CAPTURED;
+        List<int64_t> mSkippedFrameNumbers;
+        std::set<int64_t> mFutureErrorSet;
+    };
+    FrameNumberTracker mFrameNumberTracker;
+
+    void checkRepeatingSequenceCompleteLocked(const int sequenceId, const int64_t lastFrameNumber);
+    void checkAndFireSequenceCompleteLocked();
+
+    // Misc variables
+    int32_t mShadingMapSize[2];   // const after constructor
+    int32_t mPartialResultCount;  // const after constructor
+
+};
+
+} // namespace android;
+
+/**
+ * ACameraDevice opaque struct definition
+ * Leave outside of android namespace because it's NDK struct
+ */
+struct ACameraDevice {
+    ACameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
+                  std::unique_ptr<ACameraMetadata> chars) :
+            mDevice(new CameraDevice(id, cb, std::move(chars), this)) {}
+
+    ~ACameraDevice() {};
+
+    /*******************
+     * NDK public APIs *
+     *******************/
+    inline const char* getId() const { return mDevice->getId(); }
+
+    camera_status_t createCaptureRequest(
+            ACameraDevice_request_template templateId,
+            ACaptureRequest** request) const {
+        return mDevice->createCaptureRequest(templateId, request);
+    }
+
+    camera_status_t createCaptureSession(
+            const ACaptureSessionOutputContainer*       outputs,
+            const ACameraCaptureSession_stateCallbacks* callbacks,
+            /*out*/ACameraCaptureSession** session) {
+        return mDevice->createCaptureSession(outputs, callbacks, session);
+    }
+
+    /***********************
+     * Device interal APIs *
+     ***********************/
+    inline sp<ICameraDeviceCallbacks> getServiceCallback() {
+        return mDevice->getServiceCallback();
+    };
+
+    // Camera device is only functional after remote being set
+    inline void setRemoteDevice(sp<ICameraDeviceUser> remote) {
+        mDevice->setRemoteDevice(remote);
+    }
+
+  private:
+    sp<CameraDevice> mDevice;
+};
+
+#endif // _ACAMERA_DEVICE_H
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
new file mode 100644
index 0000000..ed5c3ba
--- /dev/null
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) 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_NDEBUG 0
+#define LOG_TAG "ACameraManager"
+
+#include <memory>
+#include "ACameraManager.h"
+#include "ACameraMetadata.h"
+#include "ACameraDevice.h"
+#include <utils/Vector.h>
+#include <stdlib.h>
+#include <camera/VendorTagDescriptor.h>
+
+using namespace android;
+
+//constants shared between ACameraManager and CameraManagerGlobal
+namespace {
+    const int kMaxCameraIdLen = 32;
+}
+
+namespace android {
+// Static member definitions
+const char* CameraManagerGlobal::kCameraIdKey   = "CameraId";
+const char* CameraManagerGlobal::kCallbackFpKey = "CallbackFp";
+const char* CameraManagerGlobal::kContextKey    = "CallbackContext";
+Mutex                CameraManagerGlobal::sLock;
+CameraManagerGlobal* CameraManagerGlobal::sInstance = nullptr;
+
+CameraManagerGlobal&
+CameraManagerGlobal::getInstance() {
+    Mutex::Autolock _l(sLock);
+    CameraManagerGlobal* instance = sInstance;
+    if (instance == nullptr) {
+        instance = new CameraManagerGlobal();
+        sInstance = instance;
+    }
+    return *instance;
+}
+
+CameraManagerGlobal::~CameraManagerGlobal() {
+    // clear sInstance so next getInstance call knows to create a new one
+    Mutex::Autolock _sl(sLock);
+    sInstance = nullptr;
+    Mutex::Autolock _l(mLock);
+    if (mCameraService != nullptr) {
+        IInterface::asBinder(mCameraService)->unlinkToDeath(mDeathNotifier);
+        mCameraService->removeListener(mCameraServiceListener);
+    }
+    mDeathNotifier.clear();
+    if (mCbLooper != nullptr) {
+        mCbLooper->unregisterHandler(mHandler->id());
+        mCbLooper->stop();
+    }
+    mCbLooper.clear();
+    mHandler.clear();
+    mCameraServiceListener.clear();
+    mCameraService.clear();
+}
+
+sp<ICameraService> CameraManagerGlobal::getCameraService() {
+    Mutex::Autolock _l(mLock);
+    if (mCameraService.get() == nullptr) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder;
+        do {
+            binder = sm->getService(String16(kCameraServiceName));
+            if (binder != nullptr) {
+                break;
+            }
+            ALOGW("CameraService not published, waiting...");
+            usleep(kCameraServicePollDelay);
+        } while(true);
+        if (mDeathNotifier == nullptr) {
+            mDeathNotifier = new DeathNotifier(this);
+        }
+        binder->linkToDeath(mDeathNotifier);
+        mCameraService = interface_cast<ICameraService>(binder);
+
+        // Setup looper thread to perfrom availiability callbacks
+        if (mCbLooper == nullptr) {
+            mCbLooper = new ALooper;
+            mCbLooper->setName("C2N-mgr-looper");
+            status_t ret = mCbLooper->start(
+                    /*runOnCallingThread*/false,
+                    /*canCallJava*/       true,
+                    PRIORITY_DEFAULT);
+            if (mHandler == nullptr) {
+                mHandler = new CallbackHandler();
+            }
+            mCbLooper->registerHandler(mHandler);
+        }
+
+        // register ICameraServiceListener
+        if (mCameraServiceListener == nullptr) {
+            mCameraServiceListener = new CameraServiceListener(this);
+        }
+        mCameraService->addListener(mCameraServiceListener);
+
+        // setup vendor tags
+        sp<VendorTagDescriptor> desc;
+        status_t ret = mCameraService->getCameraVendorTagDescriptor(/*out*/desc);
+
+        if (ret == OK) {
+            ret = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
+            if (ret != OK) {
+                ALOGE("%s: Failed to set vendor tag descriptors, received error %s (%d)",
+                        __FUNCTION__, strerror(-ret), ret);
+            }
+        } else if (ret == -EOPNOTSUPP) {
+            ALOGW("%s: Camera HAL too old; does not support vendor tags",
+                    __FUNCTION__);
+            VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+        } else {
+            ALOGE("%s: Failed to get vendor tag descriptors, received error %s (%d)",
+                    __FUNCTION__, strerror(-ret), ret);
+        }
+    }
+    ALOGE_IF(mCameraService == nullptr, "no CameraService!?");
+    return mCameraService;
+}
+
+void CameraManagerGlobal::DeathNotifier::binderDied(const wp<IBinder>&)
+{
+    ALOGE("Camera service binderDied!");
+    sp<CameraManagerGlobal> cm = mCameraManager.promote();
+    if (cm != nullptr) {
+        AutoMutex lock(cm->mLock);
+        for (auto pair : cm->mDeviceStatusMap) {
+            int32_t cameraId = pair.first;
+            cm->onStatusChangedLocked(
+                    ICameraServiceListener::STATUS_NOT_PRESENT, cameraId);
+        }
+        cm->mCameraService.clear();
+        // TODO: consider adding re-connect call here?
+    }
+}
+
+void CameraManagerGlobal::registerAvailabilityCallback(
+        const ACameraManager_AvailabilityCallbacks *callback) {
+    Mutex::Autolock _l(mLock);
+    Callback cb(callback);
+    auto pair = mCallbacks.insert(cb);
+    // Send initial callbacks if callback is newly registered
+    if (pair.second) {
+        for (auto pair : mDeviceStatusMap) {
+            int32_t cameraId = pair.first;
+            Status status = pair.second;
+
+            sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
+            ACameraManager_AvailabilityCallback cb = isStatusAvailable(status) ?
+                    callback->onCameraAvailable : callback->onCameraUnavailable;
+            msg->setPointer(kCallbackFpKey, (void *) cb);
+            msg->setPointer(kContextKey, callback->context);
+            msg->setInt32(kCameraIdKey, cameraId);
+            msg->post();
+        }
+    }
+}
+
+void CameraManagerGlobal::unregisterAvailabilityCallback(
+        const ACameraManager_AvailabilityCallbacks *callback) {
+    Mutex::Autolock _l(mLock);
+    Callback cb(callback);
+    mCallbacks.erase(cb);
+}
+
+bool CameraManagerGlobal::validStatus(Status status) {
+    switch (status) {
+        case ICameraServiceListener::STATUS_NOT_PRESENT:
+        case ICameraServiceListener::STATUS_PRESENT:
+        case ICameraServiceListener::STATUS_ENUMERATING:
+        case ICameraServiceListener::STATUS_NOT_AVAILABLE:
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool CameraManagerGlobal::isStatusAvailable(Status status) {
+    switch (status) {
+        case ICameraServiceListener::STATUS_PRESENT:
+            return true;
+        default:
+            return false;
+    }
+}
+
+void CameraManagerGlobal::CallbackHandler::sendSingleCallback(
+        int32_t cameraId, void* context,
+        ACameraManager_AvailabilityCallback cb) const {
+    char cameraIdStr[kMaxCameraIdLen];
+    snprintf(cameraIdStr, sizeof(cameraIdStr), "%d", cameraId);
+    (*cb)(context, cameraIdStr);
+}
+
+void CameraManagerGlobal::CallbackHandler::onMessageReceived(
+        const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatSendSingleCallback:
+        {
+            ACameraManager_AvailabilityCallback cb;
+            void* context;
+            int32_t cameraId;
+            bool found = msg->findPointer(kCallbackFpKey, (void**) &cb);
+            if (!found) {
+                ALOGE("%s: Cannot find camera callback fp!", __FUNCTION__);
+                return;
+            }
+            found = msg->findPointer(kContextKey, &context);
+            if (!found) {
+                ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+                return;
+            }
+            found = msg->findInt32(kCameraIdKey, &cameraId);
+            if (!found) {
+                ALOGE("%s: Cannot find camera ID!", __FUNCTION__);
+                return;
+            }
+            sendSingleCallback(cameraId, context, cb);
+            break;
+        }
+        default:
+            ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
+            break;
+    }
+}
+
+void CameraManagerGlobal::CameraServiceListener::onStatusChanged(
+        Status status, int32_t cameraId) {
+    sp<CameraManagerGlobal> cm = mCameraManager.promote();
+    if (cm == nullptr) {
+        ALOGE("Cannot deliver status change. Global camera manager died");
+        return;
+    }
+    cm->onStatusChanged(status, cameraId);
+}
+
+void CameraManagerGlobal::onStatusChanged(
+        Status status, int32_t cameraId) {
+    Mutex::Autolock _l(mLock);
+    onStatusChangedLocked(status, cameraId);
+}
+
+void CameraManagerGlobal::onStatusChangedLocked(
+        Status status, int32_t cameraId) {
+        if (!validStatus(status)) {
+            ALOGE("%s: Invalid status %d", __FUNCTION__, status);
+            return;
+        }
+
+        bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0);
+        Status oldStatus = firstStatus ?
+                status : // first status
+                mDeviceStatusMap[cameraId];
+
+        if (!firstStatus &&
+                isStatusAvailable(status) == isStatusAvailable(oldStatus)) {
+            // No status update. No need to send callback
+            return;
+        }
+
+        // Iterate through all registered callbacks
+        mDeviceStatusMap[cameraId] = status;
+        for (auto cb : mCallbacks) {
+            sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
+            ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
+                    cb.mAvailable : cb.mUnavailable;
+            msg->setPointer(kCallbackFpKey, (void *) cbFp);
+            msg->setPointer(kContextKey, cb.mContext);
+            msg->setInt32(kCameraIdKey, cameraId);
+            msg->post();
+        }
+}
+
+} // namespace android
+
+/**
+ * ACameraManger Implementation
+ */
+camera_status_t
+ACameraManager::getOrCreateCameraIdListLocked(ACameraIdList** cameraIdList) {
+    if (mCachedCameraIdList.numCameras == kCameraIdListNotInit) {
+        int numCameras = 0;
+        Vector<char *> cameraIds;
+        sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+        if (cs == nullptr) {
+            ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
+            return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+        }
+        // Get number of cameras
+        int numAllCameras = cs->getNumberOfCameras(ICameraService::CAMERA_TYPE_ALL);
+        // Filter API2 compatible cameras and push to cameraIds
+        for (int i = 0; i < numAllCameras; i++) {
+            // TODO: Only suppot HALs that supports API2 directly now
+            status_t camera2Support = cs->supportsCameraApi(i, ICameraService::API_VERSION_2);
+            char buf[kMaxCameraIdLen];
+            if (camera2Support == OK) {
+                numCameras++;
+                mCameraIds.insert(i);
+                snprintf(buf, sizeof(buf), "%d", i);
+                size_t cameraIdSize = strlen(buf) + 1;
+                char *cameraId = new char[cameraIdSize];
+                if (!cameraId) {
+                    ALOGE("Allocate memory for ACameraIdList failed!");
+                    return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+                }
+                strlcpy(cameraId, buf, cameraIdSize);
+                cameraIds.push(cameraId);
+            }
+        }
+        mCachedCameraIdList.numCameras = numCameras;
+        mCachedCameraIdList.cameraIds = new const char*[numCameras];
+        if (!mCachedCameraIdList.cameraIds) {
+            ALOGE("Allocate memory for ACameraIdList failed!");
+            return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+        }
+        for (int i = 0; i < numCameras; i++) {
+            mCachedCameraIdList.cameraIds[i] = cameraIds[i];
+        }
+    }
+    *cameraIdList = &mCachedCameraIdList;
+    return ACAMERA_OK;
+}
+
+camera_status_t
+ACameraManager::getCameraIdList(ACameraIdList** cameraIdList) {
+    Mutex::Autolock _l(mLock);
+    ACameraIdList* cachedList;
+    camera_status_t ret = getOrCreateCameraIdListLocked(&cachedList);
+    if (ret != ACAMERA_OK) {
+        ALOGE("Get camera ID list failed! err: %d", ret);
+        return ret;
+    }
+
+    int numCameras = cachedList->numCameras;
+    ACameraIdList *out = new ACameraIdList;
+    if (!out) {
+        ALOGE("Allocate memory for ACameraIdList failed!");
+        return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+    }
+    out->numCameras = numCameras;
+    out->cameraIds = new const char*[numCameras];
+    if (!out->cameraIds) {
+        ALOGE("Allocate memory for ACameraIdList failed!");
+        return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+    }
+    for (int i = 0; i < numCameras; i++) {
+        const char* src = cachedList->cameraIds[i];
+        size_t dstSize = strlen(src) + 1;
+        char* dst = new char[dstSize];
+        if (!dst) {
+            ALOGE("Allocate memory for ACameraIdList failed!");
+            return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+        }
+        strlcpy(dst, src, dstSize);
+        out->cameraIds[i] = dst;
+    }
+    *cameraIdList = out;
+    return ACAMERA_OK;
+}
+
+void
+ACameraManager::deleteCameraIdList(ACameraIdList* cameraIdList) {
+    if (cameraIdList != nullptr) {
+        if (cameraIdList->cameraIds != nullptr) {
+            for (int i = 0; i < cameraIdList->numCameras; i ++) {
+                delete[] cameraIdList->cameraIds[i];
+            }
+            delete[] cameraIdList->cameraIds;
+        }
+        delete cameraIdList;
+    }
+}
+
+camera_status_t ACameraManager::getCameraCharacteristics(
+        const char *cameraIdStr, ACameraMetadata **characteristics) {
+    Mutex::Autolock _l(mLock);
+    ACameraIdList* cachedList;
+    // Make sure mCameraIds is initialized
+    camera_status_t ret = getOrCreateCameraIdListLocked(&cachedList);
+    if (ret != ACAMERA_OK) {
+        ALOGE("%s: Get camera ID list failed! err: %d", __FUNCTION__, ret);
+        return ret;
+    }
+    int cameraId = atoi(cameraIdStr);
+    if (mCameraIds.count(cameraId) == 0) {
+        ALOGE("%s: Camera ID %s does not exist!", __FUNCTION__, cameraIdStr);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+    if (cs == nullptr) {
+        ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
+        return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+    }
+    CameraMetadata rawMetadata;
+    status_t serviceRet = cs->getCameraCharacteristics(cameraId, &rawMetadata);
+    if (serviceRet != OK) {
+        ALOGE("Get camera characteristics from camera service failed! Err %d", ret);
+        return ACAMERA_ERROR_UNKNOWN; // should not reach here
+    }
+
+    *characteristics = new ACameraMetadata(
+            rawMetadata.release(), ACameraMetadata::ACM_CHARACTERISTICS);
+    return ACAMERA_OK;
+}
+
+camera_status_t
+ACameraManager::openCamera(
+        const char* cameraId,
+        ACameraDevice_StateCallbacks* callback,
+        /*out*/ACameraDevice** outDevice) {
+    ACameraMetadata* rawChars;
+    camera_status_t ret = getCameraCharacteristics(cameraId, &rawChars);
+    Mutex::Autolock _l(mLock);
+    if (ret != ACAMERA_OK) {
+        ALOGE("%s: cannot get camera characteristics for camera %s. err %d",
+                __FUNCTION__, cameraId, ret);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    std::unique_ptr<ACameraMetadata> chars(rawChars);
+    rawChars = nullptr;
+
+    ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(chars));
+
+    sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+    if (cs == nullptr) {
+        ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
+        return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+    }
+
+    int id = atoi(cameraId);
+    sp<ICameraDeviceCallbacks> callbacks = device->getServiceCallback();
+    sp<ICameraDeviceUser> deviceRemote;
+    // No way to get package name from native.
+    // Send a zero length package name and let camera service figure it out from UID
+    status_t serviceRet = cs->connectDevice(
+            callbacks, id, String16(""),
+            ICameraService::USE_CALLING_UID, /*out*/deviceRemote);
+
+    if (serviceRet != OK) {
+        ALOGE("%s: connect camera device failed! err %d", __FUNCTION__, serviceRet);
+        // TODO: generate better error message here
+        delete device;
+        return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+    }
+    if (deviceRemote == nullptr) {
+        ALOGE("%s: connect camera device failed! remote device is null", __FUNCTION__);
+        delete device;
+        return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+    }
+    device->setRemoteDevice(deviceRemote);
+    *outDevice = device;
+    return ACAMERA_OK;
+}
+
+ACameraManager::~ACameraManager() {
+    Mutex::Autolock _l(mLock);
+    if (mCachedCameraIdList.numCameras != kCameraIdListNotInit) {
+        for (int i = 0; i < mCachedCameraIdList.numCameras; i++) {
+            delete[] mCachedCameraIdList.cameraIds[i];
+        }
+        delete[] mCachedCameraIdList.cameraIds;
+    }
+}
+
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
new file mode 100644
index 0000000..b68685d
--- /dev/null
+++ b/camera/ndk/impl/ACameraManager.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 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 _ACAMERA_MANAGER_H
+#define _ACAMERA_MANAGER_H
+
+#include "NdkCameraManager.h"
+
+#include <camera/CameraMetadata.h>
+#include <camera/ICameraService.h>
+#include <camera/ICameraServiceListener.h>
+#include <binder/IServiceManager.h>
+#include <utils/StrongPointer.h>
+#include <utils/Mutex.h>
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <set>
+#include <map>
+
+using namespace android;
+
+namespace android {
+
+/**
+ * Per-process singleton instance of CameraManger. Shared by all ACameraManager
+ * instances. Created when first ACameraManager is created and destroyed when
+ * all ACameraManager instances are deleted.
+ *
+ * TODO: maybe CameraManagerGlobal is better sutied in libcameraclient?
+ */
+class CameraManagerGlobal final : public RefBase {
+  public:
+    static CameraManagerGlobal& getInstance();
+    sp<ICameraService> getCameraService();
+
+    void registerAvailabilityCallback(
+            const ACameraManager_AvailabilityCallbacks *callback);
+    void unregisterAvailabilityCallback(
+            const ACameraManager_AvailabilityCallbacks *callback);
+
+  private:
+    sp<ICameraService> mCameraService;
+    const int          kCameraServicePollDelay = 500000; // 0.5s
+    const char*        kCameraServiceName      = "media.camera";
+    Mutex              mLock;
+
+    class DeathNotifier : public IBinder::DeathRecipient {
+      public:
+        DeathNotifier(CameraManagerGlobal* cm) : mCameraManager(cm) {}
+      protected:
+        // IBinder::DeathRecipient implementation
+        virtual void binderDied(const wp<IBinder>& who);
+      private:
+        const wp<CameraManagerGlobal> mCameraManager;
+    };
+    sp<DeathNotifier> mDeathNotifier;
+
+    class CameraServiceListener final : public BnCameraServiceListener {
+      public:
+        CameraServiceListener(CameraManagerGlobal* cm) : mCameraManager(cm) {}
+        virtual void onStatusChanged(Status status, int32_t cameraId);
+
+        // Torch API not implemented yet
+        virtual void onTorchStatusChanged(TorchStatus, const String16&) {};
+      private:
+        const wp<CameraManagerGlobal> mCameraManager;
+    };
+    sp<CameraServiceListener> mCameraServiceListener;
+
+    // Wrapper of ACameraManager_AvailabilityCallbacks so we can store it in std::set
+    struct Callback {
+        Callback(const ACameraManager_AvailabilityCallbacks *callback) :
+            mAvailable(callback->onCameraAvailable),
+            mUnavailable(callback->onCameraUnavailable),
+            mContext(callback->context) {}
+
+        bool operator == (const Callback& other) const {
+            return (mAvailable == other.mAvailable &&
+                    mUnavailable == other.mUnavailable &&
+                    mContext == other.mContext);
+        }
+        bool operator != (const Callback& other) const {
+            return !(*this == other);
+        }
+        bool operator < (const Callback& other) const {
+            if (*this == other) return false;
+            if (mContext != other.mContext) return mContext < other.mContext;
+            if (mAvailable != other.mAvailable) return mAvailable < other.mAvailable;
+            return mUnavailable < other.mUnavailable;
+        }
+        bool operator > (const Callback& other) const {
+            return (*this != other && !(*this < other));
+        }
+        ACameraManager_AvailabilityCallback mAvailable;
+        ACameraManager_AvailabilityCallback mUnavailable;
+        void*                               mContext;
+    };
+    std::set<Callback> mCallbacks;
+
+    // definition of handler and message
+    enum {
+        kWhatSendSingleCallback
+    };
+    static const char* kCameraIdKey;
+    static const char* kCallbackFpKey;
+    static const char* kContextKey;
+    class CallbackHandler : public AHandler {
+      public:
+        CallbackHandler() {}
+        void onMessageReceived(const sp<AMessage> &msg) override;
+      private:
+        inline void sendSingleCallback(
+                int32_t cameraId, void* context,
+                ACameraManager_AvailabilityCallback cb) const;
+    };
+    sp<CallbackHandler> mHandler;
+    sp<ALooper>         mCbLooper; // Looper thread where callbacks actually happen on
+
+    typedef ICameraServiceListener::Status Status;
+    void onStatusChanged(Status status, int32_t cameraId);
+    void onStatusChangedLocked(Status status, int32_t cameraId);
+    // Utils for status
+    static bool validStatus(Status status);
+    static bool isStatusAvailable(Status status);
+
+    // Map camera_id -> status
+    std::map<int32_t, Status> mDeviceStatusMap;
+
+    // For the singleton instance
+    static Mutex sLock;
+    static CameraManagerGlobal* sInstance;
+    CameraManagerGlobal() {};
+    ~CameraManagerGlobal();
+};
+
+} // namespace android;
+
+/**
+ * ACameraManager opaque struct definition
+ * Leave outside of android namespace because it's NDK struct
+ */
+struct ACameraManager {
+    ACameraManager() :
+            mCachedCameraIdList({kCameraIdListNotInit, nullptr}),
+            mGlobalManager(&(CameraManagerGlobal::getInstance())) {}
+    ~ACameraManager();
+    camera_status_t getCameraIdList(ACameraIdList** cameraIdList);
+    static void     deleteCameraIdList(ACameraIdList* cameraIdList);
+
+    camera_status_t getCameraCharacteristics(
+            const char *cameraId, ACameraMetadata **characteristics);
+    camera_status_t openCamera(const char* cameraId,
+                               ACameraDevice_StateCallbacks* callback,
+                               /*out*/ACameraDevice** device);
+
+  private:
+    camera_status_t getOrCreateCameraIdListLocked(ACameraIdList** cameraIdList);
+
+    enum {
+        kCameraIdListNotInit = -1
+    };
+    Mutex         mLock;
+    std::set<int> mCameraIds;          // Init by getOrCreateCameraIdListLocked
+    ACameraIdList mCachedCameraIdList; // Init by getOrCreateCameraIdListLocked
+    sp<CameraManagerGlobal> mGlobalManager;
+};
+
+#endif //_ACAMERA_MANAGER_H
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
new file mode 100644
index 0000000..fbc8d19
--- /dev/null
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 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_NDEBUG 0
+#define LOG_TAG "ACameraMetadata"
+
+#include "ACameraMetadata.h"
+#include <utils/Vector.h>
+#include <system/graphics.h>
+#include "NdkImage.h"
+
+using namespace android;
+
+/**
+ * ACameraMetadata Implementation
+ */
+ACameraMetadata::ACameraMetadata(camera_metadata_t* buffer, ACAMERA_METADATA_TYPE type) :
+        mData(buffer), mType(type) {
+    if (mType == ACM_CHARACTERISTICS) {
+        filterUnsupportedFeatures();
+        filterStreamConfigurations();
+    }
+    // TODO: filter request/result keys
+}
+
+bool
+ACameraMetadata::isNdkSupportedCapability(int32_t capability) {
+    switch (capability) {
+        case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE:
+        case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR:
+        case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING:
+        case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW:
+        case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS:
+        case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE:
+        case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT:
+            return true;
+        case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING:
+        case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING:
+        case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO:
+            return false;
+        default:
+            // Newly defined capabilities will be unsupported by default (blacklist)
+            // TODO: Should we do whitelist or blacklist here?
+            ALOGE("%s: Unknonwn capability %d", __FUNCTION__, capability);
+            return false;
+    }
+}
+
+void
+ACameraMetadata::filterUnsupportedFeatures() {
+    // Hide unsupported capabilities (reprocessing)
+    camera_metadata_entry entry = mData.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+    if (entry.count == 0 || entry.type != TYPE_BYTE) {
+        ALOGE("%s: malformed available capability key! count %zu, type %d",
+                __FUNCTION__, entry.count, entry.type);
+        return;
+    }
+
+    Vector<uint8_t> capabilities;
+    capabilities.setCapacity(entry.count);
+    for (size_t i = 0; i < entry.count; i++) {
+        uint8_t capability = entry.data.u8[i];
+        if (isNdkSupportedCapability(capability)) {
+            capabilities.push(capability);
+        }
+    }
+    mData.update(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, capabilities);
+}
+
+
+void
+ACameraMetadata::filterStreamConfigurations() {
+    const int STREAM_CONFIGURATION_SIZE = 4;
+    const int STREAM_FORMAT_OFFSET = 0;
+    const int STREAM_WIDTH_OFFSET = 1;
+    const int STREAM_HEIGHT_OFFSET = 2;
+    const int STREAM_IS_INPUT_OFFSET = 3;
+    camera_metadata_entry entry = mData.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+    if (entry.count == 0 || entry.count % 4 || entry.type != TYPE_INT32) {
+        ALOGE("%s: malformed available stream configuration key! count %zu, type %d",
+                __FUNCTION__, entry.count, entry.type);
+        return;
+    }
+
+    Vector<int32_t> filteredStreamConfigs;
+    filteredStreamConfigs.setCapacity(entry.count);
+
+    for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+        int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
+        int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
+        int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
+        int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
+        if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT) {
+            // Hide input streams
+            continue;
+        }
+        // Translate HAL formats to NDK format
+        if (format == HAL_PIXEL_FORMAT_BLOB) {
+            format = AIMAGE_FORMAT_JPEG;
+        }
+        filteredStreamConfigs.push_back(format);
+        filteredStreamConfigs.push_back(width);
+        filteredStreamConfigs.push_back(height);
+        filteredStreamConfigs.push_back(isInput);
+    }
+
+    mData.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, filteredStreamConfigs);
+
+    entry = mData.find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS);
+    Vector<int32_t> filteredDepthStreamConfigs;
+    filteredDepthStreamConfigs.setCapacity(entry.count);
+
+    for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+        int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
+        int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
+        int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
+        int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
+        if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT) {
+            // Hide input streams
+            continue;
+        }
+        // Translate HAL formats to NDK format
+        if (format == HAL_PIXEL_FORMAT_BLOB) {
+            format = AIMAGE_FORMAT_DEPTH_POINT_CLOUD;
+        } else if (format == HAL_PIXEL_FORMAT_Y16) {
+            format = AIMAGE_FORMAT_DEPTH16;
+        }
+
+        filteredDepthStreamConfigs.push_back(format);
+        filteredDepthStreamConfigs.push_back(width);
+        filteredDepthStreamConfigs.push_back(height);
+        filteredDepthStreamConfigs.push_back(isInput);
+    }
+    mData.update(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, filteredDepthStreamConfigs);
+}
+
+bool
+ACameraMetadata::isVendorTag(const uint32_t tag) {
+    uint32_t tag_section = tag >> 16;
+    if (tag_section >= VENDOR_SECTION) {
+        return true;
+    }
+    return false;
+}
+
+camera_status_t
+ACameraMetadata::getConstEntry(uint32_t tag, ACameraMetadata_const_entry* entry) const {
+    if (entry == nullptr) {
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+
+    camera_metadata_ro_entry rawEntry = mData.find(tag);
+    if (rawEntry.count == 0) {
+        ALOGE("%s: cannot find metadata tag %d", __FUNCTION__, tag);
+        return ACAMERA_ERROR_METADATA_NOT_FOUND;
+    }
+    entry->tag = tag;
+    entry->type = rawEntry.type;
+    entry->count = rawEntry.count;
+    entry->data.u8 = rawEntry.data.u8;
+    return ACAMERA_OK;
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const uint8_t* data) {
+    return updateImpl<uint8_t>(tag, count, data);
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const int32_t* data) {
+    return updateImpl<int32_t>(tag, count, data);
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const float* data) {
+    return updateImpl<float>(tag, count, data);
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const double* data) {
+    return updateImpl<double>(tag, count, data);
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const int64_t* data) {
+    return updateImpl<int64_t>(tag, count, data);
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const ACameraMetadata_rational* data) {
+    return updateImpl<camera_metadata_rational_t>(tag, count, data);
+}
+
+
+// TODO: some of key below should be hidden from user
+// ex: ACAMERA_REQUEST_ID and ACAMERA_REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
+/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
+ * The key entries below this point are generated from metadata
+ * definitions in /system/media/camera/docs. Do not modify by hand or
+ * modify the comment blocks at the start or end.
+ *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/
+
+bool
+ACameraMetadata::isCaptureRequestTag(const uint32_t tag) {
+    // Skip check for vendor keys
+    if (isVendorTag(tag)) {
+        return true;
+    }
+
+    switch (tag) {
+        case ACAMERA_COLOR_CORRECTION_MODE:
+        case ACAMERA_COLOR_CORRECTION_TRANSFORM:
+        case ACAMERA_COLOR_CORRECTION_GAINS:
+        case ACAMERA_COLOR_CORRECTION_ABERRATION_MODE:
+        case ACAMERA_CONTROL_AE_ANTIBANDING_MODE:
+        case ACAMERA_CONTROL_AE_EXPOSURE_COMPENSATION:
+        case ACAMERA_CONTROL_AE_LOCK:
+        case ACAMERA_CONTROL_AE_MODE:
+        case ACAMERA_CONTROL_AE_REGIONS:
+        case ACAMERA_CONTROL_AE_TARGET_FPS_RANGE:
+        case ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER:
+        case ACAMERA_CONTROL_AF_MODE:
+        case ACAMERA_CONTROL_AF_REGIONS:
+        case ACAMERA_CONTROL_AF_TRIGGER:
+        case ACAMERA_CONTROL_AWB_LOCK:
+        case ACAMERA_CONTROL_AWB_MODE:
+        case ACAMERA_CONTROL_AWB_REGIONS:
+        case ACAMERA_CONTROL_CAPTURE_INTENT:
+        case ACAMERA_CONTROL_EFFECT_MODE:
+        case ACAMERA_CONTROL_MODE:
+        case ACAMERA_CONTROL_SCENE_MODE:
+        case ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE:
+        case ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST:
+        case ACAMERA_EDGE_MODE:
+        case ACAMERA_FLASH_MODE:
+        case ACAMERA_HOT_PIXEL_MODE:
+        case ACAMERA_JPEG_GPS_COORDINATES:
+        case ACAMERA_JPEG_GPS_PROCESSING_METHOD:
+        case ACAMERA_JPEG_GPS_TIMESTAMP:
+        case ACAMERA_JPEG_ORIENTATION:
+        case ACAMERA_JPEG_QUALITY:
+        case ACAMERA_JPEG_THUMBNAIL_QUALITY:
+        case ACAMERA_JPEG_THUMBNAIL_SIZE:
+        case ACAMERA_LENS_APERTURE:
+        case ACAMERA_LENS_FILTER_DENSITY:
+        case ACAMERA_LENS_FOCAL_LENGTH:
+        case ACAMERA_LENS_FOCUS_DISTANCE:
+        case ACAMERA_LENS_OPTICAL_STABILIZATION_MODE:
+        case ACAMERA_NOISE_REDUCTION_MODE:
+        case ACAMERA_REQUEST_ID:
+        case ACAMERA_SCALER_CROP_REGION:
+        case ACAMERA_SENSOR_EXPOSURE_TIME:
+        case ACAMERA_SENSOR_FRAME_DURATION:
+        case ACAMERA_SENSOR_SENSITIVITY:
+        case ACAMERA_SENSOR_TEST_PATTERN_DATA:
+        case ACAMERA_SENSOR_TEST_PATTERN_MODE:
+        case ACAMERA_SHADING_MODE:
+        case ACAMERA_STATISTICS_FACE_DETECT_MODE:
+        case ACAMERA_STATISTICS_HOT_PIXEL_MAP_MODE:
+        case ACAMERA_STATISTICS_LENS_SHADING_MAP_MODE:
+        case ACAMERA_TONEMAP_CURVE_BLUE:
+        case ACAMERA_TONEMAP_CURVE_GREEN:
+        case ACAMERA_TONEMAP_CURVE_RED:
+        case ACAMERA_TONEMAP_MODE:
+        case ACAMERA_TONEMAP_GAMMA:
+        case ACAMERA_TONEMAP_PRESET_CURVE:
+        case ACAMERA_LED_TRANSMIT:
+        case ACAMERA_BLACK_LEVEL_LOCK:
+        case ACAMERA_REPROCESS_EFFECTIVE_EXPOSURE_FACTOR:
+            return true;
+        default:
+            return false;
+    }
+}
+
+/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
+ * End generated code
+ *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/camera/ndk/impl/ACameraMetadata.h b/camera/ndk/impl/ACameraMetadata.h
new file mode 100644
index 0000000..442e1dd
--- /dev/null
+++ b/camera/ndk/impl/ACameraMetadata.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 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 _ACAMERA_METADATA_H
+#define _ACAMERA_METADATA_H
+
+#include <sys/types.h>
+#include <utils/RefBase.h>
+#include <camera/CameraMetadata.h>
+
+#include "NdkCameraMetadata.h"
+
+using namespace android;
+
+/**
+ * ACameraMetadata opaque struct definition
+ * Leave outside of android namespace because it's NDK struct
+ */
+struct ACameraMetadata : public RefBase {
+  public:
+    typedef enum {
+        ACM_CHARACTERISTICS, // Read only
+        ACM_REQUEST,         // Read/Write
+        ACM_RESULT,          // Read only
+    } ACAMERA_METADATA_TYPE;
+
+    // Takes ownership of pass-in buffer
+    ACameraMetadata(camera_metadata_t *buffer, ACAMERA_METADATA_TYPE type);
+    // Clone
+    ACameraMetadata(const ACameraMetadata& other) :
+            mData(other.mData), mType(other.mType) {};
+
+    camera_status_t getConstEntry(uint32_t tag, ACameraMetadata_const_entry* entry) const;
+
+    camera_status_t update(uint32_t tag, uint32_t count, const uint8_t* data);
+    camera_status_t update(uint32_t tag, uint32_t count, const int32_t* data);
+    camera_status_t update(uint32_t tag, uint32_t count, const float* data);
+    camera_status_t update(uint32_t tag, uint32_t count, const double* data);
+    camera_status_t update(uint32_t tag, uint32_t count, const int64_t* data);
+    camera_status_t update(uint32_t tag, uint32_t count, const ACameraMetadata_rational* data);
+
+    bool isNdkSupportedCapability(const int32_t capability);
+    inline bool isVendorTag(const uint32_t tag);
+    bool isCaptureRequestTag(const uint32_t tag);
+    void filterUnsupportedFeatures(); // Hide features not yet supported by NDK
+    void filterStreamConfigurations(); // Hide input streams, translate hal format to NDK formats
+
+    template<typename INTERNAL_T, typename NDK_T>
+    camera_status_t updateImpl(uint32_t tag, uint32_t count, const NDK_T* data) {
+        if (mType != ACM_REQUEST) {
+            ALOGE("Error: Write to metadata is only allowed for capture request!");
+            return ACAMERA_ERROR_INVALID_PARAMETER;
+        }
+        if (!isCaptureRequestTag(tag)) {
+            ALOGE("Error: tag %d is not writable!", tag);
+            return ACAMERA_ERROR_INVALID_PARAMETER;
+        }
+
+        // Here we have to use reinterpret_cast because the NDK data type is
+        // exact copy of internal data type but they do not inherit from each other
+        status_t ret = mData.update(tag, reinterpret_cast<const INTERNAL_T*>(data), count);
+        if (ret == OK) {
+            return ACAMERA_OK;
+        } else {
+            return ACAMERA_ERROR_INVALID_PARAMETER;
+        }
+    }
+
+    CameraMetadata mData;
+    const ACAMERA_METADATA_TYPE mType;
+};
+
+#endif // _ACAMERA_METADATA_H
diff --git a/camera/ndk/impl/ACaptureRequest.h b/camera/ndk/impl/ACaptureRequest.h
new file mode 100644
index 0000000..6bd8406
--- /dev/null
+++ b/camera/ndk/impl/ACaptureRequest.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 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 _ACAPTURE_REQUEST_H
+#define _ACAPTURE_REQUEST_H
+
+#include "NdkCaptureRequest.h"
+#include <set>
+
+using namespace android;
+
+struct ACameraOutputTarget {
+    ACameraOutputTarget(ANativeWindow* window) : mWindow(window) {};
+
+    bool operator == (const ACameraOutputTarget& other) const {
+        return mWindow == other.mWindow;
+    }
+    bool operator != (const ACameraOutputTarget& other) const {
+        return mWindow != other.mWindow;
+    }
+    bool operator < (const ACameraOutputTarget& other) const {
+        return mWindow < other.mWindow;
+    }
+    bool operator > (const ACameraOutputTarget& other) const {
+        return mWindow > other.mWindow;
+    }
+
+    ANativeWindow* mWindow;
+};
+
+struct ACameraOutputTargets {
+    std::set<ACameraOutputTarget> mOutputs;
+};
+
+struct ACaptureRequest {
+    ACameraMetadata*      settings;
+    ACameraOutputTargets* targets;
+};
+
+#endif // _ACAPTURE_REQUEST_H
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 572fb72..a36d2f9 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -160,6 +160,7 @@
 
     virtual void onDeviceError(CameraErrorCode errorCode,
             const CaptureResultExtras& resultExtras) {
+        (void) resultExtras;
         ALOGE("%s: onDeviceError occurred with: %d", __FUNCTION__, static_cast<int>(errorCode));
         Mutex::Autolock l(mLock);
         mError = true;
@@ -177,6 +178,8 @@
 
     virtual void onCaptureStarted(const CaptureResultExtras& resultExtras,
             int64_t timestamp) {
+        (void) resultExtras;
+        (void) timestamp;
         Mutex::Autolock l(mLock);
         mLastStatus = RUNNING;
         mStatusesHit.push_back(mLastStatus);
@@ -186,6 +189,8 @@
 
     virtual void onResultReceived(const CameraMetadata& metadata,
             const CaptureResultExtras& resultExtras) {
+        (void) metadata;
+        (void) resultExtras;
         Mutex::Autolock l(mLock);
         mLastStatus = SENT_RESULT;
         mStatusesHit.push_back(mLastStatus);
@@ -193,6 +198,7 @@
     }
 
     virtual void onPrepared(int streamId) {
+        (void) streamId;
         Mutex::Autolock l(mLock);
         mLastStatus = PREPARED;
         mStatusesHit.push_back(mLastStatus);
@@ -237,16 +243,36 @@
 
 };
 
+namespace {
+    Mutex                     gLock;
+    class DeathNotifier : public IBinder::DeathRecipient
+    {
+    public:
+        DeathNotifier() {}
+
+        virtual void binderDied(const wp<IBinder>& /*who*/) {
+            ALOGV("binderDied");
+            Mutex::Autolock _l(gLock);
+            ALOGW("Camera service died!");
+        }
+    };
+    sp<DeathNotifier>         gDeathNotifier;
+}; // anonymous namespace
+
 // Exercise basic binder calls for the camera service
 TEST(CameraServiceBinderTest, CheckBinderCameraService) {
     ProcessState::self()->startThreadPool();
     sp<IServiceManager> sm = defaultServiceManager();
     sp<IBinder> binder = sm->getService(String16("media.camera"));
     ASSERT_NOT_NULL(binder);
+    if (gDeathNotifier == NULL) {
+        gDeathNotifier = new DeathNotifier();
+    }
+    binder->linkToDeath(gDeathNotifier);
     sp<ICameraService> service = interface_cast<ICameraService>(binder);
 
 
-    int32_t numCameras = service->getNumberOfCameras();
+    int32_t numCameras = service->getNumberOfCameras(ICameraService::CAMERA_TYPE_ALL);
     EXPECT_LE(0, numCameras);
 
     // Check listener binder calls
@@ -465,6 +491,7 @@
         callbacks->clearStatus();
         int requestId3 = device->submitRequestList(requestList, /*streaming*/false,
                 /*out*/&lastFrameNumber);
+        EXPECT_LE(0, requestId3);
         EXPECT_TRUE(callbacks->waitForStatus(TestCameraDeviceCallbacks::SENT_RESULT));
         EXPECT_TRUE(callbacks->waitForIdle());
         EXPECT_LE(lastFrameNumberPrev, lastFrameNumber);
diff --git a/cmds/screenrecord/FrameOutput.cpp b/cmds/screenrecord/FrameOutput.cpp
index bef74f5..ee7ace6 100644
--- a/cmds/screenrecord/FrameOutput.cpp
+++ b/cmds/screenrecord/FrameOutput.cpp
@@ -74,7 +74,7 @@
                 GL_TEXTURE_EXTERNAL_OES, true, false);
     mGlConsumer->setName(String8("virtual display"));
     mGlConsumer->setDefaultBufferSize(width, height);
-    mGlConsumer->setDefaultMaxBufferCount(5);
+    producer->setMaxDequeuedBufferCount(4);
     mGlConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_TEXTURE);
 
     mGlConsumer->setFrameAvailableListener(this);
diff --git a/cmds/screenrecord/Overlay.cpp b/cmds/screenrecord/Overlay.cpp
index c659170..9fd192c 100644
--- a/cmds/screenrecord/Overlay.cpp
+++ b/cmds/screenrecord/Overlay.cpp
@@ -176,7 +176,7 @@
                 GL_TEXTURE_EXTERNAL_OES, true, false);
     mGlConsumer->setName(String8("virtual display"));
     mGlConsumer->setDefaultBufferSize(width, height);
-    mGlConsumer->setDefaultMaxBufferCount(5);
+    mProducer->setMaxDequeuedBufferCount(4);
     mGlConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_TEXTURE);
 
     mGlConsumer->setFrameAvailableListener(this);
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index b79abce..e5fbba0 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -35,7 +35,7 @@
 	record.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright liblog libutils libbinder libstagefright_foundation
+	libstagefright libmedia liblog libutils libbinder libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
 	frameworks/av/media/libstagefright \
@@ -59,7 +59,7 @@
 	recordvideo.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright liblog libutils libbinder libstagefright_foundation
+	libstagefright libmedia liblog libutils libbinder libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
 	frameworks/av/media/libstagefright \
@@ -84,7 +84,7 @@
 	audioloop.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright liblog libutils libbinder libstagefright_foundation
+	libstagefright libmedia liblog libutils libbinder libstagefright_foundation
 
 LOCAL_C_INCLUDES:= \
 	frameworks/av/media/libstagefright \
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index 67017eb..ed44b4d 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -112,7 +112,7 @@
     looper->setName("audioloop");
     looper->start();
 
-    sp<MediaSource> encoder = MediaCodecSource::Create(looper, meta, source);
+    sp<IMediaSource> encoder = MediaCodecSource::Create(looper, meta, source);
 
     if (fileOut != NULL) {
         // target file specified, write encoded AMR output
@@ -128,7 +128,7 @@
         writer->stop();
     } else {
         // otherwise decode to speaker
-        sp<MediaSource> decoder = SimpleDecodingSource::Create(encoder);
+        sp<IMediaSource> decoder = SimpleDecodingSource::Create(encoder);
 
         if (playToSpeaker) {
             AudioPlayer *player = new AudioPlayer(NULL);
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index fbea7e9..f8b2f68 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -322,7 +322,7 @@
     looper->setName("record");
     looper->start();
 
-    sp<MediaSource> encoder =
+    sp<IMediaSource> encoder =
         MediaCodecSource::Create(looper, encMeta, audioSource);
 
     encoder->start();
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index af39d46..7a3c842 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -303,7 +303,7 @@
     looper->setName("recordvideo");
     looper->start();
 
-    sp<MediaSource> encoder =
+    sp<IMediaSource> encoder =
         MediaCodecSource::Create(
                 looper, enc_meta, source, NULL /* consumer */,
                 preferSoftwareCodec ? MediaCodecSource::FLAG_PREFER_SOFTWARE_CODEC : 0);
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index 0d64d2f..1a4bf08 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -118,7 +118,7 @@
                     DataSource::CreateFromURI(
                             NULL /* httpService */, mURI.c_str());
 
-                sp<MediaExtractor> extractor =
+                sp<IMediaExtractor> extractor =
                     MediaExtractor::Create(dataSource);
 
                 for (size_t i = 0; i < extractor->countTracks(); ++i) {
@@ -264,7 +264,7 @@
     sp<Surface> mSurface;
     bool mRenderToSurface;
     sp<ACodec> mCodec;
-    sp<MediaSource> mSource;
+    sp<IMediaSource> mSource;
     bool mIsVorbis;
 
     Vector<sp<ABuffer> > mCSD;
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 757c9f6..ca68722 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -33,6 +33,7 @@
 #include <binder/ProcessState.h>
 #include <media/ICrypto.h>
 #include <media/IMediaHTTPService.h>
+#include <media/IMediaCodecService.h>
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -73,6 +74,7 @@
 static bool gPlaybackAudio;
 static bool gWriteMP4;
 static bool gDisplayHistogram;
+static bool showProgress = true;
 static String8 gWriteMP4Filename;
 
 static sp<ANativeWindow> gSurface;
@@ -136,7 +138,7 @@
     }
 }
 
-static void dumpSource(const sp<MediaSource> &source, const String8 &filename) {
+static void dumpSource(const sp<IMediaSource> &source, const String8 &filename) {
     FILE *out = fopen(filename.string(), "wb");
 
     CHECK_EQ((status_t)OK, source->start());
@@ -169,13 +171,13 @@
     out = NULL;
 }
 
-static void playSource(sp<MediaSource> &source) {
+static void playSource(sp<IMediaSource> &source) {
     sp<MetaData> meta = source->getFormat();
 
     const char *mime;
     CHECK(meta->findCString(kKeyMIMEType, &mime));
 
-    sp<MediaSource> rawSource;
+    sp<IMediaSource> rawSource;
     if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime)) {
         rawSource = source;
     } else {
@@ -338,7 +340,7 @@
                     decodeTimesUs.push(delayDecodeUs);
                 }
 
-                if ((n++ % 16) == 0) {
+                if (showProgress && (n++ % 16) == 0) {
                     printf(".");
                     fflush(stdout);
                 }
@@ -364,8 +366,10 @@
             }
         }
 
-        printf("$");
-        fflush(stdout);
+        if (showProgress) {
+            printf("$");
+            fflush(stdout);
+        }
 
         options.setSeekTo(0);
     }
@@ -397,7 +401,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 struct DetectSyncSource : public MediaSource {
-    DetectSyncSource(const sp<MediaSource> &source);
+    DetectSyncSource(const sp<IMediaSource> &source);
 
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop();
@@ -414,14 +418,14 @@
         OTHER,
     };
 
-    sp<MediaSource> mSource;
+    sp<IMediaSource> mSource;
     StreamType mStreamType;
     bool mSawFirstIDRFrame;
 
     DISALLOW_EVIL_CONSTRUCTORS(DetectSyncSource);
 };
 
-DetectSyncSource::DetectSyncSource(const sp<MediaSource> &source)
+DetectSyncSource::DetectSyncSource(const sp<IMediaSource> &source)
     : mSource(source),
       mStreamType(OTHER),
       mSawFirstIDRFrame(false) {
@@ -503,7 +507,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 static void writeSourcesToMP4(
-        Vector<sp<MediaSource> > &sources, bool syncInfoPresent) {
+        Vector<sp<IMediaSource> > &sources, bool syncInfoPresent) {
 #if 0
     sp<MPEG4Writer> writer =
         new MPEG4Writer(gWriteMP4Filename.string());
@@ -521,7 +525,7 @@
     writer->setMaxFileDuration(60000000ll);
 
     for (size_t i = 0; i < sources.size(); ++i) {
-        sp<MediaSource> source = sources.editItemAt(i);
+        sp<IMediaSource> source = sources.editItemAt(i);
 
         CHECK_EQ(writer->addSource(
                     syncInfoPresent ? source : new DetectSyncSource(source)),
@@ -538,7 +542,7 @@
     writer->stop();
 }
 
-static void performSeekTest(const sp<MediaSource> &source) {
+static void performSeekTest(const sp<IMediaSource> &source) {
     CHECK_EQ((status_t)OK, source->start());
 
     int64_t durationUs;
@@ -612,6 +616,7 @@
     fprintf(stderr, "       -k seek test\n");
     fprintf(stderr, "       -x display a histogram of decoding times/fps "
                     "(video only)\n");
+    fprintf(stderr, "       -q don't show progress indicator\n");
     fprintf(stderr, "       -S allocate buffers from a surface\n");
     fprintf(stderr, "       -T allocate buffers from a surface texture\n");
     fprintf(stderr, "       -d(ump) output_filename (raw stream data to a file)\n");
@@ -625,7 +630,8 @@
         MEDIA_MIMETYPE_AUDIO_AMR_NB, MEDIA_MIMETYPE_AUDIO_AMR_WB,
         MEDIA_MIMETYPE_AUDIO_MPEG, MEDIA_MIMETYPE_AUDIO_G711_MLAW,
         MEDIA_MIMETYPE_AUDIO_G711_ALAW, MEDIA_MIMETYPE_AUDIO_VORBIS,
-        MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9
+        MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9,
+        MEDIA_MIMETYPE_VIDEO_DOLBY_VISION
     };
 
     const char *codecType = queryDecoders? "decoder" : "encoder";
@@ -693,7 +699,7 @@
     sp<ALooper> looper;
 
     int res;
-    while ((res = getopt(argc, argv, "han:lm:b:ptsrow:kxSTd:D:")) >= 0) {
+    while ((res = getopt(argc, argv, "haqn:lm:b:ptsrow:kxSTd:D:")) >= 0) {
         switch (res) {
             case 'a':
             {
@@ -701,6 +707,12 @@
                 break;
             }
 
+            case 'q':
+            {
+                showProgress = false;
+                break;
+            }
+
             case 'd':
             {
                 dumpStream = true;
@@ -893,8 +905,8 @@
 
     if (listComponents) {
         sp<IServiceManager> sm = defaultServiceManager();
-        sp<IBinder> binder = sm->getService(String16("media.player"));
-        sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+        sp<IBinder> binder = sm->getService(String16("media.codec"));
+        sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
 
         CHECK(service.get() != NULL);
 
@@ -977,8 +989,8 @@
             isJPEG = true;
         }
 
-        Vector<sp<MediaSource> > mediaSources;
-        sp<MediaSource> mediaSource;
+        Vector<sp<IMediaSource> > mediaSources;
+        sp<IMediaSource> mediaSource;
 
         if (isJPEG) {
             mediaSource = new JPEGSource(dataSource);
@@ -997,7 +1009,7 @@
                 mediaSources.push(mediaSource);
             }
         } else {
-            sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+            sp<IMediaExtractor> extractor = MediaExtractor::Create(dataSource);
 
             if (extractor == NULL) {
                 fprintf(stderr, "could not create extractor.\n");
@@ -1008,7 +1020,10 @@
 
             if (meta != NULL) {
                 const char *mime;
-                CHECK(meta->findCString(kKeyMIMEType, &mime));
+                if (!meta->findCString(kKeyMIMEType, &mime)) {
+                    fprintf(stderr, "extractor did not provide MIME type.\n");
+                    return -1;
+                }
 
                 if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
                     syncInfoPresent = false;
@@ -1021,7 +1036,7 @@
                 bool haveAudio = false;
                 bool haveVideo = false;
                 for (size_t i = 0; i < numTracks; ++i) {
-                    sp<MediaSource> source = extractor->getTrack(i);
+                    sp<IMediaSource> source = extractor->getTrack(i);
 
                     const char *mime;
                     CHECK(source->getFormat()->findCString(
@@ -1051,6 +1066,9 @@
                     meta = extractor->getTrackMetaData(
                             i, MediaExtractor::kIncludeExtensiveMetaData);
 
+                    if (meta == NULL) {
+                        break;
+                    }
                     const char *mime;
                     meta->findCString(kKeyMIMEType, &mime);
 
@@ -1089,7 +1107,7 @@
         } else if (dumpStream) {
             dumpSource(mediaSource, dumpStreamFilename);
         } else if (dumpPCMStream) {
-            sp<MediaSource> decSource = SimpleDecodingSource::Create(mediaSource);
+            sp<IMediaSource> decSource = SimpleDecodingSource::Create(mediaSource);
             dumpSource(decSource, dumpStreamFilename);
         } else if (seekTest) {
             performSeekTest(mediaSource);
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index 1a40e53..bca3832 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -165,7 +165,7 @@
 
     CHECK(dataSource != NULL);
 
-    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+    sp<IMediaExtractor> extractor = MediaExtractor::Create(dataSource);
     CHECK(extractor != NULL);
 
     mWriter = new MPEG2TSWriter(
diff --git a/drm/libdrmframework/Android.mk b/drm/libdrmframework/Android.mk
index 33f9d3b..cafcb94 100644
--- a/drm/libdrmframework/Android.mk
+++ b/drm/libdrmframework/Android.mk
@@ -38,6 +38,7 @@
     $(TOP)/frameworks/av/drm/libdrmframework/include \
     $(TOP)/frameworks/av/include
 
+LOCAL_CFLAGS += -Werror
 
 
 LOCAL_MODULE_TAGS := optional
diff --git a/drm/libdrmframework/DrmManagerClientImpl.cpp b/drm/libdrmframework/DrmManagerClientImpl.cpp
index 9457bb6..cbd013e 100644
--- a/drm/libdrmframework/DrmManagerClientImpl.cpp
+++ b/drm/libdrmframework/DrmManagerClientImpl.cpp
@@ -350,7 +350,8 @@
     }
 }
 
-void DrmManagerClientImpl::DeathNotifier::binderDied(const wp<IBinder>& who) {
+void DrmManagerClientImpl::DeathNotifier::binderDied(
+            const wp<IBinder>& /* who */) {
     Mutex::Autolock lock(sMutex);
     DrmManagerClientImpl::sDrmManagerService.clear();
     ALOGW("DrmManager server died!");
diff --git a/drm/libdrmframework/NoOpDrmManagerClientImpl.cpp b/drm/libdrmframework/NoOpDrmManagerClientImpl.cpp
index dab583d..1172e80 100644
--- a/drm/libdrmframework/NoOpDrmManagerClientImpl.cpp
+++ b/drm/libdrmframework/NoOpDrmManagerClientImpl.cpp
@@ -18,134 +18,209 @@
 
 namespace android {
 
-void NoOpDrmManagerClientImpl::remove(int uniqueId) {
+void NoOpDrmManagerClientImpl::remove(int /* uniqueId */) {
 }
 
-void NoOpDrmManagerClientImpl::addClient(int uniqueId) {
+void NoOpDrmManagerClientImpl::addClient(int /* uniqueId */) {
 }
 
-void NoOpDrmManagerClientImpl::removeClient(int uniqueId) {
+void NoOpDrmManagerClientImpl::removeClient(
+            int /* uniqueId */) {
 }
 
 status_t NoOpDrmManagerClientImpl::setOnInfoListener(
-            int uniqueId, const sp<DrmManagerClient::OnInfoListener>& infoListener) {
+            int /* uniqueId */,
+            const sp<DrmManagerClient::OnInfoListener>& /* infoListener */) {
     return UNKNOWN_ERROR;
 }
 
-DrmConstraints* NoOpDrmManagerClientImpl::getConstraints(int uniqueId, const String8* path, const int action) {
+DrmConstraints* NoOpDrmManagerClientImpl::getConstraints(
+            int /* uniqueId */,
+            const String8* /* path */,
+            const int /* action */) {
     return NULL;
 }
 
-DrmMetadata* NoOpDrmManagerClientImpl::getMetadata(int uniqueId, const String8* path) {
+DrmMetadata* NoOpDrmManagerClientImpl::getMetadata(
+            int /* uniqueId */,
+            const String8* /* path */) {
     return NULL;
 }
 
-bool NoOpDrmManagerClientImpl::canHandle(int uniqueId, const String8& path, const String8& mimeType) {
+bool NoOpDrmManagerClientImpl::canHandle(
+            int /* uniqueId */,
+            const String8& /* path */,
+            const String8& /* mimeType */) {
     return false;
 }
 
-DrmInfoStatus* NoOpDrmManagerClientImpl::processDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
+DrmInfoStatus* NoOpDrmManagerClientImpl::processDrmInfo(
+            int /* uniqueId */,
+            const DrmInfo* /* drmInfo */) {
     return NULL;
 }
 
-DrmInfo* NoOpDrmManagerClientImpl::acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
+DrmInfo* NoOpDrmManagerClientImpl::acquireDrmInfo(
+            int /* uniqueId */,
+            const DrmInfoRequest* /* drmInfoRequest */) {
     return NULL;
 }
 
-status_t NoOpDrmManagerClientImpl::saveRights(int uniqueId, const DrmRights& drmRights,
-            const String8& rightsPath, const String8& contentPath) {
+status_t NoOpDrmManagerClientImpl::saveRights(
+            int /* uniqueId */,
+            const DrmRights& /* drmRights */,
+            const String8& /* rightsPath */,
+            const String8& /* contentPath */) {
     return UNKNOWN_ERROR;
 }
 
-String8 NoOpDrmManagerClientImpl::getOriginalMimeType(int uniqueId, const String8& path, int fd) {
+String8 NoOpDrmManagerClientImpl::getOriginalMimeType(
+            int /* uniqueId */,
+            const String8& /* path */,
+            int /* fd */) {
     return String8();
 }
 
-int NoOpDrmManagerClientImpl::getDrmObjectType(int uniqueId, const String8& path, const String8& mimeType) {
+int NoOpDrmManagerClientImpl::getDrmObjectType(
+            int /* uniqueId */,
+            const String8& /* path */,
+            const String8& /* mimeType */) {
     return -1;
 }
 
-int NoOpDrmManagerClientImpl::checkRightsStatus(int uniqueId, const String8& path, int action) {
+int NoOpDrmManagerClientImpl::checkRightsStatus(
+            int /* uniqueId */,
+            const String8& /* path */,
+            int /* action */) {
     return -1;
 }
 
-status_t NoOpDrmManagerClientImpl::consumeRights(int uniqueId, sp<DecryptHandle> &decryptHandle, int action, bool reserve) {
+status_t NoOpDrmManagerClientImpl::consumeRights(
+            int /* uniqueId */,
+            sp<DecryptHandle> &/* decryptHandle */,
+            int /* action */,
+            bool /* reserve */) {
     return UNKNOWN_ERROR;
 }
 
 status_t NoOpDrmManagerClientImpl::setPlaybackStatus(
-            int uniqueId, sp<DecryptHandle> &decryptHandle, int playbackStatus, int64_t position) {
+            int /* uniqueId */,
+            sp<DecryptHandle> &/* decryptHandle */,
+            int /* playbackStatus */,
+            int64_t /* position */) {
     return UNKNOWN_ERROR;
 }
 
 bool NoOpDrmManagerClientImpl::validateAction(
-        int uniqueId, const String8& path, int action, const ActionDescription& description) {
+            int /* uniqueId */,
+            const String8& /* path */,
+            int /* action */,
+            const ActionDescription& /* description */) {
     return false;
 }
 
-status_t NoOpDrmManagerClientImpl::removeRights(int uniqueId, const String8& path) {
+status_t NoOpDrmManagerClientImpl::removeRights(
+            int /* uniqueId */,
+            const String8& /* path */) {
     return UNKNOWN_ERROR;
 }
 
-status_t NoOpDrmManagerClientImpl::removeAllRights(int uniqueId) {
+status_t NoOpDrmManagerClientImpl::removeAllRights(
+            int /* uniqueId */) {
     return UNKNOWN_ERROR;
 }
 
-int NoOpDrmManagerClientImpl::openConvertSession(int uniqueId, const String8& mimeType) {
+int NoOpDrmManagerClientImpl::openConvertSession(
+            int /* uniqueId */,
+            const String8& /* mimeType */) {
     return -1;
 }
 
-DrmConvertedStatus* NoOpDrmManagerClientImpl::convertData(int uniqueId, int convertId, const DrmBuffer* inputData) {
+DrmConvertedStatus* NoOpDrmManagerClientImpl::convertData(
+            int /* uniqueId */,
+            int /* convertId */,
+            const DrmBuffer* /* inputData */) {
     return NULL;
 }
 
-DrmConvertedStatus* NoOpDrmManagerClientImpl::closeConvertSession(int uniqueId, int convertId) {
+DrmConvertedStatus* NoOpDrmManagerClientImpl::closeConvertSession(
+            int /* uniqueId */,
+            int /* convertId */) {
     return NULL;
 }
 
-status_t NoOpDrmManagerClientImpl::getAllSupportInfo(int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray) {
+status_t NoOpDrmManagerClientImpl::getAllSupportInfo(
+            int /* uniqueId */,
+            int* /* length */,
+            DrmSupportInfo** /* drmSupportInfoArray */) {
     return UNKNOWN_ERROR;
 }
 
 sp<DecryptHandle> NoOpDrmManagerClientImpl::openDecryptSession(
-            int uniqueId, int fd, off64_t offset, off64_t length, const char* mime) {
+            int /* uniqueId */,
+            int /* fd */,
+            off64_t /* offset */,
+            off64_t /* length */,
+            const char* /* mime */) {
     return NULL;
 }
 
 sp<DecryptHandle> NoOpDrmManagerClientImpl::openDecryptSession(
-            int uniqueId, const char* uri, const char* mime) {
+            int /* uniqueId */,
+            const char* /* uri */,
+            const char* /* mime */) {
     return NULL;
 }
 
-sp<DecryptHandle> NoOpDrmManagerClientImpl::openDecryptSession(int uniqueId, const DrmBuffer& buf,
-            const String8& mimeType) {
+sp<DecryptHandle> NoOpDrmManagerClientImpl::openDecryptSession(
+            int /* uniqueId */,
+            const DrmBuffer& /* buf */,
+            const String8& /* mimeType */) {
     return NULL;
 }
 
-status_t NoOpDrmManagerClientImpl::closeDecryptSession(int uniqueId, sp<DecryptHandle> &decryptHandle) {
+status_t NoOpDrmManagerClientImpl::closeDecryptSession(
+            int /* uniqueId */,
+            sp<DecryptHandle> &/* decryptHandle */) {
     return UNKNOWN_ERROR;
 }
 
-status_t NoOpDrmManagerClientImpl::initializeDecryptUnit(int uniqueId, sp<DecryptHandle> &decryptHandle,
-            int decryptUnitId, const DrmBuffer* headerInfo) {
+status_t NoOpDrmManagerClientImpl::initializeDecryptUnit(
+            int /* uniqueId */,
+            sp<DecryptHandle> &/* decryptHandle */,
+            int /* decryptUnitId */,
+            const DrmBuffer* /* headerInfo */) {
     return UNKNOWN_ERROR;
 }
 
-status_t NoOpDrmManagerClientImpl::decrypt(int uniqueId, sp<DecryptHandle> &decryptHandle, int decryptUnitId,
-            const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
+status_t NoOpDrmManagerClientImpl::decrypt(
+            int /* uniqueId */,
+            sp<DecryptHandle> &/* decryptHandle */,
+            int /* decryptUnitId */,
+            const DrmBuffer* /* encBuffer */,
+            DrmBuffer** /* decBuffer */,
+            DrmBuffer* /* IV */) {
     return UNKNOWN_ERROR;
 }
 
-status_t NoOpDrmManagerClientImpl::finalizeDecryptUnit(int uniqueId, sp<DecryptHandle> &decryptHandle, int decryptUnitId) {
+status_t NoOpDrmManagerClientImpl::finalizeDecryptUnit(
+            int /* uniqueId */,
+            sp<DecryptHandle> &/* decryptHandle */,
+            int /* decryptUnitId */) {
     return UNKNOWN_ERROR;
 }
 
-ssize_t NoOpDrmManagerClientImpl::pread(int uniqueId, sp<DecryptHandle> &decryptHandle,
-            void* buffer, ssize_t numBytes, off64_t offset) {
+ssize_t NoOpDrmManagerClientImpl::pread(
+            int /* uniqueId */,
+            sp<DecryptHandle> &/* decryptHandle */,
+            void* /* buffer */,
+            ssize_t /* numBytes */,
+            off64_t /* offset */) {
     return -1;
 }
 
-status_t NoOpDrmManagerClientImpl::notify(const DrmInfoEvent& event) {
+status_t NoOpDrmManagerClientImpl::notify(
+            const DrmInfoEvent& /* event */) {
     return UNKNOWN_ERROR;
 }
 
diff --git a/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp
index 53cbf80..6666343 100644
--- a/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp
@@ -33,7 +33,7 @@
 // decrypted data.  In theory, the output size can be larger than the input
 // size, but in practice this will never happen for AES-CTR.
 ssize_t CryptoPlugin::decrypt(bool secure, const KeyId keyId, const Iv iv,
-                              Mode mode, const void* srcPtr,
+                              Mode mode, const Pattern &pattern, const void* srcPtr,
                               const SubSample* subSamples, size_t numSubSamples,
                               void* dstPtr, AString* errorDetailMsg) {
     if (secure) {
diff --git a/drm/mediadrm/plugins/clearkey/CryptoPlugin.h b/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
index fd38f28..de84c36 100644
--- a/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
@@ -44,7 +44,7 @@
 
     virtual ssize_t decrypt(
             bool secure, const KeyId keyId, const Iv iv,
-            Mode mode, const void* srcPtr,
+            Mode mode, const Pattern &pattern, const void* srcPtr,
             const SubSample* subSamples, size_t numSubSamples,
             void* dstPtr, android::AString* errorDetailMsg);
 
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
index ba4aefe..9095045 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
@@ -105,10 +105,6 @@
         return android::ERROR_DRM_CANNOT_HANDLE;
     }
 
-    virtual status_t unprovisionDevice() {
-        return android::ERROR_DRM_CANNOT_HANDLE;
-    }
-
     virtual status_t getSecureStops(List<Vector<uint8_t> >& secureStops) {
         UNUSED(secureStops);
         return android::ERROR_DRM_CANNOT_HANDLE;
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
index 851ad2c..1e80f8e 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
@@ -312,12 +312,6 @@
         return OK;
     }
 
-    status_t MockDrmPlugin::unprovisionDevice()
-    {
-        ALOGD("MockDrmPlugin::unprovisionDevice()");
-        return OK;
-    }
-
     status_t MockDrmPlugin::getSecureStop(Vector<uint8_t> const & /* ssid */,
                                           Vector<uint8_t> & secureStop)
     {
@@ -798,15 +792,17 @@
 
     ssize_t
     MockCryptoPlugin::decrypt(bool secure, const uint8_t key[16], const uint8_t iv[16],
-                              Mode mode, const void *srcPtr, const SubSample *subSamples,
-                              size_t numSubSamples, void *dstPtr, AString * /* errorDetailMsg */)
+            Mode mode, const Pattern &pattern, const void *srcPtr,
+            const SubSample *subSamples, size_t numSubSamples,
+            void *dstPtr, AString * /* errorDetailMsg */)
     {
-        ALOGD("MockCryptoPlugin::decrypt(secure=%d, key=%s, iv=%s, mode=%d, src=%p, "
+        ALOGD("MockCryptoPlugin::decrypt(secure=%d, key=%s, iv=%s, mode=%d, "
+              "pattern:{encryptBlocks=%d, skipBlocks=%d} src=%p, "
               "subSamples=%s, dst=%p)",
               (int)secure,
               arrayToString(key, sizeof(key)).string(),
               arrayToString(iv, sizeof(iv)).string(),
-              (int)mode, srcPtr,
+              (int)mode, pattern.mEncryptBlocks, pattern.mSkipBlocks, srcPtr,
               subSamplesToString(subSamples, numSubSamples).string(),
               dstPtr);
         return OK;
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
index d0f2ddb..40d4e84 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
@@ -86,8 +86,6 @@
                                           Vector<uint8_t> &certificate,
                                           Vector<uint8_t> &wrappedKey);
 
-        status_t unprovisionDevice();
-
         status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
         status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop);
         status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
@@ -161,7 +159,7 @@
 
         ssize_t decrypt(bool secure,
             const uint8_t key[16], const uint8_t iv[16],
-            Mode mode, const void *srcPtr,
+            Mode mode, const Pattern &pattern, const void *srcPtr,
             const SubSample *subSamples, size_t numSubSamples,
             void *dstPtr, AString *errorDetailMsg);
     private:
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 2b60842..f19d296 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -52,7 +52,7 @@
     typedef ICamera               TCamUser;
     typedef ICameraClient         TCamCallbacks;
     typedef status_t (ICameraService::*TCamConnectService)(const sp<ICameraClient>&,
-                                                           int, const String16&, int,
+                                                           int, const String16&, int, int,
                                                            /*out*/
                                                            sp<ICamera>&);
     static TCamConnectService     fnConnectService;
@@ -67,12 +67,15 @@
     enum {
         USE_CALLING_UID = ICameraService::USE_CALLING_UID
     };
+    enum {
+        USE_CALLING_PID = ICameraService::USE_CALLING_PID
+    };
 
             // construct a camera client from an existing remote
     static  sp<Camera>  create(const sp<ICamera>& camera);
     static  sp<Camera>  connect(int cameraId,
                                 const String16& clientPackageName,
-                                int clientUid);
+                                int clientUid, int clientPid);
 
     static  status_t  connectLegacy(int cameraId, int halVersion,
                                      const String16& clientPackageName,
@@ -126,8 +129,15 @@
             // send command to camera driver
             status_t    sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
 
-            // tell camera hal to store meta data or real YUV in video buffers.
-            status_t    storeMetaDataInBuffers(bool enabled);
+            // Tell camera how to pass video buffers. videoBufferMode is one of VIDEO_BUFFER_MODE_*.
+            // Returns OK if the specified video buffer mode is supported. If videoBufferMode is
+            // VIDEO_BUFFER_MODE_BUFFER_QUEUE, setVideoTarget() must be called before starting
+            // video recording.
+            status_t    setVideoBufferMode(int32_t videoBufferMode);
+
+            // Set the video buffer producer for camera to use in VIDEO_BUFFER_MODE_BUFFER_QUEUE
+            // mode.
+            status_t    setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer);
 
             void        setListener(const sp<CameraListener>& listener);
             void        setRecordingProxyListener(const sp<ICameraRecordingProxyListener>& listener);
diff --git a/include/camera/CameraBase.h b/include/camera/CameraBase.h
index 1b93157..d8561ed 100644
--- a/include/camera/CameraBase.h
+++ b/include/camera/CameraBase.h
@@ -61,7 +61,7 @@
 
     static sp<TCam>      connect(int cameraId,
                                  const String16& clientPackageName,
-                                 int clientUid);
+                                 int clientUid, int clientPid);
     virtual void         disconnect();
 
     void                 setListener(const sp<TCamListener>& listener);
diff --git a/include/camera/CameraUtils.h b/include/camera/CameraUtils.h
index c06f05d..f596f80 100644
--- a/include/camera/CameraUtils.h
+++ b/include/camera/CameraUtils.h
@@ -17,8 +17,10 @@
 #ifndef ANDROID_CAMERA_CLIENT_CAMERAUTILS_H
 #define ANDROID_CAMERA_CLIENT_CAMERAUTILS_H
 
+#include <binder/IMemory.h>
 #include <camera/CameraMetadata.h>
 #include <utils/Errors.h>
+#include <utils/RefBase.h>
 
 #include <stdint.h>
 
@@ -39,6 +41,12 @@
          */
         static status_t getRotationTransform(const CameraMetadata& staticInfo,
                 /*out*/int32_t* transform);
+
+        /**
+         * Check if the image data is VideoNativeHandleMetadata, that contains a native handle.
+         */
+        static bool isNativeHandleMetadata(const sp<IMemory>& imageData);
+
     private:
         CameraUtils();
 };
diff --git a/include/camera/ICamera.h b/include/camera/ICamera.h
index b025735..e35c3a4 100644
--- a/include/camera/ICamera.h
+++ b/include/camera/ICamera.h
@@ -36,6 +36,15 @@
      * Keep up-to-date with ICamera.aidl in frameworks/base
      */
 public:
+    enum {
+        // Pass real YUV data in video buffers through ICameraClient.dataCallbackTimestamp().
+        VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV = 0,
+        // Pass metadata in video buffers through ICameraClient.dataCallbackTimestamp().
+        VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA = 1,
+        // Pass video buffers through IGraphicBufferProducer set with setVideoTarget().
+        VIDEO_BUFFER_MODE_BUFFER_QUEUE = 2,
+    };
+
     DECLARE_META_INTERFACE(Camera);
 
     virtual void            disconnect() = 0;
@@ -109,8 +118,16 @@
     // send command to camera driver
     virtual status_t        sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) = 0;
 
-    // tell the camera hal to store meta data or real YUV data in video buffers.
-    virtual status_t        storeMetaDataInBuffers(bool enabled) = 0;
+
+    // Tell camera how to pass video buffers. videoBufferMode is one of VIDEO_BUFFER_MODE_*.
+    // Returns OK if the specified video buffer mode is supported. If videoBufferMode is
+    // VIDEO_BUFFER_MODE_BUFFER_QUEUE, setVideoTarget() must be called before starting video
+    // recording.
+    virtual status_t        setVideoBufferMode(int32_t videoBufferMode) = 0;
+
+    // Set the video buffer producer for camera to use in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
+    virtual status_t        setVideoTarget(
+            const sp<IGraphicBufferProducer>& bufferProducer) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index 1b68b5f..d568b4d 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -55,6 +55,10 @@
     };
 
     enum {
+        USE_CALLING_PID = -1
+    };
+
+    enum {
         USE_CALLING_UID = -1
     };
 
@@ -113,14 +117,17 @@
     virtual status_t removeListener(const sp<ICameraServiceListener>& listener)
                                                                             = 0;
     /**
-     * clientPackageName and clientUid are used for permissions checking.  if
-     * clientUid == USE_CALLING_UID, then the calling UID is used instead. Only
-     * trusted callers can set a clientUid other than USE_CALLING_UID.
+     * clientPackageName, clientUid, and clientPid are used for permissions checking. If
+     * clientUid == USE_CALLING_UID, then the calling UID is used instead. If
+     * clientPid == USE_CALLING_PID, then the calling PID is used instead. Only
+     * trusted callers can set a clientUid and clientPid other than USE_CALLING_UID and
+     * USE_CALLING_UID respectively.
      */
     virtual status_t connect(const sp<ICameraClient>& cameraClient,
             int cameraId,
             const String16& clientPackageName,
             int clientUid,
+            int clientPid,
             /*out*/
             sp<ICamera>& device) = 0;
 
diff --git a/include/camera/camera2/CaptureRequest.h b/include/camera/camera2/CaptureRequest.h
index eeab217..1dd15c4 100644
--- a/include/camera/camera2/CaptureRequest.h
+++ b/include/camera/camera2/CaptureRequest.h
@@ -25,7 +25,7 @@
 
 class Surface;
 
-struct CaptureRequest : public virtual RefBase {
+struct CaptureRequest : public RefBase {
 public:
 
     CameraMetadata          mMetadata;
diff --git a/include/camera/camera2/OutputConfiguration.h b/include/camera/camera2/OutputConfiguration.h
index 5bcbe15..137d98c 100644
--- a/include/camera/camera2/OutputConfiguration.h
+++ b/include/camera/camera2/OutputConfiguration.h
@@ -17,19 +17,20 @@
 #ifndef ANDROID_HARDWARE_CAMERA2_OUTPUTCONFIGURATION_H
 #define ANDROID_HARDWARE_CAMERA2_OUTPUTCONFIGURATION_H
 
-#include <utils/RefBase.h>
 #include <gui/IGraphicBufferProducer.h>
 
 namespace android {
 
 class Surface;
 
-class OutputConfiguration : public virtual RefBase {
+class OutputConfiguration {
 public:
 
     static const int INVALID_ROTATION;
+    static const int INVALID_SET_ID;
     sp<IGraphicBufferProducer> getGraphicBufferProducer() const;
     int                        getRotation() const;
+    int                        getSurfaceSetID() const;
 
     /**
      * Keep impl up-to-date with OutputConfiguration.java in frameworks/base
@@ -39,12 +40,29 @@
     // getRotation will be INVALID_ROTATION if error occurred
     OutputConfiguration(const Parcel& parcel);
 
-    OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation);
+    OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation,
+            int surfaceSetID = INVALID_SET_ID);
+
+    bool operator == (const OutputConfiguration& other) const {
+        return (mGbp == other.mGbp &&
+                mRotation == other.mRotation);
+    }
+    bool operator != (const OutputConfiguration& other) const {
+        return !(*this == other);
+    }
+    bool operator < (const OutputConfiguration& other) const {
+        if (*this == other) return false;
+        if (mGbp != other.mGbp) return mGbp < other.mGbp;
+        return mRotation < other.mRotation;
+    }
+    bool operator > (const OutputConfiguration& other) const {
+        return (*this != other && !(*this < other));
+    }
 
 private:
     sp<IGraphicBufferProducer> mGbp;
     int                        mRotation;
-
+    int                        mSurfaceSetID;
     // helper function
     static String16 readMaybeEmptyString16(const Parcel& parcel);
 };
diff --git a/include/camera/ndk/NdkCameraCaptureSession.h b/include/camera/ndk/NdkCameraCaptureSession.h
new file mode 100644
index 0000000..5d5cae2
--- /dev/null
+++ b/include/camera/ndk/NdkCameraCaptureSession.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 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.
+ */
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+#include "NdkCameraError.h"
+#include "NdkCameraMetadata.h"
+
+#ifndef _NDK_CAMERA_CAPTURE_SESSION_H
+#define _NDK_CAMERA_CAPTURE_SESSION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ACameraCaptureSession ACameraCaptureSession;
+
+typedef void (*ACameraCaptureSession_stateCallback)(void* context, ACameraCaptureSession *session);
+
+typedef struct ACameraCaptureSession_stateCallbacks {
+    void*                               context;
+    ACameraCaptureSession_stateCallback onClosed; // session is unusable after this callback
+    ACameraCaptureSession_stateCallback onReady;
+    ACameraCaptureSession_stateCallback onActive;
+} ACameraCaptureSession_stateCallbacks;
+
+enum {
+    CAPTURE_FAILURE_REASON_FLUSHED = 0,
+    CAPTURE_FAILURE_REASON_ERROR
+};
+
+typedef struct ACameraCaptureFailure {
+    int64_t frameNumber;
+    int     reason;
+    int     sequenceId;
+    bool    wasImageCaptured;
+} ACameraCaptureFailure;
+
+/* Note that the ACaptureRequest* in the callback will be different to what app has submitted,
+   but the contents will still be the same as what app submitted */
+typedef void (*ACameraCaptureSession_captureCallback_start)(
+        void* context, ACameraCaptureSession* session,
+        const ACaptureRequest* request, int64_t timestamp);
+
+typedef void (*ACameraCaptureSession_captureCallback_result)(
+        void* context, ACameraCaptureSession* session,
+        ACaptureRequest* request, const ACameraMetadata* result);
+
+typedef void (*ACameraCaptureSession_captureCallback_failed)(
+        void* context, ACameraCaptureSession* session,
+        ACaptureRequest* request, ACameraCaptureFailure* failure);
+
+typedef void (*ACameraCaptureSession_captureCallback_sequenceEnd)(
+        void* context, ACameraCaptureSession* session,
+        int sequenceId, int64_t frameNumber);
+
+typedef void (*ACameraCaptureSession_captureCallback_sequenceAbort)(
+        void* context, ACameraCaptureSession* session,
+        int sequenceId);
+
+typedef struct ACameraCaptureSession_captureCallbacks {
+    void*                                             context;
+    ACameraCaptureSession_captureCallback_start         onCaptureStarted;
+    ACameraCaptureSession_captureCallback_result        onCaptureProgressed;
+    ACameraCaptureSession_captureCallback_result        onCaptureCompleted;
+    ACameraCaptureSession_captureCallback_failed        onCaptureFailed;
+    ACameraCaptureSession_captureCallback_sequenceEnd   onCaptureSequenceCompleted;
+    ACameraCaptureSession_captureCallback_sequenceAbort onCaptureSequenceAborted;
+} ACameraCaptureSession_captureCallbacks;
+
+enum {
+    CAPTURE_SEQUENCE_ID_NONE = -1
+};
+
+/*
+ * Close capture session
+ */
+void ACameraCaptureSession_close(ACameraCaptureSession*);
+
+struct ACameraDevice;
+typedef struct ACameraDevice ACameraDevice;
+
+/**
+ * Get the camera device associated with this capture session
+ */
+camera_status_t ACameraCaptureSession_getDevice(
+        ACameraCaptureSession*, ACameraDevice** device);
+
+/**
+ * Send capture request(s)
+ */
+camera_status_t ACameraCaptureSession_capture(
+        ACameraCaptureSession*, /*optional*/ACameraCaptureSession_captureCallbacks*,
+        int numRequests, ACaptureRequest** requests,
+        /*optional*/int* captureSequenceId);
+
+/**
+ * Send repeating capture request(s)
+ */
+camera_status_t ACameraCaptureSession_setRepeatingRequest(
+        ACameraCaptureSession*, /*optional*/ACameraCaptureSession_captureCallbacks*,
+        int numRequests, ACaptureRequest** requests,
+        /*optional*/int* captureSequenceId);
+
+/**
+ * Stop repeating capture request(s)
+ */
+camera_status_t ACameraCaptureSession_stopRepeating(ACameraCaptureSession*);
+
+/**
+ * Stop all capture requests as soon as possible
+ */
+camera_status_t ACameraCaptureSession_abortCaptures(ACameraCaptureSession*);
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _NDK_CAMERA_CAPTURE_SESSION_H
diff --git a/include/camera/ndk/NdkCameraDevice.h b/include/camera/ndk/NdkCameraDevice.h
new file mode 100644
index 0000000..2008a68
--- /dev/null
+++ b/include/camera/ndk/NdkCameraDevice.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 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.
+ */
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#include <android/native_window.h>
+#include "NdkCameraError.h"
+#include "NdkCaptureRequest.h"
+#include "NdkCameraCaptureSession.h"
+
+#ifndef _NDK_CAMERA_DEVICE_H
+#define _NDK_CAMERA_DEVICE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ACameraDevice ACameraDevice;
+
+// Struct to hold camera state callbacks
+typedef void (*ACameraDevice_StateCallback)(void* context, ACameraDevice* device);
+typedef void (*ACameraDevice_ErrorStateCallback)(void* context, ACameraDevice* device, int error);
+
+typedef struct ACameraDevice_StateCallbacks {
+    void*                             context;
+    ACameraDevice_StateCallback       onDisconnected; // Device is unusable after this callback
+    ACameraDevice_ErrorStateCallback  onError;        // Device is unusable after this callback
+} ACameraDevice_stateCallbacks;
+
+/**
+ * Close the camera device synchronously. Open is done in ACameraManager_openCamera
+ */
+camera_status_t ACameraDevice_close(ACameraDevice*);
+
+/**
+ * Return the camera id associated with this camera device
+ * The returned pointer is still owned by framework and should not be delete/free by app
+ * The returned pointer should not be used after the device has been closed
+ */
+const char* ACameraDevice_getId(const ACameraDevice*);
+
+typedef enum {
+    TEMPLATE_PREVIEW = 1,
+    TEMPLATE_STILL_CAPTURE,
+    TEMPLATE_RECORD,
+    TEMPLATE_VIDEO_SNAPSHOT,
+    TEMPLATE_ZERO_SHUTTER_LAG,
+    TEMPLATE_MANUAL,
+} ACameraDevice_request_template;
+
+/**
+ * Create/free a default capture request for input template
+ */
+camera_status_t ACameraDevice_createCaptureRequest(
+        const ACameraDevice*, ACameraDevice_request_template, /*out*/ACaptureRequest** request);
+
+/**
+ * APIs for createing capture session
+ */
+typedef struct ACaptureSessionOutputContainer ACaptureSessionOutputContainer;
+
+typedef struct ACaptureSessionOutput ACaptureSessionOutput;
+
+camera_status_t ACaptureSessionOutputContainer_create(/*out*/ACaptureSessionOutputContainer**);
+void            ACaptureSessionOutputContainer_free(ACaptureSessionOutputContainer*);
+
+camera_status_t ACaptureSessionOutput_create(ANativeWindow*, /*out*/ACaptureSessionOutput**);
+void            ACaptureSessionOutput_free(ACaptureSessionOutput*);
+
+camera_status_t ACaptureSessionOutputContainer_add(
+        ACaptureSessionOutputContainer*, const ACaptureSessionOutput*);
+camera_status_t ACaptureSessionOutputContainer_remove(
+        ACaptureSessionOutputContainer*, const ACaptureSessionOutput*);
+
+/*
+ * Create a new capture session.
+ * If there is a preexisting session, the previous session will be closed automatically.
+ * However, app still needs to call ACameraCaptureSession_close on previous session.
+ * Otherwise the resources hold by previous session won't be freed
+ */
+camera_status_t ACameraDevice_createCaptureSession(
+        ACameraDevice*,
+        const ACaptureSessionOutputContainer*       outputs,
+        const ACameraCaptureSession_stateCallbacks* callbacks,
+        /*out*/ACameraCaptureSession** session);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _NDK_CAMERA_DEVICE_H
diff --git a/include/camera/ndk/NdkCameraError.h b/include/camera/ndk/NdkCameraError.h
new file mode 100644
index 0000000..6d671de
--- /dev/null
+++ b/include/camera/ndk/NdkCameraError.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 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.
+ */
+
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_CAMERA_ERROR_H
+#define _NDK_CAMERA_ERROR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    ACAMERA_OK = 0,
+
+    ACAMERA_ERROR_BASE                  = -10000,
+    ACAMERA_ERROR_UNKNOWN               = ACAMERA_ERROR_BASE,
+    ACAMERA_ERROR_UNSUPPORTED           = ACAMERA_ERROR_BASE - 1,
+    ACAMERA_ERROR_INVALID_PARAMETER     = ACAMERA_ERROR_BASE - 2,
+    ACAMERA_ERROR_CAMERA_DISCONNECTED   = ACAMERA_ERROR_BASE - 3,
+    ACAMERA_ERROR_NOT_ENOUGH_MEMORY     = ACAMERA_ERROR_BASE - 4,
+    ACAMERA_ERROR_METADATA_NOT_FOUND    = ACAMERA_ERROR_BASE - 5,
+    ACAMERA_ERROR_CAMERA_DEVICE         = ACAMERA_ERROR_BASE - 6,
+    ACAMERA_ERROR_CAMERA_SERVICE        = ACAMERA_ERROR_BASE - 7,
+    ACAMERA_ERROR_CAMERA_REQUEST        = ACAMERA_ERROR_BASE - 8,
+    ACAMERA_ERROR_CAMERA_RESULT         = ACAMERA_ERROR_BASE - 9,
+    ACAMERA_ERROR_CAMERA_BUFFER         = ACAMERA_ERROR_BASE - 10,
+    ACAMERA_ERROR_SESSION_CLOSED        = ACAMERA_ERROR_BASE - 11,
+    ACAMERA_ERROR_SESSION_NOT_DRAINED   = ACAMERA_ERROR_BASE - 12,
+    ACAMERA_ERROR_INVALID_OPERATION     = ACAMERA_ERROR_BASE - 13,
+    ACAMERA_ERROR_TIMEOUT               = ACAMERA_ERROR_BASE - 14,
+    ACAMERA_ERROR_STREAM_CONFIGURE_FAIL = ACAMERA_ERROR_BASE - 15,
+} camera_status_t;
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _NDK_CAMERA_ERROR_H
diff --git a/include/camera/ndk/NdkCameraManager.h b/include/camera/ndk/NdkCameraManager.h
new file mode 100644
index 0000000..adef6ed
--- /dev/null
+++ b/include/camera/ndk/NdkCameraManager.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 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.
+ */
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_CAMERA_MANAGER_H
+#define _NDK_CAMERA_MANAGER_H
+
+#include "NdkCameraError.h"
+#include "NdkCameraMetadata.h"
+#include "NdkCameraDevice.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ACameraManager ACameraManager;
+
+/**
+ * Create CameraManager instance.
+ * The caller must call ACameraManager_delete to free the resources
+ */
+ACameraManager* ACameraManager_create();
+
+/**
+ * delete the ACameraManager and free its resources
+ */
+void ACameraManager_delete(ACameraManager*);
+
+// Struct to hold list of camera devices
+typedef struct ACameraIdList {
+    int numCameras;
+    const char** cameraIds;
+} ACameraIdList;
+
+/**
+ * Create/delete a list of camera devices.
+ * ACameraManager_getCameraIdList will allocate and return an ACameraIdList.
+ * The caller must call ACameraManager_deleteCameraIdList to free the memory
+ */
+camera_status_t ACameraManager_getCameraIdList(ACameraManager*,
+                                              /*out*/ACameraIdList** cameraIdList);
+void ACameraManager_deleteCameraIdList(ACameraIdList* cameraIdList);
+
+
+// Struct to hold camera availability callbacks
+typedef void (*ACameraManager_AvailabilityCallback)(void* context, const char* cameraId);
+
+typedef struct ACameraManager_AvailabilityListener {
+    void*                               context; // optional application context.
+    ACameraManager_AvailabilityCallback onCameraAvailable;
+    ACameraManager_AvailabilityCallback onCameraUnavailable;
+} ACameraManager_AvailabilityCallbacks;
+
+/**
+ * register/unregister camera availability callbacks
+ */
+camera_status_t ACameraManager_registerAvailabilityCallback(
+        ACameraManager*, const ACameraManager_AvailabilityCallbacks *callback);
+camera_status_t ACameraManager_unregisterAvailabilityCallback(
+        ACameraManager*, const ACameraManager_AvailabilityCallbacks *callback);
+
+/**
+ * Query the characteristics of a camera.
+ * The caller must call ACameraMetadata_free to free the memory of the output characteristics.
+ */
+camera_status_t ACameraManager_getCameraCharacteristics(
+        ACameraManager*, const char *cameraId,
+        /*out*/ACameraMetadata **characteristics);
+
+/**
+ * Open a camera device synchronously.
+ * The opened camera device will be returned in
+ */
+camera_status_t ACameraManager_openCamera(
+        ACameraManager*, const char* cameraId,
+        ACameraDevice_StateCallbacks* callback,
+        /*out*/ACameraDevice** device);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif //_NDK_CAMERA_MANAGER_H
diff --git a/include/camera/ndk/NdkCameraMetadata.h b/include/camera/ndk/NdkCameraMetadata.h
new file mode 100644
index 0000000..56412ad
--- /dev/null
+++ b/include/camera/ndk/NdkCameraMetadata.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 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.
+ */
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_CAMERA_METADATA_H
+#define _NDK_CAMERA_METADATA_H
+
+#include "NdkCameraError.h"
+#include "NdkCameraMetadataTags.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ACameraMetadata ACameraMetadata;
+
+// Keep in sync with system/media/include/system/camera_metadata.h
+enum {
+    // Unsigned 8-bit integer (uint8_t)
+    ACAMERA_TYPE_BYTE = 0,
+    // Signed 32-bit integer (int32_t)
+    ACAMERA_TYPE_INT32 = 1,
+    // 32-bit float (float)
+    ACAMERA_TYPE_FLOAT = 2,
+    // Signed 64-bit integer (int64_t)
+    ACAMERA_TYPE_INT64 = 3,
+    // 64-bit float (double)
+    ACAMERA_TYPE_DOUBLE = 4,
+    // A 64-bit fraction (ACameraMetadata_rational)
+    ACAMERA_TYPE_RATIONAL = 5,
+    // Number of type fields
+    ACAMERA_NUM_TYPES
+};
+
+typedef struct ACameraMetadata_rational {
+    int32_t numerator;
+    int32_t denominator;
+} ACameraMetadata_rational;
+
+typedef struct ACameraMetadata_entry {
+    uint32_t tag;
+    uint8_t  type;
+    uint32_t count;
+    union {
+        uint8_t *u8;
+        int32_t *i32;
+        float   *f;
+        int64_t *i64;
+        double  *d;
+        ACameraMetadata_rational* r;
+    } data;
+} ACameraMetadata_entry;
+
+typedef struct ACameraMetadata_const_entry {
+    uint32_t tag;
+    uint8_t  type;
+    uint32_t count;
+    union {
+        const uint8_t *u8;
+        const int32_t *i32;
+        const float   *f;
+        const int64_t *i64;
+        const double  *d;
+        const ACameraMetadata_rational* r;
+    } data;
+} ACameraMetadata_const_entry;
+
+/*
+ * Get a metadata entry
+ */
+camera_status_t ACameraMetadata_getConstEntry(
+        const ACameraMetadata*, uint32_t tag, ACameraMetadata_const_entry* entry);
+
+// TODO: need an API to list all tags in the metadata. Same for ACaptureRequest
+
+/**
+ * Copy a metadata. Duplicates a metadata structure.
+ * The destination ACameraMetadata must be freed by the application with ACameraMetadata_free
+ * after application is done using it.
+ * Returns NULL when src cannot be copied
+ */
+ACameraMetadata* ACameraMetadata_copy(const ACameraMetadata* src);
+
+/**
+ * Frees a metadata structure.
+ */
+void ACameraMetadata_free(ACameraMetadata*);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif //_NDK_CAMERA_METADATA_H
diff --git a/include/camera/ndk/NdkCameraMetadataTags.h b/include/camera/ndk/NdkCameraMetadataTags.h
new file mode 100644
index 0000000..0c398be
--- /dev/null
+++ b/include/camera/ndk/NdkCameraMetadataTags.h
@@ -0,0 +1,877 @@
+/*
+ * Copyright (C) 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.
+ */
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_CAMERA_METADATA_TAGS_H
+#define _NDK_CAMERA_METADATA_TAGS_H
+
+typedef enum acamera_metadata_section {
+    ACAMERA_COLOR_CORRECTION,
+    ACAMERA_CONTROL,
+    ACAMERA_DEMOSAIC,
+    ACAMERA_EDGE,
+    ACAMERA_FLASH,
+    ACAMERA_FLASH_INFO,
+    ACAMERA_HOT_PIXEL,
+    ACAMERA_JPEG,
+    ACAMERA_LENS,
+    ACAMERA_LENS_INFO,
+    ACAMERA_NOISE_REDUCTION,
+    ACAMERA_QUIRKS,
+    ACAMERA_REQUEST,
+    ACAMERA_SCALER,
+    ACAMERA_SENSOR,
+    ACAMERA_SENSOR_INFO,
+    ACAMERA_SHADING,
+    ACAMERA_STATISTICS,
+    ACAMERA_STATISTICS_INFO,
+    ACAMERA_TONEMAP,
+    ACAMERA_LED,
+    ACAMERA_INFO,
+    ACAMERA_BLACK_LEVEL,
+    ACAMERA_SYNC,
+    ACAMERA_REPROCESS,
+    ACAMERA_DEPTH,
+    ACAMERA_SECTION_COUNT,
+
+    ACAMERA_VENDOR = 0x8000
+} acamera_metadata_section_t;
+
+/**
+ * Hierarchy positions in enum space.
+ */
+typedef enum acamera_metadata_section_start {
+    ACAMERA_COLOR_CORRECTION_START = ACAMERA_COLOR_CORRECTION  << 16,
+    ACAMERA_CONTROL_START          = ACAMERA_CONTROL           << 16,
+    ACAMERA_DEMOSAIC_START         = ACAMERA_DEMOSAIC          << 16,
+    ACAMERA_EDGE_START             = ACAMERA_EDGE              << 16,
+    ACAMERA_FLASH_START            = ACAMERA_FLASH             << 16,
+    ACAMERA_FLASH_INFO_START       = ACAMERA_FLASH_INFO        << 16,
+    ACAMERA_HOT_PIXEL_START        = ACAMERA_HOT_PIXEL         << 16,
+    ACAMERA_JPEG_START             = ACAMERA_JPEG              << 16,
+    ACAMERA_LENS_START             = ACAMERA_LENS              << 16,
+    ACAMERA_LENS_INFO_START        = ACAMERA_LENS_INFO         << 16,
+    ACAMERA_NOISE_REDUCTION_START  = ACAMERA_NOISE_REDUCTION   << 16,
+    ACAMERA_QUIRKS_START           = ACAMERA_QUIRKS            << 16,
+    ACAMERA_REQUEST_START          = ACAMERA_REQUEST           << 16,
+    ACAMERA_SCALER_START           = ACAMERA_SCALER            << 16,
+    ACAMERA_SENSOR_START           = ACAMERA_SENSOR            << 16,
+    ACAMERA_SENSOR_INFO_START      = ACAMERA_SENSOR_INFO       << 16,
+    ACAMERA_SHADING_START          = ACAMERA_SHADING           << 16,
+    ACAMERA_STATISTICS_START       = ACAMERA_STATISTICS        << 16,
+    ACAMERA_STATISTICS_INFO_START  = ACAMERA_STATISTICS_INFO   << 16,
+    ACAMERA_TONEMAP_START          = ACAMERA_TONEMAP           << 16,
+    ACAMERA_LED_START              = ACAMERA_LED               << 16,
+    ACAMERA_INFO_START             = ACAMERA_INFO              << 16,
+    ACAMERA_BLACK_LEVEL_START      = ACAMERA_BLACK_LEVEL       << 16,
+    ACAMERA_SYNC_START             = ACAMERA_SYNC              << 16,
+    ACAMERA_REPROCESS_START        = ACAMERA_REPROCESS         << 16,
+    ACAMERA_DEPTH_START            = ACAMERA_DEPTH             << 16,
+    ACAMERA_VENDOR_START           = ACAMERA_VENDOR            << 16
+} acamera_metadata_section_start_t;
+
+/**
+ * Main enum for camera metadata tags.
+ */
+typedef enum acamera_metadata_tag {
+    ACAMERA_COLOR_CORRECTION_MODE =                             // byte (enum)
+            ACAMERA_COLOR_CORRECTION_START,
+    ACAMERA_COLOR_CORRECTION_TRANSFORM,                         // rational[3*3]
+    ACAMERA_COLOR_CORRECTION_GAINS,                             // float[4]
+    ACAMERA_COLOR_CORRECTION_ABERRATION_MODE,                   // byte (enum)
+    ACAMERA_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,        // byte[n]
+    ACAMERA_COLOR_CORRECTION_END,
+
+    ACAMERA_CONTROL_AE_ANTIBANDING_MODE =                       // byte (enum)
+            ACAMERA_CONTROL_START,
+    ACAMERA_CONTROL_AE_EXPOSURE_COMPENSATION,                   // int32
+    ACAMERA_CONTROL_AE_LOCK,                                    // byte (enum)
+    ACAMERA_CONTROL_AE_MODE,                                    // byte (enum)
+    ACAMERA_CONTROL_AE_REGIONS,                                 // int32[5*area_count]
+    ACAMERA_CONTROL_AE_TARGET_FPS_RANGE,                        // int32[2]
+    ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER,                      // byte (enum)
+    ACAMERA_CONTROL_AF_MODE,                                    // byte (enum)
+    ACAMERA_CONTROL_AF_REGIONS,                                 // int32[5*area_count]
+    ACAMERA_CONTROL_AF_TRIGGER,                                 // byte (enum)
+    ACAMERA_CONTROL_AWB_LOCK,                                   // byte (enum)
+    ACAMERA_CONTROL_AWB_MODE,                                   // byte (enum)
+    ACAMERA_CONTROL_AWB_REGIONS,                                // int32[5*area_count]
+    ACAMERA_CONTROL_CAPTURE_INTENT,                             // byte (enum)
+    ACAMERA_CONTROL_EFFECT_MODE,                                // byte (enum)
+    ACAMERA_CONTROL_MODE,                                       // byte (enum)
+    ACAMERA_CONTROL_SCENE_MODE,                                 // byte (enum)
+    ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE,                   // byte (enum)
+    ACAMERA_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,             // byte[n]
+    ACAMERA_CONTROL_AE_AVAILABLE_MODES,                         // byte[n]
+    ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,             // int32[2*n]
+    ACAMERA_CONTROL_AE_COMPENSATION_RANGE,                      // int32[2]
+    ACAMERA_CONTROL_AE_COMPENSATION_STEP,                       // rational
+    ACAMERA_CONTROL_AF_AVAILABLE_MODES,                         // byte[n]
+    ACAMERA_CONTROL_AVAILABLE_EFFECTS,                          // byte[n]
+    ACAMERA_CONTROL_AVAILABLE_SCENE_MODES,                      // byte[n]
+    ACAMERA_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,        // byte[n]
+    ACAMERA_CONTROL_AWB_AVAILABLE_MODES,                        // byte[n]
+    ACAMERA_CONTROL_MAX_REGIONS,                                // int32[3]
+    ACAMERA_CONTROL_RESERVED_29,
+    ACAMERA_CONTROL_RESERVED_30,
+    ACAMERA_CONTROL_AE_STATE,                                   // byte (enum)
+    ACAMERA_CONTROL_AF_STATE,                                   // byte (enum)
+    ACAMERA_CONTROL_RESERVED_33,
+    ACAMERA_CONTROL_AWB_STATE,                                  // byte (enum)
+    ACAMERA_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS,  // int32[5*n]
+    ACAMERA_CONTROL_AE_LOCK_AVAILABLE,                          // byte (enum)
+    ACAMERA_CONTROL_AWB_LOCK_AVAILABLE,                         // byte (enum)
+    ACAMERA_CONTROL_AVAILABLE_MODES,                            // byte[n]
+    ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE,           // int32[2]
+    ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST,                 // int32
+    ACAMERA_CONTROL_END,
+
+    ACAMERA_DEMOSAIC_RESERVED_0 =
+            ACAMERA_DEMOSAIC_START,
+    ACAMERA_DEMOSAIC_END,
+
+    ACAMERA_EDGE_MODE =                                         // byte (enum)
+            ACAMERA_EDGE_START,
+    ACAMERA_EDGE_RESERVED_1,
+    ACAMERA_EDGE_AVAILABLE_EDGE_MODES,                          // byte[n]
+    ACAMERA_EDGE_END,
+
+    ACAMERA_FLASH_RESERVED_0 =
+            ACAMERA_FLASH_START,
+    ACAMERA_FLASH_RESERVED_1,
+    ACAMERA_FLASH_MODE,                                         // byte (enum)
+    ACAMERA_FLASH_RESERVED_3,
+    ACAMERA_FLASH_RESERVED_4,
+    ACAMERA_FLASH_STATE,                                        // byte (enum)
+    ACAMERA_FLASH_END,
+
+    ACAMERA_FLASH_INFO_AVAILABLE =                              // byte (enum)
+            ACAMERA_FLASH_INFO_START,
+    ACAMERA_FLASH_INFO_RESERVED_1,
+    ACAMERA_FLASH_INFO_END,
+
+    ACAMERA_HOT_PIXEL_MODE =                                    // byte (enum)
+            ACAMERA_HOT_PIXEL_START,
+    ACAMERA_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES,                // byte[n]
+    ACAMERA_HOT_PIXEL_END,
+
+    ACAMERA_JPEG_GPS_COORDINATES =                              // double[3]
+            ACAMERA_JPEG_START,
+    ACAMERA_JPEG_GPS_PROCESSING_METHOD,                         // byte
+    ACAMERA_JPEG_GPS_TIMESTAMP,                                 // int64
+    ACAMERA_JPEG_ORIENTATION,                                   // int32
+    ACAMERA_JPEG_QUALITY,                                       // byte
+    ACAMERA_JPEG_THUMBNAIL_QUALITY,                             // byte
+    ACAMERA_JPEG_THUMBNAIL_SIZE,                                // int32[2]
+    ACAMERA_JPEG_AVAILABLE_THUMBNAIL_SIZES,                     // int32[2*n]
+    ACAMERA_JPEG_RESERVED_8,
+    ACAMERA_JPEG_RESERVED_9,
+    ACAMERA_JPEG_END,
+
+    ACAMERA_LENS_APERTURE =                                     // float
+            ACAMERA_LENS_START,
+    ACAMERA_LENS_FILTER_DENSITY,                                // float
+    ACAMERA_LENS_FOCAL_LENGTH,                                  // float
+    ACAMERA_LENS_FOCUS_DISTANCE,                                // float
+    ACAMERA_LENS_OPTICAL_STABILIZATION_MODE,                    // byte (enum)
+    ACAMERA_LENS_FACING,                                        // byte (enum)
+    ACAMERA_LENS_POSE_ROTATION,                                 // float[4]
+    ACAMERA_LENS_POSE_TRANSLATION,                              // float[3]
+    ACAMERA_LENS_FOCUS_RANGE,                                   // float[2]
+    ACAMERA_LENS_STATE,                                         // byte (enum)
+    ACAMERA_LENS_INTRINSIC_CALIBRATION,                         // float[5]
+    ACAMERA_LENS_RADIAL_DISTORTION,                             // float[6]
+    ACAMERA_LENS_END,
+
+    ACAMERA_LENS_INFO_AVAILABLE_APERTURES =                     // float[n]
+            ACAMERA_LENS_INFO_START,
+    ACAMERA_LENS_INFO_AVAILABLE_FILTER_DENSITIES,               // float[n]
+    ACAMERA_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,                  // float[n]
+    ACAMERA_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,          // byte[n]
+    ACAMERA_LENS_INFO_HYPERFOCAL_DISTANCE,                      // float
+    ACAMERA_LENS_INFO_MINIMUM_FOCUS_DISTANCE,                   // float
+    ACAMERA_LENS_INFO_SHADING_MAP_SIZE,                         // int32[2]
+    ACAMERA_LENS_INFO_FOCUS_DISTANCE_CALIBRATION,               // byte (enum)
+    ACAMERA_LENS_INFO_END,
+
+    ACAMERA_NOISE_REDUCTION_MODE =                              // byte (enum)
+            ACAMERA_NOISE_REDUCTION_START,
+    ACAMERA_NOISE_REDUCTION_RESERVED_1,
+    ACAMERA_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,    // byte[n]
+    ACAMERA_NOISE_REDUCTION_END,
+
+    ACAMERA_QUIRKS_RESERVED_0 =
+            ACAMERA_QUIRKS_START,
+    ACAMERA_QUIRKS_RESERVED_1,
+    ACAMERA_QUIRKS_RESERVED_2,
+    ACAMERA_QUIRKS_USE_PARTIAL_RESULT,                          // Deprecated! DO NOT USE
+    ACAMERA_QUIRKS_PARTIAL_RESULT,                              // Deprecated! DO NOT USE
+    ACAMERA_QUIRKS_END,
+
+    ACAMERA_REQUEST_FRAME_COUNT =                               // Deprecated! DO NOT USE
+            ACAMERA_REQUEST_START,
+    ACAMERA_REQUEST_ID,                                         // int32
+    ACAMERA_REQUEST_RESERVED_2,
+    ACAMERA_REQUEST_RESERVED_3,
+    ACAMERA_REQUEST_RESERVED_4,
+    ACAMERA_REQUEST_RESERVED_5,
+    ACAMERA_REQUEST_MAX_NUM_OUTPUT_STREAMS,                     // int32[3]
+    ACAMERA_REQUEST_RESERVED_7,
+    ACAMERA_REQUEST_MAX_NUM_INPUT_STREAMS,                      // int32
+    ACAMERA_REQUEST_PIPELINE_DEPTH,                             // byte
+    ACAMERA_REQUEST_PIPELINE_MAX_DEPTH,                         // byte
+    ACAMERA_REQUEST_PARTIAL_RESULT_COUNT,                       // int32
+    ACAMERA_REQUEST_AVAILABLE_CAPABILITIES,                     // byte[n] (enum)
+    ACAMERA_REQUEST_AVAILABLE_REQUEST_KEYS,                     // int32[n]
+    ACAMERA_REQUEST_AVAILABLE_RESULT_KEYS,                      // int32[n]
+    ACAMERA_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,             // int32[n]
+    ACAMERA_REQUEST_END,
+
+    ACAMERA_SCALER_CROP_REGION =                                // int32[4]
+            ACAMERA_SCALER_START,
+    ACAMERA_SCALER_AVAILABLE_FORMATS,                           // Deprecated! DO NOT USE
+    ACAMERA_SCALER_AVAILABLE_JPEG_MIN_DURATIONS,                // Deprecated! DO NOT USE
+    ACAMERA_SCALER_AVAILABLE_JPEG_SIZES,                        // Deprecated! DO NOT USE
+    ACAMERA_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,                  // float
+    ACAMERA_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS,           // Deprecated! DO NOT USE
+    ACAMERA_SCALER_AVAILABLE_PROCESSED_SIZES,                   // Deprecated! DO NOT USE
+    ACAMERA_SCALER_RESERVED_7,
+    ACAMERA_SCALER_RESERVED_8,
+    ACAMERA_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP,          // int32
+    ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,             // int32[n*4] (enum)
+    ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,               // int64[4*n]
+    ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS,                   // int64[4*n]
+    ACAMERA_SCALER_CROPPING_TYPE,                               // byte (enum)
+    ACAMERA_SCALER_END,
+
+    ACAMERA_SENSOR_EXPOSURE_TIME =                              // int64
+            ACAMERA_SENSOR_START,
+    ACAMERA_SENSOR_FRAME_DURATION,                              // int64
+    ACAMERA_SENSOR_SENSITIVITY,                                 // int32
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1,                       // byte (enum)
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT2,                       // byte
+    ACAMERA_SENSOR_CALIBRATION_TRANSFORM1,                      // rational[3*3]
+    ACAMERA_SENSOR_CALIBRATION_TRANSFORM2,                      // rational[3*3]
+    ACAMERA_SENSOR_COLOR_TRANSFORM1,                            // rational[3*3]
+    ACAMERA_SENSOR_COLOR_TRANSFORM2,                            // rational[3*3]
+    ACAMERA_SENSOR_FORWARD_MATRIX1,                             // rational[3*3]
+    ACAMERA_SENSOR_FORWARD_MATRIX2,                             // rational[3*3]
+    ACAMERA_SENSOR_RESERVED_11,
+    ACAMERA_SENSOR_BLACK_LEVEL_PATTERN,                         // int32[4]
+    ACAMERA_SENSOR_MAX_ANALOG_SENSITIVITY,                      // int32
+    ACAMERA_SENSOR_ORIENTATION,                                 // int32
+    ACAMERA_SENSOR_RESERVED_15,
+    ACAMERA_SENSOR_TIMESTAMP,                                   // int64
+    ACAMERA_SENSOR_RESERVED_17,
+    ACAMERA_SENSOR_NEUTRAL_COLOR_POINT,                         // rational[3]
+    ACAMERA_SENSOR_NOISE_PROFILE,                               // double[2*CFA Channels]
+    ACAMERA_SENSOR_RESERVED_20,
+    ACAMERA_SENSOR_RESERVED_21,
+    ACAMERA_SENSOR_GREEN_SPLIT,                                 // float
+    ACAMERA_SENSOR_TEST_PATTERN_DATA,                           // int32[4]
+    ACAMERA_SENSOR_TEST_PATTERN_MODE,                           // int32 (enum)
+    ACAMERA_SENSOR_AVAILABLE_TEST_PATTERN_MODES,                // int32[n]
+    ACAMERA_SENSOR_ROLLING_SHUTTER_SKEW,                        // int64
+    ACAMERA_SENSOR_OPTICAL_BLACK_REGIONS,                       // int32[4*num_regions]
+    ACAMERA_SENSOR_DYNAMIC_BLACK_LEVEL,                         // float[4]
+    ACAMERA_SENSOR_DYNAMIC_WHITE_LEVEL,                         // int32
+    ACAMERA_SENSOR_RESERVED_30,
+    ACAMERA_SENSOR_END,
+
+    ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE =                     // int32[4]
+            ACAMERA_SENSOR_INFO_START,
+    ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE,                      // int32[2]
+    ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,               // byte (enum)
+    ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE,                    // int64[2]
+    ACAMERA_SENSOR_INFO_MAX_FRAME_DURATION,                     // int64
+    ACAMERA_SENSOR_INFO_PHYSICAL_SIZE,                          // float[2]
+    ACAMERA_SENSOR_INFO_PIXEL_ARRAY_SIZE,                       // int32[2]
+    ACAMERA_SENSOR_INFO_WHITE_LEVEL,                            // int32
+    ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE,                       // byte (enum)
+    ACAMERA_SENSOR_INFO_LENS_SHADING_APPLIED,                   // byte (enum)
+    ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,       // int32[4]
+    ACAMERA_SENSOR_INFO_END,
+
+    ACAMERA_SHADING_MODE =                                      // byte (enum)
+            ACAMERA_SHADING_START,
+    ACAMERA_SHADING_RESERVED_1,
+    ACAMERA_SHADING_AVAILABLE_MODES,                            // byte[n]
+    ACAMERA_SHADING_END,
+
+    ACAMERA_STATISTICS_FACE_DETECT_MODE =                       // byte (enum)
+            ACAMERA_STATISTICS_START,
+    ACAMERA_STATISTICS_RESERVED_1,
+    ACAMERA_STATISTICS_RESERVED_2,
+    ACAMERA_STATISTICS_HOT_PIXEL_MAP_MODE,                      // byte (enum)
+    ACAMERA_STATISTICS_FACE_IDS,                                // int32[n]
+    ACAMERA_STATISTICS_FACE_LANDMARKS,                          // int32[n*6]
+    ACAMERA_STATISTICS_FACE_RECTANGLES,                         // int32[n*4]
+    ACAMERA_STATISTICS_FACE_SCORES,                             // byte[n]
+    ACAMERA_STATISTICS_RESERVED_8,
+    ACAMERA_STATISTICS_RESERVED_9,
+    ACAMERA_STATISTICS_LENS_SHADING_CORRECTION_MAP,             // byte
+    ACAMERA_STATISTICS_LENS_SHADING_MAP,                        // float[4*n*m]
+    ACAMERA_STATISTICS_PREDICTED_COLOR_GAINS,                   // Deprecated! DO NOT USE
+    ACAMERA_STATISTICS_PREDICTED_COLOR_TRANSFORM,               // Deprecated! DO NOT USE
+    ACAMERA_STATISTICS_SCENE_FLICKER,                           // byte (enum)
+    ACAMERA_STATISTICS_HOT_PIXEL_MAP,                           // int32[2*n]
+    ACAMERA_STATISTICS_LENS_SHADING_MAP_MODE,                   // byte (enum)
+    ACAMERA_STATISTICS_END,
+
+    ACAMERA_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES =       // byte[n]
+            ACAMERA_STATISTICS_INFO_START,
+    ACAMERA_STATISTICS_INFO_RESERVED_1,
+    ACAMERA_STATISTICS_INFO_MAX_FACE_COUNT,                     // int32
+    ACAMERA_STATISTICS_INFO_RESERVED_3,
+    ACAMERA_STATISTICS_INFO_RESERVED_4,
+    ACAMERA_STATISTICS_INFO_RESERVED_5,
+    ACAMERA_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,      // byte[n]
+    ACAMERA_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,   // byte[n]
+    ACAMERA_STATISTICS_INFO_END,
+
+    ACAMERA_TONEMAP_CURVE_BLUE =                                // float[n*2]
+            ACAMERA_TONEMAP_START,
+    ACAMERA_TONEMAP_CURVE_GREEN,                                // float[n*2]
+    ACAMERA_TONEMAP_CURVE_RED,                                  // float[n*2]
+    ACAMERA_TONEMAP_MODE,                                       // byte (enum)
+    ACAMERA_TONEMAP_MAX_CURVE_POINTS,                           // int32
+    ACAMERA_TONEMAP_AVAILABLE_TONE_MAP_MODES,                   // byte[n]
+    ACAMERA_TONEMAP_GAMMA,                                      // float
+    ACAMERA_TONEMAP_PRESET_CURVE,                               // byte (enum)
+    ACAMERA_TONEMAP_END,
+
+    ACAMERA_LED_TRANSMIT =                                      // byte (enum)
+            ACAMERA_LED_START,
+    ACAMERA_LED_AVAILABLE_LEDS,                                 // byte[n] (enum)
+    ACAMERA_LED_END,
+
+    ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL =                     // byte (enum)
+            ACAMERA_INFO_START,
+    ACAMERA_INFO_END,
+
+    ACAMERA_BLACK_LEVEL_LOCK =                                  // byte (enum)
+            ACAMERA_BLACK_LEVEL_START,
+    ACAMERA_BLACK_LEVEL_END,
+
+    ACAMERA_SYNC_FRAME_NUMBER =                                 // int64 (enum)
+            ACAMERA_SYNC_START,
+    ACAMERA_SYNC_MAX_LATENCY,                                   // int32 (enum)
+    ACAMERA_SYNC_END,
+
+    ACAMERA_REPROCESS_EFFECTIVE_EXPOSURE_FACTOR =               // float
+            ACAMERA_REPROCESS_START,
+    ACAMERA_REPROCESS_MAX_CAPTURE_STALL,                        // int32
+    ACAMERA_REPROCESS_END,
+
+    ACAMERA_DEPTH_RESERVED_0 =
+            ACAMERA_DEPTH_START,
+    ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS,        // int32[n*4] (enum)
+    ACAMERA_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS,          // int64[4*n]
+    ACAMERA_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS,              // int64[4*n]
+    ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE,                           // byte (enum)
+    ACAMERA_DEPTH_END,
+
+} acamera_metadata_tag_t;
+
+/**
+ * Enumeration definitions for the various entries that need them
+ */
+
+// ACAMERA_COLOR_CORRECTION_MODE
+typedef enum acamera_metadata_enum_acamera_color_correction_mode {
+    ACAMERA_COLOR_CORRECTION_MODE_TRANSFORM_MATRIX,
+    ACAMERA_COLOR_CORRECTION_MODE_FAST,
+    ACAMERA_COLOR_CORRECTION_MODE_HIGH_QUALITY,
+} acamera_metadata_enum_android_color_correction_mode_t;
+
+// ACAMERA_COLOR_CORRECTION_ABERRATION_MODE
+typedef enum acamera_metadata_enum_acamera_color_correction_aberration_mode {
+    ACAMERA_COLOR_CORRECTION_ABERRATION_MODE_OFF,
+    ACAMERA_COLOR_CORRECTION_ABERRATION_MODE_FAST,
+    ACAMERA_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY,
+} acamera_metadata_enum_android_color_correction_aberration_mode_t;
+
+
+// ACAMERA_CONTROL_AE_ANTIBANDING_MODE
+typedef enum acamera_metadata_enum_acamera_control_ae_antibanding_mode {
+    ACAMERA_CONTROL_AE_ANTIBANDING_MODE_OFF,
+    ACAMERA_CONTROL_AE_ANTIBANDING_MODE_50HZ,
+    ACAMERA_CONTROL_AE_ANTIBANDING_MODE_60HZ,
+    ACAMERA_CONTROL_AE_ANTIBANDING_MODE_AUTO,
+} acamera_metadata_enum_android_control_ae_antibanding_mode_t;
+
+// ACAMERA_CONTROL_AE_LOCK
+typedef enum acamera_metadata_enum_acamera_control_ae_lock {
+    ACAMERA_CONTROL_AE_LOCK_OFF,
+    ACAMERA_CONTROL_AE_LOCK_ON,
+} acamera_metadata_enum_android_control_ae_lock_t;
+
+// ACAMERA_CONTROL_AE_MODE
+typedef enum acamera_metadata_enum_acamera_control_ae_mode {
+    ACAMERA_CONTROL_AE_MODE_OFF,
+    ACAMERA_CONTROL_AE_MODE_ON,
+    ACAMERA_CONTROL_AE_MODE_ON_AUTO_FLASH,
+    ACAMERA_CONTROL_AE_MODE_ON_ALWAYS_FLASH,
+    ACAMERA_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE,
+} acamera_metadata_enum_android_control_ae_mode_t;
+
+// ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER
+typedef enum acamera_metadata_enum_acamera_control_ae_precapture_trigger {
+    ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE,
+    ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER_START,
+    ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL,
+} acamera_metadata_enum_android_control_ae_precapture_trigger_t;
+
+// ACAMERA_CONTROL_AF_MODE
+typedef enum acamera_metadata_enum_acamera_control_af_mode {
+    ACAMERA_CONTROL_AF_MODE_OFF,
+    ACAMERA_CONTROL_AF_MODE_AUTO,
+    ACAMERA_CONTROL_AF_MODE_MACRO,
+    ACAMERA_CONTROL_AF_MODE_CONTINUOUS_VIDEO,
+    ACAMERA_CONTROL_AF_MODE_CONTINUOUS_PICTURE,
+    ACAMERA_CONTROL_AF_MODE_EDOF,
+} acamera_metadata_enum_android_control_af_mode_t;
+
+// ACAMERA_CONTROL_AF_TRIGGER
+typedef enum acamera_metadata_enum_acamera_control_af_trigger {
+    ACAMERA_CONTROL_AF_TRIGGER_IDLE,
+    ACAMERA_CONTROL_AF_TRIGGER_START,
+    ACAMERA_CONTROL_AF_TRIGGER_CANCEL,
+} acamera_metadata_enum_android_control_af_trigger_t;
+
+// ACAMERA_CONTROL_AWB_LOCK
+typedef enum acamera_metadata_enum_acamera_control_awb_lock {
+    ACAMERA_CONTROL_AWB_LOCK_OFF,
+    ACAMERA_CONTROL_AWB_LOCK_ON,
+} acamera_metadata_enum_android_control_awb_lock_t;
+
+// ACAMERA_CONTROL_AWB_MODE
+typedef enum acamera_metadata_enum_acamera_control_awb_mode {
+    ACAMERA_CONTROL_AWB_MODE_OFF,
+    ACAMERA_CONTROL_AWB_MODE_AUTO,
+    ACAMERA_CONTROL_AWB_MODE_INCANDESCENT,
+    ACAMERA_CONTROL_AWB_MODE_FLUORESCENT,
+    ACAMERA_CONTROL_AWB_MODE_WARM_FLUORESCENT,
+    ACAMERA_CONTROL_AWB_MODE_DAYLIGHT,
+    ACAMERA_CONTROL_AWB_MODE_CLOUDY_DAYLIGHT,
+    ACAMERA_CONTROL_AWB_MODE_TWILIGHT,
+    ACAMERA_CONTROL_AWB_MODE_SHADE,
+} acamera_metadata_enum_android_control_awb_mode_t;
+
+// ACAMERA_CONTROL_CAPTURE_INTENT
+typedef enum acamera_metadata_enum_acamera_control_capture_intent {
+    ACAMERA_CONTROL_CAPTURE_INTENT_CUSTOM,
+    ACAMERA_CONTROL_CAPTURE_INTENT_PREVIEW,
+    ACAMERA_CONTROL_CAPTURE_INTENT_STILL_CAPTURE,
+    ACAMERA_CONTROL_CAPTURE_INTENT_VIDEO_RECORD,
+    ACAMERA_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT,
+    ACAMERA_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG,
+    ACAMERA_CONTROL_CAPTURE_INTENT_MANUAL,
+} acamera_metadata_enum_android_control_capture_intent_t;
+
+// ACAMERA_CONTROL_EFFECT_MODE
+typedef enum acamera_metadata_enum_acamera_control_effect_mode {
+    ACAMERA_CONTROL_EFFECT_MODE_OFF,
+    ACAMERA_CONTROL_EFFECT_MODE_MONO,
+    ACAMERA_CONTROL_EFFECT_MODE_NEGATIVE,
+    ACAMERA_CONTROL_EFFECT_MODE_SOLARIZE,
+    ACAMERA_CONTROL_EFFECT_MODE_SEPIA,
+    ACAMERA_CONTROL_EFFECT_MODE_POSTERIZE,
+    ACAMERA_CONTROL_EFFECT_MODE_WHITEBOARD,
+    ACAMERA_CONTROL_EFFECT_MODE_BLACKBOARD,
+    ACAMERA_CONTROL_EFFECT_MODE_AQUA,
+} acamera_metadata_enum_android_control_effect_mode_t;
+
+// ACAMERA_CONTROL_MODE
+typedef enum acamera_metadata_enum_acamera_control_mode {
+    ACAMERA_CONTROL_MODE_OFF,
+    ACAMERA_CONTROL_MODE_AUTO,
+    ACAMERA_CONTROL_MODE_USE_SCENE_MODE,
+    ACAMERA_CONTROL_MODE_OFF_KEEP_STATE,
+} acamera_metadata_enum_android_control_mode_t;
+
+// ACAMERA_CONTROL_SCENE_MODE
+typedef enum acamera_metadata_enum_acamera_control_scene_mode {
+    ACAMERA_CONTROL_SCENE_MODE_DISABLED                         = 0,
+    ACAMERA_CONTROL_SCENE_MODE_FACE_PRIORITY,
+    ACAMERA_CONTROL_SCENE_MODE_ACTION,
+    ACAMERA_CONTROL_SCENE_MODE_PORTRAIT,
+    ACAMERA_CONTROL_SCENE_MODE_LANDSCAPE,
+    ACAMERA_CONTROL_SCENE_MODE_NIGHT,
+    ACAMERA_CONTROL_SCENE_MODE_NIGHT_PORTRAIT,
+    ACAMERA_CONTROL_SCENE_MODE_THEATRE,
+    ACAMERA_CONTROL_SCENE_MODE_BEACH,
+    ACAMERA_CONTROL_SCENE_MODE_SNOW,
+    ACAMERA_CONTROL_SCENE_MODE_SUNSET,
+    ACAMERA_CONTROL_SCENE_MODE_STEADYPHOTO,
+    ACAMERA_CONTROL_SCENE_MODE_FIREWORKS,
+    ACAMERA_CONTROL_SCENE_MODE_SPORTS,
+    ACAMERA_CONTROL_SCENE_MODE_PARTY,
+    ACAMERA_CONTROL_SCENE_MODE_CANDLELIGHT,
+    ACAMERA_CONTROL_SCENE_MODE_BARCODE,
+    ACAMERA_CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO,
+    ACAMERA_CONTROL_SCENE_MODE_HDR,
+    ACAMERA_CONTROL_SCENE_MODE_FACE_PRIORITY_LOW_LIGHT,
+} acamera_metadata_enum_android_control_scene_mode_t;
+
+// ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE
+typedef enum acamera_metadata_enum_acamera_control_video_stabilization_mode {
+    ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE_OFF,
+    ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE_ON,
+} acamera_metadata_enum_android_control_video_stabilization_mode_t;
+
+// ACAMERA_CONTROL_AE_STATE
+typedef enum acamera_metadata_enum_acamera_control_ae_state {
+    ACAMERA_CONTROL_AE_STATE_INACTIVE,
+    ACAMERA_CONTROL_AE_STATE_SEARCHING,
+    ACAMERA_CONTROL_AE_STATE_CONVERGED,
+    ACAMERA_CONTROL_AE_STATE_LOCKED,
+    ACAMERA_CONTROL_AE_STATE_FLASH_REQUIRED,
+    ACAMERA_CONTROL_AE_STATE_PRECAPTURE,
+} acamera_metadata_enum_android_control_ae_state_t;
+
+// ACAMERA_CONTROL_AF_STATE
+typedef enum acamera_metadata_enum_acamera_control_af_state {
+    ACAMERA_CONTROL_AF_STATE_INACTIVE,
+    ACAMERA_CONTROL_AF_STATE_PASSIVE_SCAN,
+    ACAMERA_CONTROL_AF_STATE_PASSIVE_FOCUSED,
+    ACAMERA_CONTROL_AF_STATE_ACTIVE_SCAN,
+    ACAMERA_CONTROL_AF_STATE_FOCUSED_LOCKED,
+    ACAMERA_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED,
+    ACAMERA_CONTROL_AF_STATE_PASSIVE_UNFOCUSED,
+} acamera_metadata_enum_android_control_af_state_t;
+
+// ACAMERA_CONTROL_AWB_STATE
+typedef enum acamera_metadata_enum_acamera_control_awb_state {
+    ACAMERA_CONTROL_AWB_STATE_INACTIVE,
+    ACAMERA_CONTROL_AWB_STATE_SEARCHING,
+    ACAMERA_CONTROL_AWB_STATE_CONVERGED,
+    ACAMERA_CONTROL_AWB_STATE_LOCKED,
+} acamera_metadata_enum_android_control_awb_state_t;
+
+// ACAMERA_CONTROL_AE_LOCK_AVAILABLE
+typedef enum acamera_metadata_enum_acamera_control_ae_lock_available {
+    ACAMERA_CONTROL_AE_LOCK_AVAILABLE_FALSE,
+    ACAMERA_CONTROL_AE_LOCK_AVAILABLE_TRUE,
+} acamera_metadata_enum_android_control_ae_lock_available_t;
+
+// ACAMERA_CONTROL_AWB_LOCK_AVAILABLE
+typedef enum acamera_metadata_enum_acamera_control_awb_lock_available {
+    ACAMERA_CONTROL_AWB_LOCK_AVAILABLE_FALSE,
+    ACAMERA_CONTROL_AWB_LOCK_AVAILABLE_TRUE,
+} acamera_metadata_enum_android_control_awb_lock_available_t;
+
+
+
+// ACAMERA_EDGE_MODE
+typedef enum acamera_metadata_enum_acamera_edge_mode {
+    ACAMERA_EDGE_MODE_OFF,
+    ACAMERA_EDGE_MODE_FAST,
+    ACAMERA_EDGE_MODE_HIGH_QUALITY,
+    ACAMERA_EDGE_MODE_ZERO_SHUTTER_LAG,
+} acamera_metadata_enum_android_edge_mode_t;
+
+
+// ACAMERA_FLASH_MODE
+typedef enum acamera_metadata_enum_acamera_flash_mode {
+    ACAMERA_FLASH_MODE_OFF,
+    ACAMERA_FLASH_MODE_SINGLE,
+    ACAMERA_FLASH_MODE_TORCH,
+} acamera_metadata_enum_android_flash_mode_t;
+
+// ACAMERA_FLASH_STATE
+typedef enum acamera_metadata_enum_acamera_flash_state {
+    ACAMERA_FLASH_STATE_UNAVAILABLE,
+    ACAMERA_FLASH_STATE_CHARGING,
+    ACAMERA_FLASH_STATE_READY,
+    ACAMERA_FLASH_STATE_FIRED,
+    ACAMERA_FLASH_STATE_PARTIAL,
+} acamera_metadata_enum_android_flash_state_t;
+
+
+// ACAMERA_FLASH_INFO_AVAILABLE
+typedef enum acamera_metadata_enum_acamera_flash_info_available {
+    ACAMERA_FLASH_INFO_AVAILABLE_FALSE,
+    ACAMERA_FLASH_INFO_AVAILABLE_TRUE,
+} acamera_metadata_enum_android_flash_info_available_t;
+
+
+// ACAMERA_HOT_PIXEL_MODE
+typedef enum acamera_metadata_enum_acamera_hot_pixel_mode {
+    ACAMERA_HOT_PIXEL_MODE_OFF,
+    ACAMERA_HOT_PIXEL_MODE_FAST,
+    ACAMERA_HOT_PIXEL_MODE_HIGH_QUALITY,
+} acamera_metadata_enum_android_hot_pixel_mode_t;
+
+
+
+// ACAMERA_LENS_OPTICAL_STABILIZATION_MODE
+typedef enum acamera_metadata_enum_acamera_lens_optical_stabilization_mode {
+    ACAMERA_LENS_OPTICAL_STABILIZATION_MODE_OFF,
+    ACAMERA_LENS_OPTICAL_STABILIZATION_MODE_ON,
+} acamera_metadata_enum_android_lens_optical_stabilization_mode_t;
+
+// ACAMERA_LENS_FACING
+typedef enum acamera_metadata_enum_acamera_lens_facing {
+    ACAMERA_LENS_FACING_FRONT,
+    ACAMERA_LENS_FACING_BACK,
+    ACAMERA_LENS_FACING_EXTERNAL,
+} acamera_metadata_enum_android_lens_facing_t;
+
+// ACAMERA_LENS_STATE
+typedef enum acamera_metadata_enum_acamera_lens_state {
+    ACAMERA_LENS_STATE_STATIONARY,
+    ACAMERA_LENS_STATE_MOVING,
+} acamera_metadata_enum_android_lens_state_t;
+
+
+// ACAMERA_LENS_INFO_FOCUS_DISTANCE_CALIBRATION
+typedef enum acamera_metadata_enum_acamera_lens_info_focus_distance_calibration {
+    ACAMERA_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED,
+    ACAMERA_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE,
+    ACAMERA_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED,
+} acamera_metadata_enum_android_lens_info_focus_distance_calibration_t;
+
+
+// ACAMERA_NOISE_REDUCTION_MODE
+typedef enum acamera_metadata_enum_acamera_noise_reduction_mode {
+    ACAMERA_NOISE_REDUCTION_MODE_OFF,
+    ACAMERA_NOISE_REDUCTION_MODE_FAST,
+    ACAMERA_NOISE_REDUCTION_MODE_HIGH_QUALITY,
+    ACAMERA_NOISE_REDUCTION_MODE_MINIMAL,
+    ACAMERA_NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG,
+} acamera_metadata_enum_android_noise_reduction_mode_t;
+
+
+// ACAMERA_QUIRKS_PARTIAL_RESULT
+typedef enum acamera_metadata_enum_acamera_quirks_partial_result {
+    ACAMERA_QUIRKS_PARTIAL_RESULT_FINAL,
+    ACAMERA_QUIRKS_PARTIAL_RESULT_PARTIAL,
+} acamera_metadata_enum_android_quirks_partial_result_t;
+
+
+// ACAMERA_REQUEST_AVAILABLE_CAPABILITIES
+typedef enum acamera_metadata_enum_acamera_request_available_capabilities {
+    ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
+    ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR,
+    ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING,
+    ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_RAW,
+    ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING,
+    ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS,
+    ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE,
+    ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING,
+    ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT,
+    ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO,
+} acamera_metadata_enum_android_request_available_capabilities_t;
+
+
+// ACAMERA_SCALER_AVAILABLE_FORMATS
+typedef enum acamera_metadata_enum_acamera_scaler_available_formats {
+    ACAMERA_SCALER_AVAILABLE_FORMATS_RAW16                      = 0x20,
+    ACAMERA_SCALER_AVAILABLE_FORMATS_RAW_OPAQUE                 = 0x24,
+    ACAMERA_SCALER_AVAILABLE_FORMATS_YV12                       = 0x32315659,
+    ACAMERA_SCALER_AVAILABLE_FORMATS_YCrCb_420_SP               = 0x11,
+    ACAMERA_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED     = 0x22,
+    ACAMERA_SCALER_AVAILABLE_FORMATS_YCbCr_420_888              = 0x23,
+    ACAMERA_SCALER_AVAILABLE_FORMATS_BLOB                       = 0x21,
+} acamera_metadata_enum_android_scaler_available_formats_t;
+
+// ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+typedef enum acamera_metadata_enum_acamera_scaler_available_stream_configurations {
+    ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+    ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
+} acamera_metadata_enum_android_scaler_available_stream_configurations_t;
+
+// ACAMERA_SCALER_CROPPING_TYPE
+typedef enum acamera_metadata_enum_acamera_scaler_cropping_type {
+    ACAMERA_SCALER_CROPPING_TYPE_CENTER_ONLY,
+    ACAMERA_SCALER_CROPPING_TYPE_FREEFORM,
+} acamera_metadata_enum_android_scaler_cropping_type_t;
+
+
+// ACAMERA_SENSOR_REFERENCE_ILLUMINANT1
+typedef enum acamera_metadata_enum_acamera_sensor_reference_illuminant1 {
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT               = 1,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_FLUORESCENT            = 2,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_TUNGSTEN               = 3,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_FLASH                  = 4,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_FINE_WEATHER           = 9,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_CLOUDY_WEATHER         = 10,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_SHADE                  = 11,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT_FLUORESCENT   = 12,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_DAY_WHITE_FLUORESCENT  = 13,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_COOL_WHITE_FLUORESCENT = 14,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_WHITE_FLUORESCENT      = 15,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_A             = 17,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_B             = 18,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_C             = 19,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_D55                    = 20,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_D65                    = 21,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_D75                    = 22,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_D50                    = 23,
+    ACAMERA_SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN    = 24,
+} acamera_metadata_enum_android_sensor_reference_illuminant1_t;
+
+// ACAMERA_SENSOR_TEST_PATTERN_MODE
+typedef enum acamera_metadata_enum_acamera_sensor_test_pattern_mode {
+    ACAMERA_SENSOR_TEST_PATTERN_MODE_OFF,
+    ACAMERA_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR,
+    ACAMERA_SENSOR_TEST_PATTERN_MODE_COLOR_BARS,
+    ACAMERA_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY,
+    ACAMERA_SENSOR_TEST_PATTERN_MODE_PN9,
+    ACAMERA_SENSOR_TEST_PATTERN_MODE_CUSTOM1                    = 256,
+} acamera_metadata_enum_android_sensor_test_pattern_mode_t;
+
+
+// ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
+typedef enum acamera_metadata_enum_acamera_sensor_info_color_filter_arrangement {
+    ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB,
+    ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG,
+    ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG,
+    ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR,
+    ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB,
+} acamera_metadata_enum_android_sensor_info_color_filter_arrangement_t;
+
+// ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE
+typedef enum acamera_metadata_enum_acamera_sensor_info_timestamp_source {
+    ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN,
+    ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME,
+} acamera_metadata_enum_android_sensor_info_timestamp_source_t;
+
+// ACAMERA_SENSOR_INFO_LENS_SHADING_APPLIED
+typedef enum acamera_metadata_enum_acamera_sensor_info_lens_shading_applied {
+    ACAMERA_SENSOR_INFO_LENS_SHADING_APPLIED_FALSE,
+    ACAMERA_SENSOR_INFO_LENS_SHADING_APPLIED_TRUE,
+} acamera_metadata_enum_android_sensor_info_lens_shading_applied_t;
+
+
+// ACAMERA_SHADING_MODE
+typedef enum acamera_metadata_enum_acamera_shading_mode {
+    ACAMERA_SHADING_MODE_OFF,
+    ACAMERA_SHADING_MODE_FAST,
+    ACAMERA_SHADING_MODE_HIGH_QUALITY,
+} acamera_metadata_enum_android_shading_mode_t;
+
+
+// ACAMERA_STATISTICS_FACE_DETECT_MODE
+typedef enum acamera_metadata_enum_acamera_statistics_face_detect_mode {
+    ACAMERA_STATISTICS_FACE_DETECT_MODE_OFF,
+    ACAMERA_STATISTICS_FACE_DETECT_MODE_SIMPLE,
+    ACAMERA_STATISTICS_FACE_DETECT_MODE_FULL,
+} acamera_metadata_enum_android_statistics_face_detect_mode_t;
+
+// ACAMERA_STATISTICS_HOT_PIXEL_MAP_MODE
+typedef enum acamera_metadata_enum_acamera_statistics_hot_pixel_map_mode {
+    ACAMERA_STATISTICS_HOT_PIXEL_MAP_MODE_OFF,
+    ACAMERA_STATISTICS_HOT_PIXEL_MAP_MODE_ON,
+} acamera_metadata_enum_android_statistics_hot_pixel_map_mode_t;
+
+// ACAMERA_STATISTICS_SCENE_FLICKER
+typedef enum acamera_metadata_enum_acamera_statistics_scene_flicker {
+    ACAMERA_STATISTICS_SCENE_FLICKER_NONE,
+    ACAMERA_STATISTICS_SCENE_FLICKER_50HZ,
+    ACAMERA_STATISTICS_SCENE_FLICKER_60HZ,
+} acamera_metadata_enum_android_statistics_scene_flicker_t;
+
+// ACAMERA_STATISTICS_LENS_SHADING_MAP_MODE
+typedef enum acamera_metadata_enum_acamera_statistics_lens_shading_map_mode {
+    ACAMERA_STATISTICS_LENS_SHADING_MAP_MODE_OFF,
+    ACAMERA_STATISTICS_LENS_SHADING_MAP_MODE_ON,
+} acamera_metadata_enum_android_statistics_lens_shading_map_mode_t;
+
+
+
+// ACAMERA_TONEMAP_MODE
+typedef enum acamera_metadata_enum_acamera_tonemap_mode {
+    ACAMERA_TONEMAP_MODE_CONTRAST_CURVE,
+    ACAMERA_TONEMAP_MODE_FAST,
+    ACAMERA_TONEMAP_MODE_HIGH_QUALITY,
+    ACAMERA_TONEMAP_MODE_GAMMA_VALUE,
+    ACAMERA_TONEMAP_MODE_PRESET_CURVE,
+} acamera_metadata_enum_android_tonemap_mode_t;
+
+// ACAMERA_TONEMAP_PRESET_CURVE
+typedef enum acamera_metadata_enum_acamera_tonemap_preset_curve {
+    ACAMERA_TONEMAP_PRESET_CURVE_SRGB,
+    ACAMERA_TONEMAP_PRESET_CURVE_REC709,
+} acamera_metadata_enum_android_tonemap_preset_curve_t;
+
+
+// ACAMERA_LED_TRANSMIT
+typedef enum acamera_metadata_enum_acamera_led_transmit {
+    ACAMERA_LED_TRANSMIT_OFF,
+    ACAMERA_LED_TRANSMIT_ON,
+} acamera_metadata_enum_android_led_transmit_t;
+
+// ACAMERA_LED_AVAILABLE_LEDS
+typedef enum acamera_metadata_enum_acamera_led_available_leds {
+    ACAMERA_LED_AVAILABLE_LEDS_TRANSMIT,
+} acamera_metadata_enum_android_led_available_leds_t;
+
+
+// ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL
+typedef enum acamera_metadata_enum_acamera_info_supported_hardware_level {
+    ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
+    ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
+    ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
+} acamera_metadata_enum_android_info_supported_hardware_level_t;
+
+
+// ACAMERA_BLACK_LEVEL_LOCK
+typedef enum acamera_metadata_enum_acamera_black_level_lock {
+    ACAMERA_BLACK_LEVEL_LOCK_OFF,
+    ACAMERA_BLACK_LEVEL_LOCK_ON,
+} acamera_metadata_enum_android_black_level_lock_t;
+
+
+// ACAMERA_SYNC_FRAME_NUMBER
+typedef enum acamera_metadata_enum_acamera_sync_frame_number {
+    ACAMERA_SYNC_FRAME_NUMBER_CONVERGING                        = -1,
+    ACAMERA_SYNC_FRAME_NUMBER_UNKNOWN                           = -2,
+} acamera_metadata_enum_android_sync_frame_number_t;
+
+// ACAMERA_SYNC_MAX_LATENCY
+typedef enum acamera_metadata_enum_acamera_sync_max_latency {
+    ACAMERA_SYNC_MAX_LATENCY_PER_FRAME_CONTROL                  = 0,
+    ACAMERA_SYNC_MAX_LATENCY_UNKNOWN                            = -1,
+} acamera_metadata_enum_android_sync_max_latency_t;
+
+
+
+// ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS
+typedef enum acamera_metadata_enum_acamera_depth_available_depth_stream_configurations {
+    ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT,
+    ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_INPUT,
+} acamera_metadata_enum_android_depth_available_depth_stream_configurations_t;
+
+// ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE
+typedef enum acamera_metadata_enum_acamera_depth_depth_is_exclusive {
+    ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE_FALSE,
+    ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE_TRUE,
+} acamera_metadata_enum_android_depth_depth_is_exclusive_t;
+
+
+
+#endif //_NDK_CAMERA_METADATA_TAGS_H
diff --git a/include/camera/ndk/NdkCaptureRequest.h b/include/camera/ndk/NdkCaptureRequest.h
new file mode 100644
index 0000000..566d78f
--- /dev/null
+++ b/include/camera/ndk/NdkCaptureRequest.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 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.
+ */
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+#include <android/native_window.h>
+#include "NdkCameraError.h"
+#include "NdkCameraMetadata.h"
+
+#ifndef _NDK_CAPTURE_REQUEST_H
+#define _NDK_CAPTURE_REQUEST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Container for output targets
+typedef struct ACameraOutputTargets ACameraOutputTargets;
+
+// Container for a single output target
+typedef struct ACameraOutputTarget ACameraOutputTarget;
+
+typedef struct ACaptureRequest ACaptureRequest;
+
+camera_status_t ACameraOutputTarget_create(ANativeWindow* window, ACameraOutputTarget** out);
+void ACameraOutputTarget_free(ACameraOutputTarget*);
+
+camera_status_t ACaptureRequest_addTarget(ACaptureRequest*, const ACameraOutputTarget*);
+camera_status_t ACaptureRequest_removeTarget(ACaptureRequest*, const ACameraOutputTarget*);
+//TODO: do we need API to query added targets?
+
+/*
+ * Get a metadata entry
+ */
+camera_status_t ACaptureRequest_getConstEntry(
+        const ACaptureRequest*, uint32_t tag, ACameraMetadata_const_entry* entry);
+/*
+ * Set an entry of corresponding type.
+ * The entry tag's type must match corresponding set API or an
+ * ACAMERA_ERROR_INVALID_PARAMETER error will occur.
+ * Also, the input ACameraMetadata* must belong to a capture request or an
+ * ACAMERA_ERROR_INVALID_PARAMETER error will occur.
+ */
+camera_status_t ACaptureRequest_setEntry_u8(
+        ACaptureRequest*, uint32_t tag, uint32_t count, const uint8_t* data);
+camera_status_t ACaptureRequest_setEntry_i32(
+        ACaptureRequest*, uint32_t tag, uint32_t count, const int32_t* data);
+camera_status_t ACaptureRequest_setEntry_float(
+        ACaptureRequest*, uint32_t tag, uint32_t count, const float* data);
+camera_status_t ACaptureRequest_setEntry_i64(
+        ACaptureRequest*, uint32_t tag, uint32_t count, const int64_t* data);
+camera_status_t ACaptureRequest_setEntry_double(
+        ACaptureRequest*, uint32_t tag, uint32_t count, const double* data);
+camera_status_t ACaptureRequest_setEntry_rational(
+        ACaptureRequest*, uint32_t tag, uint32_t count, const ACameraMetadata_rational* data);
+
+// free the capture request created by ACameraDevice_createCaptureRequest
+void ACaptureRequest_free(ACaptureRequest* request);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _NDK_CAPTURE_REQUEST_H
diff --git a/include/media/AudioBufferProvider.h b/include/media/AudioBufferProvider.h
index 7be449c..458d170 100644
--- a/include/media/AudioBufferProvider.h
+++ b/include/media/AudioBufferProvider.h
@@ -40,12 +40,6 @@
 
     virtual ~AudioBufferProvider() {}
 
-    // value representing an invalid presentation timestamp
-    static const int64_t kInvalidPTS = 0x7FFFFFFFFFFFFFFFLL;    // <stdint.h> is too painful
-
-    // pts is the local time when the next sample yielded by getNextBuffer
-    // will be rendered.
-    // Pass kInvalidPTS if the PTS is unknown or not applicable.
     // On entry:
     //  buffer              != NULL
     //  buffer->raw         unused
@@ -59,7 +53,7 @@
     //  status              != NO_ERROR
     //  buffer->raw         NULL
     //  buffer->frameCount  0
-    virtual status_t getNextBuffer(Buffer* buffer, int64_t pts = kInvalidPTS) = 0;
+    virtual status_t getNextBuffer(Buffer* buffer) = 0;
 
     // Release (a portion of) the buffer previously obtained by getNextBuffer().
     // It is permissible to call releaseBuffer() multiple times per getNextBuffer().
diff --git a/include/media/AudioPolicy.h b/include/media/AudioPolicy.h
index feed402..a171493 100644
--- a/include/media/AudioPolicy.h
+++ b/include/media/AudioPolicy.h
@@ -28,11 +28,13 @@
 
 // Keep in sync with AudioMix.java, AudioMixingRule.java, AudioPolicyConfig.java
 #define RULE_EXCLUSION_MASK 0x8000
-#define RULE_MATCH_ATTRIBUTE_USAGE 0x1
+#define RULE_MATCH_ATTRIBUTE_USAGE           0x1
 #define RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET (0x1 << 1)
-#define RULE_EXCLUDE_ATTRIBUTE_USAGE (RULE_EXCLUSION_MASK|RULE_MATCH_ATTRIBUTE_USAGE)
+#define RULE_MATCH_UID                      (0x1 << 2)
+#define RULE_EXCLUDE_ATTRIBUTE_USAGE  (RULE_EXCLUSION_MASK|RULE_MATCH_ATTRIBUTE_USAGE)
 #define RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET \
-    (RULE_EXCLUSION_MASK|RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET)
+                                      (RULE_EXCLUSION_MASK|RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET)
+#define RULE_EXCLUDE_UID              (RULE_EXCLUSION_MASK|RULE_MATCH_UID)
 
 #define MIX_TYPE_INVALID -1
 #define MIX_TYPE_PLAYERS 0
@@ -53,10 +55,10 @@
 #define MAX_MIXES_PER_POLICY 10
 #define MAX_CRITERIA_PER_MIX 20
 
-class AttributeMatchCriterion {
+class AudioMixMatchCriterion {
 public:
-    AttributeMatchCriterion() {}
-    AttributeMatchCriterion(audio_usage_t usage, audio_source_t source, uint32_t rule);
+    AudioMixMatchCriterion() {}
+    AudioMixMatchCriterion(audio_usage_t usage, audio_source_t source, uint32_t rule);
 
     status_t readFromParcel(Parcel *parcel);
     status_t writeToParcel(Parcel *parcel) const;
@@ -64,7 +66,8 @@
     union {
         audio_usage_t   mUsage;
         audio_source_t  mSource;
-    } mAttr;
+        uid_t           mUid;
+    } mValue;
     uint32_t        mRule;
 };
 
@@ -75,7 +78,7 @@
     static const uint32_t kCbFlagNotifyActivity = 0x1;
 
     AudioMix() {}
-    AudioMix(Vector<AttributeMatchCriterion> criteria, uint32_t mixType, audio_config_t format,
+    AudioMix(Vector<AudioMixMatchCriterion> criteria, uint32_t mixType, audio_config_t format,
              uint32_t routeFlags, String8 registrationId, uint32_t flags) :
         mCriteria(criteria), mMixType(mixType), mFormat(format),
         mRouteFlags(routeFlags), mRegistrationId(registrationId), mCbFlags(flags){}
@@ -83,7 +86,7 @@
     status_t readFromParcel(Parcel *parcel);
     status_t writeToParcel(Parcel *parcel) const;
 
-    Vector<AttributeMatchCriterion> mCriteria;
+    Vector<AudioMixMatchCriterion> mCriteria;
     uint32_t        mMixType;
     audio_config_t  mFormat;
     uint32_t        mRouteFlags;
@@ -91,6 +94,12 @@
     uint32_t        mCbFlags; // flags indicating which callbacks to use, see kCbFlag*
 };
 
+
+// definitions for audio recording configuration updates
+// which update type is reported
+#define RECORD_CONFIG_EVENT_START 1
+#define RECORD_CONFIG_EVENT_STOP  0
+
 }; // namespace android
 
 #endif  // ANDROID_AUDIO_POLICY_H
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index c4c7b0e..521557d 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -19,7 +19,9 @@
 
 #include <cutils/sched_policy.h>
 #include <media/AudioSystem.h>
+#include <media/AudioTimestamp.h>
 #include <media/IAudioRecord.h>
+#include <media/Modulo.h>
 #include <utils/threads.h>
 
 namespace android {
@@ -313,6 +315,17 @@
      */
             status_t    getPosition(uint32_t *position) const;
 
+    /* Return the record timestamp.
+     *
+     * Parameters:
+     *  timestamp: A pointer to the timestamp to be filled.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - BAD_VALUE: timestamp is NULL
+     */
+            status_t getTimestamp(ExtendedTimestamp *timestamp);
+
     /* Returns a handle on the audio input used by this AudioRecord.
      *
      * Parameters:
@@ -526,7 +539,7 @@
 
             // caller must hold lock on mLock for all _l methods
 
-            status_t openRecord_l(size_t epoch, const String16& opPackageName);
+            status_t openRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName);
 
             // FIXME enum is faster than strcmp() for parameter 'from'
             status_t restoreRecord_l(const char *from);
@@ -556,9 +569,9 @@
     bool                    mRetryOnPartialBuffer;  // sleep and retry after partial obtainBuffer()
     uint32_t                mObservedSequence;      // last observed value of mSequence
 
-    uint32_t                mMarkerPosition;        // in wrapping (overflow) frame units
+    Modulo<uint32_t>        mMarkerPosition;        // in wrapping (overflow) frame units
     bool                    mMarkerReached;
-    uint32_t                mNewPosition;           // in frames
+    Modulo<uint32_t>        mNewPosition;           // in frames
     uint32_t                mUpdatePeriod;          // in frames, zero means no EVENT_NEW_POS
 
     status_t                mStatus;
@@ -570,6 +583,11 @@
     size_t                  mReqFrameCount;         // frame count to request the first or next time
                                                     // a new IAudioRecord is needed, non-decreasing
 
+    int64_t                 mFramesRead;            // total frames read. reset to zero after
+                                                    // the start() following stop(). It is not
+                                                    // changed after restoring the track.
+    int64_t                 mFramesReadServerOffset; // An offset to server frames read due to
+                                                    // restoring AudioRecord, or stop/start.
     // constant after constructor or set()
     uint32_t                mSampleRate;
     audio_format_t          mFormat;
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 26a0bb2..2f95b90 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -31,6 +31,7 @@
 
 typedef void (*audio_error_callback)(status_t err);
 typedef void (*dynamic_policy_callback)(int event, String8 regId, int val);
+typedef void (*record_config_callback)(int event, int session, int source);
 
 class IAudioFlinger;
 class IAudioPolicyService;
@@ -92,6 +93,7 @@
 
     static void setErrorCallback(audio_error_callback cb);
     static void setDynPolicyCallback(dynamic_policy_callback cb);
+    static void setRecordConfigCallback(record_config_callback);
 
     // helper function to obtain AudioFlinger service handle
     static const sp<IAudioFlinger> get_audio_flinger();
@@ -319,6 +321,8 @@
                                       audio_io_handle_t *handle);
     static status_t stopAudioSource(audio_io_handle_t handle);
 
+    static status_t setMasterMono(bool mono);
+    static status_t getMasterMono(bool *mono);
 
     // ----------------------------------------------------------------------------
 
@@ -419,6 +423,8 @@
         virtual void onAudioPortListUpdate();
         virtual void onAudioPatchListUpdate();
         virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+        virtual void onRecordingConfigurationUpdate(int event, audio_session_t session,
+                        audio_source_t source);
 
     private:
         Mutex                               mLock;
@@ -438,6 +444,7 @@
     static sp<IAudioFlinger> gAudioFlinger;
     static audio_error_callback gAudioErrorCallback;
     static dynamic_policy_callback gDynPolicyCallback;
+    static record_config_callback gRecordConfigCallback;
 
     static size_t gInBuffSize;
     // previous parameters for recording buffer size queries
diff --git a/include/media/AudioTimestamp.h b/include/media/AudioTimestamp.h
index 99e9c3e..e6ca225 100644
--- a/include/media/AudioTimestamp.h
+++ b/include/media/AudioTimestamp.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_AUDIO_TIMESTAMP_H
 #define ANDROID_AUDIO_TIMESTAMP_H
 
+#include <string>
+#include <sstream>
 #include <time.h>
 
 namespace android {
@@ -32,6 +34,85 @@
     struct timespec mTime;     // corresponding CLOCK_MONOTONIC when frame is expected to present
 };
 
+struct ExtendedTimestamp {
+    enum Location {
+        LOCATION_CLIENT,   // timestamp of last read frame from client-server track buffer
+        LOCATION_SERVER,   // timestamp of newest frame from client-server track buffer
+        LOCATION_KERNEL,   // timestamp of newest frame in the kernel (alsa) buffer.
+        LOCATION_MAX       // for sizing arrays only
+    };
+
+    // This needs to be kept in sync with android.media.AudioTimestamp
+    enum Timebase {
+        TIMEBASE_MONOTONIC,  // Clock monotonic offset (generally 0)
+        TIMEBASE_BOOTTIME,
+        TIMEBASE_MAX,
+    };
+
+    ExtendedTimestamp() {
+        clear();
+    }
+
+    // mPosition is expressed in frame units.
+    // It is generally nonnegative, though we keep this signed for
+    // to potentially express algorithmic latency at the start of the stream
+    // and to prevent unintentional unsigned integer underflow.
+    int64_t mPosition[LOCATION_MAX];
+
+    // mTimeNs is in nanoseconds for the default timebase, monotonic.
+    // If this value is -1, then both time and position are invalid.
+    // If this value is 0, then the time is not valid but the position is valid.
+    int64_t mTimeNs[LOCATION_MAX];
+
+    // mTimebaseOffset is the offset in ns from monotonic when the
+    // timestamp was taken.  This may vary due to suspend time
+    // or NTP adjustment.
+    int64_t mTimebaseOffset[TIMEBASE_MAX];
+
+    void clear() {
+        memset(mPosition, 0, sizeof(mPosition)); // actually not necessary if time is -1
+        for (int i = 0; i < LOCATION_MAX; ++i) {
+            mTimeNs[i] = -1;
+        }
+        memset(mTimebaseOffset, 0, sizeof(mTimebaseOffset));
+    }
+
+    // Returns the best timestamp as judged from the closest-to-hw stage in the
+    // pipeline with a valid timestamp.
+    int getBestTimestamp(int64_t *position, int64_t *time, int timebase) {
+        if (position == nullptr || time == nullptr
+                || timebase < 0 || timebase >= TIMEBASE_MAX) {
+            return BAD_VALUE;
+        }
+        // look for the closest-to-hw stage in the pipeline with a valid timestamp.
+        // We omit LOCATION_CLIENT as we prefer at least LOCATION_SERVER based accuracy
+        // when getting the best timestamp.
+        for (int i = LOCATION_MAX - 1; i >= LOCATION_SERVER; --i) {
+            if (mTimeNs[i] > 0) {
+                *position = mPosition[i];
+                *time = mTimeNs[i] + mTimebaseOffset[timebase];
+                return OK;
+            }
+        }
+        return INVALID_OPERATION;
+    }
+
+    // convert fields to a printable string
+    std::string toString() {
+        std::stringstream ss;
+
+        ss << "BOOTTIME offset " << mTimebaseOffset[TIMEBASE_BOOTTIME] << "\n";
+        for (int i = 0; i < LOCATION_MAX; ++i) {
+            ss << "ExtendedTimestamp[" << i << "]  position: "
+                    << mPosition[i] << "  time: "  << mTimeNs[i] << "\n";
+        }
+        return ss.str();
+    }
+    // TODO:
+    // Consider adding buffer status:
+    // size, available, algorithmic latency
+};
+
 }   // namespace
 
 #endif  // ANDROID_AUDIO_TIMESTAMP_H
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index e02f1b7..a4b8571 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -22,6 +22,7 @@
 #include <media/AudioTimestamp.h>
 #include <media/IAudioTrack.h>
 #include <media/AudioResamplerPublic.h>
+#include <media/Modulo.h>
 #include <utils/threads.h>
 
 namespace android {
@@ -304,6 +305,11 @@
      */
             uint32_t    latency() const     { return mLatency; }
 
+    /* Returns the number of application-level buffer underruns
+     * since the AudioTrack was created.
+     */
+            uint32_t    getUnderrunCount() const;
+
     /* getters, see constructors and set() */
 
             audio_stream_type_t streamType() const;
@@ -319,6 +325,25 @@
             uint32_t    channelCount() const { return mChannelCount; }
             size_t      frameCount() const  { return mFrameCount; }
 
+    /* Return effective size of audio buffer that an application writes to
+     * or a negative error if the track is uninitialized.
+     */
+            ssize_t     getBufferSizeInFrames();
+
+    /* Set the effective size of audio buffer that an application writes to.
+     * This is used to determine the amount of available room in the buffer,
+     * which determines when a write will block.
+     * This allows an application to raise and lower the audio latency.
+     * The requested size may be adjusted so that it is
+     * greater or equal to the absolute minimum and
+     * less than or equal to the getBufferCapacityInFrames().
+     * It may also be adjusted slightly for internal reasons.
+     *
+     * Return the final size or a negative error if the track is unitialized
+     * or does not support variable sizes.
+     */
+            ssize_t     setBufferSizeInFrames(size_t size);
+
     /* Return the static buffer specified in constructor or set(), or 0 for streaming mode */
             sp<IMemory> sharedBuffer() const { return mSharedBuffer; }
 
@@ -783,6 +808,8 @@
             // FIXME enum is faster than strcmp() for parameter 'from'
             status_t restoreTrack_l(const char *from);
 
+            uint32_t    getUnderrunCount_l() const;
+
             bool     isOffloaded() const;
             bool     isDirect() const;
             bool     isOffloadedOrDirect() const;
@@ -798,7 +825,7 @@
                 { return (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0; }
 
             // increment mPosition by the delta of mServer, and return new value of mPosition
-            uint32_t updateAndGetPosition_l();
+            Modulo<uint32_t> updateAndGetPosition_l();
 
             // check sample rate and speed is compatible with AudioTrack
             bool     isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const;
@@ -810,14 +837,18 @@
     audio_io_handle_t       mOutput;                // returned by AudioSystem::getOutput()
 
     sp<AudioTrackThread>    mAudioTrackThread;
+    bool                    mThreadCanCallJava;
 
     float                   mVolume[2];
     float                   mSendLevel;
     mutable uint32_t        mSampleRate;            // mutable because getSampleRate() can update it
     uint32_t                mOriginalSampleRate;
     AudioPlaybackRate       mPlaybackRate;
-    size_t                  mFrameCount;            // corresponds to current IAudioTrack, value is
-                                                    // reported back by AudioFlinger to the client
+
+    // Corresponds to current IAudioTrack, value is reported back by AudioFlinger to the client.
+    // This allocated buffer size is maintained by the proxy.
+    size_t                  mFrameCount;            // maximum size of buffer
+
     size_t                  mReqFrameCount;         // frame count to request the first or next time
                                                     // a new IAudioTrack is needed, non-decreasing
 
@@ -885,19 +916,19 @@
     bool                    mRetryOnPartialBuffer;  // sleep and retry after partial obtainBuffer()
     uint32_t                mObservedSequence;      // last observed value of mSequence
 
-    uint32_t                mMarkerPosition;        // in wrapping (overflow) frame units
+    Modulo<uint32_t>        mMarkerPosition;        // in wrapping (overflow) frame units
     bool                    mMarkerReached;
-    uint32_t                mNewPosition;           // in frames
+    Modulo<uint32_t>        mNewPosition;           // in frames
     uint32_t                mUpdatePeriod;          // in frames, zero means no EVENT_NEW_POS
 
-    uint32_t                mServer;                // in frames, last known mProxy->getPosition()
+    Modulo<uint32_t>        mServer;                // in frames, last known mProxy->getPosition()
                                                     // which is count of frames consumed by server,
                                                     // reset by new IAudioTrack,
                                                     // whether it is reset by stop() is TBD
-    uint32_t                mPosition;              // in frames, like mServer except continues
+    Modulo<uint32_t>        mPosition;              // in frames, like mServer except continues
                                                     // monotonically after new IAudioTrack,
                                                     // and could be easily widened to uint64_t
-    uint32_t                mReleased;              // in frames, count of frames released to server
+    Modulo<uint32_t>        mReleased;              // count of frames released to server
                                                     // but not necessarily consumed by server,
                                                     // reset by stop() but continues monotonically
                                                     // after new IAudioTrack to restore mPosition,
@@ -910,6 +941,8 @@
     bool                    mRetrogradeMotionReported; // reduce log spam
     AudioTimestamp          mPreviousTimestamp;     // used to detect retrograde motion
 
+    uint32_t                mUnderrunCountOffset;   // updated when restoring tracks
+
     audio_output_flags_t    mFlags;
         // const after set(), except for bits AUDIO_OUTPUT_FLAG_FAST and AUDIO_OUTPUT_FLAG_OFFLOAD.
         // mLock must be held to read or write those bits reliably.
@@ -921,7 +954,6 @@
 
     mutable Mutex           mLock;
 
-    bool                    mIsTimed;
     int                     mPreviousPriority;          // before start()
     SchedPolicy             mPreviousSchedulingGroup;
     bool                    mAwaitBoost;    // thread should wait for priority boost before running
@@ -959,29 +991,6 @@
     sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
 };
 
-class TimedAudioTrack : public AudioTrack
-{
-public:
-    TimedAudioTrack();
-
-    /* allocate a shared memory buffer that can be passed to queueTimedBuffer */
-    status_t allocateTimedBuffer(size_t size, sp<IMemory>* buffer);
-
-    /* queue a buffer obtained via allocateTimedBuffer for playback at the
-       given timestamp.  PTS units are microseconds on the media time timeline.
-       The media time transform (set with setMediaTimeTransform) set by the
-       audio producer will handle converting from media time to local time
-       (perhaps going through the common time timeline in the case of
-       synchronized multiroom audio case) */
-    status_t queueTimedBuffer(const sp<IMemory>& buffer, int64_t pts);
-
-    /* define a transform between media time and either common time or
-       local time */
-    enum TargetTimeline {LOCAL_TIME, COMMON_TIME};
-    status_t setMediaTimeTransform(const LinearTransform& xform,
-                                   TargetTimeline target);
-};
-
 }; // namespace android
 
 #endif // ANDROID_AUDIOTRACK_H
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 5051aff..3b69ecf 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -47,7 +47,8 @@
     // or-able bits shared by createTrack and openRecord, but not all combinations make sense
     enum {
         TRACK_DEFAULT = 0,  // client requests a default AudioTrack
-        TRACK_TIMED   = 1,  // client requests a TimedAudioTrack
+        // FIXME: obsolete
+        // TRACK_TIMED= 1,  // client requests a TimedAudioTrack
         TRACK_FAST    = 2,  // client requests a fast AudioTrack or AudioRecord
         TRACK_OFFLOAD = 4,  // client requests offload to hw codec
         TRACK_DIRECT = 8,   // client requests a direct output
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 6b93f6f..ceca71a 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -165,6 +165,9 @@
                                       const audio_attributes_t *attributes,
                                       audio_io_handle_t *handle) = 0;
     virtual status_t stopAudioSource(audio_io_handle_t handle) = 0;
+
+    virtual status_t setMasterMono(bool mono) = 0;
+    virtual status_t getMasterMono(bool *mono) = 0;
 };
 
 
diff --git a/include/media/IAudioPolicyServiceClient.h b/include/media/IAudioPolicyServiceClient.h
index a7f2cc3..e8fd39f 100644
--- a/include/media/IAudioPolicyServiceClient.h
+++ b/include/media/IAudioPolicyServiceClient.h
@@ -37,6 +37,9 @@
     virtual void onAudioPatchListUpdate() = 0;
     // Notifies a change in the mixing state of a specific mix in a dynamic audio policy
     virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0;
+    // Notifies a change of audio recording configuration
+    virtual void onRecordingConfigurationUpdate(int event, audio_session_t session,
+            audio_source_t source) = 0;
 };
 
 
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index 619ac78..a31cec6 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -24,7 +24,6 @@
 #include <utils/Errors.h>
 #include <binder/IInterface.h>
 #include <binder/IMemory.h>
-#include <utils/LinearTransform.h>
 #include <utils/String8.h>
 #include <media/AudioTimestamp.h>
 
@@ -67,24 +66,6 @@
      */
     virtual status_t    attachAuxEffect(int effectId) = 0;
 
-
-    /* Allocate a shared memory buffer suitable for holding timed audio
-       samples */
-    virtual status_t    allocateTimedBuffer(size_t size,
-                                            sp<IMemory>* buffer) = 0;
-
-    /* Queue a buffer obtained via allocateTimedBuffer for playback at the given
-       timestamp */
-    virtual status_t    queueTimedBuffer(const sp<IMemory>& buffer,
-                                         int64_t pts) = 0;
-
-    /* Define the linear transform that will be applied to the timestamps
-       given to queueTimedBuffer (which are expressed in media time).
-       Target specifies whether this transform converts media time to local time
-       or Tungsten time. The values for target are defined in AudioTrack.h */
-    virtual status_t    setMediaTimeTransform(const LinearTransform& xform,
-                                              int target) = 0;
-
     /* Send parameters to the audio hardware */
     virtual status_t    setParameters(const String8& keyValuePairs) = 0;
 
diff --git a/include/media/ICrypto.h b/include/media/ICrypto.h
index ea316de..5e324ad 100644
--- a/include/media/ICrypto.h
+++ b/include/media/ICrypto.h
@@ -51,6 +51,7 @@
             const uint8_t key[16],
             const uint8_t iv[16],
             CryptoPlugin::Mode mode,
+            const CryptoPlugin::Pattern &pattern,
             const sp<IMemory> &sharedBuffer, size_t offset,
             const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
             void *dstPtr,
diff --git a/include/media/IDataSource.h b/include/media/IDataSource.h
index 07e46f7..09009f0 100644
--- a/include/media/IDataSource.h
+++ b/include/media/IDataSource.h
@@ -41,6 +41,9 @@
     // This should be called before deleting |this|. The other methods may
     // return errors if they're called after calling close().
     virtual void close() = 0;
+    // Get the flags of the source.
+    // Refer to DataSource:Flags for the definition of the flags.
+    virtual uint32_t getFlags() = 0;
 
 private:
     DISALLOW_EVIL_CONSTRUCTORS(IDataSource);
diff --git a/include/media/IDrm.h b/include/media/IDrm.h
index 9449beb6..fd51fd0 100644
--- a/include/media/IDrm.h
+++ b/include/media/IDrm.h
@@ -71,8 +71,6 @@
                                               Vector<uint8_t> &certificate,
                                               Vector<uint8_t> &wrappedKey) = 0;
 
-    virtual status_t unprovisionDevice() = 0;
-
     virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) = 0;
     virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) = 0;
 
diff --git a/include/media/IMediaCodecService.h b/include/media/IMediaCodecService.h
new file mode 100644
index 0000000..984a0fd
--- /dev/null
+++ b/include/media/IMediaCodecService.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 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 ANDROID_IMEDIACODECSERVICE_H
+#define ANDROID_IMEDIACODECSERVICE_H
+
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <media/IDataSource.h>
+#include <include/OMX.h>
+
+namespace android {
+
+class IMediaCodecService: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(MediaCodecService);
+
+    virtual sp<IOMX> getOMX() = 0;
+};
+
+class BnMediaCodecService: public BnInterface<IMediaCodecService>
+{
+public:
+    virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                uint32_t flags = 0);
+};
+
+}   // namespace android
+
+#endif  // ANDROID_IMEDIACODECSERVICE_H
diff --git a/include/media/IMediaDrmService.h b/include/media/IMediaDrmService.h
new file mode 100644
index 0000000..323fae5
--- /dev/null
+++ b/include/media/IMediaDrmService.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 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 ANDROID_IMEDIADRMSERVICE_H
+#define ANDROID_IMEDIADRMSERVICE_H
+
+#include <utils/Errors.h>  // for status_t
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+struct ICrypto;
+struct IDrm;
+
+class IMediaDrmService: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(MediaDrmService);
+
+    virtual sp<ICrypto>         makeCrypto() = 0;
+    virtual sp<IDrm>            makeDrm() = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnMediaDrmService: public BnInterface<IMediaDrmService>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IMEDIADRMSERVICE_H
diff --git a/include/media/IMediaExtractor.h b/include/media/IMediaExtractor.h
new file mode 100644
index 0000000..9f7a719
--- /dev/null
+++ b/include/media/IMediaExtractor.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2009 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 IMEDIA_EXTRACTOR_BASE_H_
+
+#define IMEDIA_EXTRACTOR_BASE_H_
+
+#include <media/IMediaSource.h>
+
+namespace android {
+
+class MetaData;
+
+class IMediaExtractor : public IInterface {
+public:
+    DECLARE_META_INTERFACE(MediaExtractor);
+
+    virtual size_t countTracks() = 0;
+    virtual sp<IMediaSource> getTrack(size_t index) = 0;
+
+    enum GetTrackMetaDataFlags {
+        kIncludeExtensiveMetaData = 1
+    };
+    virtual sp<MetaData> getTrackMetaData(
+            size_t index, uint32_t flags = 0) = 0;
+
+    // Return container specific meta-data. The default implementation
+    // returns an empty metadata object.
+    virtual sp<MetaData> getMetaData() = 0;
+
+    enum Flags {
+        CAN_SEEK_BACKWARD  = 1,  // the "seek 10secs back button"
+        CAN_SEEK_FORWARD   = 2,  // the "seek 10secs forward button"
+        CAN_PAUSE          = 4,
+        CAN_SEEK           = 8,  // the "seek bar"
+    };
+
+    // If subclasses do _not_ override this, the default is
+    // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
+    virtual uint32_t flags() const = 0;
+
+    // for DRM
+    virtual void setDrmFlag(bool flag) = 0;
+    virtual bool getDrmFlag() = 0;
+    virtual char* getDrmTrackInfo(size_t trackID, int *len)  = 0;
+    virtual void setUID(uid_t uid)  = 0;
+
+    virtual const char * name() = 0;
+};
+
+
+class BnMediaExtractor: public BnInterface<IMediaExtractor>
+{
+public:
+    virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                uint32_t flags = 0);
+};
+
+
+}  // namespace android
+
+#endif  // IMEDIA_EXTRACTOR_BASE_H_
diff --git a/include/media/IMediaExtractorService.h b/include/media/IMediaExtractorService.h
new file mode 100644
index 0000000..4d7b317
--- /dev/null
+++ b/include/media/IMediaExtractorService.h
@@ -0,0 +1,46 @@
+/*
+ * 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_IMEDIAEXTRACTORSERVICE_H
+#define ANDROID_IMEDIAEXTRACTORSERVICE_H
+
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <media/IDataSource.h>
+#include <media/IMediaExtractor.h>
+
+namespace android {
+
+class IMediaExtractorService: public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(MediaExtractorService);
+
+    virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime) = 0;
+
+};
+
+class BnMediaExtractorService: public BnInterface<IMediaExtractorService>
+{
+public:
+    virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                uint32_t flags = 0);
+};
+
+}   // namespace android
+
+#endif  // ANDROID_IMEDIAEXTRACTORSERVICE_H
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index a316ce2..99ca6f0 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -51,7 +51,6 @@
     virtual sp<IMediaMetadataRetriever> createMetadataRetriever() = 0;
     virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client, int audioSessionId = 0)
             = 0;
-
     virtual sp<IOMX>            getOMX() = 0;
     virtual sp<ICrypto>         makeCrypto() = 0;
     virtual sp<IDrm>            makeDrm() = 0;
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index 77ed5d3..caa6592 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -53,6 +53,8 @@
     virtual status_t start() = 0;
     virtual status_t stop() = 0;
     virtual status_t reset() = 0;
+    virtual status_t pause() = 0;
+    virtual status_t resume() = 0;
     virtual status_t init() = 0;
     virtual status_t close() = 0;
     virtual status_t release() = 0;
diff --git a/include/media/IMediaSource.h b/include/media/IMediaSource.h
new file mode 100644
index 0000000..1420120
--- /dev/null
+++ b/include/media/IMediaSource.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2009 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 IMEDIA_SOURCE_BASE_H_
+
+#define IMEDIA_SOURCE_BASE_H_
+
+#include <binder/IInterface.h>
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+struct MediaSource;
+class MetaData;
+class MediaBuffer;
+
+class IMediaSource : public IInterface {
+public:
+    DECLARE_META_INTERFACE(MediaSource);
+
+    // To be called before any other methods on this object, except
+    // getFormat().
+    virtual status_t start(MetaData *params = NULL) = 0;
+
+    // Any blocking read call returns immediately with a result of NO_INIT.
+    // It is an error to call any methods other than start after this call
+    // returns. Any buffers the object may be holding onto at the time of
+    // the stop() call are released.
+    // Also, it is imperative that any buffers output by this object and
+    // held onto by callers be released before a call to stop() !!!
+    virtual status_t stop() = 0;
+
+    // Returns the format of the data output by this media source.
+    virtual sp<MetaData> getFormat() = 0;
+
+    // Options that modify read() behaviour. The default is to
+    // a) not request a seek
+    // b) not be late, i.e. lateness_us = 0
+    struct ReadOptions {
+        enum SeekMode {
+            SEEK_PREVIOUS_SYNC,
+            SEEK_NEXT_SYNC,
+            SEEK_CLOSEST_SYNC,
+            SEEK_CLOSEST,
+        };
+
+        ReadOptions();
+
+        // Reset everything back to defaults.
+        void reset();
+
+        void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);
+        void clearSeekTo();
+        bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
+
+        void setLateBy(int64_t lateness_us);
+        int64_t getLateBy() const;
+
+        void setNonBlocking();
+        void clearNonBlocking();
+        bool getNonBlocking() const;
+
+    private:
+        enum Options {
+            kSeekTo_Option      = 1,
+        };
+
+        uint32_t mOptions;
+        int64_t mSeekTimeUs;
+        SeekMode mSeekMode;
+        int64_t mLatenessUs;
+        bool mNonBlocking;
+    };
+
+    // Returns a new buffer of data. Call blocks until a
+    // buffer is available, an error is encountered of the end of the stream
+    // is reached.
+    // End of stream is signalled by a result of ERROR_END_OF_STREAM.
+    // A result of INFO_FORMAT_CHANGED indicates that the format of this
+    // MediaSource has changed mid-stream, the client can continue reading
+    // but should be prepared for buffers of the new configuration.
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
+
+    // Causes this source to suspend pulling data from its upstream source
+    // until a subsequent read-with-seek. Currently only supported by
+    // OMXCodec.
+    virtual status_t pause()  = 0;
+
+    // The consumer of this media source requests that the given buffers
+    // are to be returned exclusively in response to read calls.
+    // This will be called after a successful start() and before the
+    // first read() call.
+    // Callee assumes ownership of the buffers if no error is returned.
+    virtual status_t setBuffers(const Vector<MediaBuffer *> & /* buffers */) = 0;
+
+};
+
+class BnMediaSource: public BnInterface<IMediaSource>
+{
+public:
+    virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                uint32_t flags = 0);
+
+    virtual status_t pause() {
+        return ERROR_UNSUPPORTED;
+    }
+
+    virtual status_t setBuffers(const Vector<MediaBuffer *> & /* buffers */) {
+        return ERROR_UNSUPPORTED;
+    }
+};
+
+
+}  // namespace android
+
+#endif  // IMEDIA_SOURCE_BASE_H_
diff --git a/include/media/MediaCodecInfo.h b/include/media/MediaCodecInfo.h
index ac5b075..48d0407 100644
--- a/include/media/MediaCodecInfo.h
+++ b/include/media/MediaCodecInfo.h
@@ -48,6 +48,10 @@
             kFlagSupportsAdaptivePlayback = 1 << 0,
             kFlagSupportsSecurePlayback = 1 << 1,
             kFlagSupportsTunneledPlayback = 1 << 2,
+
+            // encoder flags
+            kFlagSupportsIntraRefresh = 1 << 0,
+
         };
 
         void getSupportedProfileLevels(Vector<ProfileLevel> *profileLevels) const;
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index de82554..9e5056f 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -99,6 +99,7 @@
         virtual float       msecsPerFrame() const = 0;
         virtual status_t    getPosition(uint32_t *position) const = 0;
         virtual status_t    getTimestamp(AudioTimestamp &ts) const = 0;
+        virtual int64_t     getPlayedOutDurationUs(int64_t nowUs) const = 0;
         virtual status_t    getFramesWritten(uint32_t *frameswritten) const = 0;
         virtual int         getSessionId() const = 0;
         virtual audio_stream_type_t getAudioStreamType() const = 0;
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
index d6cc4bb..c05d782 100644
--- a/include/media/MediaRecorderBase.h
+++ b/include/media/MediaRecorderBase.h
@@ -53,6 +53,8 @@
     virtual status_t prepare() = 0;
     virtual status_t start() = 0;
     virtual status_t stop() = 0;
+    virtual status_t pause() = 0;
+    virtual status_t resume() = 0;
     virtual status_t close() = 0;
     virtual status_t reset() = 0;
     virtual status_t getMaxAmplitude(int *max) = 0;
diff --git a/include/media/Modulo.h b/include/media/Modulo.h
new file mode 100644
index 0000000..23280ac
--- /dev/null
+++ b/include/media/Modulo.h
@@ -0,0 +1,220 @@
+/*
+ * 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 ANDROID_MODULO_H
+#define ANDROID_MODULO_H
+
+namespace android {
+
+// Modulo class is used for intentionally wrapping variables such as
+// counters and timers.
+//
+// It may also be used for variables whose computation depends on the
+// associativity of addition or subtraction.
+//
+// Features:
+// 1) Modulo checks type sizes before performing operations to ensure
+//    that the wrap points match. This is critical for safe modular arithmetic.
+// 2) Modulo returns Modulo types from arithmetic operations, thereby
+//    avoiding unintentional use in a non-modular computation.  A Modulo
+//    type is converted to its base non-Modulo type through the value() function.
+// 3) Modulo separates out overflowable types from non-overflowable types.
+//    A signed overflow is technically undefined in C and C++.
+//    Modulo types do not participate in sanitization.
+// 4) Modulo comparisons are based on signed differences to account for wrap;
+//    this is not the same as the direct comparison of values.
+// 5) Safe use of binary arithmetic operations relies on conversions of
+//    signed operands to unsigned operands (which are modular arithmetic safe).
+//    Conversions which are implementation-defined are assumed to use 2's complement
+//    representation. (See A, B, C, D from the ISO/IEC FDIS 14882
+//    Information technology — Programming languages — C++).
+//
+// A: ISO/IEC 14882:2011(E) p84 section 4.7 Integral conversions
+// (2) If the destination type is unsigned, the resulting value is the least unsigned
+// integer congruent to the source integer (modulo 2^n where n is the number of bits
+// used to represent the unsigned type). [ Note: In a two’s complement representation,
+// this conversion is conceptual and there is no change in the bit pattern (if there
+// is no truncation). — end note ]
+// (3) If the destination type is signed, the value is unchanged if it can be represented
+// in the destination type (and bit-field width); otherwise, the value is
+// implementation-defined.
+//
+// B: ISO/IEC 14882:2011(E) p88 section 5 Expressions
+// (9) Many binary operators that expect operands of arithmetic or enumeration type
+// cause conversions and yield result types in a similar way. The purpose is to
+// yield a common type, which is also the type of the result. This pattern is called
+// the usual arithmetic conversions, which are defined as follows:
+// [...]
+// Otherwise, if both operands have signed integer types or both have unsigned
+// integer types, the operand with the type of lesser integer conversion rank shall be
+// converted to the type of the operand with greater rank.
+// — Otherwise, if the operand that has unsigned integer type has rank greater than
+// or equal to the rank of the type of the other operand, the operand with signed
+// integer type shall be converted to the type of the operand with unsigned integer type.
+//
+// C: ISO/IEC 14882:2011(E) p86 section 4.13 Integer conversion rank
+// [...] The rank of long long int shall be greater than the rank of long int,
+// which shall be greater than the rank of int, which shall be greater than the
+// rank of short int, which shall be greater than the rank of signed char.
+// — The rank of any unsigned integer type shall equal the rank of the corresponding
+// signed integer type.
+//
+// D: ISO/IEC 14882:2011(E) p75 section 3.9.1 Fundamental types
+// [...] Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo
+// 2^n where n is the number of bits in the value representation of that particular
+// size of integer.
+//
+// Note:
+// Other libraries do exist for safe integer operations which can detect the
+// possibility of overflow (SafeInt from MS and safe-iop in android).
+// Signed safe computation is also possible from the art header safe_math.h.
+
+template <typename T> class Modulo {
+    T mValue;
+
+public:
+    typedef typename std::make_signed<T>::type signedT;
+    typedef typename std::make_unsigned<T>::type unsignedT;
+
+    Modulo() { } // intentionally uninitialized data
+    Modulo(const T &value) { mValue = value; }
+    const T & value() const { return mValue; } // not assignable
+    signedT signedValue() const { return mValue; }
+    unsignedT unsignedValue() const { return mValue; }
+    void getValue(T *value) const { *value = mValue; } // more type safe than value()
+
+    // modular operations valid only if size of T <= size of S.
+    template <typename S>
+    __attribute__((no_sanitize("integer")))
+    Modulo<T> operator +=(const Modulo<S> &other) {
+        static_assert(sizeof(T) <= sizeof(S), "argument size mismatch");
+        mValue += other.unsignedValue();
+        return *this;
+    }
+
+    template <typename S>
+    __attribute__((no_sanitize("integer")))
+    Modulo<T> operator -=(const Modulo<S> &other) {
+        static_assert(sizeof(T) <= sizeof(S), "argument size mismatch");
+        mValue -= other.unsignedValue();
+        return *this;
+    }
+
+    // modular operations resulting in a value valid only at the smaller of the two
+    // Modulo base type sizes, but we only allow equal sizes to avoid confusion.
+    template <typename S>
+    __attribute__((no_sanitize("integer")))
+    const Modulo<T> operator +(const Modulo<S> &other) const {
+        static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+        return Modulo<T>(mValue + other.unsignedValue());
+    }
+
+    template <typename S>
+    __attribute__((no_sanitize("integer")))
+    const Modulo<T> operator -(const Modulo<S> &other) const {
+        static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+        return Modulo<T>(mValue - other.unsignedValue());
+    }
+
+    // modular operations that should be checked only at the smaller of
+    // the two type sizes, but we only allow equal sizes to avoid confusion.
+    //
+    // Caution: These relational and comparison operations are not equivalent to
+    // the base type operations.
+    template <typename S>
+    __attribute__((no_sanitize("integer")))
+    bool operator >(const Modulo<S> &other) const {
+        static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+        return static_cast<signedT>(mValue - other.unsignedValue()) > 0;
+    }
+
+    template <typename S>
+    __attribute__((no_sanitize("integer")))
+    bool operator >=(const Modulo<S> &other) const {
+        static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+        return static_cast<signedT>(mValue - other.unsignedValue()) >= 0;
+    }
+
+    template <typename S>
+    __attribute__((no_sanitize("integer")))
+    bool operator ==(const Modulo<S> &other) const {
+        static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+        return static_cast<signedT>(mValue - other.unsignedValue()) == 0;
+    }
+
+    template <typename S>
+    __attribute__((no_sanitize("integer")))
+    bool operator <=(const Modulo<S> &other) const {
+        static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+        return static_cast<signedT>(mValue - other.unsignedValue()) <= 0;
+    }
+
+    template <typename S>
+    __attribute__((no_sanitize("integer")))
+    bool operator <(const Modulo<S> &other) const {
+        static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+        return static_cast<signedT>(mValue - other.unsignedValue()) < 0;
+    }
+
+
+    // modular operations with a non-Modulo type allowed with wrapping
+    // because there should be no confusion as to the meaning.
+    template <typename S>
+    __attribute__((no_sanitize("integer")))
+    Modulo<T> operator +=(const S &other) {
+        mValue += unsignedT(other);
+        return *this;
+    }
+
+    template <typename S>
+    __attribute__((no_sanitize("integer")))
+    Modulo<T> operator -=(const S &other) {
+        mValue -= unsignedT(other);
+        return *this;
+    }
+
+    // modular operations with a non-Modulo type allowed with wrapping,
+    // but we restrict this only when size of T is greater than or equal to
+    // the size of S to avoid confusion with the nature of overflow.
+    //
+    // Use of this follows left-associative style.
+    //
+    // Note: a Modulo type may be promoted by using "differences" off of
+    // a larger sized type, but we do not automate this.
+    template <typename S>
+    __attribute__((no_sanitize("integer")))
+    const Modulo<T> operator +(const S &other) const {
+        static_assert(sizeof(T) >= sizeof(S), "argument size mismatch");
+        return Modulo<T>(mValue + unsignedT(other));
+    }
+
+    template <typename S>
+    __attribute__((no_sanitize("integer")))
+    const Modulo<T> operator -(const S &other) const {
+        static_assert(sizeof(T) >= sizeof(S), "argument size mismatch");
+        return Modulo<T>(mValue - unsignedT(other));
+    }
+
+    // multiply is intentionally omitted, but it is a common operator in
+    // modular arithmetic.
+
+    // shift operations are intentionally omitted, but perhaps useful.
+    // For example, left-shifting a negative number is undefined in C++11.
+};
+
+} // namespace android
+
+#endif /* ANDROID_MODULO_H */
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 3fe749c..00df523 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -215,7 +215,6 @@
                     const KeyedVector<String8, String8> *headers);
 
             status_t        setDataSource(int fd, int64_t offset, int64_t length);
-            status_t        setDataSource(const sp<IStreamSource> &source);
             status_t        setDataSource(const sp<IDataSource> &source);
             status_t        setVideoSurfaceTexture(
                                     const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 15ff82d..64e3660 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -95,6 +95,7 @@
     VIDEO_ENCODER_H264 = 2,
     VIDEO_ENCODER_MPEG_4_SP = 3,
     VIDEO_ENCODER_VP8 = 4,
+    VIDEO_ENCODER_HEVC = 5,
 
     VIDEO_ENCODER_LIST_END // must be the last - used to validate the video encoder type
 };
@@ -233,6 +234,8 @@
     status_t    start();
     status_t    stop();
     status_t    reset();
+    status_t    pause();
+    status_t    resume();
     status_t    init();
     status_t    close();
     status_t    release();
diff --git a/include/media/nbaio/AudioBufferProviderSource.h b/include/media/nbaio/AudioBufferProviderSource.h
index b16e20a..4747dcf 100644
--- a/include/media/nbaio/AudioBufferProviderSource.h
+++ b/include/media/nbaio/AudioBufferProviderSource.h
@@ -42,9 +42,8 @@
     //virtual size_t framesOverrun();
     //virtual size_t overruns();
     virtual ssize_t availableToRead();
-    virtual ssize_t read(void *buffer, size_t count, int64_t readPTS);
-    virtual ssize_t readVia(readVia_t via, size_t total, void *user,
-                            int64_t readPTS, size_t block);
+    virtual ssize_t read(void *buffer, size_t count);
+    virtual ssize_t readVia(readVia_t via, size_t total, void *user, size_t block);
 
 private:
     AudioBufferProvider * const mProvider;
diff --git a/include/media/nbaio/AudioStreamInSource.h b/include/media/nbaio/AudioStreamInSource.h
index 5169f1e..eaea63c 100644
--- a/include/media/nbaio/AudioStreamInSource.h
+++ b/include/media/nbaio/AudioStreamInSource.h
@@ -45,7 +45,7 @@
     // FIXME Use an audio HAL API to query the buffer filling status when it's available.
     virtual ssize_t availableToRead() { return mStreamBufferSizeBytes / mFrameSize; }
 
-    virtual ssize_t read(void *buffer, size_t count, int64_t readPTS);
+    virtual ssize_t read(void *buffer, size_t count);
 
     // NBAIO_Sink end
 
diff --git a/include/media/nbaio/AudioStreamOutSink.h b/include/media/nbaio/AudioStreamOutSink.h
index 9949b88..0998d45 100644
--- a/include/media/nbaio/AudioStreamOutSink.h
+++ b/include/media/nbaio/AudioStreamOutSink.h
@@ -47,11 +47,6 @@
 
     virtual ssize_t write(const void *buffer, size_t count);
 
-    // AudioStreamOutSink wraps a HAL's output stream.  Its
-    // getNextWriteTimestamp method is simply a passthru to the HAL's underlying
-    // implementation of GNWT (if any)
-    virtual status_t getNextWriteTimestamp(int64_t *timestamp);
-
     virtual status_t getTimestamp(AudioTimestamp& timestamp);
 
     // NBAIO_Sink end
diff --git a/include/media/nbaio/MonoPipe.h b/include/media/nbaio/MonoPipe.h
index b09b35f..df9cafe 100644
--- a/include/media/nbaio/MonoPipe.h
+++ b/include/media/nbaio/MonoPipe.h
@@ -18,7 +18,6 @@
 #define ANDROID_AUDIO_MONO_PIPE_H
 
 #include <time.h>
-#include <utils/LinearTransform.h>
 #include "NBAIO.h"
 #include <media/SingleStateQueue.h>
 
@@ -60,20 +59,6 @@
     virtual ssize_t write(const void *buffer, size_t count);
     //virtual ssize_t writeVia(writeVia_t via, size_t total, void *user, size_t block);
 
-    // MonoPipe's implementation of getNextWriteTimestamp works in conjunction
-    // with MonoPipeReader.  Every time a MonoPipeReader reads from the pipe, it
-    // receives a "readPTS" indicating the point in time for which the reader
-    // would like to read data.  This "last read PTS" is offset by the amt of
-    // data the reader is currently mixing and then cached cached along with the
-    // updated read pointer.  This cached value is the local time for which the
-    // reader is going to request data next time it reads data (assuming we are
-    // in steady state and operating with no underflows).  Writers to the
-    // MonoPipe who would like to know when their next write operation will hit
-    // the speakers can call getNextWriteTimestamp which will return the value
-    // of the last read PTS plus the duration of the amt of data waiting to be
-    // read in the MonoPipe.
-    virtual status_t getNextWriteTimestamp(int64_t *timestamp);
-
             // average number of frames present in the pipe under normal conditions.
             // See throttling mechanism in MonoPipe::write()
             size_t  getAvgFrames() const { return mSetpoint; }
@@ -95,43 +80,21 @@
             status_t getTimestamp(AudioTimestamp& timestamp);
 
 private:
-    // A pair of methods and a helper variable which allows the reader and the
-    // writer to update and observe the values of mFront and mNextRdPTS in an
-    // atomic lock-less fashion.
-    //
-    // :: Important ::
-    // Two assumptions must be true in order for this lock-less approach to
-    // function properly on all systems.  First, there may only be one updater
-    // thread in the system.  Second, the updater thread must be running at a
-    // strictly higher priority than the observer threads.  Currently, both of
-    // these assumptions are true.  The only updater is always a single
-    // FastMixer thread (which runs with SCHED_FIFO/RT priority while the only
-    // observer is always an AudioFlinger::PlaybackThread running with
-    // traditional (non-RT) audio priority.
-    void updateFrontAndNRPTS(int32_t newFront, int64_t newNextRdPTS);
-    void observeFrontAndNRPTS(int32_t *outFront, int64_t *outNextRdPTS);
-    volatile int32_t mUpdateSeq;
-
     const size_t    mReqFrames;     // as requested in constructor, unrounded
     const size_t    mMaxFrames;     // always a power of 2
     void * const    mBuffer;
     // mFront and mRear will never be separated by more than mMaxFrames.
     // 32-bit overflow is possible if the pipe is active for a long time, but if that happens it's
     // safe because we "&" with (mMaxFrames-1) at end of computations to calculate a buffer index.
-    volatile int32_t mFront;        // written by the reader with updateFrontAndNRPTS, observed by
-                                    // the writer with observeFrontAndNRPTS
+    volatile int32_t mFront;        // written by reader with android_atomic_release_store,
+                                    // read by writer with android_atomic_acquire_load
     volatile int32_t mRear;         // written by writer with android_atomic_release_store,
                                     // read by reader with android_atomic_acquire_load
-    volatile int64_t mNextRdPTS;    // written by the reader with updateFrontAndNRPTS, observed by
-                                    // the writer with observeFrontAndNRPTS
     bool            mWriteTsValid;  // whether mWriteTs is valid
     struct timespec mWriteTs;       // time that the previous write() completed
     size_t          mSetpoint;      // target value for pipe fill depth
     const bool      mWriteCanBlock; // whether write() should block if the pipe is full
 
-    int64_t offsetTimestampByAudioFrames(int64_t ts, size_t audFrames);
-    LinearTransform mSamplesToLocalTime;
-
     bool            mIsShutdown;    // whether shutdown(true) was called, no barriers are needed
 
     AudioTimestampSingleStateQueue::Shared      mTimestampShared;
diff --git a/include/media/nbaio/MonoPipeReader.h b/include/media/nbaio/MonoPipeReader.h
index 78fe867..4a7c3c5 100644
--- a/include/media/nbaio/MonoPipeReader.h
+++ b/include/media/nbaio/MonoPipeReader.h
@@ -47,7 +47,7 @@
 
     virtual ssize_t availableToRead();
 
-    virtual ssize_t read(void *buffer, size_t count, int64_t readPTS);
+    virtual ssize_t read(void *buffer, size_t count);
 
     virtual void    onTimestamp(const AudioTimestamp& timestamp);
 
diff --git a/include/media/nbaio/NBAIO.h b/include/media/nbaio/NBAIO.h
index d9bbc8d..2f7e291 100644
--- a/include/media/nbaio/NBAIO.h
+++ b/include/media/nbaio/NBAIO.h
@@ -79,8 +79,7 @@
 
 // Callbacks used by NBAIO_Sink::writeVia() and NBAIO_Source::readVia() below.
 typedef ssize_t (*writeVia_t)(void *user, void *buffer, size_t count);
-typedef ssize_t (*readVia_t)(void *user, const void *buffer,
-                             size_t count, int64_t readPTS);
+typedef ssize_t (*readVia_t)(void *user, const void *buffer, size_t count);
 
 // Check whether an NBAIO_Format is valid
 bool Format_isValid(const NBAIO_Format& format);
@@ -210,21 +209,6 @@
     //  < 0     status_t error occurred prior to the first frame transfer during this callback.
     virtual ssize_t writeVia(writeVia_t via, size_t total, void *user, size_t block = 0);
 
-    // Get the time (on the LocalTime timeline) at which the first frame of audio of the next write
-    // operation to this sink will be eventually rendered by the HAL.
-    // Inputs:
-    //  ts      A pointer pointing to the int64_t which will hold the result.
-    // Return value:
-    //  OK      Everything went well, *ts holds the time at which the first audio frame of the next
-    //          write operation will be rendered, or AudioBufferProvider::kInvalidPTS if this sink
-    //          does not know the answer for some reason.  Sinks which eventually lead to a HAL
-    //          which implements get_next_write_timestamp may return Invalid temporarily if the DMA
-    //          output of the audio driver has not started yet.  Sinks which lead to a HAL which
-    //          does not implement get_next_write_timestamp, or which don't lead to a HAL at all,
-    //          will always return kInvalidPTS.
-    //  <other> Something unexpected happened internally.  Check the logs and start debugging.
-    virtual status_t getNextWriteTimestamp(int64_t *ts) { return INVALID_OPERATION; }
-
     // Returns NO_ERROR if a timestamp is available.  The timestamp includes the total number
     // of frames presented to an external observer, together with the value of CLOCK_MONOTONIC
     // as of this presentation count.  The timestamp parameter is undefined if error is returned.
@@ -271,8 +255,6 @@
     // Inputs:
     //  buffer  Non-NULL destination buffer owned by consumer.
     //  count   Maximum number of frames to transfer.
-    //  readPTS The presentation time (on the LocalTime timeline) for which data
-    //          is being requested, or kInvalidPTS if not known.
     // Return value:
     //  > 0     Number of frames successfully transferred prior to first error.
     //  = 0     Count was zero.
@@ -282,7 +264,7 @@
     //  WOULD_BLOCK No frames can be transferred without blocking.
     //  OVERRUN     read() has not been called frequently enough, or with enough frames to keep up.
     //              One or more frames were lost due to overrun, try again to read more recent data.
-    virtual ssize_t read(void *buffer, size_t count, int64_t readPTS) = 0;
+    virtual ssize_t read(void *buffer, size_t count) = 0;
 
     // Transfer data from source using a series of callbacks.  More suitable for zero-fill,
     // synthesis, and non-contiguous transfers (e.g. circular buffer or readv).
@@ -291,8 +273,6 @@
     //  total   Estimate of the number of frames the consumer desires.  This is an estimate,
     //          and it can consume a different number of frames during the series of callbacks.
     //  user    Arbitrary void * reserved for data consumer.
-    //  readPTS The presentation time (on the LocalTime timeline) for which data
-    //          is being requested, or kInvalidPTS if not known.
     //  block   Number of frames per block, that is a suggested value for 'count' in each callback.
     //          Zero means no preference.  This parameter is a hint only, and may be ignored.
     // Return value:
@@ -315,8 +295,7 @@
     //  > 0     Number of frames successfully transferred during this callback prior to first error.
     //  = 0     Count was zero.
     //  < 0     status_t error occurred prior to the first frame transfer during this callback.
-    virtual ssize_t readVia(readVia_t via, size_t total, void *user,
-                            int64_t readPTS, size_t block = 0);
+    virtual ssize_t readVia(readVia_t via, size_t total, void *user, size_t block = 0);
 
     // Invoked asynchronously by corresponding sink when a new timestamp is available.
     // Default implementation ignores the timestamp.
diff --git a/include/media/nbaio/PipeReader.h b/include/media/nbaio/PipeReader.h
index 350e6ab..398353b 100644
--- a/include/media/nbaio/PipeReader.h
+++ b/include/media/nbaio/PipeReader.h
@@ -45,7 +45,7 @@
 
     virtual ssize_t availableToRead();
 
-    virtual ssize_t read(void *buffer, size_t count, int64_t readPTS);
+    virtual ssize_t read(void *buffer, size_t count);
 
     // NBAIO_Source end
 
diff --git a/include/media/nbaio/SourceAudioBufferProvider.h b/include/media/nbaio/SourceAudioBufferProvider.h
index daf6bc3..29172e1 100644
--- a/include/media/nbaio/SourceAudioBufferProvider.h
+++ b/include/media/nbaio/SourceAudioBufferProvider.h
@@ -31,7 +31,7 @@
     virtual ~SourceAudioBufferProvider();
 
     // AudioBufferProvider interface
-    virtual status_t getNextBuffer(Buffer *buffer, int64_t pts);
+    virtual status_t getNextBuffer(Buffer *buffer);
     virtual void     releaseBuffer(Buffer *buffer);
 
     // ExtendedAudioBufferProvider interface
diff --git a/include/media/stagefright/AACWriter.h b/include/media/stagefright/AACWriter.h
index aa60a19..a1f63d7 100644
--- a/include/media/stagefright/AACWriter.h
+++ b/include/media/stagefright/AACWriter.h
@@ -31,7 +31,7 @@
 
     status_t initCheck() const;
 
-    virtual status_t addSource(const sp<MediaSource> &source);
+    virtual status_t addSource(const sp<IMediaSource> &source);
     virtual bool reachedEOS();
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop() { return reset(); }
@@ -48,7 +48,7 @@
 
     int   mFd;
     status_t mInitCheck;
-    sp<MediaSource> mSource;
+    sp<IMediaSource> mSource;
     bool mStarted;
     volatile bool mPaused;
     volatile bool mResumed;
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 743a0fd..349db64 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -72,15 +72,17 @@
         size_t countBuffers();
         IOMX::buffer_id bufferIDAt(size_t index) const;
         sp<ABuffer> bufferAt(size_t index) const;
+        sp<RefBase> memRefAt(size_t index) const;
 
     private:
         friend struct ACodec;
 
         Vector<IOMX::buffer_id> mBufferIDs;
         Vector<sp<ABuffer> > mBuffers;
+        Vector<sp<RefBase> > mMemRefs;
 
         PortDescription();
-        void addBuffer(IOMX::buffer_id id, const sp<ABuffer> &buffer);
+        void addBuffer(IOMX::buffer_id id, const sp<ABuffer> &buffer, const sp<RefBase> &memRef);
 
         DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
     };
@@ -182,6 +184,7 @@
         unsigned mDequeuedAt;
 
         sp<ABuffer> mData;
+        sp<RefBase> mMemRef;
         sp<GraphicBuffer> mGraphicBuffer;
         int mFenceFd;
         FrameRenderTracker::Info *mRenderInfo;
@@ -374,6 +377,8 @@
 
     status_t setPriority(int32_t priority);
     status_t setOperatingRate(float rateFloat, bool isVideo);
+    status_t getIntraRefreshPeriod(uint32_t *intraRefreshPeriod);
+    status_t setIntraRefreshPeriod(uint32_t intraRefreshPeriod, bool inConfigure);
 
     status_t setMinBufferSize(OMX_U32 portIndex, size_t size);
 
diff --git a/include/media/stagefright/AMRWriter.h b/include/media/stagefright/AMRWriter.h
index b38be55..fbbdf2e 100644
--- a/include/media/stagefright/AMRWriter.h
+++ b/include/media/stagefright/AMRWriter.h
@@ -20,12 +20,12 @@
 
 #include <stdio.h>
 
+#include <media/IMediaSource.h>
 #include <media/stagefright/MediaWriter.h>
 #include <utils/threads.h>
 
 namespace android {
 
-struct MediaSource;
 class MetaData;
 
 struct AMRWriter : public MediaWriter {
@@ -33,7 +33,7 @@
 
     status_t initCheck() const;
 
-    virtual status_t addSource(const sp<MediaSource> &source);
+    virtual status_t addSource(const sp<IMediaSource> &source);
     virtual bool reachedEOS();
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop() { return reset(); }
@@ -45,7 +45,7 @@
 private:
     int   mFd;
     status_t mInitCheck;
-    sp<MediaSource> mSource;
+    sp<IMediaSource> mSource;
     bool mStarted;
     volatile bool mPaused;
     volatile bool mResumed;
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 86ce50d..f7499b6 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -18,6 +18,7 @@
 
 #define AUDIO_PLAYER_H_
 
+#include <media/IMediaSource.h>
 #include <media/MediaPlayerInterface.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <utils/threads.h>
@@ -27,7 +28,6 @@
 struct AudioPlaybackRate;
 class AudioTrack;
 struct AwesomePlayer;
-class MediaSource;
 
 class AudioPlayer {
 public:
@@ -50,7 +50,7 @@
     virtual ~AudioPlayer();
 
     // Caller retains ownership of "source".
-    void setSource(const sp<MediaSource> &source);
+    void setSource(const sp<IMediaSource> &source);
 
     status_t start(bool sourceAlreadyStarted = false);
 
@@ -66,7 +66,7 @@
     status_t getPlaybackRate(AudioPlaybackRate *rate /* nonnull */);
 
 private:
-    sp<MediaSource> mSource;
+    sp<IMediaSource> mSource;
     sp<AudioTrack> mAudioTrack;
 
     MediaBuffer *mInputBuffer;
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 069e897..3d00d30 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -23,6 +23,7 @@
 #include <camera/ICamera.h>
 #include <camera/ICameraRecordingProxyListener.h>
 #include <camera/CameraParameters.h>
+#include <gui/BufferItemConsumer.h>
 #include <utils/List.h>
 #include <utils/RefBase.h>
 #include <utils/String16.h>
@@ -60,6 +61,8 @@
      *          permissions checking.
      * @param clientUid the UID of the camera-using application if camera is
      *          NULL; otherwise ignored. Used for permissions checking.
+     * @param clientPid the PID of the camera-using application if camera is
+     *          NULL; otherwise ignored. Used for permissions checking.
      * @param videoSize the dimension (in pixels) of the video frame
      * @param frameRate the target frames per second
      * @param surface the preview surface for display where preview
@@ -80,6 +83,7 @@
                                           int32_t cameraId,
                                           const String16& clientName,
                                           uid_t clientUid,
+                                          pid_t clientPid,
                                           Size videoSize,
                                           int32_t frameRate,
                                           const sp<IGraphicBufferProducer>& surface,
@@ -122,6 +126,12 @@
     virtual void signalBufferReturned(MediaBuffer* buffer);
 
 protected:
+
+    /**
+     * The class for listening to BnCameraRecordingProxyListener. This is used to receive video
+     * buffers in VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV and VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA
+     * mode. When a frame is available, CameraSource::dataCallbackTimestamp() will be called.
+     */
     class ProxyListener: public BnCameraRecordingProxyListener {
     public:
         ProxyListener(const sp<CameraSource>& source);
@@ -132,6 +142,28 @@
         sp<CameraSource> mSource;
     };
 
+    /**
+     * The class for listening to BufferQueue's onFrameAvailable. This is used to receive video
+     * buffers in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode. When a frame is available,
+     * CameraSource::processBufferQueueFrame() will be called.
+     */
+    class BufferQueueListener : public Thread,  public BufferItemConsumer::FrameAvailableListener {
+    public:
+        BufferQueueListener(const sp<BufferItemConsumer> &consumer,
+                const sp<CameraSource> &cameraSource);
+        virtual void onFrameAvailable(const BufferItem& item);
+        virtual bool threadLoop();
+    private:
+        static const nsecs_t kFrameAvailableTimeout = 50000000; // 50ms
+
+        sp<BufferItemConsumer> mConsumer;
+        sp<CameraSource> mCameraSource;
+
+        Mutex mLock;
+        Condition mFrameAvailableSignal;
+        bool mFrameAvailable;
+    };
+
     // isBinderAlive needs linkToDeath to work.
     class DeathNotifier: public IBinder::DeathRecipient {
     public:
@@ -169,7 +201,7 @@
     int64_t mTimeBetweenFrameCaptureUs;
 
     CameraSource(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
-                 int32_t cameraId, const String16& clientName, uid_t clientUid,
+                 int32_t cameraId, const String16& clientName, uid_t clientUid, pid_t clientPid,
                  Size videoSize, int32_t frameRate,
                  const sp<IGraphicBufferProducer>& surface,
                  bool storeMetaDataInVideoBuffers);
@@ -204,26 +236,49 @@
     int32_t mNumGlitches;
     int64_t mGlitchDurationThresholdUs;
     bool mCollectStats;
-    bool mIsMetaDataStoredInVideoBuffers;
+
+    // The mode video buffers are received from camera. One of VIDEO_BUFFER_MODE_*.
+    int32_t mVideoBufferMode;
+
+    /**
+     * The following variables are used in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
+     */
+    static const size_t kConsumerBufferCount = 8;
+    // Consumer and producer of the buffer queue between this class and camera.
+    sp<BufferItemConsumer> mVideoBufferConsumer;
+    sp<IGraphicBufferProducer> mVideoBufferProducer;
+    // Memory used to send the buffers to encoder, where sp<IMemory> stores VideoNativeMetadata.
+    sp<IMemoryHeap> mMemoryHeapBase;
+    List<sp<IMemory>> mMemoryBases;
+    // A mapping from ANativeWindowBuffer sent to encoder to BufferItem received from camera.
+    // This is protected by mLock.
+    KeyedVector<ANativeWindowBuffer*, BufferItem> mReceivedBufferItemMap;
+    sp<BufferQueueListener> mBufferQueueListener;
 
     void releaseQueuedFrames();
     void releaseOneRecordingFrame(const sp<IMemory>& frame);
-
+    // Process a buffer item received in BufferQueueListener.
+    void processBufferQueueFrame(const BufferItem& buffer);
 
     status_t init(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
-                  int32_t cameraId, const String16& clientName, uid_t clientUid,
+                  int32_t cameraId, const String16& clientName, uid_t clientUid, pid_t clientPid,
                   Size videoSize, int32_t frameRate, bool storeMetaDataInVideoBuffers);
 
     status_t initWithCameraAccess(
                   const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
-                  int32_t cameraId, const String16& clientName, uid_t clientUid,
+                  int32_t cameraId, const String16& clientName, uid_t clientUid, pid_t clientPid,
                   Size videoSize, int32_t frameRate, bool storeMetaDataInVideoBuffers);
 
+    // Initialize the buffer queue used in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
+    status_t initBufferQueue(uint32_t width, uint32_t height, uint32_t format,
+                  android_dataspace dataSpace, uint32_t bufferCount);
+
     status_t isCameraAvailable(const sp<ICamera>& camera,
                                const sp<ICameraRecordingProxy>& proxy,
                                int32_t cameraId,
                                const String16& clientName,
-                               uid_t clientUid);
+                               uid_t clientUid,
+                               pid_t clientPid);
 
     status_t isCameraColorFormatSupported(const CameraParameters& params);
     status_t configureCamera(CameraParameters* params,
@@ -236,6 +291,10 @@
     status_t checkFrameRate(const CameraParameters& params,
                     int32_t frameRate);
 
+    // Check if this frame should be skipped based on the frame's timestamp in microsecond.
+    // mLock must be locked before calling this function.
+    bool shouldSkipFrameLocked(int64_t timestampUs);
+
     void stopCameraRecording();
     status_t reset();
 
diff --git a/include/media/stagefright/CameraSourceTimeLapse.h b/include/media/stagefright/CameraSourceTimeLapse.h
index 34213be..1023027 100644
--- a/include/media/stagefright/CameraSourceTimeLapse.h
+++ b/include/media/stagefright/CameraSourceTimeLapse.h
@@ -38,6 +38,7 @@
         int32_t cameraId,
         const String16& clientName,
         uid_t clientUid,
+        pid_t clientPid,
         Size videoSize,
         int32_t videoFrameRate,
         const sp<IGraphicBufferProducer>& surface,
@@ -114,6 +115,7 @@
         int32_t cameraId,
         const String16& clientName,
         uid_t clientUid,
+        pid_t clientPid,
         Size videoSize,
         int32_t videoFrameRate,
         const sp<IGraphicBufferProducer>& surface,
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
index 1a2bcdb..01b744b 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -77,6 +77,7 @@
         virtual size_t countBuffers() = 0;
         virtual IOMX::buffer_id bufferIDAt(size_t index) const = 0;
         virtual sp<ABuffer> bufferAt(size_t index) const = 0;
+        virtual sp<RefBase> memRefAt(size_t index) const { return NULL; }
 
     protected:
         PortDescription();
diff --git a/include/media/stagefright/MPEG2TSWriter.h b/include/media/stagefright/MPEG2TSWriter.h
index 3d7960b..4516fb6 100644
--- a/include/media/stagefright/MPEG2TSWriter.h
+++ b/include/media/stagefright/MPEG2TSWriter.h
@@ -34,7 +34,7 @@
             void *cookie,
             ssize_t (*write)(void *cookie, const void *data, size_t size));
 
-    virtual status_t addSource(const sp<MediaSource> &source);
+    virtual status_t addSource(const sp<IMediaSource> &source);
     virtual status_t start(MetaData *param = NULL);
     virtual status_t stop() { return reset(); }
     virtual status_t pause();
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index a195fe8..a6901a8 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -20,6 +20,7 @@
 
 #include <stdio.h>
 
+#include <media/IMediaSource.h>
 #include <media/stagefright/MediaWriter.h>
 #include <utils/List.h>
 #include <utils/threads.h>
@@ -28,7 +29,6 @@
 
 class AMessage;
 class MediaBuffer;
-class MediaSource;
 class MetaData;
 
 class MPEG4Writer : public MediaWriter {
@@ -39,7 +39,7 @@
     // 1. No more than 2 tracks can be added
     // 2. Only video or audio source can be added
     // 3. No more than one video and/or one audio source can be added.
-    virtual status_t addSource(const sp<MediaSource> &source);
+    virtual status_t addSource(const sp<IMediaSource> &source);
 
     // Returns INVALID_OPERATION if there is no source or track.
     virtual status_t start(MetaData *param = NULL);
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index c8a50e8..1e0c7d4 100644
--- a/include/media/stagefright/MediaBuffer.h
+++ b/include/media/stagefright/MediaBuffer.h
@@ -22,6 +22,7 @@
 
 #include <pthread.h>
 
+#include <binder/MemoryDealer.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
@@ -93,6 +94,8 @@
 private:
     friend class MediaBufferGroup;
     friend class OMXDecoder;
+    friend class BnMediaSource;
+    friend class BpMediaSource;
 
     // For use by OMXDecoder, reference count must be 1, drop reference
     // count to 0 without signalling the observer.
@@ -118,6 +121,7 @@
 
     MediaBuffer(const MediaBuffer &);
     MediaBuffer &operator=(const MediaBuffer &);
+    sp<IMemory> mMemory;
 };
 
 }  // namespace android
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index c187e4b..ea708e3 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -125,6 +125,7 @@
             const uint8_t key[16],
             const uint8_t iv[16],
             CryptoPlugin::Mode mode,
+            const CryptoPlugin::Pattern &pattern,
             int64_t presentationTimeUs,
             uint32_t flags,
             AString *errorDetailMsg = NULL);
@@ -253,6 +254,7 @@
     struct BufferInfo {
         uint32_t mBufferID;
         sp<ABuffer> mData;
+        sp<RefBase> mMemRef;
         sp<ABuffer> mEncryptedData;
         sp<IMemory> mSharedEncryptedBuffer;
         sp<AMessage> mNotify;
@@ -355,8 +357,8 @@
     status_t init(const AString &name, bool nameIsType, bool encoder);
 
     void setState(State newState);
-    void returnBuffersToCodec();
-    void returnBuffersToCodecOnPort(int32_t portIndex);
+    void returnBuffersToCodec(bool isReclaim = false);
+    void returnBuffersToCodecOnPort(int32_t portIndex, bool isReclaim = false);
     size_t updateBuffers(int32_t portIndex, const sp<AMessage> &msg);
     status_t onQueueInputBuffer(const sp<AMessage> &msg);
     status_t onReleaseOutputBuffer(const sp<AMessage> &msg);
diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h
index d8c70fe..e3f3f5e 100644
--- a/include/media/stagefright/MediaCodecSource.h
+++ b/include/media/stagefright/MediaCodecSource.h
@@ -50,6 +50,7 @@
 
     bool isVideo() const { return mIsVideo; }
     sp<IGraphicBufferProducer> getGraphicBufferProducer();
+    void setInputBufferTimeOffset(int64_t timeOffsetUs);
 
     // MediaSource
     virtual status_t start(MetaData *params = NULL);
@@ -78,6 +79,7 @@
         kWhatStart,
         kWhatStop,
         kWhatPause,
+        kWhatSetInputBufferTimeOffset,
         kWhatStopStalled,
     };
 
@@ -121,6 +123,7 @@
     List<MediaBuffer *> mInputBufferQueue;
     List<size_t> mAvailEncoderInputIndices;
     List<int64_t> mDecodingTimeQueue; // decoding time (us) for video
+    int64_t mInputBufferTimeOffsetUs;
 
     // audio drift time
     int64_t mFirstSampleTimeUs;
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 21eb04a..e5bcec6 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -30,6 +30,7 @@
 extern const char *MEDIA_MIMETYPE_VIDEO_H263;
 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_AUDIO_AMR_NB;
 extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
@@ -64,6 +65,7 @@
 extern const char *MEDIA_MIMETYPE_TEXT_SUBRIP;
 extern const char *MEDIA_MIMETYPE_TEXT_VTT;
 extern const char *MEDIA_MIMETYPE_TEXT_CEA_608;
+extern const char *MEDIA_MIMETYPE_TEXT_CEA_708;
 extern const char *MEDIA_MIMETYPE_DATA_TIMED_ID3;
 
 }  // namespace android
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 183933a..6bf8c9e 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -18,7 +18,8 @@
 
 #define MEDIA_EXTRACTOR_H_
 
-#include <utils/RefBase.h>
+#include <media/IMediaExtractor.h>
+#include <media/IMediaSource.h>
 
 namespace android {
 
@@ -26,13 +27,15 @@
 class MediaSource;
 class MetaData;
 
-class MediaExtractor : public RefBase {
+class MediaExtractor : public BnMediaExtractor {
 public:
-    static sp<MediaExtractor> Create(
+    static sp<IMediaExtractor> Create(
+            const sp<DataSource> &source, const char *mime = NULL);
+    static sp<MediaExtractor> CreateFromService(
             const sp<DataSource> &source, const char *mime = NULL);
 
     virtual size_t countTracks() = 0;
-    virtual sp<MediaSource> getTrack(size_t index) = 0;
+    virtual sp<IMediaSource> getTrack(size_t index) = 0;
 
     enum GetTrackMetaDataFlags {
         kIncludeExtensiveMetaData = 1
@@ -68,8 +71,10 @@
     virtual void setUID(uid_t uid) {
     }
 
+    virtual const char * name() { return "<unspecified>"; }
+
 protected:
-    MediaExtractor() : mIsDrm(false) {}
+    MediaExtractor();
     virtual ~MediaExtractor() {}
 
 private:
diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h
index ed0d578..1bd3ed0 100644
--- a/include/media/stagefright/MediaSource.h
+++ b/include/media/stagefright/MediaSource.h
@@ -20,6 +20,7 @@
 
 #include <sys/types.h>
 
+#include <media/IMediaSource.h>
 #include <media/stagefright/MediaErrors.h>
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
@@ -29,7 +30,7 @@
 class MediaBuffer;
 class MetaData;
 
-struct MediaSource : public virtual RefBase {
+struct MediaSource : public BnMediaSource {
     MediaSource();
 
     // To be called before any other methods on this object, except
@@ -47,8 +48,6 @@
     // Returns the format of the data output by this media source.
     virtual sp<MetaData> getFormat() = 0;
 
-    struct ReadOptions;
-
     // Returns a new buffer of data. Call blocks until a
     // buffer is available, an error is encountered of the end of the stream
     // is reached.
@@ -59,48 +58,9 @@
     virtual status_t read(
             MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
 
-    // Options that modify read() behaviour. The default is to
-    // a) not request a seek
-    // b) not be late, i.e. lateness_us = 0
-    struct ReadOptions {
-        enum SeekMode {
-            SEEK_PREVIOUS_SYNC,
-            SEEK_NEXT_SYNC,
-            SEEK_CLOSEST_SYNC,
-            SEEK_CLOSEST,
-        };
-
-        ReadOptions();
-
-        // Reset everything back to defaults.
-        void reset();
-
-        void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);
-        void clearSeekTo();
-        bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
-
-        void setLateBy(int64_t lateness_us);
-        int64_t getLateBy() const;
-
-        void setNonBlocking();
-        void clearNonBlocking();
-        bool getNonBlocking() const;
-
-    private:
-        enum Options {
-            kSeekTo_Option      = 1,
-        };
-
-        uint32_t mOptions;
-        int64_t mSeekTimeUs;
-        SeekMode mSeekMode;
-        int64_t mLatenessUs;
-        bool mNonBlocking;
-    };
-
     // Causes this source to suspend pulling data from its upstream source
     // until a subsequent read-with-seek. This is currently not supported
-    // as such by any source. E.g. MediaCodecSource does not susped its
+    // as such by any source. E.g. MediaCodecSource does not suspend its
     // upstream source, and instead discard upstream data while paused.
     virtual status_t pause() {
         return ERROR_UNSUPPORTED;
diff --git a/include/media/stagefright/MediaWriter.h b/include/media/stagefright/MediaWriter.h
index 8e02506..b6476c9 100644
--- a/include/media/stagefright/MediaWriter.h
+++ b/include/media/stagefright/MediaWriter.h
@@ -20,10 +20,10 @@
 
 #include <utils/RefBase.h>
 #include <media/IMediaRecorderClient.h>
+#include <media/IMediaSource.h>
 
 namespace android {
 
-struct MediaSource;
 class MetaData;
 
 struct MediaWriter : public RefBase {
@@ -32,7 +32,7 @@
           mMaxFileDurationLimitUs(0) {
     }
 
-    virtual status_t addSource(const sp<MediaSource> &source) = 0;
+    virtual status_t addSource(const sp<IMediaSource> &source) = 0;
     virtual bool reachedEOS() = 0;
     virtual status_t start(MetaData *params = NULL) = 0;
     virtual status_t stop() = 0;
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 8d4e15a..91341b8 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -22,6 +22,7 @@
 
 #include <stdint.h>
 
+#include <binder/Parcel.h>
 #include <utils/RefBase.h>
 #include <utils/KeyedVector.h>
 #include <utils/String8.h>
@@ -181,6 +182,12 @@
 
     // H264 supplemental enhancement information offsets/sizes
     kKeySEI               = 'sei ', // raw data
+
+    // MPEG user data offsets
+    kKeyMpegUserData      = 'mpud', // size_t[]
+
+    // Size of NALU length in mkv/mp4
+    kKeyNalLengthSize     = 'nals', // int32_t
 };
 
 enum {
@@ -239,6 +246,10 @@
 
     void dumpToLog() const;
 
+    status_t writeToParcel(Parcel &parcel);
+    status_t updateFromParcel(const Parcel &parcel);
+    static sp<MetaData> createFromParcel(const Parcel &parcel);
+
 protected:
     virtual ~MetaData();
 
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index fd74452..b8bb824 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -19,6 +19,7 @@
 
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/MediaSource.h>
+#include <media/IMediaExtractor.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
@@ -84,7 +85,7 @@
     };
 
     struct TrackInfo {
-        sp<MediaSource> mSource;
+        sp<IMediaSource> mSource;
         size_t mTrackIndex;
         status_t mFinalResult;
         MediaBuffer *mSample;
@@ -97,7 +98,7 @@
 
     sp<DataSource> mDataSource;
 
-    sp<MediaExtractor> mImpl;
+    sp<IMediaExtractor> mImpl;
     bool mIsWidevineExtractor;
 
     Vector<TrackInfo> mSelectedTracks;
@@ -113,6 +114,7 @@
 
     bool getTotalBitrate(int64_t *bitRate) const;
     void updateDurationAndBitrate();
+    status_t appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer);
 
     DISALLOW_EVIL_CONSTRUCTORS(NuMediaExtractor);
 };
diff --git a/include/media/stagefright/SimpleDecodingSource.h b/include/media/stagefright/SimpleDecodingSource.h
index 07e1f79..534097b 100644
--- a/include/media/stagefright/SimpleDecodingSource.h
+++ b/include/media/stagefright/SimpleDecodingSource.h
@@ -45,7 +45,7 @@
     // does not support secure input or pausing.
     // if |desiredCodec| is given, use this specific codec.
     static sp<SimpleDecodingSource> Create(
-            const sp<MediaSource> &source, uint32_t flags = 0,
+            const sp<IMediaSource> &source, uint32_t flags = 0,
             const sp<ANativeWindow> &nativeWindow = NULL,
             const char *desiredCodec = NULL);
 
@@ -70,11 +70,11 @@
 private:
     // Construct this using a codec, source and looper.
     SimpleDecodingSource(
-            const sp<MediaCodec> &codec, const sp<MediaSource> &source, const sp<ALooper> &looper,
+            const sp<MediaCodec> &codec, const sp<IMediaSource> &source, const sp<ALooper> &looper,
             bool usingSurface, const sp<AMessage> &format);
 
     sp<MediaCodec> mCodec;
-    sp<MediaSource> mSource;
+    sp<IMediaSource> mSource;
     sp<ALooper> mLooper;
     bool mUsingSurface;
     enum State {
diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h
index 5e9d7d4..17631a0 100644
--- a/include/media/stagefright/Utils.h
+++ b/include/media/stagefright/Utils.h
@@ -85,6 +85,8 @@
 void readFromAMessage(
         const sp<AMessage> &msg, AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
 
+AString nameForFd(int fd);
+
 }  // namespace android
 
 #endif  // UTILS_H_
diff --git a/include/ndk/NdkImage.h b/include/ndk/NdkImage.h
new file mode 100644
index 0000000..5c92294
--- /dev/null
+++ b/include/ndk/NdkImage.h
@@ -0,0 +1,99 @@
+/*
+ * 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 file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_IMAGE_H
+#define _NDK_IMAGE_H
+
+#include "NdkMediaError.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct AImage AImage;
+
+// Formats not listed here will not be supported by AImageReader
+enum {
+    AIMAGE_FORMAT_YUV_420_888       = 0x23,
+    AIMAGE_FORMAT_JPEG              = 0x100,
+    AIMAGE_FORMAT_RAW16             = 0x20,
+    AIMAGE_FORMAT_RAW_PRIVATE       = 0x24,
+    AIMAGE_FORMAT_RAW10             = 0x25,
+    AIMAGE_FORMAT_RAW12             = 0x26,
+    AIMAGE_FORMAT_DEPTH16           = 0x44363159,
+    AIMAGE_FORMAT_DEPTH_POINT_CLOUD = 0x101
+};
+
+typedef struct AImageCropRect {
+    int32_t left;
+    int32_t top;
+    int32_t right;
+    int32_t bottom;
+} AImageCropRect;
+
+// Return the image back to system and delete the AImage from memory
+// Do NOT use `image` after this call
+void AImage_delete(AImage* image);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+media_status_t AImage_getWidth(const AImage* image, /*out*/int32_t* width);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+media_status_t AImage_getHeight(const AImage* image, /*out*/int32_t* height);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+media_status_t AImage_getFormat(const AImage* image, /*out*/int32_t* format);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+media_status_t AImage_getCropRect(const AImage* image, /*out*/AImageCropRect* rect);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+media_status_t AImage_getTimestamp(const AImage* image, /*out*/int64_t* timestampNs);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+media_status_t AImage_getNumberOfPlanes(const AImage* image, /*out*/int32_t* numPlanes);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+media_status_t AImage_getPlanePixelStride(
+        const AImage* image, int planeIdx, /*out*/int32_t* pixelStride);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+media_status_t AImage_getPlaneRowStride(
+        const AImage* image, int planeIdx, /*out*/int32_t* rowStride);
+
+// AMEDIA_ERROR_INVALID_OBJECT will be returned if the parent AImageReader is deleted
+// Note that once the AImage or the parent AImageReader is deleted, the `*data` returned from
+// previous AImage_getPlaneData call becomes dangling pointer. Do NOT use it after
+// AImage or AImageReader is deleted
+media_status_t AImage_getPlaneData(
+        const AImage* image, int planeIdx,
+        /*out*/uint8_t** data, /*out*/int* dataLength);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif //_NDK_IMAGE_H
diff --git a/include/ndk/NdkImageReader.h b/include/ndk/NdkImageReader.h
new file mode 100644
index 0000000..041c378
--- /dev/null
+++ b/include/ndk/NdkImageReader.h
@@ -0,0 +1,77 @@
+/*
+ * 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 file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+#ifndef _NDK_IMAGE_READER_H
+#define _NDK_IMAGE_READER_H
+
+#include <android/native_window.h>
+#include "NdkMediaError.h"
+#include "NdkImage.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct AImageReader AImageReader;
+
+media_status_t AImageReader_new(
+        int32_t width, int32_t height, int32_t format, int32_t maxImages,
+        /*out*/AImageReader** reader);
+
+// Return all images acquired from this AImageReader back to system and delete
+// the AImageReader instance from memory
+// Do NOT use `reader` after this call
+void AImageReader_delete(AImageReader* reader);
+
+// Do NOT call ANativeWindow_release on the output. Just use AImageReader_delete.
+media_status_t AImageReader_getWindow(AImageReader*, /*out*/ANativeWindow** window);
+
+media_status_t AImageReader_getWidth(const AImageReader* reader, /*out*/int32_t* width);
+media_status_t AImageReader_getHeight(const AImageReader* reader, /*out*/int32_t* height);
+media_status_t AImageReader_getFormat(const AImageReader* reader, /*out*/int32_t* format);
+media_status_t AImageReader_getMaxImages(const AImageReader* reader, /*out*/int32_t* maxImages);
+
+media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image);
+
+media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image);
+
+// The callback happens on one dedicated thread per AImageReader instance
+// It's okay to use AImageReader_*/AImage_* APIs within the callback
+typedef void (*AImageReader_ImageCallback)(void* context, AImageReader* reader);
+
+typedef struct AImageReader_ImageListener {
+    void*                      context; // optional application context.
+    AImageReader_ImageCallback onImageAvailable;
+} AImageReader_ImageListener;
+
+media_status_t AImageReader_setImageListener(
+        AImageReader* reader, AImageReader_ImageListener* listener);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif //_NDK_IMAGE_READER_H
diff --git a/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h
index 4f6a1ef..c6035bd 100644
--- a/include/ndk/NdkMediaCodec.h
+++ b/include/ndk/NdkMediaCodec.h
@@ -154,6 +154,18 @@
 media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec*, size_t idx, bool render);
 
 /**
+ * Dynamically sets the output surface of a codec.
+ *
+ *  This can only be used if the codec was configured with an output surface.  The
+ *  new output surface should have a compatible usage type to the original output surface.
+ *  E.g. codecs may not support switching from a SurfaceTexture (GPU readable) output
+ *  to ImageReader (software readable) output.
+ *
+ * For more details, see the Java documentation for MediaCodec.setOutputSurface.
+ */
+media_status_t AMediaCodec_setOutputSurface(AMediaCodec*, ANativeWindow* surface);
+
+/**
  * If you are done with a buffer, use this call to update its surface timestamp
  * and return it to the codec to render it on the output surface. If you
  * have not specified an output surface when configuring this video codec,
@@ -164,12 +176,16 @@
 media_status_t AMediaCodec_releaseOutputBufferAtTime(
         AMediaCodec *mData, size_t idx, int64_t timestampNs);
 
-
 typedef enum {
     AMEDIACODECRYPTOINFO_MODE_CLEAR = 0,
     AMEDIACODECRYPTOINFO_MODE_AES_CTR = 1
 } cryptoinfo_mode_t;
 
+typedef struct {
+    int32_t encryptBlocks;
+    int32_t skipBlocks;
+} cryptoinfo_pattern_t;
+
 /**
  * Create an AMediaCodecCryptoInfo from scratch. Use this if you need to use custom
  * crypto info, rather than one obtained from AMediaExtractor.
@@ -199,6 +215,13 @@
 media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo*);
 
 /**
+ * Set the crypto pattern on an AMediaCryptoInfo object
+ */
+void AMediaCodecCryptoInfo_setPattern(
+        AMediaCodecCryptoInfo *info,
+        cryptoinfo_pattern_t *pattern);
+
+/**
  * The number of subsamples that make up the buffer's contents.
  */
 size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo*);
diff --git a/include/ndk/NdkMediaError.h b/include/ndk/NdkMediaError.h
index 12613eb..60d401b 100644
--- a/include/ndk/NdkMediaError.h
+++ b/include/ndk/NdkMediaError.h
@@ -53,6 +53,10 @@
     AMEDIA_DRM_NEED_KEY                = AMEDIA_DRM_ERROR_BASE - 8,
     AMEDIA_DRM_LICENSE_EXPIRED         = AMEDIA_DRM_ERROR_BASE - 9,
 
+    AMEDIA_IMGREADER_ERROR_BASE          = -30000,
+    AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE = AMEDIA_IMGREADER_ERROR_BASE - 1,
+    AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED = AMEDIA_IMGREADER_ERROR_BASE - 2,
+
 } media_status_t;
 
 
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 1e5064f..cae5560 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -26,6 +26,8 @@
 #include <utils/RefBase.h>
 #include <audio_utils/roundup.h>
 #include <media/AudioResamplerPublic.h>
+#include <media/AudioTimestamp.h>
+#include <media/Modulo.h>
 #include <media/SingleStateQueue.h>
 
 namespace android {
@@ -58,7 +60,8 @@
     volatile int32_t mRear;     // written by producer (output: client, input: server)
     volatile int32_t mFlush;    // incremented by client to indicate a request to flush;
                                 // server notices and discards all data between mFront and mRear
-    volatile uint32_t mUnderrunFrames;  // server increments for each unavailable but desired frame
+    volatile uint32_t mUnderrunFrames; // server increments for each unavailable but desired frame
+    volatile uint32_t mUnderrunCount;  // server increments for each underrun occurrence
 };
 
 // Represents a single state of an AudioTrack that was created in static mode (shared memory buffer
@@ -116,6 +119,11 @@
 
 typedef SingleStateQueue<AudioPlaybackRate> PlaybackRateQueue;
 
+
+typedef SingleStateQueue<ExtendedTimestamp> ExtendedTimestampQueue;
+
+typedef SingleStateQueue<AudioTimestamp> TimestampQueue;
+
 // ----------------------------------------------------------------------------
 
 // Important: do not add any virtual methods, including ~
@@ -169,12 +177,14 @@
 
                 uint16_t    mPad2;           // unused
 
+                // server write-only, client read
+                ExtendedTimestampQueue::Shared mExtendedTimestampQueue; // capture
+                TimestampQueue::Shared mTimestampQueue; // playback
+
 public:
 
     volatile    int32_t     mFlags;         // combinations of CBLK_*
 
-                // Cache line boundary (32 bytes)
-
 public:
                 union {
                     AudioTrackSharedStreaming   mStreaming;
@@ -203,6 +213,8 @@
         size_t  mNonContig;             // number of additional non-contiguous frames available
     };
 
+    size_t frameCount() const { return mFrameCount; }
+
 protected:
     // These refer to shared memory, and are virtual addresses with respect to the current process.
     // They may have different virtual addresses within the other process.
@@ -280,11 +292,11 @@
     // Call to force an obtainBuffer() to return quickly with -EINTR
     void        interrupt();
 
-    size_t      getPosition() {
+    Modulo<uint32_t> getPosition() {
         return mEpoch + mCblk->mServer;
     }
 
-    void        setEpoch(size_t epoch) {
+    void        setEpoch(const Modulo<uint32_t> &epoch) {
         mEpoch = epoch;
     }
 
@@ -300,14 +312,21 @@
     // in order for the client to be aligned at start of buffer
     virtual size_t  getMisalignment();
 
-    size_t      getEpoch() const {
+    Modulo<uint32_t> getEpoch() const {
         return mEpoch;
     }
 
-    size_t      getFramesFilled();
+    size_t      getBufferSizeInFrames() const { return mBufferSizeInFrames; }
+    // See documentation for AudioTrack.setBufferSizeInFrames()
+    size_t      setBufferSizeInFrames(size_t requestedSize);
+
+protected:
+    // This is set by AudioTrack.setBufferSizeInFrames().
+    // A write will not fill the buffer above this limit.
+    size_t      mBufferSizeInFrames;      // effective size of the buffer
 
 private:
-    size_t      mEpoch;
+    Modulo<uint32_t> mEpoch;
 };
 
 // ----------------------------------------------------------------------------
@@ -319,7 +338,10 @@
             size_t frameSize, bool clientInServer = false)
         : ClientProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/,
           clientInServer),
-          mPlaybackRateMutator(&cblk->mPlaybackRateQueue) { }
+          mPlaybackRateMutator(&cblk->mPlaybackRateQueue),
+          mTimestampObserver(&cblk->mTimestampQueue) {
+    }
+
     virtual ~AudioTrackClientProxy() { }
 
     // No barriers on the following operations, so the ordering of loads/stores
@@ -343,11 +365,28 @@
         mPlaybackRateMutator.push(playbackRate);
     }
 
+    status_t    getTimestamp(AudioTimestamp *timestamp) {
+        if (timestamp == nullptr) {
+            return BAD_VALUE;
+        }
+        (void) mTimestampObserver.poll(mTimestamp);
+        // if no data is pushed by server, mTimestamp should be initialized by its constructor
+        // to all zero elements.
+        if (mTimestamp.mTime.tv_sec == 0 && mTimestamp.mTime.tv_nsec == 0) {
+            return WOULD_BLOCK;
+        }
+        *timestamp = mTimestamp;
+        return OK;
+    }
+
     virtual void flush();
 
     virtual uint32_t    getUnderrunFrames() const {
         return mCblk->u.mStreaming.mUnderrunFrames;
     }
+    virtual uint32_t    getUnderrunCount() const {
+        return mCblk->u.mStreaming.mUnderrunCount;
+    }
 
     bool        clearStreamEndDone();   // and return previous value
 
@@ -357,6 +396,8 @@
 
 private:
     PlaybackRateQueue::Mutator   mPlaybackRateMutator;
+    TimestampQueue::Observer mTimestampObserver;
+    AudioTimestamp mTimestamp;
 };
 
 class StaticAudioTrackClientProxy : public AudioTrackClientProxy {
@@ -414,8 +455,39 @@
     AudioRecordClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
             size_t frameSize)
         : ClientProxy(cblk, buffers, frameCount, frameSize,
-            false /*isOut*/, false /*clientInServer*/) { }
+            false /*isOut*/, false /*clientInServer*/)
+        , mTimestampObserver(&cblk->mExtendedTimestampQueue) { }
     ~AudioRecordClientProxy() { }
+
+    status_t    getTimestamp(ExtendedTimestamp *timestamp) {
+        if (timestamp == nullptr) {
+            return BAD_VALUE;
+        }
+        (void) mTimestampObserver.poll(mTimestamp);
+        *timestamp = mTimestamp;
+        return OK;
+    }
+
+    void        clearTimestamp() {
+        mTimestamp.clear();
+    }
+
+    // Advances the client read pointer to the server write head pointer
+    // effectively flushing the client read buffer. The effect is
+    // instantaneous. Returns the number of frames flushed.
+    uint32_t    flush() {
+        int32_t rear = android_atomic_acquire_load(&mCblk->u.mStreaming.mRear);
+        int32_t front = mCblk->u.mStreaming.mFront;
+        android_atomic_release_store(rear, &mCblk->u.mStreaming.mFront);
+        return (Modulo<int32_t>(rear) - front).unsignedValue();
+    }
+
+private:
+    // The shared buffer contents referred to by the timestamp observer
+    // is initialized when the server proxy created.  A local zero timestamp
+    // is initialized by the client constructor.
+    ExtendedTimestampQueue::Observer mTimestampObserver;
+    ExtendedTimestamp mTimestamp; // initialized by constructor
 };
 
 // ----------------------------------------------------------------------------
@@ -464,6 +536,7 @@
 protected:
     size_t      mAvailToClient; // estimated frames available to client prior to releaseBuffer()
     int32_t     mFlush;         // our copy of cblk->u.mStreaming.mFlush, for streaming output only
+    int64_t     mReleased;      // our copy of cblk->mServer, at 64 bit resolution
 };
 
 // Proxy used by AudioFlinger for servicing AudioTrack
@@ -472,7 +545,9 @@
     AudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
             size_t frameSize, bool clientInServer = false, uint32_t sampleRate = 0)
         : ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer),
-          mPlaybackRateObserver(&cblk->mPlaybackRateQueue) {
+          mPlaybackRateObserver(&cblk->mPlaybackRateQueue),
+          mUnderrunCount(0), mUnderrunning(false),
+          mTimestampMutator(&cblk->mTimestampQueue) {
         mCblk->mSampleRate = sampleRate;
         mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
     }
@@ -507,14 +582,25 @@
     virtual uint32_t    getUnderrunFrames() const { return mCblk->u.mStreaming.mUnderrunFrames; }
 
     // Return the total number of frames that AudioFlinger has obtained and released
-    virtual size_t      framesReleased() const { return mCblk->mServer; }
+    virtual size_t      framesReleased() const { return mReleased; }
 
     // Return the playback speed and pitch read atomically. Not multi-thread safe on server side.
     AudioPlaybackRate getPlaybackRate();
 
+    // Expose timestamp to client proxy. Should only be called by a single thread.
+                   void setTimestamp(const AudioTimestamp &timestamp) {
+                       mTimestampMutator.push(timestamp);
+                   }
+
 private:
     AudioPlaybackRate             mPlaybackRate;  // last observed playback rate
     PlaybackRateQueue::Observer   mPlaybackRateObserver;
+
+    // The server keeps a copy here where it is safe from the client.
+    uint32_t                      mUnderrunCount; // echoed to mCblk
+    bool                          mUnderrunning;  // used to detect edge of underrun
+
+    TimestampQueue::Mutator       mTimestampMutator;
 };
 
 class StaticAudioTrackServerProxy : public AudioTrackServerProxy {
@@ -557,9 +643,20 @@
 public:
     AudioRecordServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
             size_t frameSize, bool clientInServer)
-        : ServerProxy(cblk, buffers, frameCount, frameSize, false /*isOut*/, clientInServer) { }
+        : ServerProxy(cblk, buffers, frameCount, frameSize, false /*isOut*/, clientInServer)
+        , mTimestampMutator(&cblk->mExtendedTimestampQueue) { }
+
+    // Return the total number of frames that AudioFlinger has obtained and released
+    virtual int64_t     framesReleased() const { return mReleased; }
+
+    // Expose timestamp to client proxy. Should only be called by a single thread.
+    virtual void        setExtendedTimestamp(const ExtendedTimestamp &timestamp) {
+                            mTimestampMutator.push(timestamp);
+                        }
 protected:
     virtual ~AudioRecordServerProxy() { }
+
+    ExtendedTimestampQueue::Mutator       mTimestampMutator;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
new file mode 100644
index 0000000..324ebbb
--- /dev/null
+++ b/media/audioserver/Android.mk
@@ -0,0 +1,35 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	main_audioserver.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libaudioflinger \
+	libaudiopolicyservice \
+	libbinder \
+	liblog \
+	libmedia \
+	libradioservice \
+	libsoundtriggerservice \
+	libutils \
+
+LOCAL_C_INCLUDES := \
+	frameworks/av/services/audioflinger \
+	frameworks/av/services/audiopolicy \
+	frameworks/av/services/audiopolicy/common/managerdefinitions/include \
+	frameworks/av/services/audiopolicy/common/include \
+	frameworks/av/services/audiopolicy/engine/interface \
+	frameworks/av/services/audiopolicy/service \
+	frameworks/av/services/radio \
+	frameworks/av/services/soundtrigger \
+	$(call include-path-for, audio-utils) \
+	external/sonic \
+
+LOCAL_MODULE := audioserver
+LOCAL_32_BIT_ONLY := true
+
+LOCAL_INIT_RC := audioserver.rc
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
new file mode 100644
index 0000000..1b39c8d
--- /dev/null
+++ b/media/audioserver/audioserver.rc
@@ -0,0 +1,6 @@
+service audioserver /system/bin/audioserver
+    class main
+    user audioserver
+    # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
+    group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
+    ioprio rt 4
diff --git a/media/audioserver/main_audioserver.cpp b/media/audioserver/main_audioserver.cpp
new file mode 100644
index 0000000..a7123aa
--- /dev/null
+++ b/media/audioserver/main_audioserver.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 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 "audioserver"
+//#define LOG_NDEBUG 0
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+// from LOCAL_C_INCLUDES
+#include "AudioFlinger.h"
+#include "AudioPolicyService.h"
+#include "RadioService.h"
+#include "SoundTriggerHwService.h"
+
+using namespace android;
+
+int main(int argc __unused, char **argv __unused)
+{
+    signal(SIGPIPE, SIG_IGN);
+
+    // TODO: add logging b/24511453#3
+
+    sp<ProcessState> proc(ProcessState::self());
+    sp<IServiceManager> sm(defaultServiceManager());
+    ALOGI("ServiceManager: %p", sm.get());
+    AudioFlinger::instantiate();
+    AudioPolicyService::instantiate();
+    RadioService::instantiate();
+    SoundTriggerHwService::instantiate();
+    ProcessState::self()->startThreadPool();
+    IPCThreadState::self()->joinThreadPool();
+}
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index af904a6..a1892e4 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -722,17 +722,20 @@
 
     if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE){
         pOutTmp = pOut;
-    }else if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
+    } else if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
         if (pContext->pBundledContext->frameCount != frameCount) {
             if (pContext->pBundledContext->workBuffer != NULL) {
                 free(pContext->pBundledContext->workBuffer);
             }
             pContext->pBundledContext->workBuffer =
-                    (LVM_INT16 *)malloc(frameCount * sizeof(LVM_INT16) * 2);
+                    (LVM_INT16 *)calloc(frameCount, sizeof(LVM_INT16) * 2);
+            if (pContext->pBundledContext->workBuffer == NULL) {
+                return -ENOMEM;
+            }
             pContext->pBundledContext->frameCount = frameCount;
         }
         pOutTmp = pContext->pBundledContext->workBuffer;
-    }else{
+    } else {
         ALOGV("LVM_ERROR : LvmBundle_process invalid access mode");
         return -EINVAL;
     }
@@ -2872,7 +2875,7 @@
     EffectContext * pContext = (EffectContext *) self;
     LVM_ReturnStatus_en     LvmStatus = LVM_SUCCESS;                /* Function call status */
     int    status = 0;
-    int    lvmStatus = 0;
+    int    processStatus = 0;
     LVM_INT16   *in  = (LVM_INT16 *)inBuffer->raw;
     LVM_INT16   *out = (LVM_INT16 *)outBuffer->raw;
 
@@ -2960,19 +2963,22 @@
         //pContext->pBundledContext->NumberEffectsEnabled,
         //pContext->pBundledContext->NumberEffectsCalled, pContext->EffectType);
 
-        if(status == -ENODATA){
+        if (status == -ENODATA){
             ALOGV("\tEffect_process() processing last frame");
         }
         pContext->pBundledContext->NumberEffectsCalled = 0;
         /* Process all the available frames, block processing is
            handled internalLY by the LVM bundle */
-        lvmStatus = android::LvmBundle_process(    (LVM_INT16 *)inBuffer->raw,
+        processStatus = android::LvmBundle_process(    (LVM_INT16 *)inBuffer->raw,
                                                 (LVM_INT16 *)outBuffer->raw,
                                                 outBuffer->frameCount,
                                                 pContext);
-        if(lvmStatus != LVM_SUCCESS){
-            ALOGV("\tLVM_ERROR : LvmBundle_process returned error %d", lvmStatus);
-            return lvmStatus;
+        if (processStatus != 0){
+            ALOGV("\tLVM_ERROR : LvmBundle_process returned error %d", processStatus);
+            if (status == 0) {
+                status = processStatus;
+            }
+            return status;
         }
     } else {
         //ALOGV("\tEffect_process Not Calling process with %d effects enabled, %d called: Effect %d",
@@ -3091,7 +3097,10 @@
             //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_GET_PARAM start");
 
             effect_param_t *p = (effect_param_t *)pCmdData;
-
+            if (SIZE_MAX - sizeof(effect_param_t) < (size_t)p->psize) {
+                android_errorWriteLog(0x534e4554, "26347509");
+                return -EINVAL;
+            }
             if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) ||
                     cmdSize < (sizeof(effect_param_t) + p->psize) ||
                     pReplyData == NULL || replySize == NULL ||
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index a48a4e3..4dc8b45 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -1956,7 +1956,10 @@
             //ALOGV("\tReverb_command cmdCode Case: "
             //        "EFFECT_CMD_GET_PARAM start");
             effect_param_t *p = (effect_param_t *)pCmdData;
-
+            if (SIZE_MAX - sizeof(effect_param_t) < (size_t)p->psize) {
+                android_errorWriteLog(0x534e4554, "26347509");
+                return -EINVAL;
+            }
             if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) ||
                     cmdSize < (sizeof(effect_param_t) + p->psize) ||
                     pReplyData == NULL || replySize == NULL ||
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index 0b4ab3d..f48bac1 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -1259,9 +1259,17 @@
                 fr = inBuffer->frameCount;
             }
             if (session->inBufSize < session->framesIn + fr) {
+                int16_t *buf;
                 session->inBufSize = session->framesIn + fr;
-                session->inBuf = (int16_t *)realloc(session->inBuf,
+                buf = (int16_t *)realloc(session->inBuf,
                                  session->inBufSize * session->inChannelCount * sizeof(int16_t));
+                if (buf == NULL) {
+                    session->framesIn = 0;
+                    free(session->inBuf);
+                    session->inBuf = NULL;
+                    return -ENOMEM;
+                }
+                session->inBuf = buf;
             }
             memcpy(session->inBuf + session->framesIn * session->inChannelCount,
                    inBuffer->s16,
@@ -1330,9 +1338,17 @@
         effect->session->apm->ProcessStream(session->procFrame);
 
         if (session->outBufSize < session->framesOut + session->frameCount) {
+            int16_t *buf;
             session->outBufSize = session->framesOut + session->frameCount;
-            session->outBuf = (int16_t *)realloc(session->outBuf,
-                              session->outBufSize * session->outChannelCount * sizeof(int16_t));
+            buf = (int16_t *)realloc(session->outBuf,
+                             session->outBufSize * session->outChannelCount * sizeof(int16_t));
+            if (buf == NULL) {
+                session->framesOut = 0;
+                free(session->outBuf);
+                session->outBuf = NULL;
+                return -ENOMEM;
+            }
+            session->outBuf = buf;
         }
 
         if (session->outResampler != NULL) {
@@ -1788,9 +1804,17 @@
                 fr = inBuffer->frameCount;
             }
             if (session->revBufSize < session->framesRev + fr) {
+                int16_t *buf;
                 session->revBufSize = session->framesRev + fr;
-                session->revBuf = (int16_t *)realloc(session->revBuf,
-                                  session->revBufSize * session->inChannelCount * sizeof(int16_t));
+                buf = (int16_t *)realloc(session->revBuf,
+                                 session->revBufSize * session->inChannelCount * sizeof(int16_t));
+                if (buf == NULL) {
+                    session->framesRev = 0;
+                    free(session->revBuf);
+                    session->revBuf = NULL;
+                    return -ENOMEM;
+                }
+                session->revBuf = buf;
             }
             memcpy(session->revBuf + session->framesRev * session->inChannelCount,
                    inBuffer->s16,
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index be88aa0..479ccbb 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -30,14 +30,19 @@
     AudioSystem.cpp \
     mediaplayer.cpp \
     IMediaCodecList.cpp \
+    IMediaCodecService.cpp \
+    IMediaDrmService.cpp \
     IMediaHTTPConnection.cpp \
     IMediaHTTPService.cpp \
     IMediaLogService.cpp \
+    IMediaExtractor.cpp           \
+    IMediaExtractorService.cpp \
     IMediaPlayerService.cpp \
     IMediaPlayerClient.cpp \
     IMediaRecorderClient.cpp \
     IMediaPlayer.cpp \
     IMediaRecorder.cpp \
+    IMediaSource.cpp \
     IRemoteDisplay.cpp \
     IRemoteDisplayClient.cpp \
     IResourceManagerClient.cpp \
diff --git a/media/libmedia/AudioPolicy.cpp b/media/libmedia/AudioPolicy.cpp
index 9d07011..ea22b6c 100644
--- a/media/libmedia/AudioPolicy.cpp
+++ b/media/libmedia/AudioPolicy.cpp
@@ -22,37 +22,37 @@
 namespace android {
 
 //
-//  AttributeMatchCriterion implementation
+//  AudioMixMatchCriterion implementation
 //
-AttributeMatchCriterion::AttributeMatchCriterion(audio_usage_t usage,
+AudioMixMatchCriterion::AudioMixMatchCriterion(audio_usage_t usage,
                                                  audio_source_t source,
                                                  uint32_t rule)
 : mRule(rule)
 {
     if (mRule == RULE_MATCH_ATTRIBUTE_USAGE ||
             mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) {
-        mAttr.mUsage = usage;
+        mValue.mUsage = usage;
     } else {
-        mAttr.mSource = source;
+        mValue.mSource = source;
     }
 }
 
-status_t AttributeMatchCriterion::readFromParcel(Parcel *parcel)
+status_t AudioMixMatchCriterion::readFromParcel(Parcel *parcel)
 {
     mRule = parcel->readInt32();
     if (mRule == RULE_MATCH_ATTRIBUTE_USAGE ||
             mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) {
-        mAttr.mUsage = (audio_usage_t)parcel->readInt32();
+        mValue.mUsage = (audio_usage_t)parcel->readInt32();
     } else {
-        mAttr.mSource = (audio_source_t)parcel->readInt32();
+        mValue.mSource = (audio_source_t)parcel->readInt32();
     }
     return NO_ERROR;
 }
 
-status_t AttributeMatchCriterion::writeToParcel(Parcel *parcel) const
+status_t AudioMixMatchCriterion::writeToParcel(Parcel *parcel) const
 {
     parcel->writeInt32(mRule);
-    parcel->writeInt32(mAttr.mUsage);
+    parcel->writeInt32(mValue.mUsage);
     return NO_ERROR;
 }
 
@@ -74,7 +74,7 @@
         size = MAX_CRITERIA_PER_MIX;
     }
     for (size_t i = 0; i < size; i++) {
-        AttributeMatchCriterion criterion;
+        AudioMixMatchCriterion criterion;
         if (criterion.readFromParcel(parcel) == NO_ERROR) {
             mCriteria.add(criterion);
         }
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 011b31f..ec57d96 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -284,6 +284,8 @@
     mSequence = 1;
     mObservedSequence = mSequence;
     mInOverrun = false;
+    mFramesRead = 0;
+    mFramesReadServerOffset = 0;
 
     return NO_ERROR;
 }
@@ -299,6 +301,12 @@
         return NO_ERROR;
     }
 
+    // discard data in buffer
+    const uint32_t framesFlushed = mProxy->flush();
+    mFramesReadServerOffset -= mFramesRead + framesFlushed;
+    mFramesRead = 0;
+    mProxy->clearTimestamp();  // timestamp is invalid until next server push
+
     // reset current position as seen by client to 0
     mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());
     // force refresh of remaining frames by processAudioBuffer() as last
@@ -308,6 +316,10 @@
     mNewPosition = mProxy->getPosition() + mUpdatePeriod;
     int32_t flags = android_atomic_acquire_load(&mCblk->mFlags);
 
+    // we reactivate markers (mMarkerPosition != 0) as the position is reset to 0.
+    // This is legacy behavior.  This is not done in stop() to avoid a race condition
+    // where the last marker event is issued twice.
+    mMarkerReached = false;
     mActive = true;
 
     status_t status = NO_ERROR;
@@ -348,9 +360,10 @@
     mActive = false;
     mProxy->interrupt();
     mAudioRecord->stop();
-    // the record head position will reset to 0, so if a marker is set, we need
-    // to activate it again
-    mMarkerReached = false;
+
+    // Note: legacy handling - stop does not clear record marker and
+    // periodic update position; we update those on start().
+
     sp<AudioRecordThread> t = mAudioRecordThread;
     if (t != 0) {
         t->pause();
@@ -391,7 +404,7 @@
     }
 
     AutoMutex lock(mLock);
-    *marker = mMarkerPosition;
+    mMarkerPosition.getValue(marker);
 
     return NO_ERROR;
 }
@@ -433,7 +446,7 @@
     }
 
     AutoMutex lock(mLock);
-    *position = mProxy->getPosition();
+    mProxy->getPosition().getValue(position);
 
     return NO_ERROR;
 }
@@ -444,6 +457,27 @@
     return AudioSystem::getInputFramesLost(getInputPrivate());
 }
 
+status_t AudioRecord::getTimestamp(ExtendedTimestamp *timestamp)
+{
+    if (timestamp == nullptr) {
+        return BAD_VALUE;
+    }
+    AutoMutex lock(mLock);
+    status_t status = mProxy->getTimestamp(timestamp);
+    if (status == OK) {
+        timestamp->mPosition[ExtendedTimestamp::LOCATION_CLIENT] = mFramesRead;
+        timestamp->mTimeNs[ExtendedTimestamp::LOCATION_CLIENT] = 0;
+        // server side frame offset in case AudioRecord has been restored.
+        for (int i = ExtendedTimestamp::LOCATION_SERVER;
+                i < ExtendedTimestamp::LOCATION_MAX; ++i) {
+            if (timestamp->mTimeNs[i] >= 0) {
+                timestamp->mPosition[i] += mFramesReadServerOffset;
+            }
+        }
+    }
+    return status;
+}
+
 // ---- Explicit Routing ---------------------------------------------------
 status_t AudioRecord::setInputDevice(audio_port_handle_t deviceId) {
     AutoMutex lock(mLock);
@@ -475,7 +509,7 @@
 // -------------------------------------------------------------------------
 
 // must be called with mLock held
-status_t AudioRecord::openRecord_l(size_t epoch, const String16& opPackageName)
+status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName)
 {
     const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
     if (audioFlinger == 0) {
@@ -832,7 +866,10 @@
 
         releaseBuffer(&audioBuffer);
     }
-
+    if (read > 0) {
+        mFramesRead += read / mFrameSize;
+        // mFramesReadTime = systemTime(SYSTEM_TIME_MONOTONIC); // not provided at this time.
+    }
     return read;
 }
 
@@ -885,23 +922,23 @@
     }
 
     // Get current position of server
-    size_t position = mProxy->getPosition();
+    Modulo<uint32_t> position(mProxy->getPosition());
 
     // Manage marker callback
     bool markerReached = false;
-    size_t markerPosition = mMarkerPosition;
+    Modulo<uint32_t> markerPosition(mMarkerPosition);
     // FIXME fails for wraparound, need 64 bits
-    if (!mMarkerReached && (markerPosition > 0) && (position >= markerPosition)) {
+    if (!mMarkerReached && markerPosition.value() > 0 && position >= markerPosition) {
         mMarkerReached = markerReached = true;
     }
 
     // Determine the number of new position callback(s) that will be needed, while locked
     size_t newPosCount = 0;
-    size_t newPosition = mNewPosition;
+    Modulo<uint32_t> newPosition(mNewPosition);
     uint32_t updatePeriod = mUpdatePeriod;
     // FIXME fails for wraparound, need 64 bits
     if (updatePeriod > 0 && position >= newPosition) {
-        newPosCount = ((position - newPosition) / updatePeriod) + 1;
+        newPosCount = ((position - newPosition).value() / updatePeriod) + 1;
         mNewPosition += updatePeriod * newPosCount;
     }
 
@@ -928,7 +965,7 @@
         mCbf(EVENT_MARKER, mUserData, &markerPosition);
     }
     while (newPosCount > 0) {
-        size_t temp = newPosition;
+        size_t temp = newPosition.value(); // FIXME size_t != uint32_t
         mCbf(EVENT_NEW_POS, mUserData, &temp);
         newPosition += updatePeriod;
         newPosCount--;
@@ -946,10 +983,10 @@
     // Compute the estimated time until the next timed event (position, markers)
     uint32_t minFrames = ~0;
     if (!markerReached && position < markerPosition) {
-        minFrames = markerPosition - position;
+        minFrames = (markerPosition - position).value();
     }
     if (updatePeriod > 0) {
-        uint32_t remaining = newPosition - position;
+        uint32_t remaining = (newPosition - position).value();
         if (remaining < minFrames) {
             minFrames = remaining;
         }
@@ -983,6 +1020,7 @@
         requested = &timeout;
     }
 
+    size_t readFrames = 0;
     while (mRemainingFrames > 0) {
 
         Buffer audioBuffer;
@@ -1044,6 +1082,7 @@
         }
 
         releaseBuffer(&audioBuffer);
+        readFrames += releasedFrames;
 
         // FIXME here is where we would repeat EVENT_MORE_DATA again on same advanced buffer
         // if callback doesn't like to accept the full chunk
@@ -1067,6 +1106,11 @@
 #endif
 
     }
+    if (readFrames > 0) {
+        AutoMutex lock(mLock);
+        mFramesRead += readFrames;
+        // mFramesReadTime = systemTime(SYSTEM_TIME_MONOTONIC); // not provided at this time.
+    }
     mRemainingFrames = notificationFrames;
     mRetryOnPartialBuffer = true;
 
@@ -1082,7 +1126,7 @@
     // if the new IAudioRecord is created, openRecord_l() will modify the
     // following member variables: mAudioRecord, mCblkMemory, mCblk, mBufferMemory.
     // It will also delete the strong references on previous IAudioRecord and IMemory
-    size_t position = mProxy->getPosition();
+    Modulo<uint32_t> position(mProxy->getPosition());
     mNewPosition = position + mUpdatePeriod;
     status_t result = openRecord_l(position, mOpPackageName);
     if (result == NO_ERROR) {
@@ -1091,6 +1135,7 @@
             // FIXME this fails if we have a new AudioFlinger instance
             result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0);
         }
+        mFramesReadServerOffset = mFramesRead; // server resets to zero so we need an offset.
     }
     if (result != NO_ERROR) {
         ALOGW("restoreRecord_l() failed status %d", result);
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 9d645f0..1ea2003 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -37,6 +37,7 @@
 sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
 audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
 dynamic_policy_callback AudioSystem::gDynPolicyCallback = NULL;
+record_config_callback  AudioSystem::gRecordConfigCallback = NULL;
 
 
 // establish binder interface to AudioFlinger service
@@ -652,6 +653,12 @@
     gDynPolicyCallback = cb;
 }
 
+/*static*/ void AudioSystem::setRecordConfigCallback(record_config_callback cb)
+{
+    Mutex::Autolock _l(gLock);
+    gRecordConfigCallback = cb;
+}
+
 // client singleton for AudioPolicyService binder interface
 // protected by gLockAPS
 sp<IAudioPolicyService> AudioSystem::gAudioPolicyService;
@@ -1159,6 +1166,20 @@
     return aps->stopAudioSource(handle);
 }
 
+status_t AudioSystem::setMasterMono(bool mono)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->setMasterMono(mono);
+}
+
+status_t AudioSystem::getMasterMono(bool *mono)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+    return aps->getMasterMono(mono);
+}
+
 // ---------------------------------------------------------------------------
 
 int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
@@ -1223,6 +1244,19 @@
     }
 }
 
+void AudioSystem::AudioPolicyServiceClient::onRecordingConfigurationUpdate(
+        int event, audio_session_t session, audio_source_t source) {
+    record_config_callback cb = NULL;
+    {
+        Mutex::Autolock _l(AudioSystem::gLock);
+        cb = gRecordConfigCallback;
+    }
+
+    if (cb != NULL) {
+        cb(event, session, source);
+    }
+}
+
 void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused)
 {
     {
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 82b6736..bd229c8 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -163,7 +163,6 @@
 
 AudioTrack::AudioTrack()
     : mStatus(NO_INIT),
-      mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
       mPausedPosition(0),
@@ -193,7 +192,6 @@
         const audio_attributes_t* pAttributes,
         bool doNotReconnect)
     : mStatus(NO_INIT),
-      mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
       mPausedPosition(0),
@@ -223,7 +221,6 @@
         const audio_attributes_t* pAttributes,
         bool doNotReconnect)
     : mStatus(NO_INIT),
-      mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
       mPausedPosition(0),
@@ -288,6 +285,8 @@
           streamType, sampleRate, format, channelMask, frameCount, flags, notificationFrames,
           sessionId, transferType, uid, pid);
 
+    mThreadCanCallJava = threadCanCallJava;
+
     switch (transferType) {
     case TRANSFER_DEFAULT:
         if (sharedBuffer != 0) {
@@ -356,11 +355,16 @@
         if ((mAttributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
             flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
         }
+        if ((mAttributes.flags & AUDIO_FLAG_LOW_LATENCY) != 0) {
+            flags = (audio_output_flags_t) (flags | AUDIO_OUTPUT_FLAG_FAST);
+        }
     }
 
     // these below should probably come from the audioFlinger too...
     if (format == AUDIO_FORMAT_DEFAULT) {
         format = AUDIO_FORMAT_PCM_16_BIT;
+    } else if (format == AUDIO_FORMAT_IEC61937) { // HDMI pass-through?
+        mAttributes.flags |= AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO;
     }
 
     // validate parameters
@@ -396,13 +400,13 @@
     }
 
     if (flags & AUDIO_OUTPUT_FLAG_DIRECT) {
-        if (audio_is_linear_pcm(format)) {
+        if (audio_has_proportional_frames(format)) {
             mFrameSize = channelCount * audio_bytes_per_sample(format);
         } else {
             mFrameSize = sizeof(uint8_t);
         }
     } else {
-        ALOG_ASSERT(audio_is_linear_pcm(format));
+        ALOG_ASSERT(audio_has_proportional_frames(format));
         mFrameSize = channelCount * audio_bytes_per_sample(format);
         // createTrack will return an error if PCM format is not supported by server,
         // so no need to check for specific PCM formats here
@@ -493,6 +497,7 @@
     mPreviousTimestampValid = false;
     mTimestampStartupGlitchReported = false;
     mRetrogradeMotionReported = false;
+    mUnderrunCountOffset = 0;
 
     return NO_ERROR;
 }
@@ -744,7 +749,7 @@
     if (rate == mSampleRate) {
         return NO_ERROR;
     }
-    if (mIsTimed || isOffloadedOrDirect_l() || (mFlags & AUDIO_OUTPUT_FLAG_FAST)) {
+    if (isOffloadedOrDirect_l() || (mFlags & AUDIO_OUTPUT_FLAG_FAST)) {
         return INVALID_OPERATION;
     }
     if (mOutput == AUDIO_IO_HANDLE_NONE) {
@@ -771,10 +776,6 @@
 
 uint32_t AudioTrack::getSampleRate() const
 {
-    if (mIsTimed) {
-        return 0;
-    }
-
     AutoMutex lock(mLock);
 
     // sample rate can be updated during playback by the offloaded decoder so we need to
@@ -794,10 +795,6 @@
 
 uint32_t AudioTrack::getOriginalSampleRate() const
 {
-    if (mIsTimed) {
-        return 0;
-    }
-
     return mOriginalSampleRate;
 }
 
@@ -807,7 +804,7 @@
     if (isAudioPlaybackRateEqual(playbackRate, mPlaybackRate)) {
         return NO_ERROR;
     }
-    if (mIsTimed || isOffloadedOrDirect_l()) {
+    if (isOffloadedOrDirect_l()) {
         return INVALID_OPERATION;
     }
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
@@ -855,9 +852,34 @@
     return mPlaybackRate;
 }
 
+ssize_t AudioTrack::getBufferSizeInFrames()
+{
+    AutoMutex lock(mLock);
+    if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
+        return NO_INIT;
+    }
+    return mProxy->getBufferSizeInFrames();
+}
+
+ssize_t AudioTrack::setBufferSizeInFrames(size_t bufferSizeInFrames)
+{
+    AutoMutex lock(mLock);
+    if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
+        return NO_INIT;
+    }
+    // Reject if timed track or compressed audio.
+    if (!audio_is_linear_pcm(mFormat)) {
+        return INVALID_OPERATION;
+    }
+    // TODO also need to inform the server side (through mAudioTrack) that
+    // the buffer count is reduced, otherwise the track may never start
+    // because the server thinks it is never filled.
+    return mProxy->setBufferSizeInFrames(bufferSizeInFrames);
+}
+
 status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
 {
-    if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) {
+    if (mSharedBuffer == 0 || isOffloadedOrDirect()) {
         return INVALID_OPERATION;
     }
 
@@ -920,7 +942,7 @@
     }
 
     AutoMutex lock(mLock);
-    *marker = mMarkerPosition;
+    mMarkerPosition.getValue(marker);
 
     return NO_ERROR;
 }
@@ -960,7 +982,7 @@
 
 status_t AudioTrack::setPosition(uint32_t position)
 {
-    if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) {
+    if (mSharedBuffer == 0 || isOffloadedOrDirect()) {
         return INVALID_OPERATION;
     }
     if (position > mFrameCount) {
@@ -1018,14 +1040,14 @@
 
         // IAudioTrack::stop() isn't synchronous; we don't know when presentation completes
         *position = (mState == STATE_STOPPED || mState == STATE_FLUSHED) ?
-                0 : updateAndGetPosition_l();
+                0 : updateAndGetPosition_l().value();
     }
     return NO_ERROR;
 }
 
 status_t AudioTrack::getBufferPosition(uint32_t *position)
 {
-    if (mSharedBuffer == 0 || mIsTimed) {
+    if (mSharedBuffer == 0) {
         return INVALID_OPERATION;
     }
     if (position == NULL) {
@@ -1039,7 +1061,7 @@
 
 status_t AudioTrack::reload()
 {
-    if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) {
+    if (mSharedBuffer == 0 || isOffloadedOrDirect()) {
         return INVALID_OPERATION;
     }
 
@@ -1168,22 +1190,27 @@
         mSampleRate = mAfSampleRate;
         mOriginalSampleRate = mAfSampleRate;
     }
-    // Client decides whether the track is TIMED (see below), but can only express a preference
-    // for FAST.  Server will perform additional tests.
-    if ((mFlags & AUDIO_OUTPUT_FLAG_FAST) && !((
+    // Client can only express a preference for FAST.  Server will perform additional tests.
+    if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
+        bool useCaseAllowed =
             // either of these use cases:
             // use case 1: shared buffer
             (mSharedBuffer != 0) ||
             // use case 2: callback transfer mode
             (mTransfer == TRANSFER_CALLBACK) ||
             // use case 3: obtain/release mode
-            (mTransfer == TRANSFER_OBTAIN)) &&
-            // matching sample rate
-            (mSampleRate == mAfSampleRate))) {
-        ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client; transfer %d, track %u Hz, output %u Hz",
+            (mTransfer == TRANSFER_OBTAIN) ||
+            // use case 4: synchronous write
+            ((mTransfer == TRANSFER_SYNC) && mThreadCanCallJava);
+        // sample rates must also match
+        bool fastAllowed = useCaseAllowed && (mSampleRate == mAfSampleRate);
+        if (!fastAllowed) {
+            ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client; transfer %d,"
+                "track %u Hz, output %u Hz",
                 mTransfer, mSampleRate, mAfSampleRate);
-        // once denied, do not request again if IAudioTrack is re-created
-        mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
+            // once denied, do not request again if IAudioTrack is re-created
+            mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
+        }
     }
 
     // The client's AudioTrack buffer is divided into n parts for purpose of wakeup by server, where
@@ -1196,7 +1223,7 @@
     mNotificationFramesAct = mNotificationFramesReq;
 
     size_t frameCount = mReqFrameCount;
-    if (!audio_is_linear_pcm(mFormat)) {
+    if (!audio_has_proportional_frames(mFormat)) {
 
         if (mSharedBuffer != 0) {
             // Same comment as below about ignoring frameCount parameter for set()
@@ -1247,14 +1274,11 @@
     }
 
     IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
-    if (mIsTimed) {
-        trackFlags |= IAudioFlinger::TRACK_TIMED;
-    }
 
     pid_t tid = -1;
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
         trackFlags |= IAudioFlinger::TRACK_FAST;
-        if (mAudioTrackThread != 0) {
+        if (mAudioTrackThread != 0 && !mThreadCanCallJava) {
             tid = mAudioTrackThread->getTid();
         }
     }
@@ -1328,7 +1352,9 @@
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
         if (trackFlags & IAudioFlinger::TRACK_FAST) {
             ALOGV("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %zu", frameCount);
-            mAwaitBoost = true;
+            if (!mThreadCanCallJava) {
+                mAwaitBoost = true;
+            }
         } else {
             ALOGV("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu", frameCount);
             // once denied, do not request again if IAudioTrack is re-created
@@ -1587,7 +1613,7 @@
 
 ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking)
 {
-    if (mTransfer != TRANSFER_SYNC || mIsTimed) {
+    if (mTransfer != TRANSFER_SYNC) {
         return INVALID_OPERATION;
     }
 
@@ -1637,73 +1663,6 @@
 
 // -------------------------------------------------------------------------
 
-TimedAudioTrack::TimedAudioTrack() {
-    mIsTimed = true;
-}
-
-status_t TimedAudioTrack::allocateTimedBuffer(size_t size, sp<IMemory>* buffer)
-{
-    AutoMutex lock(mLock);
-    status_t result = UNKNOWN_ERROR;
-
-#if 1
-    // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed
-    // while we are accessing the cblk
-    sp<IAudioTrack> audioTrack = mAudioTrack;
-    sp<IMemory> iMem = mCblkMemory;
-#endif
-
-    // If the track is not invalid already, try to allocate a buffer.  alloc
-    // fails indicating that the server is dead, flag the track as invalid so
-    // we can attempt to restore in just a bit.
-    audio_track_cblk_t* cblk = mCblk;
-    if (!(cblk->mFlags & CBLK_INVALID)) {
-        result = mAudioTrack->allocateTimedBuffer(size, buffer);
-        if (result == DEAD_OBJECT) {
-            android_atomic_or(CBLK_INVALID, &cblk->mFlags);
-        }
-    }
-
-    // If the track is invalid at this point, attempt to restore it. and try the
-    // allocation one more time.
-    if (cblk->mFlags & CBLK_INVALID) {
-        result = restoreTrack_l("allocateTimedBuffer");
-
-        if (result == NO_ERROR) {
-            result = mAudioTrack->allocateTimedBuffer(size, buffer);
-        }
-    }
-
-    return result;
-}
-
-status_t TimedAudioTrack::queueTimedBuffer(const sp<IMemory>& buffer,
-                                           int64_t pts)
-{
-    status_t status = mAudioTrack->queueTimedBuffer(buffer, pts);
-    {
-        AutoMutex lock(mLock);
-        audio_track_cblk_t* cblk = mCblk;
-        // restart track if it was disabled by audioflinger due to previous underrun
-        if (buffer->size() != 0 && status == NO_ERROR &&
-                (mState == STATE_ACTIVE) && (cblk->mFlags & CBLK_DISABLED)) {
-            android_atomic_and(~CBLK_DISABLED, &cblk->mFlags);
-            ALOGW("queueTimedBuffer() track %p disabled, restarting", this);
-            // FIXME ignoring status
-            mAudioTrack->start();
-        }
-    }
-    return status;
-}
-
-status_t TimedAudioTrack::setMediaTimeTransform(const LinearTransform& xform,
-                                                TargetTimeline target)
-{
-    return mAudioTrack->setMediaTimeTransform(xform, target);
-}
-
-// -------------------------------------------------------------------------
-
 nsecs_t AudioTrack::processAudioBuffer()
 {
     // Currently the AudioTrack thread is not created if there are no callbacks.
@@ -1774,23 +1733,23 @@
     }
 
     // Get current position of server
-    size_t position = updateAndGetPosition_l();
+    Modulo<uint32_t> position(updateAndGetPosition_l());
 
     // Manage marker callback
     bool markerReached = false;
-    size_t markerPosition = mMarkerPosition;
-    // FIXME fails for wraparound, need 64 bits
-    if (!mMarkerReached && (markerPosition > 0) && (position >= markerPosition)) {
+    Modulo<uint32_t> markerPosition(mMarkerPosition);
+    // uses 32 bit wraparound for comparison with position.
+    if (!mMarkerReached && markerPosition.value() > 0 && position >= markerPosition) {
         mMarkerReached = markerReached = true;
     }
 
     // Determine number of new position callback(s) that will be needed, while locked
     size_t newPosCount = 0;
-    size_t newPosition = mNewPosition;
-    size_t updatePeriod = mUpdatePeriod;
+    Modulo<uint32_t> newPosition(mNewPosition);
+    uint32_t updatePeriod = mUpdatePeriod;
     // FIXME fails for wraparound, need 64 bits
     if (updatePeriod > 0 && position >= newPosition) {
-        newPosCount = ((position - newPosition) / updatePeriod) + 1;
+        newPosCount = ((position - newPosition).value() / updatePeriod) + 1;
         mNewPosition += updatePeriod * newPosCount;
     }
 
@@ -1891,7 +1850,7 @@
         mCbf(EVENT_MARKER, mUserData, &markerPosition);
     }
     while (newPosCount > 0) {
-        size_t temp = newPosition;
+        size_t temp = newPosition.value(); // FIXME size_t != uint32_t
         mCbf(EVENT_NEW_POS, mUserData, &temp);
         newPosition += updatePeriod;
         newPosCount--;
@@ -1915,14 +1874,14 @@
     // FIXME only for non-compressed audio
     uint32_t minFrames = ~0;
     if (!markerReached && position < markerPosition) {
-        minFrames = markerPosition - position;
+        minFrames = (markerPosition - position).value();
     }
     if (loopPeriod > 0 && loopPeriod < minFrames) {
         // loopPeriod is already adjusted for actual position.
         minFrames = loopPeriod;
     }
     if (updatePeriod > 0) {
-        minFrames = min(minFrames, uint32_t(newPosition - position));
+        minFrames = min(minFrames, (newPosition - position).value());
     }
 
     // If > 0, poll periodically to recover from a stuck server.  A good value is 2.
@@ -1987,7 +1946,7 @@
             return NS_NEVER;
         }
 
-        if (mRetryOnPartialBuffer && audio_is_linear_pcm(mFormat)) {
+        if (mRetryOnPartialBuffer && audio_has_proportional_frames(mFormat)) {
             mRetryOnPartialBuffer = false;
             if (avail < mRemainingFrames) {
                 if (ns > 0) { // account for obtain time
@@ -2033,7 +1992,7 @@
             // buffer size and skip the loop entirely.
 
             nsecs_t myns;
-            if (audio_is_linear_pcm(mFormat)) {
+            if (audio_has_proportional_frames(mFormat)) {
                 // time to wait based on buffer occupancy
                 const nsecs_t datans = mRemainingFrames <= avail ? 0 :
                         framesToNanoseconds(mRemainingFrames - avail, sampleRate, speed);
@@ -2112,6 +2071,9 @@
         return DEAD_OBJECT;
     }
 
+    // Save so we can return count since creation.
+    mUnderrunCountOffset = getUnderrunCount_l();
+
     // save the old static buffer position
     size_t bufferPosition = 0;
     int loopCount = 0;
@@ -2157,11 +2119,11 @@
     return result;
 }
 
-uint32_t AudioTrack::updateAndGetPosition_l()
+Modulo<uint32_t> AudioTrack::updateAndGetPosition_l()
 {
     // This is the sole place to read server consumed frames
-    uint32_t newServer = mProxy->getPosition();
-    uint32_t delta = newServer > mServer ? newServer - mServer : 0;
+    Modulo<uint32_t> newServer(mProxy->getPosition());
+    const int32_t delta = (newServer - mServer).signedValue();
     // TODO There is controversy about whether there can be "negative jitter" in server position.
     //      This should be investigated further, and if possible, it should be addressed.
     //      A more definite failure mode is infrequent polling by client.
@@ -2170,12 +2132,14 @@
     //      That should ensure delta never goes negative for infrequent polling
     //      unless the server has more than 2^31 frames in its buffer,
     //      in which case the use of uint32_t for these counters has bigger issues.
-    if (newServer < mServer) {
-        ALOGE("detected illegal retrograde motion by the server: mServer advanced by %d",
-              (int32_t) newServer - mServer);
-    }
+    ALOGE_IF(delta < 0,
+            "detected illegal retrograde motion by the server: mServer advanced by %d",
+            delta);
     mServer = newServer;
-    return mPosition += delta;
+    if (delta > 0) { // avoid retrograde
+        mPosition += delta;
+    }
+    return mPosition;
 }
 
 bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const
@@ -2197,7 +2161,6 @@
     return mAudioTrack->setParameters(keyValuePairs);
 }
 
-__attribute__((no_sanitize("integer")))
 status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp)
 {
     AutoMutex lock(mLock);
@@ -2206,11 +2169,6 @@
     // Set false here to cover all the error return cases.
     mPreviousTimestampValid = false;
 
-    // FIXME not implemented for fast tracks; should use proxy and SSQ
-    if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
-        return INVALID_OPERATION;
-    }
-
     switch (mState) {
     case STATE_ACTIVE:
     case STATE_PAUSED:
@@ -2240,7 +2198,10 @@
 
     // The presented frame count must always lag behind the consumed frame count.
     // To avoid a race, read the presented frames first.  This ensures that presented <= consumed.
-    status_t status = mAudioTrack->getTimestamp(timestamp);
+
+    // FastTrack timestamps are read through shared memory; otherwise use Binder.
+    status_t status = (mFlags & AUDIO_OUTPUT_FLAG_FAST) ?
+            mProxy->getTimestamp(&timestamp) : mAudioTrack->getTimestamp(timestamp);
     if (status != NO_ERROR) {
         ALOGV_IF(status != WOULD_BLOCK, "getTimestamp error:%#x", status);
         return status;
@@ -2310,15 +2271,19 @@
         // If this delta between these is greater than the client position, it means that
         // actually presented is still stuck at the starting line (figuratively speaking),
         // waiting for the first frame to go by.  So we can't report a valid timestamp yet.
-        if ((uint32_t) (mServer - timestamp.mPosition) > mPosition) {
+        // Note: We explicitly use non-Modulo comparison here - potential wrap issue when
+        // mPosition exceeds 32 bits.
+        // TODO Remove when timestamp is updated to contain pipeline status info.
+        const int32_t pipelineDepthInFrames = (mServer - timestamp.mPosition).signedValue();
+        if (pipelineDepthInFrames > 0 /* should be true, but we check anyways */
+                && (uint32_t)pipelineDepthInFrames > mPosition.value()) {
             return INVALID_OPERATION;
         }
         // Convert timestamp position from server time base to client time base.
         // TODO The following code should work OK now because timestamp.mPosition is 32-bit.
         // But if we change it to 64-bit then this could fail.
-        // Split this out instead of using += to prevent unsigned overflow
-        // checks in the outer sum.
-        timestamp.mPosition = timestamp.mPosition + static_cast<int32_t>(mPosition) - mServer;
+        // Use Modulo computation here.
+        timestamp.mPosition = (mPosition - mServer + timestamp.mPosition).value();
         // Immediately after a call to getPosition_l(), mPosition and
         // mServer both represent the same frame position.  mPosition is
         // in client's point of view, and mServer is in server's point of
@@ -2332,9 +2297,9 @@
     // This is sometimes caused by erratic reports of the available space in the ALSA drivers.
     if (status == NO_ERROR) {
         if (previousTimestampValid) {
-#define TIME_TO_NANOS(time) ((uint64_t)time.tv_sec * 1000000000 + time.tv_nsec)
-            const uint64_t previousTimeNanos = TIME_TO_NANOS(mPreviousTimestamp.mTime);
-            const uint64_t currentTimeNanos = TIME_TO_NANOS(timestamp.mTime);
+#define TIME_TO_NANOS(time) ((int64_t)time.tv_sec * 1000000000 + time.tv_nsec)
+            const int64_t previousTimeNanos = TIME_TO_NANOS(mPreviousTimestamp.mTime);
+            const int64_t currentTimeNanos = TIME_TO_NANOS(timestamp.mTime);
 #undef TIME_TO_NANOS
             if (currentTimeNanos < previousTimeNanos) {
                 ALOGW("retrograde timestamp time");
@@ -2343,8 +2308,8 @@
 
             // Looking at signed delta will work even when the timestamps
             // are wrapping around.
-            int32_t deltaPosition = static_cast<int32_t>(timestamp.mPosition
-                    - mPreviousTimestamp.mPosition);
+            int32_t deltaPosition = (Modulo<uint32_t>(timestamp.mPosition)
+                    - mPreviousTimestamp.mPosition).signedValue();
             // position can bobble slightly as an artifact; this hides the bobble
             static const int32_t MINIMUM_POSITION_DELTA = 8;
             if (deltaPosition < 0) {
@@ -2422,6 +2387,17 @@
     return NO_ERROR;
 }
 
+uint32_t AudioTrack::getUnderrunCount() const
+{
+    AutoMutex lock(mLock);
+    return getUnderrunCount_l();
+}
+
+uint32_t AudioTrack::getUnderrunCount_l() const
+{
+    return mProxy->getUnderrunCount() + mUnderrunCountOffset;
+}
+
 uint32_t AudioTrack::getUnderrunFrames() const
 {
     AutoMutex lock(mLock);
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 9d5d996..988386e 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -66,7 +66,9 @@
 
 ClientProxy::ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
         size_t frameSize, bool isOut, bool clientInServer)
-    : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer), mEpoch(0)
+    : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer)
+    , mBufferSizeInFrames(frameCount)
+    , mEpoch(0)
 {
 }
 
@@ -151,6 +153,7 @@
             rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
             front = cblk->u.mStreaming.mFront;
         }
+        // write to rear, read from front
         ssize_t filled = rear - front;
         // pipe should not be overfull
         if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
@@ -166,9 +169,15 @@
             cblk->u.mStreaming.mFront = rear;
             (void) android_atomic_or(CBLK_OVERRUN, &cblk->mFlags);
         }
-        // don't allow filling pipe beyond the nominal size
-        size_t avail = mIsOut ? mFrameCount - filled : filled;
-        if (avail > 0) {
+        // Don't allow filling pipe beyond the user settable size.
+        // The calculation for avail can go negative if the buffer size
+        // is suddenly dropped below the amount already in the buffer.
+        // So use a signed calculation to prevent a numeric overflow abort.
+        ssize_t adjustableSize = (ssize_t) mBufferSizeInFrames;
+        ssize_t avail =  (mIsOut) ? adjustableSize - filled : filled;
+        if (avail < 0) {
+            avail = 0;
+        } else if (avail > 0) {
             // 'avail' may be non-contiguous, so return only the first contiguous chunk
             size_t part1;
             if (mIsOut) {
@@ -178,7 +187,7 @@
                 front &= mFrameCountP2 - 1;
                 part1 = mFrameCountP2 - front;
             }
-            if (part1 > avail) {
+            if (part1 > (size_t)avail) {
                 part1 = avail;
             }
             if (part1 > buffer->mFrameCount) {
@@ -347,25 +356,18 @@
             (mFrameCountP2 - 1);
 }
 
-size_t ClientProxy::getFramesFilled() {
-    audio_track_cblk_t* cblk = mCblk;
-    int32_t front;
-    int32_t rear;
-
-    if (mIsOut) {
-        front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
-        rear = cblk->u.mStreaming.mRear;
-    } else {
-        rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
-        front = cblk->u.mStreaming.mFront;
+size_t ClientProxy::setBufferSizeInFrames(size_t size)
+{
+    // TODO set minimum to 2X the fast mixer buffer size.
+    size_t minimum = 128 * 2; // arbitrary
+    size_t maximum = frameCount();
+    if (size < minimum) {
+        size = minimum;
+    } else if (size > maximum) {
+        size = maximum;
     }
-    ssize_t filled = rear - front;
-    // pipe should not be overfull
-    if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
-        ALOGE("Shared memory control block is corrupt (filled=%zd); shutting down", filled);
-        return 0;
-    }
-    return (size_t)filled;
+    mBufferSizeInFrames = size;
+    return size;
 }
 
 // ---------------------------------------------------------------------------
@@ -595,7 +597,7 @@
 ServerProxy::ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
         size_t frameSize, bool isOut, bool clientInServer)
     : Proxy(cblk, buffers, frameCount, frameSize, isOut, clientInServer),
-      mAvailToClient(0), mFlush(0)
+      mAvailToClient(0), mFlush(0), mReleased(0)
 {
 }
 
@@ -731,6 +733,7 @@
     }
 
     cblk->mServer += stepCount;
+    mReleased += stepCount;
 
     size_t half = mFrameCount / 2;
     if (half == 0) {
@@ -802,10 +805,25 @@
 void AudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
 {
     audio_track_cblk_t* cblk = mCblk;
-    cblk->u.mStreaming.mUnderrunFrames += frameCount;
+    if (frameCount > 0) {
+        cblk->u.mStreaming.mUnderrunFrames += frameCount;
 
-    // FIXME also wake futex so that underrun is noticed more quickly
-    (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags);
+        if (!mUnderrunning) { // start of underrun?
+            mUnderrunCount++;
+            cblk->u.mStreaming.mUnderrunCount = mUnderrunCount;
+            mUnderrunning = true;
+            ALOGV("tallyUnderrunFrames(%3u) at uf = %u, bump mUnderrunCount = %u",
+                frameCount, cblk->u.mStreaming.mUnderrunFrames, mUnderrunCount);
+        }
+
+        // FIXME also wake futex so that underrun is noticed more quickly
+        (void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags);
+    } else {
+        ALOGV_IF(mUnderrunning,
+            "tallyUnderrunFrames(%3u) at uf = %u, underrun finished",
+            frameCount, cblk->u.mStreaming.mUnderrunFrames);
+        mUnderrunning = false; // so we can detect the next edge
+    }
 }
 
 AudioPlaybackRate AudioTrackServerProxy::getPlaybackRate()
@@ -1016,6 +1034,8 @@
     mFramesReadySafe = clampToSize(mFramesReady);
 
     cblk->mServer += stepCount;
+    mReleased += stepCount;
+
     // This may overflow, but client is not supposed to rely on it
     StaticAudioTrackPosLoop posLoop;
     posLoop.mBufferPosition = mState.mPosition;
@@ -1031,7 +1051,7 @@
     buffer->mNonContig = 0;
 }
 
-void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount __unused)
+void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
 {
     // Unlike AudioTrackServerProxy::tallyUnderrunFrames() used for streaming tracks,
     // we don't have a location to count underrun frames.  The underrun frame counter
@@ -1039,7 +1059,9 @@
     // possible for static buffer tracks other than at end of buffer, so this is not a loss.
 
     // FIXME also wake futex so that underrun is noticed more quickly
-    (void) android_atomic_or(CBLK_UNDERRUN, &mCblk->mFlags);
+    if (frameCount > 0) {
+        (void) android_atomic_or(CBLK_UNDERRUN, &mCblk->mFlags);
+    }
 }
 
 // ---------------------------------------------------------------------------
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 76b5924..c95d4c4 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -74,6 +74,8 @@
     START_AUDIO_SOURCE,
     STOP_AUDIO_SOURCE,
     SET_AUDIO_PORT_CALLBACK_ENABLED,
+    SET_MASTER_MONO,
+    GET_MASTER_MONO,
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -767,6 +769,37 @@
         status = (status_t)reply.readInt32();
         return status;
     }
+
+    virtual status_t setMasterMono(bool mono)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(static_cast<int32_t>(mono));
+        status_t status = remote()->transact(SET_MASTER_MONO, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        return static_cast<status_t>(reply.readInt32());
+    }
+
+    virtual status_t getMasterMono(bool *mono)
+    {
+        if (mono == nullptr) {
+            return BAD_VALUE;
+        }
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+
+        status_t status = remote()->transact(GET_MASTER_MONO, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = static_cast<status_t>(reply.readInt32());
+        if (status == NO_ERROR) {
+            *mono = static_cast<bool>(reply.readInt32());
+        }
+        return status;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1311,6 +1344,25 @@
             return NO_ERROR;
         } break;
 
+        case SET_MASTER_MONO: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            bool mono = static_cast<bool>(data.readInt32());
+            status_t status = setMasterMono(mono);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        } break;
+
+        case GET_MASTER_MONO: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            bool mono;
+            status_t status = getMasterMono(&mono);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->writeInt32(static_cast<int32_t>(mono));
+            }
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IAudioPolicyServiceClient.cpp b/media/libmedia/IAudioPolicyServiceClient.cpp
index 65cc7d6..fe5df28 100644
--- a/media/libmedia/IAudioPolicyServiceClient.cpp
+++ b/media/libmedia/IAudioPolicyServiceClient.cpp
@@ -30,7 +30,8 @@
 enum {
     PORT_LIST_UPDATE = IBinder::FIRST_CALL_TRANSACTION,
     PATCH_LIST_UPDATE,
-    MIX_STATE_UPDATE
+    MIX_STATE_UPDATE,
+    RECORDING_CONFIGURATION_UPDATE
 };
 
 class BpAudioPolicyServiceClient : public BpInterface<IAudioPolicyServiceClient>
@@ -63,6 +64,16 @@
         data.writeInt32(state);
         remote()->transact(MIX_STATE_UPDATE, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    void onRecordingConfigurationUpdate(int event, audio_session_t session,
+            audio_source_t source) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyServiceClient::getInterfaceDescriptor());
+        data.writeInt32(event);
+        data.writeInt32(session);
+        data.writeInt32(source);
+        remote()->transact(RECORDING_CONFIGURATION_UPDATE, data, &reply, IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyServiceClient, "android.media.IAudioPolicyServiceClient");
@@ -89,7 +100,15 @@
             int32_t state = data.readInt32();
             onDynamicPolicyMixStateUpdate(regId, state);
             return NO_ERROR;
-    }
+        } break;
+    case RECORDING_CONFIGURATION_UPDATE: {
+            CHECK_INTERFACE(IAudioPolicyServiceClient, data, reply);
+            int event = (int) data.readInt32();
+            audio_session_t session = (audio_session_t) data.readInt32();
+            audio_source_t source = (audio_source_t) data.readInt32();
+            onRecordingConfigurationUpdate(event, session, source);
+            return NO_ERROR;
+        } break;
     default:
         return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index 651cb61..636e3bb 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -36,9 +36,6 @@
     RESERVED, // was MUTE
     PAUSE,
     ATTACH_AUX_EFFECT,
-    ALLOCATE_TIMED_BUFFER,
-    QUEUE_TIMED_BUFFER,
-    SET_MEDIA_TIME_TRANSFORM,
     SET_PARAMETERS,
     GET_TIMESTAMP,
     SIGNAL,
@@ -115,55 +112,6 @@
         return status;
     }
 
-    virtual status_t allocateTimedBuffer(size_t size, sp<IMemory>* buffer) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
-        data.writeInt64(size);
-        status_t status = remote()->transact(ALLOCATE_TIMED_BUFFER,
-                                             data, &reply);
-        if (status == NO_ERROR) {
-            status = reply.readInt32();
-            if (status == NO_ERROR) {
-                *buffer = interface_cast<IMemory>(reply.readStrongBinder());
-                if (*buffer != 0 && (*buffer)->pointer() == NULL) {
-                    (*buffer).clear();
-                }
-            }
-        }
-        return status;
-    }
-
-    virtual status_t queueTimedBuffer(const sp<IMemory>& buffer,
-                                      int64_t pts) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
-        data.writeStrongBinder(IInterface::asBinder(buffer));
-        data.writeInt64(pts);
-        status_t status = remote()->transact(QUEUE_TIMED_BUFFER,
-                                             data, &reply);
-        if (status == NO_ERROR) {
-            status = reply.readInt32();
-        }
-        return status;
-    }
-
-    virtual status_t setMediaTimeTransform(const LinearTransform& xform,
-                                           int target) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
-        data.writeInt64(xform.a_zero);
-        data.writeInt64(xform.b_zero);
-        data.writeInt32(xform.a_to_b_numer);
-        data.writeInt32(xform.a_to_b_denom);
-        data.writeInt32(target);
-        status_t status = remote()->transact(SET_MEDIA_TIME_TRANSFORM,
-                                             data, &reply);
-        if (status == NO_ERROR) {
-            status = reply.readInt32();
-        }
-        return status;
-    }
-
     virtual status_t setParameters(const String8& keyValuePairs) {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
@@ -235,35 +183,6 @@
             reply->writeInt32(attachAuxEffect(data.readInt32()));
             return NO_ERROR;
         } break;
-        case ALLOCATE_TIMED_BUFFER: {
-            CHECK_INTERFACE(IAudioTrack, data, reply);
-            sp<IMemory> buffer;
-            status_t status = allocateTimedBuffer(data.readInt64(), &buffer);
-            reply->writeInt32(status);
-            if (status == NO_ERROR) {
-                reply->writeStrongBinder(IInterface::asBinder(buffer));
-            }
-            return NO_ERROR;
-        } break;
-        case QUEUE_TIMED_BUFFER: {
-            CHECK_INTERFACE(IAudioTrack, data, reply);
-            sp<IMemory> buffer = interface_cast<IMemory>(
-                data.readStrongBinder());
-            uint64_t pts = data.readInt64();
-            reply->writeInt32(queueTimedBuffer(buffer, pts));
-            return NO_ERROR;
-        } break;
-        case SET_MEDIA_TIME_TRANSFORM: {
-            CHECK_INTERFACE(IAudioTrack, data, reply);
-            LinearTransform xform;
-            xform.a_zero = data.readInt64();
-            xform.b_zero = data.readInt64();
-            xform.a_to_b_numer = data.readInt32();
-            xform.a_to_b_denom = data.readInt32();
-            int target = data.readInt32();
-            reply->writeInt32(setMediaTimeTransform(xform, target));
-            return NO_ERROR;
-        } break;
         case SET_PARAMETERS: {
             CHECK_INTERFACE(IAudioTrack, data, reply);
             String8 keyValuePairs(data.readString8());
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
index a398ff7..79059c6 100644
--- a/media/libmedia/ICrypto.cpp
+++ b/media/libmedia/ICrypto.cpp
@@ -98,7 +98,7 @@
             bool secure,
             const uint8_t key[16],
             const uint8_t iv[16],
-            CryptoPlugin::Mode mode,
+            CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
             const sp<IMemory> &sharedBuffer, size_t offset,
             const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
             void *dstPtr,
@@ -107,6 +107,8 @@
         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
         data.writeInt32(secure);
         data.writeInt32(mode);
+        data.writeInt32(pattern.mEncryptBlocks);
+        data.writeInt32(pattern.mSkipBlocks);
 
         static const uint8_t kDummy[16] = { 0 };
 
@@ -261,7 +263,11 @@
             CHECK_INTERFACE(ICrypto, data, reply);
 
             const char *mime = data.readCString();
-            reply->writeInt32(requiresSecureDecoderComponent(mime));
+            if (mime == NULL) {
+                reply->writeInt32(BAD_VALUE);
+            } else {
+                reply->writeInt32(requiresSecureDecoderComponent(mime));
+            }
 
             return OK;
         }
@@ -272,6 +278,9 @@
 
             bool secure = data.readInt32() != 0;
             CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();
+            CryptoPlugin::Pattern pattern;
+            pattern.mEncryptBlocks = data.readInt32();
+            pattern.mSkipBlocks = data.readInt32();
 
             uint8_t key[16];
             data.read(key, sizeof(key));
@@ -282,6 +291,10 @@
             size_t totalSize = data.readInt32();
             sp<IMemory> sharedBuffer =
                 interface_cast<IMemory>(data.readStrongBinder());
+            if (sharedBuffer == NULL) {
+                reply->writeInt32(BAD_VALUE);
+                return OK;
+            }
             int32_t offset = data.readInt32();
 
             int32_t numSubSamples = data.readInt32();
@@ -297,7 +310,7 @@
             if (secure) {
                 secureBufferId = reinterpret_cast<void *>(static_cast<uintptr_t>(data.readInt64()));
             } else {
-                dstPtr = calloc(1, totalSize);
+                dstPtr = malloc(totalSize);
             }
 
             AString errorDetailMsg;
@@ -321,14 +334,16 @@
 
             if (overflow || sumSubsampleSizes != totalSize) {
                 result = -EINVAL;
-            } else if (offset + totalSize > sharedBuffer->size()) {
+            } else if (totalSize > sharedBuffer->size()) {
+                result = -EINVAL;
+            } else if ((size_t)offset > sharedBuffer->size() - totalSize) {
                 result = -EINVAL;
             } else {
                 result = decrypt(
                     secure,
                     key,
                     iv,
-                    mode,
+                    mode, pattern,
                     sharedBuffer, offset,
                     subSamples, numSubSamples,
                     secure ? secureBufferId : dstPtr,
diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
index 76d1d68..ac864a4 100644
--- a/media/libmedia/IDataSource.cpp
+++ b/media/libmedia/IDataSource.cpp
@@ -32,6 +32,7 @@
     READ_AT,
     GET_SIZE,
     CLOSE,
+    GET_FLAGS,
 };
 
 struct BpDataSource : public BpInterface<IDataSource> {
@@ -68,6 +69,13 @@
         data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
         remote()->transact(CLOSE, data, &reply);
     }
+
+    virtual uint32_t getFlags() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
+        remote()->transact(GET_FLAGS, data, &reply);
+        return reply.readUint32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(DataSource, "android.media.IDataSource");
@@ -100,6 +108,11 @@
             close();
             return NO_ERROR;
         } break;
+        case GET_FLAGS: {
+            CHECK_INTERFACE(IDataSource, data, reply);
+            reply->writeUint32(getFlags());
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp
index b1ad0c5..5a4591c 100644
--- a/media/libmedia/IDrm.cpp
+++ b/media/libmedia/IDrm.cpp
@@ -54,7 +54,6 @@
     SIGN_RSA,
     VERIFY,
     SET_LISTENER,
-    UNPROVISION_DEVICE,
     GET_SECURE_STOP,
     RELEASE_ALL_SECURE_STOPS
 };
@@ -277,18 +276,6 @@
         return reply.readInt32();
     }
 
-    virtual status_t unprovisionDevice() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        status_t status = remote()->transact(UNPROVISION_DEVICE, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        return reply.readInt32();
-    }
-
     virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) {
         Parcel data, reply;
         data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
@@ -749,14 +736,6 @@
             return OK;
         }
 
-        case UNPROVISION_DEVICE:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            status_t result = unprovisionDevice();
-            reply->writeInt32(result);
-            return OK;
-        }
-
         case GET_SECURE_STOPS:
         {
             CHECK_INTERFACE(IDrm, data, reply);
diff --git a/media/libmedia/IMediaCodecList.cpp b/media/libmedia/IMediaCodecList.cpp
index e2df104..737f50c 100644
--- a/media/libmedia/IMediaCodecList.cpp
+++ b/media/libmedia/IMediaCodecList.cpp
@@ -157,6 +157,10 @@
         {
             CHECK_INTERFACE(IMediaCodecList, data, reply);
             const char *type = data.readCString();
+            if (type == NULL) {
+                reply->writeInt32(NAME_NOT_FOUND);
+                return NO_ERROR;
+            }
             bool isEncoder = static_cast<bool>(data.readInt32());
             size_t startIndex = static_cast<size_t>(data.readInt32());
             ssize_t index = findCodecByType(type, isEncoder, startIndex);
@@ -172,6 +176,10 @@
         {
             CHECK_INTERFACE(IMediaCodecList, data, reply);
             const char *name = data.readCString();
+            if (name == NULL) {
+                reply->writeInt32(NAME_NOT_FOUND);
+                return NO_ERROR;
+            }
             ssize_t index = findCodecByName(name);
             if (index > INT32_MAX || index < 0) {
                 index = NAME_NOT_FOUND;
diff --git a/media/libmedia/IMediaCodecService.cpp b/media/libmedia/IMediaCodecService.cpp
new file mode 100644
index 0000000..dcf2b27
--- /dev/null
+++ b/media/libmedia/IMediaCodecService.cpp
@@ -0,0 +1,72 @@
+/*
+**
+** 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 "IMediaCodecService"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/Parcel.h>
+#include <media/IMediaCodecService.h>
+
+namespace android {
+
+enum {
+    GET_OMX = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpMediaCodecService : public BpInterface<IMediaCodecService>
+{
+public:
+    BpMediaCodecService(const sp<IBinder>& impl)
+        : BpInterface<IMediaCodecService>(impl)
+    {
+    }
+
+    virtual sp<IOMX> getOMX() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaCodecService::getInterfaceDescriptor());
+        remote()->transact(GET_OMX, data, &reply);
+        return interface_cast<IOMX>(reply.readStrongBinder());
+    }
+
+};
+
+IMPLEMENT_META_INTERFACE(MediaCodecService, "android.media.IMediaCodecService");
+
+// ----------------------------------------------------------------------
+
+status_t BnMediaCodecService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+
+        case GET_OMX: {
+            CHECK_INTERFACE(IMediaCodecService, data, reply);
+            sp<IOMX> omx = getOMX();
+            reply->writeStrongBinder(IInterface::asBinder(omx));
+            return NO_ERROR;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+} // namespace android
diff --git a/media/libmedia/IMediaDrmService.cpp b/media/libmedia/IMediaDrmService.cpp
new file mode 100644
index 0000000..9b6ecfd
--- /dev/null
+++ b/media/libmedia/IMediaDrmService.cpp
@@ -0,0 +1,88 @@
+/*
+**
+** 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 <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
+#include <media/ICrypto.h>
+#include <media/IDrm.h>
+#include <media/IMediaDrmService.h>
+
+#include <utils/Errors.h>  // for status_t
+#include <utils/String8.h>
+
+namespace android {
+
+enum {
+    MAKE_CRYPTO = IBinder::FIRST_CALL_TRANSACTION,
+    MAKE_DRM,
+};
+
+class BpMediaDrmService: public BpInterface<IMediaDrmService>
+{
+public:
+    BpMediaDrmService(const sp<IBinder>& impl)
+        : BpInterface<IMediaDrmService>(impl)
+    {
+    }
+
+    virtual sp<ICrypto> makeCrypto() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaDrmService::getInterfaceDescriptor());
+        remote()->transact(MAKE_CRYPTO, data, &reply);
+        return interface_cast<ICrypto>(reply.readStrongBinder());
+    }
+
+    virtual sp<IDrm> makeDrm() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaDrmService::getInterfaceDescriptor());
+        remote()->transact(MAKE_DRM, data, &reply);
+        return interface_cast<IDrm>(reply.readStrongBinder());
+    }
+
+};
+
+IMPLEMENT_META_INTERFACE(MediaDrmService, "android.media.IMediaDrmService");
+
+// ----------------------------------------------------------------------
+
+status_t BnMediaDrmService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+        case MAKE_CRYPTO: {
+            CHECK_INTERFACE(IMediaDrmService, data, reply);
+            sp<ICrypto> crypto = makeCrypto();
+            reply->writeStrongBinder(IInterface::asBinder(crypto));
+            return NO_ERROR;
+        } break;
+        case MAKE_DRM: {
+            CHECK_INTERFACE(IMediaDrmService, data, reply);
+            sp<IDrm> drm = makeDrm();
+            reply->writeStrongBinder(IInterface::asBinder(drm));
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+} // namespace android
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
new file mode 100644
index 0000000..76d5648
--- /dev/null
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2009 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 "BpMediaExtractor"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <media/IMediaExtractor.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+enum {
+    COUNTTRACKS = IBinder::FIRST_CALL_TRANSACTION,
+    GETTRACK,
+    GETTRACKMETADATA,
+    GETMETADATA,
+    FLAGS,
+    SETDRMFLAG,
+    GETDRMFLAG,
+    GETDRMTRACKINFO,
+    SETUID,
+    NAME
+};
+
+class BpMediaExtractor : public BpInterface<IMediaExtractor> {
+public:
+    BpMediaExtractor(const sp<IBinder>& impl)
+        : BpInterface<IMediaExtractor>(impl)
+    {
+    }
+
+    virtual size_t countTracks() {
+        ALOGV("countTracks");
+        Parcel data, reply;
+        data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+        status_t ret = remote()->transact(COUNTTRACKS, data, &reply);
+        size_t numTracks = 0;
+        if (ret == NO_ERROR) {
+            numTracks = reply.readUint32();
+        }
+        return numTracks;
+    }
+    virtual sp<IMediaSource> getTrack(size_t index) {
+        ALOGV("getTrack(%zu)", index);
+        Parcel data, reply;
+        data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+        data.writeUint32(index);
+        status_t ret = remote()->transact(GETTRACK, data, &reply);
+        if (ret == NO_ERROR) {
+            return interface_cast<IMediaSource>(reply.readStrongBinder());
+        }
+        return NULL;
+    }
+
+    virtual sp<MetaData> getTrackMetaData(
+            size_t index, uint32_t flags) {
+        ALOGV("getTrackMetaData(%zu, %u)", index, flags);
+        Parcel data, reply;
+        data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+        data.writeUint32(index);
+        data.writeUint32(flags);
+        status_t ret = remote()->transact(GETTRACKMETADATA, data, &reply);
+        if (ret == NO_ERROR) {
+            return MetaData::createFromParcel(reply);
+        }
+        return NULL;
+    }
+
+    virtual sp<MetaData> getMetaData() {
+        ALOGV("getMetaData");
+        Parcel data, reply;
+        data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+        status_t ret = remote()->transact(GETMETADATA, data, &reply);
+        if (ret == NO_ERROR) {
+            return MetaData::createFromParcel(reply);
+        }
+        return NULL;
+    }
+
+    virtual uint32_t flags() const {
+        ALOGV("flags NOT IMPLEMENTED");
+        return 0;
+    }
+
+    virtual void setDrmFlag(bool flag __unused) {
+        ALOGV("setDrmFlag NOT IMPLEMENTED");
+    }
+    virtual bool getDrmFlag() {
+        ALOGV("getDrmFlag NOT IMPLEMENTED");
+       return false;
+    }
+    virtual char* getDrmTrackInfo(size_t trackID __unused, int *len __unused) {
+        ALOGV("getDrmTrackInfo NOT IMPLEMENTED");
+        return NULL;
+    }
+    virtual void setUID(uid_t uid __unused) {
+        ALOGV("setUID NOT IMPLEMENTED");
+    }
+
+    virtual const char * name() {
+        ALOGV("name NOT IMPLEMENTED");
+        return NULL;
+    }
+};
+
+IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor");
+
+#undef LOG_TAG
+#define LOG_TAG "BnMediaExtractor"
+
+status_t BnMediaExtractor::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+        case COUNTTRACKS: {
+            ALOGV("countTracks");
+            CHECK_INTERFACE(IMediaExtractor, data, reply);
+            size_t numTracks = countTracks();
+            if (numTracks > INT32_MAX) {
+                numTracks = 0;
+            }
+            reply->writeUint32(uint32_t(numTracks));
+            return NO_ERROR;
+        }
+        case GETTRACK: {
+            ALOGV("getTrack()");
+            CHECK_INTERFACE(IMediaExtractor, data, reply);
+            uint32_t idx;
+            if (data.readUint32(&idx) == NO_ERROR) {
+                return reply->writeStrongBinder(IInterface::asBinder(getTrack((size_t(idx)))));
+            }
+            return UNKNOWN_ERROR;
+        }
+        case GETTRACKMETADATA: {
+            ALOGV("getTrackMetaData");
+            CHECK_INTERFACE(IMediaExtractor, data, reply);
+            uint32_t idx;
+            uint32_t flags;
+            if (data.readUint32(&idx) == NO_ERROR &&
+                    data.readUint32(&flags) == NO_ERROR) {
+                sp<MetaData> meta = getTrackMetaData(idx, flags);
+                meta->writeToParcel(*reply);
+                return NO_ERROR;
+            }
+            return UNKNOWN_ERROR;
+        }
+        case GETMETADATA: {
+            ALOGV("getMetaData");
+            CHECK_INTERFACE(IMediaExtractor, data, reply);
+            sp<MetaData> meta = getMetaData();
+            if (meta != NULL) {
+                meta->writeToParcel(*reply);
+                return NO_ERROR;
+            }
+            return UNKNOWN_ERROR;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+
+}  // namespace android
+
diff --git a/media/libmedia/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp
new file mode 100644
index 0000000..dcbbde2
--- /dev/null
+++ b/media/libmedia/IMediaExtractorService.cpp
@@ -0,0 +1,87 @@
+/*
+**
+** Copyright 2007, 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 "IMediaExtractorService"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/Parcel.h>
+#include <media/IMediaExtractorService.h>
+
+namespace android {
+
+enum {
+    MAKE_EXTRACTOR = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpMediaExtractorService : public BpInterface<IMediaExtractorService>
+{
+public:
+    BpMediaExtractorService(const sp<IBinder>& impl)
+        : BpInterface<IMediaExtractorService>(impl)
+    {
+    }
+
+    virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaExtractorService::getInterfaceDescriptor());
+        data.writeStrongBinder(IInterface::asBinder(source));
+        if (mime != NULL) {
+            data.writeCString(mime);
+        }
+        status_t ret = remote()->transact(MAKE_EXTRACTOR, data, &reply);
+        if (ret == NO_ERROR) {
+            return interface_cast<IMediaExtractor>(reply.readStrongBinder());
+        }
+        return NULL;
+    }
+
+};
+
+IMPLEMENT_META_INTERFACE(MediaExtractorService, "android.media.IMediaExtractorService");
+
+// ----------------------------------------------------------------------
+
+status_t BnMediaExtractorService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+
+        case MAKE_EXTRACTOR: {
+            CHECK_INTERFACE(IMediaExtractorService, data, reply);
+            sp<IBinder> b;
+            status_t ret = data.readStrongBinder(&b);
+            if (ret != NO_ERROR || b == NULL) {
+                ALOGE("Error reading source from parcel");
+                return ret;
+            }
+            sp<IDataSource> source = interface_cast<IDataSource>(b);
+            const char *mime = data.readCString();
+            sp<IMediaExtractor> ex = makeExtractor(source, mime);
+            reply->writeStrongBinder(IInterface::asBinder(ex));
+            return NO_ERROR;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+} // namespace android
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index dbf524e..0bee8d3 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -224,6 +224,11 @@
 
             const char* srcUrl = data.readCString();
 
+            if (httpService == NULL || srcUrl == NULL) {
+                reply->writeInt32(BAD_VALUE);
+                return NO_ERROR;
+            }
+
             KeyedVector<String8, String8> headers;
             size_t numHeaders = (size_t) data.readInt64();
             for (size_t i = 0; i < numHeaders; ++i) {
@@ -250,7 +255,11 @@
             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
             sp<IDataSource> source =
                 interface_cast<IDataSource>(data.readStrongBinder());
-            reply->writeInt32(setDataSource(source));
+            if (source == NULL) {
+                reply->writeInt32(BAD_VALUE);
+            } else {
+                reply->writeInt32(setDataSource(source));
+            }
             return NO_ERROR;
         } break;
         case GET_FRAME_AT_TIME: {
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 942aec3..519a1fd 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -444,6 +444,10 @@
             }
 
             const char* url = data.readCString();
+            if (url == NULL) {
+                reply->writeInt32(BAD_VALUE);
+                return NO_ERROR;
+            }
             KeyedVector<String8, String8> headers;
             int32_t numHeaders = data.readInt32();
             for (int i = 0; i < numHeaders; ++i) {
@@ -467,14 +471,22 @@
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             sp<IStreamSource> source =
                 interface_cast<IStreamSource>(data.readStrongBinder());
-            reply->writeInt32(setDataSource(source));
+            if (source == NULL) {
+                reply->writeInt32(BAD_VALUE);
+            } else {
+                reply->writeInt32(setDataSource(source));
+            }
             return NO_ERROR;
         }
         case SET_DATA_SOURCE_CALLBACK: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
             sp<IDataSource> source =
                 interface_cast<IDataSource>(data.readStrongBinder());
-            reply->writeInt32(setDataSource(source));
+            if (source == NULL) {
+                reply->writeInt32(BAD_VALUE);
+            } else {
+                reply->writeInt32(setDataSource(source));
+            }
             return NO_ERROR;
         }
         case SET_VIDEO_SURFACETEXTURE: {
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 05f8670..afc94ab 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -220,6 +220,10 @@
             const String16 opPackageName = data.readString16();
             sp<IRemoteDisplayClient> client(
                     interface_cast<IRemoteDisplayClient>(data.readStrongBinder()));
+            if (client == NULL) {
+                reply->writeStrongBinder(NULL);
+                return NO_ERROR;
+            }
             String8 iface(data.readString8());
             sp<IRemoteDisplay> display(listenForRemoteDisplay(opPackageName, client, iface));
             reply->writeStrongBinder(IInterface::asBinder(display));
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index ee3b584..0eea820 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -54,7 +54,9 @@
     SET_PREVIEW_SURFACE,
     SET_CAMERA,
     SET_LISTENER,
-    SET_CLIENT_NAME
+    SET_CLIENT_NAME,
+    PAUSE,
+    RESUME
 };
 
 class BpMediaRecorder: public BpInterface<IMediaRecorder>
@@ -276,6 +278,24 @@
         return reply.readInt32();
     }
 
+    status_t pause()
+    {
+        ALOGV("pause");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(PAUSE, data, &reply);
+        return reply.readInt32();
+    }
+
+    status_t resume()
+    {
+        ALOGV("resume");
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+        remote()->transact(RESUME, data, &reply);
+        return reply.readInt32();
+    }
+
     status_t close()
     {
         ALOGV("close");
@@ -340,6 +360,18 @@
             reply->writeInt32(start());
             return NO_ERROR;
         } break;
+        case PAUSE: {
+            ALOGV("PAUSE");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(pause());
+            return NO_ERROR;
+        } break;
+        case RESUME: {
+            ALOGV("RESUME");
+            CHECK_INTERFACE(IMediaRecorder, data, reply);
+            reply->writeInt32(resume());
+            return NO_ERROR;
+        } break;
         case PREPARE: {
             ALOGV("PREPARE");
             CHECK_INTERFACE(IMediaRecorder, data, reply);
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
new file mode 100644
index 0000000..fc9a123
--- /dev/null
+++ b/media/libmedia/IMediaSource.cpp
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2009 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 "BpMediaSource"
+#include <utils/Log.h>
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <media/IMediaSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+enum {
+    START = IBinder::FIRST_CALL_TRANSACTION,
+    STOP,
+    PAUSE,
+    GETFORMAT,
+    READ,
+    RELEASE_BUFFER
+};
+
+enum {
+    NULL_BUFFER,
+    SHARED_BUFFER,
+    INLINE_BUFFER
+};
+
+class RemoteMediaBufferReleaser : public BBinder {
+public:
+    RemoteMediaBufferReleaser(MediaBuffer *buf) {
+        mBuf = buf;
+    }
+    ~RemoteMediaBufferReleaser() {
+        if (mBuf) {
+            ALOGW("RemoteMediaBufferReleaser dtor called while still holding buffer");
+            mBuf->release();
+        }
+    }
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0) {
+        if (code == RELEASE_BUFFER) {
+            mBuf->release();
+            mBuf = NULL;
+            return OK;
+        } else {
+            return BBinder::onTransact(code, data, reply, flags);
+        }
+    }
+private:
+    MediaBuffer *mBuf;
+};
+
+
+class RemoteMediaBufferWrapper : public MediaBuffer {
+public:
+    RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source);
+protected:
+    virtual ~RemoteMediaBufferWrapper();
+private:
+    sp<IMemory> mMemory;
+    sp<IBinder> mRemoteSource;
+};
+
+RemoteMediaBufferWrapper::RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source)
+: MediaBuffer(mem->pointer(), mem->size()) {
+    mMemory = mem;
+    mRemoteSource = source;
+}
+
+RemoteMediaBufferWrapper::~RemoteMediaBufferWrapper() {
+    mMemory.clear();
+    // Explicitly ask the remote side to release the buffer. We could also just clear
+    // mRemoteSource, but that doesn't immediately release the reference on the remote side.
+    Parcel data, reply;
+    mRemoteSource->transact(RELEASE_BUFFER, data, &reply);
+    mRemoteSource.clear();
+}
+
+class BpMediaSource : public BpInterface<IMediaSource> {
+public:
+    BpMediaSource(const sp<IBinder>& impl)
+        : BpInterface<IMediaSource>(impl)
+    {
+    }
+
+    virtual status_t start(MetaData *params) {
+        ALOGV("start");
+        Parcel data, reply;
+        data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+        if (params) {
+            params->writeToParcel(data);
+        }
+        status_t ret = remote()->transact(START, data, &reply);
+        if (ret == NO_ERROR && params) {
+            ALOGW("ignoring potentially modified MetaData from start");
+            ALOGW("input:");
+            params->dumpToLog();
+            sp<MetaData> meta = MetaData::createFromParcel(reply);
+            ALOGW("output:");
+            meta->dumpToLog();
+        }
+        return ret;
+    }
+
+    virtual status_t stop() {
+        ALOGV("stop");
+        Parcel data, reply;
+        data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+        return remote()->transact(STOP, data, &reply);
+    }
+
+    virtual sp<MetaData> getFormat() {
+        ALOGV("getFormat");
+        Parcel data, reply;
+        data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+        status_t ret = remote()->transact(GETFORMAT, data, &reply);
+        if (ret == NO_ERROR) {
+            mMetaData = MetaData::createFromParcel(reply);
+            return mMetaData;
+        }
+        return NULL;
+    }
+
+    virtual status_t read(MediaBuffer **buffer, const ReadOptions *options) {
+        ALOGV("read");
+        Parcel data, reply;
+        data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+        if (options) {
+            data.writeByteArray(sizeof(*options), (uint8_t*) options);
+        }
+        status_t ret = remote()->transact(READ, data, &reply);
+        if (ret != NO_ERROR) {
+            return ret;
+        }
+        // wrap the returned data in a MediaBuffer
+        ret = reply.readInt32();
+        int32_t buftype = reply.readInt32();
+        if (buftype == SHARED_BUFFER) {
+            sp<IBinder> remote = reply.readStrongBinder();
+            sp<IBinder> binder = reply.readStrongBinder();
+            sp<IMemory> mem = interface_cast<IMemory>(binder);
+            if (mem == NULL) {
+                ALOGE("received NULL IMemory for shared buffer");
+            }
+            size_t offset = reply.readInt32();
+            size_t length = reply.readInt32();
+            MediaBuffer *buf = new RemoteMediaBufferWrapper(mem, remote);
+            buf->set_range(offset, length);
+            buf->meta_data()->updateFromParcel(reply);
+            *buffer = buf;
+        } else if (buftype == NULL_BUFFER) {
+            ALOGV("got status %d and NULL buffer", ret);
+            *buffer = NULL;
+        } else {
+            int32_t len = reply.readInt32();
+            ALOGV("got status %d and len %d", ret, len);
+            *buffer = new MediaBuffer(len);
+            reply.read((*buffer)->data(), len);
+            (*buffer)->meta_data()->updateFromParcel(reply);
+        }
+        return ret;
+    }
+
+    virtual status_t pause() {
+        ALOGV("pause");
+        Parcel data, reply;
+        data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+        return remote()->transact(PAUSE, data, &reply);
+    }
+
+    virtual status_t setBuffers(const Vector<MediaBuffer *> & buffers __unused) {
+        ALOGV("setBuffers NOT IMPLEMENTED");
+        return ERROR_UNSUPPORTED; // default
+    }
+
+private:
+    // NuPlayer passes pointers-to-metadata around, so we use this to keep the metadata alive
+    // XXX: could we use this for caching, or does metadata change on the fly?
+    sp<MetaData> mMetaData;
+
+};
+
+IMPLEMENT_META_INTERFACE(MediaSource, "android.media.IMediaSource");
+
+#undef LOG_TAG
+#define LOG_TAG "BnMediaSource"
+
+status_t BnMediaSource::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch (code) {
+        case START: {
+            ALOGV("start");
+            CHECK_INTERFACE(IMediaSource, data, reply);
+            sp<MetaData> meta;
+            if (data.dataAvail()) {
+                meta = MetaData::createFromParcel(data);
+            }
+            status_t ret = start(meta.get());
+            if (ret == NO_ERROR && meta != NULL) {
+                meta->writeToParcel(*reply);
+            }
+            return ret;
+        }
+        case STOP: {
+            ALOGV("stop");
+            CHECK_INTERFACE(IMediaSource, data, reply);
+            return stop();
+        }
+        case PAUSE: {
+            ALOGV("pause");
+            CHECK_INTERFACE(IMediaSource, data, reply);
+            return pause();
+        }
+        case GETFORMAT: {
+            ALOGV("getFormat");
+            CHECK_INTERFACE(IMediaSource, data, reply);
+            sp<MetaData> meta = getFormat();
+            if (meta != NULL) {
+                meta->writeToParcel(*reply);
+                return NO_ERROR;
+            }
+            return UNKNOWN_ERROR;
+        }
+        case READ: {
+            ALOGV("read");
+            CHECK_INTERFACE(IMediaSource, data, reply);
+            status_t ret;
+            MediaBuffer *buf = NULL;
+            ReadOptions opts;
+            uint32_t len;
+            if (data.readUint32(&len) == NO_ERROR &&
+                    len == sizeof(opts) && data.read((void*)&opts, len) == NO_ERROR) {
+                ret = read(&buf, &opts);
+            } else {
+                ret = read(&buf, NULL);
+            }
+
+            reply->writeInt32(ret);
+            if (buf != NULL) {
+                size_t usedSize = buf->range_length();
+                // even if we're using shared memory, we might not want to use it, since for small
+                // sizes it's faster to copy data through the Binder transaction
+                if (buf->mMemory != NULL && usedSize >= 64 * 1024) {
+                    ALOGV("buffer is using shared memory: %zu", usedSize);
+                    reply->writeInt32(SHARED_BUFFER);
+                    RemoteMediaBufferReleaser *wrapper = new RemoteMediaBufferReleaser(buf);
+                    reply->writeStrongBinder(wrapper);
+                    reply->writeStrongBinder(IInterface::asBinder(buf->mMemory));
+                    reply->writeInt32(buf->range_offset());
+                    reply->writeInt32(usedSize);
+                    buf->meta_data()->writeToParcel(*reply);
+                } else {
+                    // buffer is not in shared memory, or is small: copy it
+                    if (buf->mMemory != NULL) {
+                        ALOGV("%zu shared mem available, but only %zu used", buf->mMemory->size(), buf->range_length());
+                    }
+                    reply->writeInt32(INLINE_BUFFER);
+                    reply->writeByteArray(buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
+                    buf->meta_data()->writeToParcel(*reply);
+                    buf->release();
+                }
+            } else {
+                ALOGV("ret %d, buf %p", ret, buf);
+                reply->writeInt32(NULL_BUFFER);
+            }
+            return NO_ERROR;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+IMediaSource::ReadOptions::ReadOptions() {
+    reset();
+}
+
+void IMediaSource::ReadOptions::reset() {
+    mOptions = 0;
+    mSeekTimeUs = 0;
+    mLatenessUs = 0;
+    mNonBlocking = false;
+}
+
+void IMediaSource::ReadOptions::setNonBlocking() {
+    mNonBlocking = true;
+}
+
+void IMediaSource::ReadOptions::clearNonBlocking() {
+    mNonBlocking = false;
+}
+
+bool IMediaSource::ReadOptions::getNonBlocking() const {
+    return mNonBlocking;
+}
+
+void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
+    mOptions |= kSeekTo_Option;
+    mSeekTimeUs = time_us;
+    mSeekMode = mode;
+}
+
+void IMediaSource::ReadOptions::clearSeekTo() {
+    mOptions &= ~kSeekTo_Option;
+    mSeekTimeUs = 0;
+    mSeekMode = SEEK_CLOSEST_SYNC;
+}
+
+bool IMediaSource::ReadOptions::getSeekTo(
+        int64_t *time_us, SeekMode *mode) const {
+    *time_us = mSeekTimeUs;
+    *mode = mSeekMode;
+    return (mOptions & kSeekTo_Option) != 0;
+}
+
+void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
+    mLatenessUs = lateness_us;
+}
+
+int64_t IMediaSource::ReadOptions::getLateBy() const {
+    return mLatenessUs;
+}
+
+
+}  // namespace android
+
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 5423c2a..550b506 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -642,6 +642,12 @@
             sp<IOMXObserver> observer =
                 interface_cast<IOMXObserver>(data.readStrongBinder());
 
+            if (name == NULL || observer == NULL) {
+                ALOGE("b/26392700");
+                reply->writeInt32(INVALID_OPERATION);
+                return NO_ERROR;
+            }
+
             node_id node;
 
             status_t err = allocateNode(name, observer, &node);
@@ -787,6 +793,12 @@
                 interface_cast<IMemory>(data.readStrongBinder());
             OMX_U32 allottedSize = data.readInt32();
 
+            if (params == NULL) {
+                ALOGE("b/26392700");
+                reply->writeInt32(INVALID_OPERATION);
+                return NO_ERROR;
+            }
+
             buffer_id buffer;
             status_t err = useBuffer(node, port_index, params, &buffer, allottedSize);
             reply->writeInt32(err);
@@ -886,8 +898,13 @@
             sp<IGraphicBufferConsumer> bufferConsumer =
                     interface_cast<IGraphicBufferConsumer>(data.readStrongBinder());
 
-            MetadataBufferType type;
-            status_t err = setInputSurface(node, port_index, bufferConsumer, &type);
+            MetadataBufferType type = kMetadataBufferTypeInvalid;
+            status_t err = INVALID_OPERATION;
+            if (bufferConsumer == NULL) {
+                ALOGE("b/26392700");
+            } else {
+                err = setInputSurface(node, port_index, bufferConsumer, &type);
+            }
 
             reply->writeInt32(type);
             reply->writeInt32(err);
@@ -995,6 +1012,12 @@
                 interface_cast<IMemory>(data.readStrongBinder());
             OMX_U32 allottedSize = data.readInt32();
 
+            if (params == NULL) {
+                ALOGE("b/26392700");
+                reply->writeInt32(INVALID_OPERATION);
+                return NO_ERROR;
+            }
+
             buffer_id buffer;
             status_t err = allocateBufferWithBackup(
                     node, port_index, params, &buffer, allottedSize);
@@ -1058,6 +1081,12 @@
             node_id node = (node_id)data.readInt32();
             const char *parameter_name = data.readCString();
 
+            if (parameter_name == NULL) {
+                ALOGE("b/26392700");
+                reply->writeInt32(INVALID_OPERATION);
+                return NO_ERROR;
+            }
+
             OMX_INDEXTYPE index;
             status_t err = getExtensionIndex(node, parameter_name, &index);
 
diff --git a/media/libmedia/IResourceManagerService.cpp b/media/libmedia/IResourceManagerService.cpp
index 4598686..6cb4440 100644
--- a/media/libmedia/IResourceManagerService.cpp
+++ b/media/libmedia/IResourceManagerService.cpp
@@ -132,6 +132,9 @@
             int64_t clientId = data.readInt64();
             sp<IResourceManagerClient> client(
                     interface_cast<IResourceManagerClient>(data.readStrongBinder()));
+            if (client == NULL) {
+                return NO_ERROR;
+            }
             Vector<MediaResource> resources;
             readFromParcel(data, &resources);
             addResource(pid, clientId, client, resources);
diff --git a/media/libmedia/IStreamSource.cpp b/media/libmedia/IStreamSource.cpp
index 840e453..8c0905c 100644
--- a/media/libmedia/IStreamSource.cpp
+++ b/media/libmedia/IStreamSource.cpp
@@ -111,7 +111,11 @@
                 sp<IMemory> mem =
                     interface_cast<IMemory>(data.readStrongBinder());
 
-                buffers.push(mem);
+                if (mem != NULL) {
+                    buffers.push(mem);
+                } else if (data.dataAvail() == 0) {
+                    break;
+                }
             }
             setBuffers(buffers);
             break;
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index 2a17696..ff0e52e 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -37,7 +37,8 @@
 const MediaProfiles::NameToTagMap MediaProfiles::sVideoEncoderNameMap[] = {
     {"h263", VIDEO_ENCODER_H263},
     {"h264", VIDEO_ENCODER_H264},
-    {"m4v",  VIDEO_ENCODER_MPEG_4_SP}
+    {"m4v",  VIDEO_ENCODER_MPEG_4_SP},
+    {"hevc", VIDEO_ENCODER_HEVC}
 };
 
 const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = {
diff --git a/media/libmedia/MidiIoWrapper.cpp b/media/libmedia/MidiIoWrapper.cpp
index 5197ce2..faae954 100644
--- a/media/libmedia/MidiIoWrapper.cpp
+++ b/media/libmedia/MidiIoWrapper.cpp
@@ -42,7 +42,7 @@
 
 MidiIoWrapper::MidiIoWrapper(int fd, off64_t offset, int64_t size) {
     ALOGV("MidiIoWrapper(fd=%d)", fd);
-    mFd = dup(fd);
+    mFd = fd < 0 ? -1 : dup(fd);
     mBase = offset;
     mLength = size;
 }
@@ -61,7 +61,9 @@
 
 MidiIoWrapper::~MidiIoWrapper() {
     ALOGV("~MidiIoWrapper");
-    close(mFd);
+    if (mFd >= 0) {
+        close(mFd);
+    }
 }
 
 int MidiIoWrapper::readAt(void *buffer, int offset, int size) {
@@ -70,6 +72,10 @@
     if (mDataSource != NULL) {
         return mDataSource->readAt(offset, buffer, size);
     }
+    if (mFd < 0) {
+        errno = EBADF;
+        return -1; // as per failed read.
+    }
     lseek(mFd, mBase + offset, SEEK_SET);
     if (offset + size > mLength) {
         size = mLength - offset;
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 502ab2d..337e963 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -181,22 +181,6 @@
     return err;
 }
 
-status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source)
-{
-    ALOGV("setDataSource");
-    status_t err = UNKNOWN_ERROR;
-    const sp<IMediaPlayerService>& service(getMediaPlayerService());
-    if (service != 0) {
-        sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
-        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
-            (NO_ERROR != player->setDataSource(source))) {
-            player.clear();
-        }
-        err = attachNewPlayer(player);
-    }
-    return err;
-}
-
 status_t MediaPlayer::setDataSource(const sp<IDataSource> &source)
 {
     ALOGV("setDataSource(IDataSource)");
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 8bbd8f1..bfdf41d 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -561,6 +561,50 @@
     return ret;
 }
 
+status_t MediaRecorder::pause()
+{
+    ALOGV("pause");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_RECORDING)) {
+        ALOGE("stop called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->pause();
+    if (OK != ret) {
+        ALOGE("pause failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+
+    return ret;
+}
+
+status_t MediaRecorder::resume()
+{
+    ALOGV("resume");
+    if (mMediaRecorder == NULL) {
+        ALOGE("media recorder is not initialized yet");
+        return INVALID_OPERATION;
+    }
+    if (!(mCurrentState & MEDIA_RECORDER_RECORDING)) {
+        ALOGE("resume called in an invalid state: %d", mCurrentState);
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mMediaRecorder->resume();
+    if (OK != ret) {
+        ALOGE("resume failed: %d", ret);
+        mCurrentState = MEDIA_RECORDER_ERROR;
+        return ret;
+    }
+
+    return ret;
+}
+
 status_t MediaRecorder::close()
 {
     ALOGV("close");
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
index 147d35f..b57f6ef 100644
--- a/media/libmediaplayerservice/Crypto.cpp
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -239,6 +239,7 @@
         const uint8_t key[16],
         const uint8_t iv[16],
         CryptoPlugin::Mode mode,
+        const CryptoPlugin::Pattern &pattern,
         const sp<IMemory> &sharedBuffer, size_t offset,
         const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
         void *dstPtr,
@@ -256,7 +257,7 @@
     const void *srcPtr = static_cast<uint8_t *>(sharedBuffer->pointer()) + offset;
 
     return mPlugin->decrypt(
-            secure, key, iv, mode, srcPtr, subSamples, numSubSamples, dstPtr,
+            secure, key, iv, mode, pattern, srcPtr, subSamples, numSubSamples, dstPtr,
             errorDetailMsg);
 }
 
diff --git a/media/libmediaplayerservice/Crypto.h b/media/libmediaplayerservice/Crypto.h
index 99ea95d..7705f30 100644
--- a/media/libmediaplayerservice/Crypto.h
+++ b/media/libmediaplayerservice/Crypto.h
@@ -54,6 +54,7 @@
             const uint8_t key[16],
             const uint8_t iv[16],
             CryptoPlugin::Mode mode,
+            const CryptoPlugin::Pattern &pattern,
             const sp<IMemory> &sharedBuffer, size_t offset,
             const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
             void *dstPtr,
diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp
index b9cfe80..321ccbf 100644
--- a/media/libmediaplayerservice/Drm.cpp
+++ b/media/libmediaplayerservice/Drm.cpp
@@ -516,24 +516,6 @@
     return mPlugin->provideProvisionResponse(response, certificate, wrappedKey);
 }
 
-status_t Drm::unprovisionDevice() {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    if (mPlugin == NULL) {
-        return -EINVAL;
-    }
-
-    if (!checkPermission("android.permission.REMOVE_DRM_CERTIFICATES")) {
-        return -EPERM;
-    }
-
-    return mPlugin->unprovisionDevice();
-}
-
 status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
     Mutex::Autolock autoLock(mLock);
 
diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h
index 056723c..d40019b 100644
--- a/media/libmediaplayerservice/Drm.h
+++ b/media/libmediaplayerservice/Drm.h
@@ -77,8 +77,6 @@
                                               Vector<uint8_t> &certificate,
                                               Vector<uint8_t> &wrappedKey);
 
-    virtual status_t unprovisionDevice();
-
     virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
     virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop);
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 7dd8c78..bb24403 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -284,9 +284,7 @@
     // reset battery stats
     // if the mediaserver has crashed, battery stats could be left
     // in bad state, reset the state upon service start.
-    BatteryNotifier& notifier(BatteryNotifier::getInstance());
-    notifier.noteResetVideo();
-    notifier.noteResetAudio();
+    BatteryNotifier::getInstance().noteResetVideo();
 
     MediaPlayerFactory::registerBuiltinFactories();
 }
@@ -348,6 +346,7 @@
 }
 
 sp<IOMX> MediaPlayerService::getOMX() {
+    ALOGI("MediaPlayerService::getOMX");
     Mutex::Autolock autoLock(mLock);
 
     if (mOMX.get() == NULL) {
@@ -729,7 +728,8 @@
 
 status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
 {
-    ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
+    ALOGV("setDataSource fd=%d (%s), offset=%lld, length=%lld",
+            fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
     struct stat sb;
     int ret = fstat(fd, &sb);
     if (ret != 0) {
@@ -1245,7 +1245,10 @@
             if (client->mAudioOutput != NULL)
                 client->mAudioOutput->switchToNextOutput();
             client->mNextClient->start();
-            client->mNextClient->mClient->notify(MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj);
+            if (client->mNextClient->mClient != NULL) {
+                client->mNextClient->mClient->notify(
+                        MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj);
+            }
         }
     }
 
@@ -1449,6 +1452,76 @@
     return mTrack->getTimestamp(ts);
 }
 
+// TODO: Remove unnecessary calls to getPlayedOutDurationUs()
+// as it acquires locks and may query the audio driver.
+//
+// Some calls could conceivably retrieve extrapolated data instead of
+// accessing getTimestamp() or getPosition() every time a data buffer with
+// a media time is received.
+//
+// Calculate duration of played samples if played at normal rate (i.e., 1.0).
+int64_t MediaPlayerService::AudioOutput::getPlayedOutDurationUs(int64_t nowUs) const
+{
+    Mutex::Autolock lock(mLock);
+    if (mTrack == 0 || mSampleRateHz == 0) {
+        return 0;
+    }
+
+    uint32_t numFramesPlayed;
+    int64_t numFramesPlayedAt;
+    AudioTimestamp ts;
+    static const int64_t kStaleTimestamp100ms = 100000;
+
+    status_t res = mTrack->getTimestamp(ts);
+    if (res == OK) {                 // case 1: mixing audio tracks and offloaded tracks.
+        numFramesPlayed = ts.mPosition;
+        numFramesPlayedAt = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
+        const int64_t timestampAge = nowUs - numFramesPlayedAt;
+        if (timestampAge > kStaleTimestamp100ms) {
+            // This is an audio FIXME.
+            // getTimestamp returns a timestamp which may come from audio mixing threads.
+            // After pausing, the MixerThread may go idle, thus the mTime estimate may
+            // become stale. Assuming that the MixerThread runs 20ms, with FastMixer at 5ms,
+            // the max latency should be about 25ms with an average around 12ms (to be verified).
+            // For safety we use 100ms.
+            ALOGV("getTimestamp: returned stale timestamp nowUs(%lld) numFramesPlayedAt(%lld)",
+                    (long long)nowUs, (long long)numFramesPlayedAt);
+            numFramesPlayedAt = nowUs - kStaleTimestamp100ms;
+        }
+        //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAt);
+    } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
+        numFramesPlayed = 0;
+        numFramesPlayedAt = nowUs;
+        //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
+        //        numFramesPlayed, (long long)numFramesPlayedAt);
+    } else {                         // case 3: transitory at new track or audio fast tracks.
+        res = mTrack->getPosition(&numFramesPlayed);
+        CHECK_EQ(res, (status_t)OK);
+        numFramesPlayedAt = nowUs;
+        numFramesPlayedAt += 1000LL * mTrack->latency() / 2; /* XXX */
+        //ALOGD("getPosition: %u %lld", numFramesPlayed, (long long)numFramesPlayedAt);
+    }
+
+    // CHECK_EQ(numFramesPlayed & (1 << 31), 0);  // can't be negative until 12.4 hrs, test
+    // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
+    int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000000LL / mSampleRateHz)
+            + nowUs - numFramesPlayedAt;
+    if (durationUs < 0) {
+        // Occurs when numFramesPlayed position is very small and the following:
+        // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
+        //     numFramesPlayedAt is greater than nowUs by time more than numFramesPlayed.
+        // (2) In case 3, using getPosition and adding mAudioSink->latency() to
+        //     numFramesPlayedAt, by a time amount greater than numFramesPlayed.
+        //
+        // Both of these are transitory conditions.
+        ALOGV("getPlayedOutDurationUs: negative duration %lld set to zero", (long long)durationUs);
+        durationUs = 0;
+    }
+    ALOGV("getPlayedOutDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
+            (long long)durationUs, (long long)nowUs, numFramesPlayed, (long long)numFramesPlayedAt);
+    return durationUs;
+}
+
 status_t MediaPlayerService::AudioOutput::getFramesWritten(uint32_t *frameswritten) const
 {
     Mutex::Autolock lock(mLock);
@@ -1889,8 +1962,13 @@
 void MediaPlayerService::AudioOutput::close()
 {
     ALOGV("close");
-    Mutex::Autolock lock(mLock);
-    close_l();
+    sp<AudioTrack> track;
+    {
+        Mutex::Autolock lock(mLock);
+        track = mTrack;
+        close_l(); // clears mTrack
+    }
+    // destruction of the track occurs outside of mutex.
 }
 
 void MediaPlayerService::AudioOutput::setVolume(float left, float right)
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 60d4617..bd98ef1 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -88,6 +88,7 @@
         virtual float           msecsPerFrame() const;
         virtual status_t        getPosition(uint32_t *position) const;
         virtual status_t        getTimestamp(AudioTimestamp &ts) const;
+        virtual int64_t         getPlayedOutDurationUs(int64_t nowUs) const;
         virtual status_t        getFramesWritten(uint32_t *frameswritten) const;
         virtual int             getSessionId() const;
         virtual uint32_t        getSampleRate() const;
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 08c7899..3b4e148 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -250,6 +250,29 @@
     return mRecorder->stop();
 }
 
+status_t MediaRecorderClient::pause()
+{
+    ALOGV("pause");
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        ALOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->pause();
+
+}
+
+status_t MediaRecorderClient::resume()
+{
+    ALOGV("resume");
+    Mutex::Autolock lock(mLock);
+    if (mRecorder == NULL) {
+        ALOGE("recorder is not initialized");
+        return NO_INIT;
+    }
+    return mRecorder->resume();
+}
+
 status_t MediaRecorderClient::init()
 {
     ALOGV("init");
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 05130d4..c0d9c4c 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -51,6 +51,8 @@
     virtual     status_t   start();
     virtual     status_t   stop();
     virtual     status_t   reset();
+    virtual     status_t   pause();
+    virtual     status_t   resume();
     virtual     status_t   init();
     virtual     status_t   close();
     virtual     status_t   release();
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index b45fd4f..b5e5225 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -35,6 +35,7 @@
 #include <media/MediaMetadataRetrieverInterface.h>
 #include <media/MediaPlayerInterface.h>
 #include <media/stagefright/DataSource.h>
+#include <media/stagefright/Utils.h>
 #include <private/media/VideoFrame.h>
 #include "MetadataRetrieverClient.h"
 #include "StagefrightMetadataRetriever.h"
@@ -133,7 +134,8 @@
 
 status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t length)
 {
-    ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
+    ALOGV("setDataSource fd=%d (%s), offset=%lld, length=%lld",
+            fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
     Mutex::Autolock lock(mLock);
     struct stat sb;
     int ret = fstat(fd, &sb);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 3b13f2a..b335d09 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -780,8 +780,9 @@
         return INVALID_OPERATION;
     }
 
-    // Get UID here for permission checking
+    // Get UID and PID here for permission checking
     mClientUid = IPCThreadState::self()->getCallingUid();
+    mClientPid = IPCThreadState::self()->getCallingPid();
 
     status_t status = OK;
 
@@ -905,7 +906,7 @@
     return status;
 }
 
-sp<MediaSource> StagefrightRecorder::createAudioSource() {
+sp<MediaCodecSource> StagefrightRecorder::createAudioSource() {
     int32_t sourceSampleRate = mSampleRate;
 
     if (mCaptureFpsEnable && mCaptureFps >= mFrameRate) {
@@ -980,7 +981,7 @@
     }
     format->setInt32("priority", 0 /* realtime */);
 
-    sp<MediaSource> audioEncoder =
+    sp<MediaCodecSource> audioEncoder =
             MediaCodecSource::Create(mLooper, format, audioSource);
     mAudioSourceNode = audioSource;
 
@@ -1039,13 +1040,14 @@
         return status;
     }
 
-    sp<MediaSource> audioEncoder = createAudioSource();
+    sp<MediaCodecSource> audioEncoder = createAudioSource();
     if (audioEncoder == NULL) {
         return UNKNOWN_ERROR;
     }
 
     CHECK(mWriter != 0);
     mWriter->addSource(audioEncoder);
+    mAudioEncoderSource = audioEncoder;
 
     if (mMaxFileDurationUs != 0) {
         mWriter->setMaxFileDuration(mMaxFileDurationUs);
@@ -1073,10 +1075,11 @@
         return BAD_VALUE;
     }
 
-    sp<MediaSource> source;
+    sp<MediaCodecSource> source;
 
     if (mAudioSource != AUDIO_SOURCE_CNT) {
         source = createAudioSource();
+        mAudioEncoderSource = source;
     } else {
         setDefaultVideoEncoderIfNecessary();
 
@@ -1090,6 +1093,7 @@
         if (err != OK) {
             return err;
         }
+        mVideoEncoderSource = source;
     }
 
     mWriter = new ARTPWriter(mOutputFd);
@@ -1130,7 +1134,7 @@
             return err;
         }
 
-        sp<MediaSource> encoder;
+        sp<MediaCodecSource> encoder;
         err = setupVideoEncoder(mediaSource, &encoder);
 
         if (err != OK) {
@@ -1138,6 +1142,7 @@
         }
 
         writer->addSource(encoder);
+        mVideoEncoderSource = encoder;
     }
 
     if (mMaxFileDurationUs != 0) {
@@ -1432,13 +1437,13 @@
         }
 
         mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera(
-                mCamera, mCameraProxy, mCameraId, mClientName, mClientUid,
+                mCamera, mCameraProxy, mCameraId, mClientName, mClientUid, mClientPid,
                 videoSize, mFrameRate, mPreviewSurface,
                 mTimeBetweenCaptureUs);
         *cameraSource = mCameraSourceTimeLapse;
     } else {
         *cameraSource = CameraSource::CreateFromCamera(
-                mCamera, mCameraProxy, mCameraId, mClientName, mClientUid,
+                mCamera, mCameraProxy, mCameraId, mClientName, mClientUid, mClientPid,
                 videoSize, mFrameRate,
                 mPreviewSurface);
     }
@@ -1475,7 +1480,7 @@
 
 status_t StagefrightRecorder::setupVideoEncoder(
         sp<MediaSource> cameraSource,
-        sp<MediaSource> *source) {
+        sp<MediaCodecSource> *source) {
     source->clear();
 
     sp<AMessage> format = new AMessage();
@@ -1497,6 +1502,10 @@
             format->setString("mime", MEDIA_MIMETYPE_VIDEO_VP8);
             break;
 
+        case VIDEO_ENCODER_HEVC:
+            format->setString("mime", MEDIA_MIMETYPE_VIDEO_HEVC);
+            break;
+
         default:
             CHECK(!"Should not be here, unsupported video encoding.");
             break;
@@ -1604,12 +1613,13 @@
             return UNKNOWN_ERROR;
     }
 
-    sp<MediaSource> audioEncoder = createAudioSource();
+    sp<MediaCodecSource> audioEncoder = createAudioSource();
     if (audioEncoder == NULL) {
         return UNKNOWN_ERROR;
     }
 
     writer->addSource(audioEncoder);
+    mAudioEncoderSource = audioEncoder;
     return OK;
 }
 
@@ -1635,13 +1645,14 @@
             return err;
         }
 
-        sp<MediaSource> encoder;
+        sp<MediaCodecSource> encoder;
         err = setupVideoEncoder(mediaSource, &encoder);
         if (err != OK) {
             return err;
         }
 
         writer->addSource(encoder);
+        mVideoEncoderSource = encoder;
         mTotalBitRate += mVideoBitRate;
     }
 
@@ -1712,25 +1723,49 @@
 
 status_t StagefrightRecorder::pause() {
     ALOGV("pause");
-    if (mWriter == NULL) {
-        return UNKNOWN_ERROR;
-    }
-    mWriter->pause();
-
-    if (mStarted) {
-        mStarted = false;
-
-        uint32_t params = 0;
-        if (mAudioSource != AUDIO_SOURCE_CNT) {
-            params |= IMediaPlayerService::kBatteryDataTrackAudio;
-        }
-        if (mVideoSource != VIDEO_SOURCE_LIST_END) {
-            params |= IMediaPlayerService::kBatteryDataTrackVideo;
-        }
-
-        addBatteryData(params);
+    if (!mStarted) {
+        return INVALID_OPERATION;
     }
 
+    // Already paused --- no-op.
+    if (mPauseStartTimeUs != 0) {
+        return OK;
+    }
+
+    if (mAudioEncoderSource != NULL) {
+        mAudioEncoderSource->pause();
+    }
+    if (mVideoEncoderSource != NULL) {
+        mVideoEncoderSource->pause();
+    }
+
+    mPauseStartTimeUs = systemTime() / 1000;
+
+    return OK;
+}
+
+status_t StagefrightRecorder::resume() {
+    ALOGV("resume");
+    if (!mStarted) {
+        return INVALID_OPERATION;
+    }
+
+    // Not paused --- no-op.
+    if (mPauseStartTimeUs == 0) {
+        return OK;
+    }
+
+    // 30 ms buffer to avoid timestamp overlap
+    mTotalPausedDurationUs += (systemTime() / 1000) - mPauseStartTimeUs - 30000;
+    if (mAudioEncoderSource != NULL) {
+        mAudioEncoderSource->setInputBufferTimeOffset(-mTotalPausedDurationUs);
+        mAudioEncoderSource->start();
+    }
+    if (mVideoEncoderSource != NULL) {
+        mVideoEncoderSource->setInputBufferTimeOffset(-mTotalPausedDurationUs);
+        mVideoEncoderSource->start();
+    }
+    mPauseStartTimeUs = 0;
 
     return OK;
 }
@@ -1748,9 +1783,12 @@
         err = mWriter->stop();
         mWriter.clear();
     }
+    mTotalPausedDurationUs = 0;
 
     mGraphicBufferProducer.clear();
     mPersistentSurface.clear();
+    mAudioEncoderSource.clear();
+    mVideoEncoderSource.clear();
 
     if (mOutputFd >= 0) {
         ::close(mOutputFd);
@@ -1826,6 +1864,7 @@
     mTotalBitRate = 0;
 
     mOutputFd = -1;
+    mPauseStartTimeUs = 0;
 
     return OK;
 }
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index da00bc7..761e987 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -30,6 +30,7 @@
 class ICameraRecordingProxy;
 class CameraSource;
 class CameraSourceTimeLapse;
+struct MediaCodecSource;
 struct MediaSource;
 struct MediaWriter;
 class MetaData;
@@ -62,6 +63,7 @@
     virtual status_t prepare();
     virtual status_t start();
     virtual status_t pause();
+    virtual status_t resume();
     virtual status_t stop();
     virtual status_t close();
     virtual status_t reset();
@@ -78,6 +80,7 @@
     sp<IMediaRecorderClient> mListener;
     String16 mClientName;
     uid_t mClientUid;
+    pid_t mClientPid;
     sp<MediaWriter> mWriter;
     int mOutputFd;
     sp<AudioSource> mAudioSourceNode;
@@ -121,6 +124,11 @@
     bool mIsMetaDataStoredInVideoBuffers;
     MediaProfiles *mEncoderProfiles;
 
+    int64_t mPauseStartTimeUs;
+    int64_t mTotalPausedDurationUs;
+    sp<MediaCodecSource> mAudioEncoderSource;
+    sp<MediaCodecSource> mVideoEncoderSource;
+
     bool mStarted;
     // Needed when GLFrames are encoded.
     // An <IGraphicBufferProducer> pointer
@@ -139,7 +147,7 @@
     status_t setupRawAudioRecording();
     status_t setupRTPRecording();
     status_t setupMPEG2TSRecording();
-    sp<MediaSource> createAudioSource();
+    sp<MediaCodecSource> createAudioSource();
     status_t checkVideoEncoderCapabilities();
     status_t checkAudioEncoderCapabilities();
     // Generic MediaSource set-up. Returns the appropriate
@@ -148,7 +156,7 @@
     status_t setupMediaSource(sp<MediaSource> *mediaSource);
     status_t setupCameraSource(sp<CameraSource> *cameraSource);
     status_t setupAudioEncoder(const sp<MediaWriter>& writer);
-    status_t setupVideoEncoder(sp<MediaSource> cameraSource, sp<MediaSource> *source);
+    status_t setupVideoEncoder(sp<MediaSource> cameraSource, sp<MediaCodecSource> *source);
 
     // Encoding parameter handling utilities
     status_t setParameter(const String8 &key, const String8 &value);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 45da218..baa95fa 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -42,6 +42,7 @@
 
 static int64_t kLowWaterMarkUs = 2000000ll;  // 2secs
 static int64_t kHighWaterMarkUs = 5000000ll;  // 5secs
+static int64_t kHighWaterMarkRebufferUs = 15000000ll;  // 15secs
 static const ssize_t kLowWaterMarkBytes = 40000;
 static const ssize_t kHighWaterMarkBytes = 200000;
 
@@ -66,11 +67,8 @@
       mFd(-1),
       mDrmManagerClient(NULL),
       mBitrate(-1ll),
-      mPollBufferingGeneration(0),
-      mPendingReadBufferTypes(0),
-      mBuffering(false),
-      mPrepareBuffering(false),
-      mPrevBufferPercentage(-1) {
+      mPendingReadBufferTypes(0) {
+    mBufferingMonitor = new BufferingMonitor(notify);
     resetDataSource();
     DataSource::RegisterDefaultSniffers();
 }
@@ -91,6 +89,13 @@
     mDrmManagerClient = NULL;
     mStarted = false;
     mStopRead = true;
+
+    if (mBufferingMonitorLooper != NULL) {
+        mBufferingMonitorLooper->unregisterHandler(mBufferingMonitor->id());
+        mBufferingMonitorLooper->stop();
+        mBufferingMonitorLooper = NULL;
+    }
+    mBufferingMonitor->stop();
 }
 
 status_t NuPlayer::GenericSource::setDataSource(
@@ -135,7 +140,7 @@
 }
 
 status_t NuPlayer::GenericSource::initFromDataSource() {
-    sp<MediaExtractor> extractor;
+    sp<IMediaExtractor> extractor;
     String8 mimeType;
     float confidence;
     sp<AMessage> dummy;
@@ -210,9 +215,16 @@
     }
 
     for (size_t i = 0; i < numtracks; ++i) {
-        sp<MediaSource> track = extractor->getTrack(i);
+        sp<IMediaSource> track = extractor->getTrack(i);
+        if (track == NULL) {
+            continue;
+        }
 
         sp<MetaData> meta = extractor->getTrackMetaData(i);
+        if (meta == NULL) {
+            ALOGE("no metadata for track %zu", i);
+            return UNKNOWN_ERROR;
+        }
 
         const char *mime;
         CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -253,22 +265,25 @@
             }
         }
 
-        if (track != NULL) {
-            mSources.push(track);
-            int64_t durationUs;
-            if (meta->findInt64(kKeyDuration, &durationUs)) {
-                if (durationUs > mDurationUs) {
-                    mDurationUs = durationUs;
-                }
-            }
-
-            int32_t bitrate;
-            if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
-                totalBitrate += bitrate;
-            } else {
-                totalBitrate = -1;
+        mSources.push(track);
+        int64_t durationUs;
+        if (meta->findInt64(kKeyDuration, &durationUs)) {
+            if (durationUs > mDurationUs) {
+                mDurationUs = durationUs;
             }
         }
+
+        int32_t bitrate;
+        if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
+            totalBitrate += bitrate;
+        } else {
+            totalBitrate = -1;
+        }
+    }
+
+    if (mSources.size() == 0) {
+        ALOGE("b/23705695");
+        return UNKNOWN_ERROR;
     }
 
     mBitrate = totalBitrate;
@@ -318,7 +333,7 @@
 
 status_t NuPlayer::GenericSource::setBuffers(
         bool audio, Vector<MediaBuffer *> &buffers) {
-    if (mIsSecure && !audio) {
+    if (mIsSecure && !audio && mVideoTrack.mSource != NULL) {
         return mVideoTrack.mSource->setBuffers(buffers);
     }
     return INVALID_OPERATION;
@@ -328,6 +343,10 @@
     return mIsStreaming;
 }
 
+void NuPlayer::GenericSource::setOffloadAudio(bool offload) {
+    mBufferingMonitor->setOffloadAudio(offload);
+}
+
 NuPlayer::GenericSource::~GenericSource() {
     if (mLooper != NULL) {
         mLooper->unregisterHandler(id());
@@ -456,10 +475,18 @@
     }
 
     if (mIsStreaming) {
-        mPrepareBuffering = true;
+        if (mBufferingMonitorLooper == NULL) {
+            mBufferingMonitor->prepare(mCachedSource, mWVMExtractor, mDurationUs, mBitrate,
+                    mIsStreaming);
 
-        ensureCacheIsFetching();
-        restartPollBuffering();
+            mBufferingMonitorLooper = new ALooper;
+            mBufferingMonitorLooper->setName("GSBMonitor");
+            mBufferingMonitorLooper->start();
+            mBufferingMonitorLooper->registerHandler(mBufferingMonitor);
+        }
+
+        mBufferingMonitor->ensureCacheIsFetching();
+        mBufferingMonitor->restartPollBuffering();
     } else {
         notifyPrepared();
     }
@@ -482,7 +509,7 @@
         }
         mBitrate = -1;
 
-        cancelPollBuffering();
+        mBufferingMonitor->cancelPollBuffering();
     }
     notifyPrepared(err);
 }
@@ -561,182 +588,6 @@
     return OK;
 }
 
-void NuPlayer::GenericSource::schedulePollBuffering() {
-    sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
-    msg->setInt32("generation", mPollBufferingGeneration);
-    msg->post(1000000ll);
-}
-
-void NuPlayer::GenericSource::cancelPollBuffering() {
-    mBuffering = false;
-    ++mPollBufferingGeneration;
-    mPrevBufferPercentage = -1;
-}
-
-void NuPlayer::GenericSource::restartPollBuffering() {
-    if (mIsStreaming) {
-        cancelPollBuffering();
-        onPollBuffering();
-    }
-}
-
-void NuPlayer::GenericSource::notifyBufferingUpdate(int32_t percentage) {
-    // Buffering percent could go backward as it's estimated from remaining
-    // data and last access time. This could cause the buffering position
-    // drawn on media control to jitter slightly. Remember previously reported
-    // percentage and don't allow it to go backward.
-    if (percentage < mPrevBufferPercentage) {
-        percentage = mPrevBufferPercentage;
-    } else if (percentage > 100) {
-        percentage = 100;
-    }
-
-    mPrevBufferPercentage = percentage;
-
-    ALOGV("notifyBufferingUpdate: buffering %d%%", percentage);
-
-    sp<AMessage> msg = dupNotify();
-    msg->setInt32("what", kWhatBufferingUpdate);
-    msg->setInt32("percentage", percentage);
-    msg->post();
-}
-
-void NuPlayer::GenericSource::startBufferingIfNecessary() {
-    ALOGV("startBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d",
-            mPrepareBuffering, mBuffering);
-
-    if (mPrepareBuffering) {
-        return;
-    }
-
-    if (!mBuffering) {
-        mBuffering = true;
-
-        ensureCacheIsFetching();
-        sendCacheStats();
-
-        sp<AMessage> notify = dupNotify();
-        notify->setInt32("what", kWhatPauseOnBufferingStart);
-        notify->post();
-    }
-}
-
-void NuPlayer::GenericSource::stopBufferingIfNecessary() {
-    ALOGV("stopBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d",
-            mPrepareBuffering, mBuffering);
-
-    if (mPrepareBuffering) {
-        mPrepareBuffering = false;
-        notifyPrepared();
-        return;
-    }
-
-    if (mBuffering) {
-        mBuffering = false;
-
-        sendCacheStats();
-
-        sp<AMessage> notify = dupNotify();
-        notify->setInt32("what", kWhatResumeOnBufferingEnd);
-        notify->post();
-    }
-}
-
-void NuPlayer::GenericSource::sendCacheStats() {
-    int32_t kbps = 0;
-    status_t err = UNKNOWN_ERROR;
-
-    if (mWVMExtractor != NULL) {
-        err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
-    } else if (mCachedSource != NULL) {
-        err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
-    }
-
-    if (err == OK) {
-        sp<AMessage> notify = dupNotify();
-        notify->setInt32("what", kWhatCacheStats);
-        notify->setInt32("bandwidth", kbps);
-        notify->post();
-    }
-}
-
-void NuPlayer::GenericSource::ensureCacheIsFetching() {
-    if (mCachedSource != NULL) {
-        mCachedSource->resumeFetchingIfNecessary();
-    }
-}
-
-void NuPlayer::GenericSource::onPollBuffering() {
-    status_t finalStatus = UNKNOWN_ERROR;
-    int64_t cachedDurationUs = -1ll;
-    ssize_t cachedDataRemaining = -1;
-
-    ALOGW_IF(mWVMExtractor != NULL && mCachedSource != NULL,
-            "WVMExtractor and NuCachedSource both present");
-
-    if (mWVMExtractor != NULL) {
-        cachedDurationUs =
-                mWVMExtractor->getCachedDurationUs(&finalStatus);
-    } else if (mCachedSource != NULL) {
-        cachedDataRemaining =
-                mCachedSource->approxDataRemaining(&finalStatus);
-
-        if (finalStatus == OK) {
-            off64_t size;
-            int64_t bitrate = 0ll;
-            if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
-                bitrate = size * 8000000ll / mDurationUs;
-            } else if (mBitrate > 0) {
-                bitrate = mBitrate;
-            }
-            if (bitrate > 0) {
-                cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
-            }
-        }
-    }
-
-    if (finalStatus != OK) {
-        ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus);
-
-        if (finalStatus == ERROR_END_OF_STREAM) {
-            notifyBufferingUpdate(100);
-        }
-
-        stopBufferingIfNecessary();
-        return;
-    } else if (cachedDurationUs >= 0ll) {
-        if (mDurationUs > 0ll) {
-            int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs;
-            int percentage = 100.0 * cachedPosUs / mDurationUs;
-            if (percentage > 100) {
-                percentage = 100;
-            }
-
-            notifyBufferingUpdate(percentage);
-        }
-
-        ALOGV("onPollBuffering: cachedDurationUs %.1f sec",
-                cachedDurationUs / 1000000.0f);
-
-        if (cachedDurationUs < kLowWaterMarkUs) {
-            startBufferingIfNecessary();
-        } else if (cachedDurationUs > kHighWaterMarkUs) {
-            stopBufferingIfNecessary();
-        }
-    } else if (cachedDataRemaining >= 0) {
-        ALOGV("onPollBuffering: cachedDataRemaining %zd bytes",
-                cachedDataRemaining);
-
-        if (cachedDataRemaining < kLowWaterMarkBytes) {
-            startBufferingIfNecessary();
-        } else if (cachedDataRemaining > kHighWaterMarkBytes) {
-            stopBufferingIfNecessary();
-        }
-    }
-
-    schedulePollBuffering();
-}
-
 void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
       case kWhatPrepareAsync:
@@ -765,6 +616,11 @@
           break;
       }
 
+      case kWhatSendGlobalTimedTextData:
+      {
+          sendGlobalTextData(kWhatTimedTextData, mFetchTimedTextDataGeneration, msg);
+          break;
+      }
       case kWhatSendTimedTextData:
       {
           sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
@@ -776,7 +632,7 @@
       {
           int32_t trackIndex;
           CHECK(msg->findInt32("trackIndex", &trackIndex));
-          const sp<MediaSource> source = mSources.itemAt(trackIndex);
+          const sp<IMediaSource> source = mSources.itemAt(trackIndex);
 
           Track* track;
           const char *mime;
@@ -819,17 +675,7 @@
       case kWhatStart:
       case kWhatResume:
       {
-          restartPollBuffering();
-          break;
-      }
-
-      case kWhatPollBuffering:
-      {
-          int32_t generation;
-          CHECK(msg->findInt32("generation", &generation));
-          if (generation == mPollBufferingGeneration) {
-              onPollBuffering();
-          }
+          mBufferingMonitor->restartPollBuffering();
           break;
       }
 
@@ -959,16 +805,47 @@
     }
 }
 
+void NuPlayer::GenericSource::sendGlobalTextData(
+        uint32_t what,
+        int32_t curGen,
+        sp<AMessage> msg) {
+    int32_t msgGeneration;
+    CHECK(msg->findInt32("generation", &msgGeneration));
+    if (msgGeneration != curGen) {
+        // stale
+        return;
+    }
+
+    uint32_t textType;
+    const void *data;
+    size_t size = 0;
+    if (mTimedTextTrack.mSource->getFormat()->findData(
+                    kKeyTextFormatData, &textType, &data, &size)) {
+        mGlobalTimedText = new ABuffer(size);
+        if (mGlobalTimedText->data()) {
+            memcpy(mGlobalTimedText->data(), data, size);
+            sp<AMessage> globalMeta = mGlobalTimedText->meta();
+            globalMeta->setInt64("timeUs", 0);
+            globalMeta->setString("mime", MEDIA_MIMETYPE_TEXT_3GPP);
+            globalMeta->setInt32("global", 1);
+            sp<AMessage> notify = dupNotify();
+            notify->setInt32("what", what);
+            notify->setBuffer("buffer", mGlobalTimedText);
+            notify->post();
+        }
+    }
+}
+
 sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
     sp<AMessage> msg = new AMessage(kWhatGetFormat, this);
     msg->setInt32("audio", audio);
 
     sp<AMessage> response;
-    void *format;
+    sp<RefBase> format;
     status_t err = msg->postAndAwaitResponse(&response);
     if (err == OK && response != NULL) {
-        CHECK(response->findPointer("format", &format));
-        return (MetaData *)format;
+        CHECK(response->findObject("format", &format));
+        return static_cast<MetaData*>(format.get());
     } else {
         return NULL;
     }
@@ -980,7 +857,7 @@
 
     sp<AMessage> response = new AMessage;
     sp<MetaData> format = doGetFormatMeta(audio);
-    response->setPointer("format", format.get());
+    response->setObject("format", format);
 
     sp<AReplyToken> replyID;
     CHECK(msg->senderAwaitsResponse(&replyID));
@@ -988,7 +865,7 @@
 }
 
 sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
-    sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
+    sp<IMediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
 
     if (source == NULL) {
         return NULL;
@@ -999,6 +876,10 @@
 
 status_t NuPlayer::GenericSource::dequeueAccessUnit(
         bool audio, sp<ABuffer> *accessUnit) {
+    if (!mStarted) {
+        return -EWOULDBLOCK;
+    }
+
     Track *track = audio ? &mAudioTrack : &mVideoTrack;
 
     if (track->mSource == NULL) {
@@ -1045,6 +926,7 @@
     CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
     if (audio) {
         mAudioLastDequeueTimeUs = timeUs;
+        mBufferingMonitor->updateDequeuedBufferTime(timeUs);
     } else {
         mVideoLastDequeueTimeUs = timeUs;
     }
@@ -1085,6 +967,10 @@
 
     sp<AMessage> format = new AMessage();
     sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
+    if (meta == NULL) {
+        ALOGE("no metadata for track %zu", trackIndex);
+        return NULL;
+    }
 
     const char *mime;
     CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -1232,7 +1118,7 @@
         return OK;
     }
 
-    const sp<MediaSource> source = mSources.itemAt(trackIndex);
+    const sp<IMediaSource> source = mSources.itemAt(trackIndex);
     sp<MetaData> meta = source->getFormat();
     const char *mime;
     CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -1271,6 +1157,10 @@
             msg->post();
         }
 
+        sp<AMessage> msg2 = new AMessage(kWhatSendGlobalTimedTextData, this);
+        msg2->setInt32("generation", mFetchTimedTextDataGeneration);
+        msg2->post();
+
         if (mTimedTextTrack.mSource != NULL
                 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
             sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
@@ -1323,6 +1213,8 @@
 }
 
 status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
+    mBufferingMonitor->updateDequeuedBufferTime(-1ll);
+
     // If the Widevine source is stopped, do not attempt to read any
     // more buffers.
     if (mStopRead) {
@@ -1349,8 +1241,8 @@
     // 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.
-    stopBufferingIfNecessary();
-    restartPollBuffering();
+    mBufferingMonitor->stopBufferingIfNecessary();
+    mBufferingMonitor->restartPollBuffering();
 
     return OK;
 }
@@ -1430,6 +1322,14 @@
         meta->setBuffer("sei", sei);
     }
 
+    const void *mpegUserDataPointer;
+    size_t mpegUserDataLength;
+    if (mb->meta_data()->findData(
+            kKeyMpegUserData, &dataType, &mpegUserDataPointer, &mpegUserDataLength)) {
+        sp<ABuffer> mpegUserData = ABuffer::CreateAsCopy(mpegUserDataPointer, mpegUserDataLength);
+        meta->setBuffer("mpegUserData", mpegUserData);
+    }
+
     if (actualTimeUs) {
         *actualTimeUs = timeUs;
     }
@@ -1531,14 +1431,17 @@
             CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
             if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
                 mAudioTimeUs = timeUs;
+                mBufferingMonitor->updateQueuedTime(true /* isAudio */, timeUs);
             } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
                 mVideoTimeUs = timeUs;
+                mBufferingMonitor->updateQueuedTime(false /* isAudio */, timeUs);
             }
 
             queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
 
             sp<ABuffer> buffer = mediaBufferToABuffer(
-                    mbuf, trackType, seekTimeUs, actualTimeUs);
+                    mbuf, trackType, seekTimeUs,
+                    numBuffers == 0 ? actualTimeUs : NULL);
             track->mPackets->queueAccessUnit(buffer);
             formatChange = false;
             seeking = false;
@@ -1575,4 +1478,330 @@
     }
 }
 
+NuPlayer::GenericSource::BufferingMonitor::BufferingMonitor(const sp<AMessage> &notify)
+    : mNotify(notify),
+      mDurationUs(-1ll),
+      mBitrate(-1ll),
+      mIsStreaming(false),
+      mAudioTimeUs(0),
+      mVideoTimeUs(0),
+      mPollBufferingGeneration(0),
+      mPrepareBuffering(false),
+      mBuffering(false),
+      mPrevBufferPercentage(-1),
+      mOffloadAudio(false),
+      mFirstDequeuedBufferRealUs(-1ll),
+      mFirstDequeuedBufferMediaUs(-1ll),
+      mlastDequeuedBufferMediaUs(-1ll) {
+}
+
+NuPlayer::GenericSource::BufferingMonitor::~BufferingMonitor() {
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::prepare(
+        const sp<NuCachedSource2> &cachedSource,
+        const sp<WVMExtractor> &wvmExtractor,
+        int64_t durationUs,
+        int64_t bitrate,
+        bool isStreaming) {
+    Mutex::Autolock _l(mLock);
+    prepare_l(cachedSource, wvmExtractor, durationUs, bitrate, isStreaming);
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::stop() {
+    Mutex::Autolock _l(mLock);
+    prepare_l(NULL /* cachedSource */, NULL /* wvmExtractor */, -1 /* durationUs */,
+            -1 /* bitrate */, false /* isStreaming */);
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering() {
+    Mutex::Autolock _l(mLock);
+    cancelPollBuffering_l();
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::restartPollBuffering() {
+    Mutex::Autolock _l(mLock);
+    if (mIsStreaming) {
+        cancelPollBuffering_l();
+        onPollBuffering_l();
+    }
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary() {
+    Mutex::Autolock _l(mLock);
+    stopBufferingIfNecessary_l();
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching() {
+    Mutex::Autolock _l(mLock);
+    ensureCacheIsFetching_l();
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::updateQueuedTime(bool isAudio, int64_t timeUs) {
+    Mutex::Autolock _l(mLock);
+    if (isAudio) {
+        mAudioTimeUs = timeUs;
+    } else {
+        mVideoTimeUs = timeUs;
+    }
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::setOffloadAudio(bool offload) {
+    Mutex::Autolock _l(mLock);
+    mOffloadAudio = offload;
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::updateDequeuedBufferTime(int64_t mediaUs) {
+    Mutex::Autolock _l(mLock);
+    if (mediaUs < 0) {
+        mFirstDequeuedBufferRealUs = -1ll;
+        mFirstDequeuedBufferMediaUs = -1ll;
+    } else if (mFirstDequeuedBufferRealUs < 0) {
+        mFirstDequeuedBufferRealUs = ALooper::GetNowUs();
+        mFirstDequeuedBufferMediaUs = mediaUs;
+    }
+    mlastDequeuedBufferMediaUs = mediaUs;
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::prepare_l(
+        const sp<NuCachedSource2> &cachedSource,
+        const sp<WVMExtractor> &wvmExtractor,
+        int64_t durationUs,
+        int64_t bitrate,
+        bool isStreaming) {
+    ALOGW_IF(wvmExtractor != NULL && cachedSource != NULL,
+            "WVMExtractor and NuCachedSource are both present when "
+            "BufferingMonitor::prepare_l is called, ignore NuCachedSource");
+
+    mCachedSource = cachedSource;
+    mWVMExtractor = wvmExtractor;
+    mDurationUs = durationUs;
+    mBitrate = bitrate;
+    mIsStreaming = isStreaming;
+    mAudioTimeUs = 0;
+    mVideoTimeUs = 0;
+    mPrepareBuffering = (cachedSource != NULL || wvmExtractor != NULL);
+    cancelPollBuffering_l();
+    mOffloadAudio = false;
+    mFirstDequeuedBufferRealUs = -1ll;
+    mFirstDequeuedBufferMediaUs = -1ll;
+    mlastDequeuedBufferMediaUs = -1ll;
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering_l() {
+    mBuffering = false;
+    ++mPollBufferingGeneration;
+    mPrevBufferPercentage = -1;
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::notifyBufferingUpdate_l(int32_t percentage) {
+    // Buffering percent could go backward as it's estimated from remaining
+    // data and last access time. This could cause the buffering position
+    // drawn on media control to jitter slightly. Remember previously reported
+    // percentage and don't allow it to go backward.
+    if (percentage < mPrevBufferPercentage) {
+        percentage = mPrevBufferPercentage;
+    } else if (percentage > 100) {
+        percentage = 100;
+    }
+
+    mPrevBufferPercentage = percentage;
+
+    ALOGV("notifyBufferingUpdate_l: buffering %d%%", percentage);
+
+    sp<AMessage> msg = mNotify->dup();
+    msg->setInt32("what", kWhatBufferingUpdate);
+    msg->setInt32("percentage", percentage);
+    msg->post();
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::startBufferingIfNecessary_l() {
+    ALOGD("startBufferingIfNecessary_l: mPrepareBuffering=%d, mBuffering=%d",
+            mPrepareBuffering, mBuffering);
+
+    if (mPrepareBuffering) {
+        return;
+    }
+
+    if (!mBuffering) {
+        mBuffering = true;
+
+        ensureCacheIsFetching_l();
+        sendCacheStats_l();
+
+        sp<AMessage> notify = mNotify->dup();
+        notify->setInt32("what", kWhatPauseOnBufferingStart);
+        notify->post();
+    }
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary_l() {
+    ALOGD("stopBufferingIfNecessary_l: mPrepareBuffering=%d, mBuffering=%d",
+            mPrepareBuffering, mBuffering);
+
+    if (mPrepareBuffering) {
+        mPrepareBuffering = false;
+
+        sp<AMessage> notify = mNotify->dup();
+        notify->setInt32("what", kWhatPrepared);
+        notify->setInt32("err", OK);
+        notify->post();
+
+        return;
+    }
+
+    if (mBuffering) {
+        mBuffering = false;
+
+        sendCacheStats_l();
+
+        sp<AMessage> notify = mNotify->dup();
+        notify->setInt32("what", kWhatResumeOnBufferingEnd);
+        notify->post();
+    }
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::sendCacheStats_l() {
+    int32_t kbps = 0;
+    status_t err = UNKNOWN_ERROR;
+
+    if (mWVMExtractor != NULL) {
+        err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps);
+    } else if (mCachedSource != NULL) {
+        err = mCachedSource->getEstimatedBandwidthKbps(&kbps);
+    }
+
+    if (err == OK) {
+        sp<AMessage> notify = mNotify->dup();
+        notify->setInt32("what", kWhatCacheStats);
+        notify->setInt32("bandwidth", kbps);
+        notify->post();
+    }
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching_l() {
+    if (mCachedSource != NULL) {
+        mCachedSource->resumeFetchingIfNecessary();
+    }
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::schedulePollBuffering_l() {
+    sp<AMessage> msg = new AMessage(kWhatPollBuffering, this);
+    msg->setInt32("generation", mPollBufferingGeneration);
+    // Enquires buffering status every second.
+    msg->post(1000000ll);
+}
+
+int64_t NuPlayer::GenericSource::BufferingMonitor::getLastReadPosition_l() {
+    if (mAudioTimeUs > 0) {
+        return mAudioTimeUs;
+    } else if (mVideoTimeUs > 0) {
+        return mVideoTimeUs;
+    } else {
+        return 0;
+    }
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::onPollBuffering_l() {
+    status_t finalStatus = UNKNOWN_ERROR;
+    int64_t cachedDurationUs = -1ll;
+    ssize_t cachedDataRemaining = -1;
+
+    if (mWVMExtractor != NULL) {
+        cachedDurationUs =
+                mWVMExtractor->getCachedDurationUs(&finalStatus);
+    } else if (mCachedSource != NULL) {
+        cachedDataRemaining =
+                mCachedSource->approxDataRemaining(&finalStatus);
+
+        if (finalStatus == OK) {
+            off64_t size;
+            int64_t bitrate = 0ll;
+            if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) {
+                // |bitrate| uses bits/second unit, while size is number of bytes.
+                bitrate = size * 8000000ll / mDurationUs;
+            } else if (mBitrate > 0) {
+                bitrate = mBitrate;
+            }
+            if (bitrate > 0) {
+                cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate;
+            }
+        }
+    }
+
+    if (finalStatus != OK) {
+        ALOGV("onPollBuffering_l: EOS (finalStatus = %d)", finalStatus);
+
+        if (finalStatus == ERROR_END_OF_STREAM) {
+            notifyBufferingUpdate_l(100);
+        }
+
+        stopBufferingIfNecessary_l();
+        return;
+    } else if (cachedDurationUs >= 0ll) {
+        if (mDurationUs > 0ll) {
+            int64_t cachedPosUs = getLastReadPosition_l() + cachedDurationUs;
+            int percentage = 100.0 * cachedPosUs / mDurationUs;
+            if (percentage > 100) {
+                percentage = 100;
+            }
+
+            notifyBufferingUpdate_l(percentage);
+        }
+
+        ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec",
+                cachedDurationUs / 1000000.0f);
+
+        if (cachedDurationUs < kLowWaterMarkUs) {
+            // Take into account the data cached in downstream components to try to avoid
+            // unnecessary pause.
+            if (mOffloadAudio && mFirstDequeuedBufferRealUs >= 0) {
+                int64_t downStreamCacheUs = mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs
+                        - (ALooper::GetNowUs() - mFirstDequeuedBufferRealUs);
+                if (downStreamCacheUs > 0) {
+                    cachedDurationUs += downStreamCacheUs;
+                }
+            }
+
+            if (cachedDurationUs < kLowWaterMarkUs) {
+                startBufferingIfNecessary_l();
+            }
+        } else {
+            int64_t highWaterMark = mPrepareBuffering ? kHighWaterMarkUs : kHighWaterMarkRebufferUs;
+            if (cachedDurationUs > highWaterMark) {
+                stopBufferingIfNecessary_l();
+            }
+        }
+    } else if (cachedDataRemaining >= 0) {
+        ALOGV("onPollBuffering_l: cachedDataRemaining %zd bytes",
+                cachedDataRemaining);
+
+        if (cachedDataRemaining < kLowWaterMarkBytes) {
+            startBufferingIfNecessary_l();
+        } else if (cachedDataRemaining > kHighWaterMarkBytes) {
+            stopBufferingIfNecessary_l();
+        }
+    }
+
+    schedulePollBuffering_l();
+}
+
+void NuPlayer::GenericSource::BufferingMonitor::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+      case kWhatPollBuffering:
+      {
+          int32_t generation;
+          CHECK(msg->findInt32("generation", &generation));
+          Mutex::Autolock _l(mLock);
+          if (generation == mPollBufferingGeneration) {
+              onPollBuffering_l();
+          }
+          break;
+      }
+      default:
+          TRESPASS();
+          break;
+    }
+}
+
 }  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index ac980ef..2fd703e 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -77,6 +77,8 @@
 
     virtual bool isStreaming() const;
 
+    virtual void setOffloadAudio(bool offload);
+
 protected:
     virtual ~GenericSource();
 
@@ -90,6 +92,7 @@
         kWhatFetchSubtitleData,
         kWhatFetchTimedTextData,
         kWhatSendSubtitleData,
+        kWhatSendGlobalTimedTextData,
         kWhatSendTimedTextData,
         kWhatChangeAVSource,
         kWhatPollBuffering,
@@ -106,11 +109,88 @@
 
     struct Track {
         size_t mIndex;
-        sp<MediaSource> mSource;
+        sp<IMediaSource> mSource;
         sp<AnotherPacketSource> mPackets;
     };
 
-    Vector<sp<MediaSource> > mSources;
+    // Helper to monitor buffering status. The polling happens every second.
+    // When necessary, it will send out buffering events to the player.
+    struct BufferingMonitor : public AHandler {
+    public:
+        BufferingMonitor(const sp<AMessage> &notify);
+
+        // Set up state.
+        void prepare(const sp<NuCachedSource2> &cachedSource,
+                const sp<WVMExtractor> &wvmExtractor,
+                int64_t durationUs,
+                int64_t bitrate,
+                bool isStreaming);
+        // Stop and reset buffering monitor.
+        void stop();
+        // Cancel the current monitor task.
+        void cancelPollBuffering();
+        // Restart the monitor task.
+        void restartPollBuffering();
+        // Stop buffering task and send out corresponding events.
+        void stopBufferingIfNecessary();
+        // Make sure data source is getting data.
+        void ensureCacheIsFetching();
+        // Update media time of just extracted buffer from data source.
+        void updateQueuedTime(bool isAudio, int64_t timeUs);
+
+        // Set the offload mode.
+        void setOffloadAudio(bool offload);
+        // Update media time of last dequeued buffer which is sent to the decoder.
+        void updateDequeuedBufferTime(int64_t mediaUs);
+
+    protected:
+        virtual ~BufferingMonitor();
+        virtual void onMessageReceived(const sp<AMessage> &msg);
+
+    private:
+        enum {
+            kWhatPollBuffering,
+        };
+
+        sp<AMessage> mNotify;
+
+        sp<NuCachedSource2> mCachedSource;
+        sp<WVMExtractor> mWVMExtractor;
+        int64_t mDurationUs;
+        int64_t mBitrate;
+        bool mIsStreaming;
+
+        int64_t mAudioTimeUs;
+        int64_t mVideoTimeUs;
+        int32_t mPollBufferingGeneration;
+        bool mPrepareBuffering;
+        bool mBuffering;
+        int32_t mPrevBufferPercentage;
+
+        mutable Mutex mLock;
+
+        bool mOffloadAudio;
+        int64_t mFirstDequeuedBufferRealUs;
+        int64_t mFirstDequeuedBufferMediaUs;
+        int64_t mlastDequeuedBufferMediaUs;
+
+        void prepare_l(const sp<NuCachedSource2> &cachedSource,
+                const sp<WVMExtractor> &wvmExtractor,
+                int64_t durationUs,
+                int64_t bitrate,
+                bool isStreaming);
+        void cancelPollBuffering_l();
+        void notifyBufferingUpdate_l(int32_t percentage);
+        void startBufferingIfNecessary_l();
+        void stopBufferingIfNecessary_l();
+        void sendCacheStats_l();
+        void ensureCacheIsFetching_l();
+        int64_t getLastReadPosition_l();
+        void onPollBuffering_l();
+        void schedulePollBuffering_l();
+    };
+
+    Vector<sp<IMediaSource> > mSources;
     Track mAudioTrack;
     int64_t mAudioTimeUs;
     int64_t mAudioLastDequeueTimeUs;
@@ -146,16 +226,15 @@
     bool mStarted;
     bool mStopRead;
     int64_t mBitrate;
-    int32_t mPollBufferingGeneration;
+    sp<BufferingMonitor> mBufferingMonitor;
     uint32_t mPendingReadBufferTypes;
-    bool mBuffering;
-    bool mPrepareBuffering;
-    int32_t mPrevBufferPercentage;
+    sp<ABuffer> mGlobalTimedText;
 
     mutable Mutex mReadBufferLock;
     mutable Mutex mDisconnectLock;
 
     sp<ALooper> mLooper;
+    sp<ALooper> mBufferingMonitorLooper;
 
     void resetDataSource();
 
@@ -187,6 +266,10 @@
             uint32_t what, media_track_type type,
             int32_t curGen, sp<AnotherPacketSource> packets, sp<AMessage> msg);
 
+    void sendGlobalTextData(
+            uint32_t what,
+            int32_t curGen, sp<AMessage> msg);
+
     void sendTextData(
             uint32_t what, media_track_type type,
             int32_t curGen, sp<AnotherPacketSource> packets, sp<AMessage> msg);
@@ -206,16 +289,6 @@
     void queueDiscontinuityIfNeeded(
             bool seeking, bool formatChange, media_track_type trackType, Track *track);
 
-    void schedulePollBuffering();
-    void cancelPollBuffering();
-    void restartPollBuffering();
-    void onPollBuffering();
-    void notifyBufferingUpdate(int32_t percentage);
-    void startBufferingIfNecessary();
-    void stopBufferingIfNecessary();
-    void sendCacheStats();
-    void ensureCacheIsFetching();
-
     DISALLOW_EVIL_CONSTRUCTORS(GenericSource);
 };
 
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 126625a..3fffdc1a 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -101,15 +101,20 @@
 }
 
 sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
-    if (mLiveSession == NULL) {
-        return NULL;
+    sp<AMessage> format;
+    status_t err = -EWOULDBLOCK;
+    if (mLiveSession != NULL) {
+        err = mLiveSession->getStreamFormat(
+                audio ? LiveSession::STREAMTYPE_AUDIO
+                      : LiveSession::STREAMTYPE_VIDEO,
+                &format);
     }
 
-    sp<AMessage> format;
-    status_t err = mLiveSession->getStreamFormat(
-            audio ? LiveSession::STREAMTYPE_AUDIO
-                  : LiveSession::STREAMTYPE_VIDEO,
-            &format);
+    if (err == -EWOULDBLOCK) {
+        format = new AMessage();
+        format->setInt32("err", err);
+        return format;
+    }
 
     if (err != OK) {
         return NULL;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 36c38a2..2528777 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -191,7 +191,8 @@
       mResetting(false),
       mSourceStarted(false),
       mPaused(false),
-      mPausedByClient(false),
+      mPausedByClient(true),
+      mPendingBufferingFlag(PENDING_BUFFERING_FLAG_NONE),
       mPausedForBuffering(false) {
     clearFlushComplete();
 }
@@ -422,8 +423,15 @@
 
 void NuPlayer::writeTrackInfo(
         Parcel* reply, const sp<AMessage> format) const {
+    if (format == NULL) {
+        ALOGE("NULL format");
+        return;
+    }
     int32_t trackType;
-    CHECK(format->findInt32("type", &trackType));
+    if (!format->findInt32("type", &trackType)) {
+        ALOGE("no track type");
+        return;
+    }
 
     AString mime;
     if (!format->findString("mime", &mime)) {
@@ -436,12 +444,16 @@
         } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
             mime = "video/";
         } else {
-            TRESPASS();
+            ALOGE("unknown track type: %d", trackType);
+            return;
         }
     }
 
     AString lang;
-    CHECK(format->findString("language", &lang));
+    if (!format->findString("language", &lang)) {
+        ALOGE("no language");
+        return;
+    }
 
     reply->writeInt32(2); // write something non-zero
     reply->writeInt32(trackType);
@@ -704,6 +716,10 @@
                 onStart();
             }
             mPausedByClient = false;
+            if (mPendingBufferingFlag != PENDING_BUFFERING_FLAG_NONE) {
+                notifyListener(MEDIA_INFO, mPendingBufferingFlag, 0);
+                mPendingBufferingFlag = PENDING_BUFFERING_FLAG_NONE;
+            }
             break;
         }
 
@@ -720,6 +736,7 @@
             if (err == OK) {
                 if (rate.mSpeed == 0.f) {
                     onPause();
+                    mPausedByClient = true;
                     // save all other settings (using non-paused speed)
                     // so we can restore them on start
                     AudioPlaybackRate newRate = rate;
@@ -727,6 +744,7 @@
                     mPlaybackSettings = newRate;
                 } else { /* rate.mSpeed != 0.f */
                     onResume();
+                    mPausedByClient = false;
                     mPlaybackSettings = rate;
                 }
             }
@@ -834,16 +852,21 @@
 
             bool mHadAnySourcesBefore =
                 (mAudioDecoder != NULL) || (mVideoDecoder != NULL);
+            bool rescan = false;
 
             // initialize video before audio because successful initialization of
             // video may change deep buffer mode of audio.
             if (mSurface != NULL) {
-                instantiateDecoder(false, &mVideoDecoder);
+                if (instantiateDecoder(false, &mVideoDecoder) == -EWOULDBLOCK) {
+                    rescan = true;
+                }
             }
 
             // Don't try to re-open audio sink if there's an existing decoder.
             if (mAudioSink != NULL && mAudioDecoder == NULL) {
-                instantiateDecoder(true, &mAudioDecoder);
+                if (instantiateDecoder(true, &mAudioDecoder) == -EWOULDBLOCK) {
+                    rescan = true;
+                }
             }
 
             if (!mHadAnySourcesBefore
@@ -870,8 +893,7 @@
                 break;
             }
 
-            if ((mAudioDecoder == NULL && mAudioSink != NULL)
-                    || (mVideoDecoder == NULL && mSurface != NULL)) {
+            if (rescan) {
                 msg->post(100000ll);
                 mScanSourcesPending = true;
             }
@@ -1188,6 +1210,8 @@
                 break;
             }
 
+            mPendingBufferingFlag = PENDING_BUFFERING_FLAG_NONE;
+
             mDeferredActions.push_back(
                     new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
                                            FLUSH_CMD_FLUSH /* video */));
@@ -1306,6 +1330,7 @@
     }
 
     sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
+    ALOGV_IF(audioMeta == NULL, "no metadata for audio source");  // video only stream
     audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
     if (mAudioSink != NULL) {
         streamType = mAudioSink->getAudioStreamType();
@@ -1508,7 +1533,12 @@
     sp<AMessage> format = mSource->getFormat(audio);
 
     if (format == NULL) {
-        return -EWOULDBLOCK;
+        return UNKNOWN_ERROR;
+    } else {
+        status_t err;
+        if (format->findInt32("err", &err) && err) {
+            return err;
+        }
     }
 
     format->setInt32("priority", 0 /* realtime */);
@@ -1543,10 +1573,14 @@
 
         determineAudioModeChange();
         if (mOffloadAudio) {
+            mSource->setOffloadAudio(true /* offload */);
+
             const bool hasVideo = (mSource->getFormat(false /*audio */) != NULL);
             format->setInt32("has-video", hasVideo);
             *decoder = new DecoderPassThrough(notify, mSource, mRenderer);
         } else {
+            mSource->setOffloadAudio(false /* offload */);
+
             *decoder = new Decoder(notify, mSource, mPID, mRenderer);
         }
     } else {
@@ -1878,6 +1912,7 @@
     }
     mPreviousSeekTimeUs = seekTimeUs;
     mSource->seekTo(seekTimeUs);
+    mPendingBufferingFlag = PENDING_BUFFERING_FLAG_NONE;
     ++mTimedTextGeneration;
 
     // everything's flushed, continue playback.
@@ -2122,7 +2157,12 @@
 
         case Source::kWhatBufferingStart:
         {
-            notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_START, 0);
+            if (mPausedByClient) {
+                mPendingBufferingFlag = PENDING_BUFFERING_FLAG_START;
+            } else {
+                notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_START, 0);
+                mPendingBufferingFlag = PENDING_BUFFERING_FLAG_NONE;
+            }
             break;
         }
 
@@ -2144,7 +2184,12 @@
 
         case Source::kWhatBufferingEnd:
         {
-            notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_END, 0);
+            if (mPausedByClient) {
+                mPendingBufferingFlag = PENDING_BUFFERING_FLAG_END;
+            } else {
+                notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_END, 0);
+                mPendingBufferingFlag = PENDING_BUFFERING_FLAG_NONE;
+            }
             break;
         }
 
@@ -2302,7 +2347,7 @@
     const void *data;
     size_t size = 0;
     int64_t timeUs;
-    int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS;
+    int32_t flag = TextDescriptions::IN_BAND_TEXT_3GPP;
 
     AString mime;
     CHECK(buffer->meta()->findString("mime", &mime));
@@ -2314,7 +2359,12 @@
     Parcel parcel;
     if (size > 0) {
         CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-        flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
+        int32_t global = 0;
+        if (buffer->meta()->findInt32("global", &global) && global) {
+            flag |= TextDescriptions::GLOBAL_DESCRIPTIONS;
+        } else {
+            flag |= TextDescriptions::LOCAL_DESCRIPTIONS;
+        }
         TextDescriptions::getParcelOfDescriptions(
                 (const uint8_t *)data, size, flag, timeUs / 1000, &parcel);
     }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 4cec1a1..cefbb19 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -182,6 +182,12 @@
         FLUSH_CMD_SHUTDOWN,
     };
 
+    enum PendingBufferingFlag {
+        PENDING_BUFFERING_FLAG_NONE = MEDIA_INFO_UNKNOWN,
+        PENDING_BUFFERING_FLAG_START = MEDIA_INFO_BUFFERING_START,
+        PENDING_BUFFERING_FLAG_END = MEDIA_INFO_BUFFERING_END,
+    };
+
     // Status of flush responses from the decoder and renderer.
     bool mFlushComplete[2][2];
 
@@ -208,6 +214,9 @@
     // still become true, when we pause internally due to buffering.
     bool mPausedByClient;
 
+    // Pending buffering flag which is not sent to client due to being paused.
+    PendingBufferingFlag mPendingBufferingFlag;
+
     // Pause state as requested by source (internally) due to buffering
     bool mPausedForBuffering;
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
index ac3c6b6..13716cf 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
@@ -30,6 +30,9 @@
 
 namespace android {
 
+// In CEA-708B, the maximum bandwidth of CC is set to 9600bps.
+static const size_t kMaxBandwithSizeBytes = 9600 / 8;
+
 struct CCData {
     CCData(uint8_t type, uint8_t data1, uint8_t data2)
         : mType(type), mData1(data1), mData2(data2) {
@@ -116,15 +119,19 @@
 
 NuPlayer::CCDecoder::CCDecoder(const sp<AMessage> &notify)
     : mNotify(notify),
-      mCurrentChannel(0),
-      mSelectedTrack(-1) {
-      for (size_t i = 0; i < sizeof(mTrackIndices)/sizeof(mTrackIndices[0]); ++i) {
-          mTrackIndices[i] = -1;
-      }
+      mSelectedTrack(-1),
+      mDTVCCPacket(new ABuffer(kMaxBandwithSizeBytes)) {
+    mDTVCCPacket->setRange(0, 0);
+
+    // In CEA-608, streams from packets which have the value 0 of cc_type contain CC1 and CC2, and
+    // streams from packets which have the value 1 of cc_type contain CC3 and CC4.
+    // The following array indicates the current transmitting channels for each value of cc_type.
+    mLine21Channels[0] = 0; // CC1
+    mLine21Channels[1] = 2; // CC3
 }
 
 size_t NuPlayer::CCDecoder::getTrackCount() const {
-    return mFoundChannels.size();
+    return mTracks.size();
 }
 
 sp<AMessage> NuPlayer::CCDecoder::getTrackInfo(size_t index) const {
@@ -134,13 +141,31 @@
 
     sp<AMessage> format = new AMessage();
 
+    CCTrack track = mTracks[index];
+
     format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE);
     format->setString("language", "und");
-    format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
-    //CC1, field 0 channel 0
-    bool isDefaultAuto = (mFoundChannels[index] == 0);
+
+    switch (track.mTrackType) {
+        case kTrackTypeCEA608:
+            format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
+            break;
+        case kTrackTypeCEA708:
+            format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_708);
+            break;
+        default:
+            ALOGE("Unknown track type: %d", track.mTrackType);
+            return NULL;
+    }
+
+    // For CEA-608 CC1, field 0 channel 0
+    bool isDefaultAuto = track.mTrackType == kTrackTypeCEA608
+            && track.mTrackChannel == 0;
+    // For CEA-708, Primary Caption Service.
+    bool isDefaultOnly = track.mTrackType == kTrackTypeCEA708
+            && track.mTrackChannel == 1;
     format->setInt32("auto", isDefaultAuto);
-    format->setInt32("default", isDefaultAuto);
+    format->setInt32("default", isDefaultAuto || isDefaultOnly);
     format->setInt32("forced", 0);
 
     return format;
@@ -167,24 +192,20 @@
         mSelectedTrack = -1;
     }
 
+    // Clear the previous track payloads
+    mCCMap.clear();
+
     return OK;
 }
 
 bool NuPlayer::CCDecoder::isSelected() const {
-    return mSelectedTrack >= 0 && mSelectedTrack < (int32_t) getTrackCount();
+    return mSelectedTrack >= 0 && mSelectedTrack < (int32_t)getTrackCount();
 }
 
 bool NuPlayer::CCDecoder::isTrackValid(size_t index) const {
     return index < getTrackCount();
 }
 
-int32_t NuPlayer::CCDecoder::getTrackIndex(size_t channel) const {
-    if (channel < sizeof(mTrackIndices)/sizeof(mTrackIndices[0])) {
-        return mTrackIndices[channel];
-    }
-    return -1;
-}
-
 // returns true if a new CC track is found
 bool NuPlayer::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) {
     sp<ABuffer> sei;
@@ -197,7 +218,7 @@
 
     bool trackAdded = false;
 
-    const NALPosition *nal = (NALPosition *) sei->data();
+    const NALPosition *nal = (NALPosition *)sei->data();
 
     for (size_t i = 0; i < sei->size() / sizeof(NALPosition); ++i, ++nal) {
         trackAdded |= parseSEINalUnit(
@@ -208,9 +229,8 @@
 }
 
 // returns true if a new CC track is found
-bool NuPlayer::CCDecoder::parseSEINalUnit(
-        int64_t timeUs, const uint8_t *nalStart, size_t nalSize) {
-    unsigned nalType = nalStart[0] & 0x1f;
+bool NuPlayer::CCDecoder::parseSEINalUnit(int64_t timeUs, const uint8_t *data, size_t size) {
+    unsigned nalType = data[0] & 0x1f;
 
     // the buffer should only have SEI in it
     if (nalType != 6) {
@@ -218,7 +238,8 @@
     }
 
     bool trackAdded = false;
-    NALBitReader br(nalStart + 1, nalSize - 1);
+    NALBitReader br(data + 1, size - 1);
+
     // sei_message()
     while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message()
         uint32_t payload_type = 0;
@@ -256,53 +277,7 @@
             }
 
             if (isCC && payload_size > 2) {
-                // MPEG_cc_data()
-                // ATSC A/53 Part 4: 6.2.3.1
-                br.skipBits(1); //process_em_data_flag
-                bool process_cc_data_flag = br.getBits(1);
-                br.skipBits(1); //additional_data_flag
-                size_t cc_count = br.getBits(5);
-                br.skipBits(8); // em_data;
-                payload_size -= 2;
-
-                if (process_cc_data_flag) {
-                    AString out;
-
-                    sp<ABuffer> ccBuf = new ABuffer(cc_count * sizeof(CCData));
-                    ccBuf->setRange(0, 0);
-
-                    for (size_t i = 0; i < cc_count && payload_size >= 3; i++) {
-                        uint8_t marker = br.getBits(5);
-                        CHECK_EQ(marker, 0x1f);
-
-                        bool cc_valid = br.getBits(1);
-                        uint8_t cc_type = br.getBits(2);
-                        // remove odd parity bit
-                        uint8_t cc_data_1 = br.getBits(8) & 0x7f;
-                        uint8_t cc_data_2 = br.getBits(8) & 0x7f;
-
-                        payload_size -= 3;
-
-                        if (cc_valid
-                                && (cc_type == 0 || cc_type == 1)) {
-                            CCData cc(cc_type, cc_data_1, cc_data_2);
-                            if (!isNullPad(&cc)) {
-                                size_t channel;
-                                if (cc.getChannel(&channel) && getTrackIndex(channel) < 0) {
-                                    mTrackIndices[channel] = mFoundChannels.size();
-                                    mFoundChannels.push_back(channel);
-                                    trackAdded = true;
-                                }
-                                memcpy(ccBuf->data() + ccBuf->size(),
-                                        (void *)&cc, sizeof(cc));
-                                ccBuf->setRange(0, ccBuf->size() + sizeof(CCData));
-                            }
-                        }
-                    }
-
-                    mCCMap.add(timeUs, ccBuf);
-                    break;
-                }
+                trackAdded |= parseMPEGCCData(timeUs, br.data(), br.numBitsLeft() / 8);
             } else {
                 ALOGV("Malformed SEI payload type 4");
             }
@@ -317,31 +292,202 @@
     return trackAdded;
 }
 
-sp<ABuffer> NuPlayer::CCDecoder::filterCCBuf(
-        const sp<ABuffer> &ccBuf, size_t index) {
-    sp<ABuffer> filteredCCBuf = new ABuffer(ccBuf->size());
-    filteredCCBuf->setRange(0, 0);
+// returns true if a new CC track is found
+bool NuPlayer::CCDecoder::extractFromMPEGUserData(const sp<ABuffer> &accessUnit) {
+    sp<ABuffer> mpegUserData;
+    if (!accessUnit->meta()->findBuffer("mpegUserData", &mpegUserData)
+            || mpegUserData == NULL) {
+        return false;
+    }
 
-    size_t cc_count = ccBuf->size() / sizeof(CCData);
-    const CCData* cc_data = (const CCData*)ccBuf->data();
+    int64_t timeUs;
+    CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
+
+    bool trackAdded = false;
+
+    const size_t *userData = (size_t *)mpegUserData->data();
+
+    for (size_t i = 0; i < mpegUserData->size() / sizeof(size_t); ++i) {
+        trackAdded |= parseMPEGUserDataUnit(
+                timeUs, accessUnit->data() + userData[i], accessUnit->size() - userData[i]);
+    }
+
+    return trackAdded;
+}
+
+// returns true if a new CC track is found
+bool NuPlayer::CCDecoder::parseMPEGUserDataUnit(int64_t timeUs, const uint8_t *data, size_t size) {
+    ABitReader br(data + 4, 5);
+
+    uint32_t user_identifier = br.getBits(32);
+    uint8_t user_data_type = br.getBits(8);
+
+    if (user_identifier == 'GA94' && user_data_type == 0x3) {
+        return parseMPEGCCData(timeUs, data + 9, size - 9);
+    }
+
+    return false;
+}
+
+// returns true if a new CC track is found
+bool NuPlayer::CCDecoder::parseMPEGCCData(int64_t timeUs, const uint8_t *data, size_t size) {
+    bool trackAdded = false;
+
+    // MPEG_cc_data()
+    // ATSC A/53 Part 4: 6.2.3.1
+    ABitReader br(data, size);
+
+    if (br.numBitsLeft() <= 16) {
+        return false;
+    }
+
+    br.skipBits(1);
+    bool process_cc_data_flag = br.getBits(1);
+    br.skipBits(1);
+    size_t cc_count = br.getBits(5);
+    br.skipBits(8);
+
+    if (!process_cc_data_flag || 3 * 8 * cc_count >= br.numBitsLeft()) {
+        return false;
+    }
+
+    sp<ABuffer> line21CCBuf = NULL;
+
     for (size_t i = 0; i < cc_count; ++i) {
-        size_t channel;
-        if (cc_data[i].getChannel(&channel)) {
-            mCurrentChannel = channel;
-        }
-        if (mCurrentChannel == mFoundChannels[index]) {
-            memcpy(filteredCCBuf->data() + filteredCCBuf->size(),
-                    (void *)&cc_data[i], sizeof(CCData));
-            filteredCCBuf->setRange(0, filteredCCBuf->size() + sizeof(CCData));
+        br.skipBits(5);
+        bool cc_valid = br.getBits(1);
+        uint8_t cc_type = br.getBits(2);
+
+        if (cc_valid) {
+            if (cc_type == 3) {
+                if (mDTVCCPacket->size() > 0) {
+                    trackAdded |= parseDTVCCPacket(
+                            timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
+                    mDTVCCPacket->setRange(0, 0);
+                }
+                memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
+                mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
+                br.skipBits(16);
+            } else if (mDTVCCPacket->size() > 0 && cc_type == 2) {
+                memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
+                mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
+                br.skipBits(16);
+            } else if (cc_type == 0 || cc_type == 1) {
+                uint8_t cc_data_1 = br.getBits(8) & 0x7f;
+                uint8_t cc_data_2 = br.getBits(8) & 0x7f;
+
+                CCData cc(cc_type, cc_data_1, cc_data_2);
+
+                if (isNullPad(&cc)) {
+                    continue;
+                }
+
+                size_t channel;
+                if (cc.getChannel(&channel)) {
+                    mLine21Channels[cc_type] = channel;
+
+                    // create a new track if it does not exist.
+                    getTrackIndex(kTrackTypeCEA608, channel, &trackAdded);
+                }
+
+                if (isSelected() && mTracks[mSelectedTrack].mTrackType == kTrackTypeCEA608
+                        && mTracks[mSelectedTrack].mTrackChannel == mLine21Channels[cc_type]) {
+                    if (line21CCBuf == NULL) {
+                        line21CCBuf = new ABuffer((cc_count - i) * sizeof(CCData));
+                        line21CCBuf->setRange(0, 0);
+                    }
+                    memcpy(line21CCBuf->data() + line21CCBuf->size(), &cc, sizeof(cc));
+                    line21CCBuf->setRange(0, line21CCBuf->size() + sizeof(CCData));
+                }
+            } else {
+                br.skipBits(16);
+            }
+        } else {
+            if ((cc_type == 3 || cc_type == 2) && mDTVCCPacket->size() > 0) {
+                trackAdded |= parseDTVCCPacket(timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
+                mDTVCCPacket->setRange(0, 0);
+            }
+            br.skipBits(16);
         }
     }
 
-    return filteredCCBuf;
+    if (isSelected() && mTracks[mSelectedTrack].mTrackType == kTrackTypeCEA608
+            && line21CCBuf != NULL && line21CCBuf->size() > 0) {
+        mCCMap.add(timeUs, line21CCBuf);
+    }
+
+    return trackAdded;
+}
+
+// returns true if a new CC track is found
+bool NuPlayer::CCDecoder::parseDTVCCPacket(int64_t timeUs, const uint8_t *data, size_t size) {
+    // CEA-708B 5 DTVCC Packet Layer.
+    ABitReader br(data, size);
+    br.skipBits(2);
+
+    size_t packet_size = br.getBits(6);
+    if (packet_size == 0) packet_size = 64;
+    packet_size *= 2;
+
+    if (size != packet_size) {
+        return false;
+    }
+
+    bool trackAdded = false;
+
+    while (br.numBitsLeft() >= 16) {
+        // CEA-708B Figure 5 and 6.
+        uint8_t service_number = br.getBits(3);
+        size_t block_size = br.getBits(5);
+
+        if (service_number == 64) {
+            br.skipBits(2);
+            service_number = br.getBits(6);
+
+            if (service_number < 64) {
+                return trackAdded;
+            }
+        }
+
+        if (br.numBitsLeft() < block_size * 8) {
+            return trackAdded;
+        }
+
+        if (block_size > 0) {
+            size_t trackIndex = getTrackIndex(kTrackTypeCEA708, service_number, &trackAdded);
+            if (mSelectedTrack == (ssize_t)trackIndex) {
+                sp<ABuffer> ccPacket = new ABuffer(block_size);
+                memcpy(ccPacket->data(), br.data(), block_size);
+                mCCMap.add(timeUs, ccPacket);
+            }
+        }
+        br.skipBits(block_size * 8);
+    }
+
+    return trackAdded;
+}
+
+// return the track index for a given type and channel.
+// if the track does not exist, creates a new one.
+size_t NuPlayer::CCDecoder::getTrackIndex(
+        int32_t trackType, size_t channel, bool *trackAdded) {
+    CCTrack track(trackType, channel);
+    ssize_t index = mTrackIndices.indexOfKey(track);
+
+    if (index < 0) {
+        // A new track is added.
+        index = mTracks.size();
+        mTrackIndices.add(track, index);
+        mTracks.add(track);
+        *trackAdded = true;
+        return index;
+    }
+
+    return mTrackIndices.valueAt(index);
 }
 
 void NuPlayer::CCDecoder::decode(const sp<ABuffer> &accessUnit) {
-    if (extractFromSEI(accessUnit)) {
-        ALOGI("Found CEA-608 track");
+    if (extractFromMPEGUserData(accessUnit) || extractFromSEI(accessUnit)) {
         sp<AMessage> msg = mNotify->dup();
         msg->setInt32("what", kWhatTrackAdded);
         msg->post();
@@ -350,8 +496,7 @@
 }
 
 void NuPlayer::CCDecoder::display(int64_t timeUs) {
-    if (!isTrackValid(mSelectedTrack)) {
-        ALOGE("Could not find current track(index=%d)", mSelectedTrack);
+    if (!isSelected()) {
         return;
     }
 
@@ -361,7 +506,26 @@
         return;
     }
 
-    sp<ABuffer> ccBuf = filterCCBuf(mCCMap.valueAt(index), mSelectedTrack);
+    sp<ABuffer> ccBuf;
+
+    if (index == 0) {
+        ccBuf = mCCMap.valueAt(index);
+    } else {
+        size_t size = 0;
+
+        for (ssize_t i = 0; i <= index; ++i) {
+            size += mCCMap.valueAt(i)->size();
+        }
+
+        ccBuf = new ABuffer(size);
+        ccBuf->setRange(0, 0);
+
+        for (ssize_t i = 0; i <= index; ++i) {
+            sp<ABuffer> buf = mCCMap.valueAt(i);
+            memcpy(ccBuf->data() + ccBuf->size(), buf->data(), buf->size());
+            ccBuf->setRange(0, ccBuf->size() + buf->size());
+        }
+    }
 
     if (ccBuf->size() > 0) {
 #if 0
@@ -384,6 +548,25 @@
 
 void NuPlayer::CCDecoder::flush() {
     mCCMap.clear();
+    mDTVCCPacket->setRange(0, 0);
+}
+
+int32_t NuPlayer::CCDecoder::CCTrack::compare(const NuPlayer::CCDecoder::CCTrack& rhs) const {
+    int32_t cmp = mTrackType - rhs.mTrackType;
+    if (cmp != 0) return cmp;
+    return mTrackChannel - rhs.mTrackChannel;
+}
+
+bool NuPlayer::CCDecoder::CCTrack::operator<(const NuPlayer::CCDecoder::CCTrack& rhs) const {
+    return compare(rhs) < 0;
+}
+
+bool NuPlayer::CCDecoder::CCTrack::operator==(const NuPlayer::CCDecoder::CCTrack& rhs) const {
+    return compare(rhs) == 0;
+}
+
+bool NuPlayer::CCDecoder::CCTrack::operator!=(const NuPlayer::CCDecoder::CCTrack& rhs) const {
+    return compare(rhs) != 0;
 }
 
 }  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
index 77fb0fe..a297334 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
@@ -28,6 +28,11 @@
         kWhatTrackAdded,
     };
 
+    enum {
+        kTrackTypeCEA608,
+        kTrackTypeCEA708,
+    };
+
     CCDecoder(const sp<AMessage> &notify);
 
     size_t getTrackCount() const;
@@ -39,18 +44,50 @@
     void flush();
 
 private:
+    // CC track identifier.
+    struct CCTrack {
+        CCTrack() : mTrackType(0), mTrackChannel(0) { }
+
+        CCTrack(const int32_t trackType, const size_t trackChannel)
+            : mTrackType(trackType), mTrackChannel(trackChannel) { }
+
+        int32_t mTrackType;
+        size_t mTrackChannel;
+
+        // The ordering of CCTracks is to build a map of track to index.
+        // It is necessary to find the index of the matched CCTrack when CC data comes.
+        int compare(const NuPlayer::CCDecoder::CCTrack& rhs) const;
+        inline bool operator<(const NuPlayer::CCDecoder::CCTrack& rhs) const;
+        inline bool operator==(const NuPlayer::CCDecoder::CCTrack& rhs) const;
+        inline bool operator!=(const NuPlayer::CCDecoder::CCTrack& rhs) const;
+    };
+
     sp<AMessage> mNotify;
     KeyedVector<int64_t, sp<ABuffer> > mCCMap;
-    size_t mCurrentChannel;
-    int32_t mSelectedTrack;
-    int32_t mTrackIndices[4];
-    Vector<size_t> mFoundChannels;
+    ssize_t mSelectedTrack;
+    KeyedVector<CCTrack, size_t> mTrackIndices;
+    Vector<CCTrack> mTracks;
+
+    // CEA-608 closed caption
+    size_t mLine21Channels[2]; // The current channels of NTSC_CC_FIELD_{1, 2}
+
+    // CEA-708 closed caption
+    sp<ABuffer> mDTVCCPacket;
 
     bool isTrackValid(size_t index) const;
-    int32_t getTrackIndex(size_t channel) const;
+    size_t getTrackIndex(int32_t trackType, size_t channel, bool *trackAdded);
+
+    // Extract from H.264 SEIs
     bool extractFromSEI(const sp<ABuffer> &accessUnit);
-    bool parseSEINalUnit(int64_t timeUs, const uint8_t *nalStart, size_t nalSize);
-    sp<ABuffer> filterCCBuf(const sp<ABuffer> &ccBuf, size_t index);
+    bool parseSEINalUnit(int64_t timeUs, const uint8_t *data, size_t size);
+
+    // Extract from MPEG user data
+    bool extractFromMPEGUserData(const sp<ABuffer> &accessUnit);
+    bool parseMPEGUserDataUnit(int64_t timeUs, const uint8_t *data, size_t size);
+
+    // Extract CC tracks from MPEG_cc_data
+    bool parseMPEGCCData(int64_t timeUs, const uint8_t *data, size_t size);
+    bool parseDTVCCPacket(int64_t timeUs, const uint8_t *data, size_t size);
 
     DISALLOW_EVIL_CONSTRUCTORS(CCDecoder);
 };
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index ce87f87..4678956 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -525,7 +525,10 @@
         ALOGI("[%s] resubmitting CSD", mComponentName.c_str());
         msg->setBuffer("buffer", buffer);
         mCSDsToSubmit.removeAt(0);
-        CHECK(onInputBufferFetched(msg));
+        if (!onInputBufferFetched(msg)) {
+            handleError(UNKNOWN_ERROR);
+            return false;
+        }
         return true;
     }
 
@@ -862,7 +865,11 @@
 
         // copy into codec buffer
         if (buffer != codecBuffer) {
-            CHECK_LE(buffer->size(), codecBuffer->capacity());
+            if (buffer->size() > codecBuffer->capacity()) {
+                handleError(ERROR_BUFFER_TOO_SMALL);
+                mDequeuedInputBuffers.push_back(bufferIx);
+                return false;
+            }
             codecBuffer->setRange(0, buffer->size());
             memcpy(codecBuffer->data(), buffer->data(), buffer->size());
         }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index 514ec1a..f224635 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -223,6 +223,11 @@
         status_t err = dequeueAccessUnit(&accessUnit);
 
         if (err == -EWOULDBLOCK) {
+            // Flush out the aggregate buffer to try to avoid underrun.
+            accessUnit = aggregateBuffer(NULL /* accessUnit */);
+            if (accessUnit != NULL) {
+                break;
+            }
             return err;
         } else if (err != OK) {
             if (err == INFO_DISCONTINUITY) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index f288c36..332fef6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -334,8 +334,8 @@
     // down for audio offload mode. If that happens, the NuPlayerRenderer will no longer know the
     // current position. So similar to seekTo, update |mPositionUs| to the pause position by calling
     // getCurrentPosition here.
-    int msec;
-    getCurrentPosition(&msec);
+    int unused;
+    getCurrentPosition(&unused);
 
     Mutex::Autolock autoLock(mLock);
 
@@ -364,11 +364,12 @@
 status_t NuPlayerDriver::setPlaybackSettings(const AudioPlaybackRate &rate) {
     status_t err = mPlayer->setPlaybackSettings(rate);
     if (err == OK) {
+        // try to update position
+        int unused;
+        getCurrentPosition(&unused);
         Mutex::Autolock autoLock(mLock);
         if (rate.mSpeed == 0.f && mState == STATE_RUNNING) {
             mState = STATE_PAUSED;
-            // try to update position
-            (void)mPlayer->getCurrentPosition(&mPositionUs);
             notifyListener_l(MEDIA_PAUSED);
         } else if (rate.mSpeed != 0.f && mState == STATE_PAUSED) {
             mState = STATE_RUNNING;
@@ -390,7 +391,7 @@
 }
 
 status_t NuPlayerDriver::seekTo(int msec) {
-    ALOGD("seekTo(%p) %d ms", this, msec);
+    ALOGD("seekTo(%p) %d ms at state %d", this, msec, mState);
     Mutex::Autolock autoLock(mLock);
 
     int64_t seekTimeUs = msec * 1000ll;
@@ -423,7 +424,7 @@
     int64_t tempUs = 0;
     {
         Mutex::Autolock autoLock(mLock);
-        if (mSeekInProgress || mState == STATE_PAUSED) {
+        if (mSeekInProgress || (mState == STATE_PAUSED && !mAtEOS)) {
             tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
             *msec = (int)divRound(tempUs, (int64_t)(1000));
             return OK;
@@ -458,7 +459,7 @@
 }
 
 status_t NuPlayerDriver::reset() {
-    ALOGD("reset(%p)", this);
+    ALOGD("reset(%p) at state %d", this, mState);
     Mutex::Autolock autoLock(mLock);
 
     switch (mState) {
@@ -725,7 +726,8 @@
 
 void NuPlayerDriver::notifyListener_l(
         int msg, int ext1, int ext2, const Parcel *in) {
-    ALOGD("notifyListener_l(%p), (%d, %d, %d)", this, msg, ext1, ext2);
+    ALOGD("notifyListener_l(%p), (%d, %d, %d), loop setting(%d, %d)",
+            this, msg, ext1, ext2, mAutoLoop, mLooping);
     switch (msg) {
         case MEDIA_PLAYBACK_COMPLETE:
         {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index c6a7805..a049a30 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -69,6 +69,11 @@
 // is closed to allow the audio DSP to power down.
 static const int64_t kOffloadPauseMaxUs = 10000000ll;
 
+// Maximum allowed delay from AudioSink, 1.5 seconds.
+static const int64_t kMaxAllowedAudioSinkDelayUs = 1500000ll;
+
+static const int64_t kMinimumAudioClockUpdatePeriodUs = 20 /* msec */ * 1000;
+
 // static
 const NuPlayer::Renderer::PcmInfo NuPlayer::Renderer::AUDIO_PCMINFO_INITIALIZER = {
         AUDIO_CHANNEL_NONE,
@@ -95,6 +100,7 @@
       mVideoQueueGeneration(0),
       mAudioDrainGeneration(0),
       mVideoDrainGeneration(0),
+      mAudioEOSGeneration(0),
       mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
       mAudioFirstAnchorTimeMediaUs(-1),
       mAnchorTimeMediaUs(-1),
@@ -112,6 +118,8 @@
       mVideoRenderingStartGeneration(0),
       mAudioRenderingStartGeneration(0),
       mRenderingDataDelivered(false),
+      mNextAudioClockUpdateTimeUs(-1),
+      mLastAudioMediaTimeUs(-1),
       mAudioOffloadPauseTimeoutGeneration(0),
       mAudioTornDown(false),
       mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
@@ -311,8 +319,33 @@
     msg->post();
 }
 
-// Called on any threads.
+// Called on any threads without mLock acquired.
 status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs) {
+    status_t result = mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
+    if (result == OK) {
+        return result;
+    }
+
+    // MediaClock has not started yet. Try to start it if possible.
+    {
+        Mutex::Autolock autoLock(mLock);
+        if (mAudioFirstAnchorTimeMediaUs == -1) {
+            return result;
+        }
+
+        AudioTimestamp ts;
+        status_t res = mAudioSink->getTimestamp(ts);
+        if (res != OK) {
+            return result;
+        }
+
+        // AudioSink has rendered some frames.
+        int64_t nowUs = ALooper::GetNowUs();
+        int64_t nowMediaUs = mAudioSink->getPlayedOutDurationUs(nowUs)
+                + mAudioFirstAnchorTimeMediaUs;
+        mMediaClock->updateAnchor(nowMediaUs, nowUs, -1);
+    }
+
     return mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
 }
 
@@ -500,6 +533,19 @@
             break;
         }
 
+        case kWhatEOS:
+        {
+            int32_t generation;
+            CHECK(msg->findInt32("audioEOSGeneration", &generation));
+            if (generation != mAudioEOSGeneration) {
+                break;
+            }
+            status_t finalResult;
+            CHECK(msg->findInt32("finalResult", &finalResult));
+            notifyEOS(true /* audio */, finalResult);
+            break;
+        }
+
         case kWhatConfigPlayback:
         {
             sp<AReplyToken> replyID;
@@ -755,7 +801,7 @@
     if (mAudioFirstAnchorTimeMediaUs >= 0) {
         int64_t nowUs = ALooper::GetNowUs();
         int64_t nowMediaUs =
-            mAudioFirstAnchorTimeMediaUs + getPlayedOutAudioDurationUs(nowUs);
+            mAudioFirstAnchorTimeMediaUs + mAudioSink->getPlayedOutDurationUs(nowUs);
         // we don't know how much data we are queueing for offloaded tracks.
         mMediaClock->updateAnchor(nowMediaUs, nowUs, INT64_MAX);
     }
@@ -864,6 +910,7 @@
                 postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs());
             }
             notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs);
+            mLastAudioMediaTimeUs = getDurationUsIfPlayedAtSampleRate(mNumFramesWritten);
 
             mAudioQueue.erase(mAudioQueue.begin());
             entry = NULL;
@@ -973,7 +1020,7 @@
 // Calculate duration of pending samples if played at normal rate (i.e., 1.0).
 int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) {
     int64_t writtenAudioDurationUs = getDurationUsIfPlayedAtSampleRate(mNumFramesWritten);
-    return writtenAudioDurationUs - getPlayedOutAudioDurationUs(nowUs);
+    return writtenAudioDurationUs - mAudioSink->getPlayedOutDurationUs(nowUs);
 }
 
 int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) {
@@ -994,9 +1041,37 @@
         return;
     }
     setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs);
+
+    // mNextAudioClockUpdateTimeUs is -1 if we're waiting for audio sink to start
+    if (mNextAudioClockUpdateTimeUs == -1) {
+        AudioTimestamp ts;
+        if (mAudioSink->getTimestamp(ts) == OK && ts.mPosition > 0) {
+            mNextAudioClockUpdateTimeUs = 0; // start our clock updates
+        }
+    }
     int64_t nowUs = ALooper::GetNowUs();
-    int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs);
-    mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs);
+    if (mNextAudioClockUpdateTimeUs >= 0) {
+        if (nowUs >= mNextAudioClockUpdateTimeUs) {
+            int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs);
+            mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs);
+            mNextAudioClockUpdateTimeUs = nowUs + kMinimumAudioClockUpdatePeriodUs;
+        }
+    } else {
+        int64_t unused;
+        if ((mMediaClock->getMediaTime(nowUs, &unused) != OK)
+                && (getDurationUsIfPlayedAtSampleRate(mNumFramesWritten)
+                        > kMaxAllowedAudioSinkDelayUs)) {
+            // Enough data has been sent to AudioSink, but AudioSink has not rendered
+            // any data yet. Something is wrong with AudioSink, e.g., the device is not
+            // connected to audio out.
+            // Switch to system clock. This essentially creates a virtual AudioSink with
+            // initial latenty of getDurationUsIfPlayedAtSampleRate(mNumFramesWritten).
+            // This virtual AudioSink renders audio data starting from the very first sample
+            // and it's paced by system clock.
+            ALOGW("AudioSink stuck. ARE YOU CONNECTED TO AUDIO OUT? Switching to system clock.");
+            mMediaClock->updateAnchor(mAudioFirstAnchorTimeMediaUs, nowUs, mediaTimeUs);
+        }
+    }
     mAnchorNumFramesWritten = mNumFramesWritten;
     mAnchorTimeMediaUs = mediaTimeUs;
 }
@@ -1025,6 +1100,7 @@
         return;
     }
 
+    bool needRepostDrainVideoQueue = false;
     int64_t delayUs;
     int64_t nowUs = ALooper::GetNowUs();
     int64_t realTimeUs;
@@ -1045,8 +1121,14 @@
             } else if (!mVideoSampleReceived) {
                 // Always render the first video frame.
                 realTimeUs = nowUs;
-            } else {
+            } else if (mAudioFirstAnchorTimeMediaUs < 0
+                || mMediaClock->getRealTimeFor(mediaTimeUs, &realTimeUs) == OK) {
                 realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
+            } else if (mediaTimeUs - mAudioFirstAnchorTimeMediaUs >= 0) {
+                needRepostDrainVideoQueue = true;
+                realTimeUs = nowUs;
+            } else {
+                realTimeUs = nowUs;
             }
         }
         if (!mHasAudio) {
@@ -1059,15 +1141,25 @@
         // received after this buffer, repost in 10 msec. Otherwise repost
         // in 500 msec.
         delayUs = realTimeUs - nowUs;
+        int64_t postDelayUs = -1;
         if (delayUs > 500000) {
-            int64_t postDelayUs = 500000;
+            postDelayUs = 500000;
             if (mHasAudio && (mLastAudioBufferDrained - entry.mBufferOrdinal) <= 0) {
                 postDelayUs = 10000;
             }
+        } else if (needRepostDrainVideoQueue) {
+            // CHECK(mPlaybackRate > 0);
+            // CHECK(mAudioFirstAnchorTimeMediaUs >= 0);
+            // CHECK(mediaTimeUs - mAudioFirstAnchorTimeMediaUs >= 0);
+            postDelayUs = mediaTimeUs - mAudioFirstAnchorTimeMediaUs;
+            postDelayUs /= mPlaybackRate;
+        }
+
+        if (postDelayUs >= 0) {
             msg->setWhat(kWhatPostDrainVideoQueue);
             msg->post(postDelayUs);
             mVideoScheduler->restart();
-            ALOGI("possible video time jump of %dms, retrying in %dms",
+            ALOGI("possible video time jump of %dms or uninitialized media clock, retrying in %dms",
                     (int)(delayUs / 1000), (int)(postDelayUs / 1000));
             mDrainVideoQueuePending = true;
             return;
@@ -1107,10 +1199,10 @@
 
     int64_t nowUs = ALooper::GetNowUs();
     int64_t realTimeUs;
+    int64_t mediaTimeUs = -1;
     if (mFlags & FLAG_REAL_TIME) {
         CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs));
     } else {
-        int64_t mediaTimeUs;
         CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
 
         realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
@@ -1131,6 +1223,14 @@
             ALOGV("rendering video at media time %.2f secs",
                     (mFlags & FLAG_REAL_TIME ? realTimeUs :
                     mediaUs) / 1E6);
+
+            if (!(mFlags & FLAG_REAL_TIME)
+                    && mLastAudioMediaTimeUs != -1
+                    && mediaTimeUs > mLastAudioMediaTimeUs) {
+                // If audio ends before video, video continues to drive media clock.
+                // Also smooth out videos >= 10fps.
+                mMediaClock->updateMaxTimeMedia(mediaTimeUs + 100000);
+            }
         }
     } else {
         setVideoLateByUs(0);
@@ -1173,6 +1273,13 @@
 }
 
 void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) {
+    if (audio && delayUs > 0) {
+        sp<AMessage> msg = new AMessage(kWhatEOS, this);
+        msg->setInt32("audioEOSGeneration", mAudioEOSGeneration);
+        msg->setInt32("finalResult", finalResult);
+        msg->post(delayUs);
+        return;
+    }
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatEOS);
     notify->setInt32("audio", static_cast<int32_t>(audio));
@@ -1323,6 +1430,7 @@
         if (audio) {
             notifyComplete = mNotifyCompleteAudio;
             mNotifyCompleteAudio = false;
+            mLastAudioMediaTimeUs = -1;
         } else {
             notifyComplete = mNotifyCompleteVideo;
             mNotifyCompleteVideo = false;
@@ -1347,6 +1455,7 @@
             flushQueue(&mAudioQueue);
 
             ++mAudioDrainGeneration;
+            ++mAudioEOSGeneration;
             prepareForMediaRenderingStart_l();
 
             // the frame count will be reset after flush.
@@ -1380,6 +1489,7 @@
             }
             mNumFramesWritten = 0;
         }
+        mNextAudioClockUpdateTimeUs = -1;
     } else {
         flushQueue(&mVideoQueue);
 
@@ -1489,10 +1599,9 @@
     mDrainAudioQueuePending = false;
     mDrainVideoQueuePending = false;
 
-    if (mHasAudio) {
-        mAudioSink->pause();
-        startAudioOffloadPauseTimeout();
-    }
+    // Note: audio data may not have been decoded, and the AudioSink may not be opened.
+    mAudioSink->pause();
+    startAudioOffloadPauseTimeout();
 
     ALOGV("now paused audio queue has %zu entries, video has %zu entries",
           mAudioQueue.size(), mVideoQueue.size());
@@ -1503,8 +1612,9 @@
         return;
     }
 
-    if (mHasAudio) {
-        cancelAudioOffloadPauseTimeout();
+    // Note: audio data may not have been decoded, and the AudioSink may not be opened.
+    cancelAudioOffloadPauseTimeout();
+    if (mAudioSink->ready()) {
         status_t err = mAudioSink->start();
         if (err != OK) {
             ALOGE("cannot start AudioSink err %d", err);
@@ -1558,70 +1668,6 @@
     return mSyncQueues;
 }
 
-// TODO: Remove unnecessary calls to getPlayedOutAudioDurationUs()
-// as it acquires locks and may query the audio driver.
-//
-// Some calls could conceivably retrieve extrapolated data instead of
-// accessing getTimestamp() or getPosition() every time a data buffer with
-// a media time is received.
-//
-// Calculate duration of played samples if played at normal rate (i.e., 1.0).
-int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) {
-    uint32_t numFramesPlayed;
-    int64_t numFramesPlayedAt;
-    AudioTimestamp ts;
-    static const int64_t kStaleTimestamp100ms = 100000;
-
-    status_t res = mAudioSink->getTimestamp(ts);
-    if (res == OK) {                 // case 1: mixing audio tracks and offloaded tracks.
-        numFramesPlayed = ts.mPosition;
-        numFramesPlayedAt =
-            ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
-        const int64_t timestampAge = nowUs - numFramesPlayedAt;
-        if (timestampAge > kStaleTimestamp100ms) {
-            // This is an audio FIXME.
-            // getTimestamp returns a timestamp which may come from audio mixing threads.
-            // After pausing, the MixerThread may go idle, thus the mTime estimate may
-            // become stale. Assuming that the MixerThread runs 20ms, with FastMixer at 5ms,
-            // the max latency should be about 25ms with an average around 12ms (to be verified).
-            // For safety we use 100ms.
-            ALOGV("getTimestamp: returned stale timestamp nowUs(%lld) numFramesPlayedAt(%lld)",
-                    (long long)nowUs, (long long)numFramesPlayedAt);
-            numFramesPlayedAt = nowUs - kStaleTimestamp100ms;
-        }
-        //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAt);
-    } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
-        numFramesPlayed = 0;
-        numFramesPlayedAt = nowUs;
-        //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
-        //        numFramesPlayed, (long long)numFramesPlayedAt);
-    } else {                         // case 3: transitory at new track or audio fast tracks.
-        res = mAudioSink->getPosition(&numFramesPlayed);
-        CHECK_EQ(res, (status_t)OK);
-        numFramesPlayedAt = nowUs;
-        numFramesPlayedAt += 1000LL * mAudioSink->latency() / 2; /* XXX */
-        //ALOGD("getPosition: %u %lld", numFramesPlayed, (long long)numFramesPlayedAt);
-    }
-
-    //CHECK_EQ(numFramesPlayed & (1 << 31), 0);  // can't be negative until 12.4 hrs, test
-    int64_t durationUs = getDurationUsIfPlayedAtSampleRate(numFramesPlayed)
-            + nowUs - numFramesPlayedAt;
-    if (durationUs < 0) {
-        // Occurs when numFramesPlayed position is very small and the following:
-        // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
-        //     numFramesPlayedAt is greater than nowUs by time more than numFramesPlayed.
-        // (2) In case 3, using getPosition and adding mAudioSink->latency() to
-        //     numFramesPlayedAt, by a time amount greater than numFramesPlayed.
-        //
-        // Both of these are transitory conditions.
-        ALOGV("getPlayedOutAudioDurationUs: negative duration %lld set to zero", (long long)durationUs);
-        durationUs = 0;
-    }
-    ALOGV("getPlayedOutAudioDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
-            (long long)durationUs, (long long)nowUs, numFramesPlayed, (long long)numFramesPlayedAt);
-    return durationUs;
-}
-
 void NuPlayer::Renderer::onAudioTearDown(AudioTearDownReason reason) {
     if (mAudioTornDown) {
         return;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 9479c31..1bc9c97 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -148,6 +148,7 @@
     int32_t mVideoQueueGeneration;
     int32_t mAudioDrainGeneration;
     int32_t mVideoDrainGeneration;
+    int32_t mAudioEOSGeneration;
 
     sp<MediaClock> mMediaClock;
     float mPlaybackRate; // audio track rate
@@ -178,7 +179,9 @@
     int32_t mAudioRenderingStartGeneration;
     bool mRenderingDataDelivered;
 
-    int64_t mLastPositionUpdateUs;
+    int64_t mNextAudioClockUpdateTimeUs;
+    // the media timestamp of last audio sample right before EOS.
+    int64_t mLastAudioMediaTimeUs;
 
     int32_t mAudioOffloadPauseTimeoutGeneration;
     bool mAudioTornDown;
@@ -212,7 +215,6 @@
     bool onDrainAudioQueue();
     void drainAudioQueueUntilLastEOS();
     int64_t getPendingAudioPlayoutDurationUs(int64_t nowUs);
-    int64_t getPlayedOutAudioDurationUs(int64_t nowUs);
     void postDrainAudioQueue_l(int64_t delayUs = 0);
 
     void clearAnchorTime_l();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 11a6a9f..fba4540 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -122,6 +122,8 @@
         return true;
     }
 
+    virtual void setOffloadAudio(bool /* offload */) {}
+
 protected:
     virtual ~Source() {}
 
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index af0351e..ec33478 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -76,6 +76,11 @@
 }
 
 void NuPlayer::RTSPSource::prepareAsync() {
+    if (mIsSDP && mHTTPService == NULL) {
+        notifyPrepared(BAD_VALUE);
+        return;
+    }
+
     if (mLooper == NULL) {
         mLooper = new ALooper;
         mLooper->setName("rtsp");
@@ -380,10 +385,8 @@
         case MyHandler::kWhatSeekDone:
         {
             mState = CONNECTED;
-            if (mSeekReplyID != NULL) {
-                // Unblock seekTo here in case we attempted to seek in a live stream
-                finishSeek(OK);
-            }
+            // Unblock seekTo here in case we attempted to seek in a live stream
+            finishSeek(OK);
             break;
         }
 
@@ -404,12 +407,13 @@
 
             status_t err = OK;
             msg->findInt32("err", &err);
-            finishSeek(err);
 
             if (err == OK) {
                 int64_t timeUs;
                 CHECK(msg->findInt64("time", &timeUs));
                 mHandler->continueSeekAfterPause(timeUs);
+            } else {
+                finishSeek(err);
             }
             break;
         }
@@ -744,7 +748,9 @@
 }
 
 void NuPlayer::RTSPSource::finishSeek(status_t err) {
-    CHECK(mSeekReplyID != NULL);
+    if (mSeekReplyID == NULL) {
+        return;
+    }
     sp<AMessage> seekReply = new AMessage;
     seekReply->setInt32("err", err);
     seekReply->postReply(mSeekReplyID);
diff --git a/media/libnbaio/Android.mk b/media/libnbaio/Android.mk
index 1353f28..16c5040 100644
--- a/media/libnbaio/Android.mk
+++ b/media/libnbaio/Android.mk
@@ -28,7 +28,6 @@
 LOCAL_SHARED_LIBRARIES := \
     libaudioutils \
     libbinder \
-    libcommon_time_client \
     libcutils \
     libutils \
     liblog
diff --git a/media/libnbaio/AudioBufferProviderSource.cpp b/media/libnbaio/AudioBufferProviderSource.cpp
index 551f516..cba8b59 100644
--- a/media/libnbaio/AudioBufferProviderSource.cpp
+++ b/media/libnbaio/AudioBufferProviderSource.cpp
@@ -46,16 +46,14 @@
     return mBuffer.raw != NULL ? mBuffer.frameCount - mConsumed : 0;
 }
 
-ssize_t AudioBufferProviderSource::read(void *buffer,
-                                        size_t count,
-                                        int64_t readPTS)
+ssize_t AudioBufferProviderSource::read(void *buffer, size_t count)
 {
     if (CC_UNLIKELY(!mNegotiated)) {
         return NEGOTIATE;
     }
     if (CC_UNLIKELY(mBuffer.raw == NULL)) {
         mBuffer.frameCount = count;
-        status_t status = mProvider->getNextBuffer(&mBuffer, readPTS);
+        status_t status = mProvider->getNextBuffer(&mBuffer);
         if (status != OK) {
             return status == NOT_ENOUGH_DATA ? (ssize_t) WOULD_BLOCK : (ssize_t) status;
         }
@@ -81,8 +79,7 @@
     return count;
 }
 
-ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *user,
-                                           int64_t readPTS, size_t block)
+ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *user, size_t block)
 {
     if (CC_UNLIKELY(!mNegotiated)) {
         return NEGOTIATE;
@@ -102,7 +99,7 @@
         // 1 <= count <= block
         if (CC_UNLIKELY(mBuffer.raw == NULL)) {
             mBuffer.frameCount = count;
-            status_t status = mProvider->getNextBuffer(&mBuffer, readPTS);
+            status_t status = mProvider->getNextBuffer(&mBuffer);
             if (CC_LIKELY(status == OK)) {
                 ALOG_ASSERT(mBuffer.raw != NULL && mBuffer.frameCount <= count);
                 // mConsumed is 0 either from constructor or after releaseBuffer()
@@ -120,8 +117,8 @@
             count = available;
         }
         if (CC_LIKELY(count > 0)) {
-            char* readTgt = (char *) mBuffer.raw + (mConsumed * mFrameSize);
-            ssize_t ret = via(user, readTgt, count, readPTS);
+            ssize_t ret = via(user, (char *) mBuffer.raw + (mConsumed * mFrameSize), count);
+
             if (CC_UNLIKELY(ret <= 0)) {
                 if (CC_LIKELY(accumulator > 0)) {
                     return accumulator;
diff --git a/media/libnbaio/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp
index 6aab48a..286e0eb 100644
--- a/media/libnbaio/AudioStreamInSource.cpp
+++ b/media/libnbaio/AudioStreamInSource.cpp
@@ -64,7 +64,7 @@
     return mFramesOverrun;
 }
 
-ssize_t AudioStreamInSource::read(void *buffer, size_t count, int64_t readPTS __unused)
+ssize_t AudioStreamInSource::read(void *buffer, size_t count)
 {
     if (CC_UNLIKELY(!Format_isValid(mFormat))) {
         return NEGOTIATE;
diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp
index 0d5f935..3f4e0bb 100644
--- a/media/libnbaio/AudioStreamOutSink.cpp
+++ b/media/libnbaio/AudioStreamOutSink.cpp
@@ -66,18 +66,6 @@
     return ret;
 }
 
-status_t AudioStreamOutSink::getNextWriteTimestamp(int64_t *timestamp) {
-    ALOG_ASSERT(timestamp != NULL);
-
-    if (NULL == mStream)
-        return INVALID_OPERATION;
-
-    if (NULL == mStream->get_next_write_timestamp)
-        return INVALID_OPERATION;
-
-    return mStream->get_next_write_timestamp(mStream, timestamp);
-}
-
 status_t AudioStreamOutSink::getTimestamp(AudioTimestamp& timestamp)
 {
     if (mStream->get_presentation_position == NULL) {
diff --git a/media/libnbaio/MonoPipe.cpp b/media/libnbaio/MonoPipe.cpp
index 129e9ef..aef9834 100644
--- a/media/libnbaio/MonoPipe.cpp
+++ b/media/libnbaio/MonoPipe.cpp
@@ -19,10 +19,8 @@
 #define LOG_TAG "MonoPipe"
 //#define LOG_NDEBUG 0
 
-#include <common_time/cc_helper.h>
 #include <cutils/atomic.h>
 #include <cutils/compiler.h>
-#include <utils/LinearTransform.h>
 #include <utils/Log.h>
 #include <utils/Trace.h>
 #include <media/AudioBufferProvider.h>
@@ -32,26 +30,8 @@
 
 namespace android {
 
-static uint64_t cacheN; // output of CCHelper::getLocalFreq()
-static bool cacheValid; // whether cacheN is valid
-static pthread_once_t cacheOnceControl = PTHREAD_ONCE_INIT;
-
-static void cacheOnceInit()
-{
-    CCHelper tmpHelper;
-    status_t res;
-    if (OK != (res = tmpHelper.getLocalFreq(&cacheN))) {
-        ALOGE("Failed to fetch local time frequency when constructing a"
-              " MonoPipe (res = %d).  getNextWriteTimestamp calls will be"
-              " non-functional", res);
-        return;
-    }
-    cacheValid = true;
-}
-
 MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock) :
         NBAIO_Sink(format),
-        mUpdateSeq(0),
         mReqFrames(reqFrames),
         mMaxFrames(roundup(reqFrames)),
         mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
@@ -66,36 +46,6 @@
         mTimestampMutator(&mTimestampShared),
         mTimestampObserver(&mTimestampShared)
 {
-    uint64_t N, D;
-
-    mNextRdPTS = AudioBufferProvider::kInvalidPTS;
-
-    mSamplesToLocalTime.a_zero = 0;
-    mSamplesToLocalTime.b_zero = 0;
-    mSamplesToLocalTime.a_to_b_numer = 0;
-    mSamplesToLocalTime.a_to_b_denom = 0;
-
-    D = Format_sampleRate(format);
-
-    (void) pthread_once(&cacheOnceControl, cacheOnceInit);
-    if (!cacheValid) {
-        // log has already been done
-        return;
-    }
-    N = cacheN;
-
-    LinearTransform::reduce(&N, &D);
-    static const uint64_t kSignedHiBitsMask   = ~(0x7FFFFFFFull);
-    static const uint64_t kUnsignedHiBitsMask = ~(0xFFFFFFFFull);
-    if ((N & kSignedHiBitsMask) || (D & kUnsignedHiBitsMask)) {
-        ALOGE("Cannot reduce sample rate to local clock frequency ratio to fit"
-              " in a 32/32 bit rational.  (max reduction is 0x%016" PRIx64 "/0x%016" PRIx64
-              ").  getNextWriteTimestamp calls will be non-functional", N, D);
-        return;
-    }
-
-    mSamplesToLocalTime.a_to_b_numer = static_cast<int32_t>(N);
-    mSamplesToLocalTime.a_to_b_denom = static_cast<uint32_t>(D);
 }
 
 MonoPipe::~MonoPipe()
@@ -223,104 +173,6 @@
     mSetpoint = setpoint;
 }
 
-status_t MonoPipe::getNextWriteTimestamp(int64_t *timestamp)
-{
-    int32_t front;
-
-    ALOG_ASSERT(NULL != timestamp);
-
-    if (0 == mSamplesToLocalTime.a_to_b_denom)
-        return UNKNOWN_ERROR;
-
-    observeFrontAndNRPTS(&front, timestamp);
-
-    if (AudioBufferProvider::kInvalidPTS != *timestamp) {
-        // If we have a valid read-pointer and next read timestamp pair, then
-        // use the current value of the write pointer to figure out how many
-        // frames are in the buffer, and offset the timestamp by that amt.  Then
-        // next time we write to the MonoPipe, the data will hit the speakers at
-        // the next read timestamp plus the current amount of data in the
-        // MonoPipe.
-        size_t pendingFrames = (mRear - front) & (mMaxFrames - 1);
-        *timestamp = offsetTimestampByAudioFrames(*timestamp, pendingFrames);
-    }
-
-    return OK;
-}
-
-void MonoPipe::updateFrontAndNRPTS(int32_t newFront, int64_t newNextRdPTS)
-{
-    // Set the MSB of the update sequence number to indicate that there is a
-    // multi-variable update in progress.  Use an atomic store with an "acquire"
-    // barrier to make sure that the next operations cannot be re-ordered and
-    // take place before the change to mUpdateSeq is commited..
-    int32_t tmp = mUpdateSeq | 0x80000000;
-    android_atomic_acquire_store(tmp, &mUpdateSeq);
-
-    // Update mFront and mNextRdPTS
-    mFront = newFront;
-    mNextRdPTS = newNextRdPTS;
-
-    // We are finished with the update.  Compute the next sequnce number (which
-    // should be the old sequence number, plus one, and with the MSB cleared)
-    // and then store it in mUpdateSeq using an atomic store with a "release"
-    // barrier so our update operations cannot be re-ordered past the update of
-    // the sequence number.
-    tmp = (tmp + 1) & 0x7FFFFFFF;
-    android_atomic_release_store(tmp, &mUpdateSeq);
-}
-
-void MonoPipe::observeFrontAndNRPTS(int32_t *outFront, int64_t *outNextRdPTS)
-{
-    // Perform an atomic observation of mFront and mNextRdPTS.  Basically,
-    // atomically observe the sequence number, then observer the variables, then
-    // atomically observe the sequence number again.  If the two observations of
-    // the sequence number match, and the update-in-progress bit was not set,
-    // then we know we have a successful atomic observation.  Otherwise, we loop
-    // around and try again.
-    //
-    // Note, it is very important that the observer be a lower priority thread
-    // than the updater.  If the updater is lower than the observer, or they are
-    // the same priority and running with SCHED_FIFO (implying that quantum
-    // based premption is disabled) then we run the risk of deadlock.
-    int32_t seqOne, seqTwo;
-
-    do {
-        seqOne        = android_atomic_acquire_load(&mUpdateSeq);
-        *outFront     = mFront;
-        *outNextRdPTS = mNextRdPTS;
-        seqTwo        = android_atomic_release_load(&mUpdateSeq);
-    } while ((seqOne != seqTwo) || (seqOne & 0x80000000));
-}
-
-int64_t MonoPipe::offsetTimestampByAudioFrames(int64_t ts, size_t audFrames)
-{
-    if (0 == mSamplesToLocalTime.a_to_b_denom)
-        return AudioBufferProvider::kInvalidPTS;
-
-    if (ts == AudioBufferProvider::kInvalidPTS)
-        return AudioBufferProvider::kInvalidPTS;
-
-    int64_t frame_lt_duration;
-    if (!mSamplesToLocalTime.doForwardTransform(audFrames,
-                                                &frame_lt_duration)) {
-        // This should never fail, but if there is a bug which is causing it
-        // to fail, this message would probably end up flooding the logs
-        // because the conversion would probably fail forever.  Log the
-        // error, but then zero out the ratio in the linear transform so
-        // that we don't try to do any conversions from now on.  This
-        // MonoPipe's getNextWriteTimestamp is now broken for good.
-        ALOGE("Overflow when attempting to convert %zu audio frames to"
-              " duration in local time.  getNextWriteTimestamp will fail from"
-              " now on.", audFrames);
-        mSamplesToLocalTime.a_to_b_numer = 0;
-        mSamplesToLocalTime.a_to_b_denom = 0;
-        return AudioBufferProvider::kInvalidPTS;
-    }
-
-    return ts + frame_lt_duration;
-}
-
 void MonoPipe::shutdown(bool newState)
 {
     mIsShutdown = newState;
diff --git a/media/libnbaio/MonoPipeReader.cpp b/media/libnbaio/MonoPipeReader.cpp
index e4d3ed8..7e09544 100644
--- a/media/libnbaio/MonoPipeReader.cpp
+++ b/media/libnbaio/MonoPipeReader.cpp
@@ -43,25 +43,11 @@
     return ret;
 }
 
-ssize_t MonoPipeReader::read(void *buffer, size_t count, int64_t readPTS)
+ssize_t MonoPipeReader::read(void *buffer, size_t count)
 {
-    // Compute the "next read PTS" and cache it.  Callers of read pass a read
-    // PTS indicating the local time for which they are requesting data along
-    // with a count (which is the number of audio frames they are going to
-    // ultimately pass to the next stage of the pipeline).  Offsetting readPTS
-    // by the duration of count will give us the readPTS which will be passed to
-    // us next time, assuming they system continues to operate in steady state
-    // with no discontinuities.  We stash this value so it can be used by the
-    // MonoPipe writer to imlement getNextWriteTimestamp.
-    int64_t nextReadPTS;
-    nextReadPTS = mPipe->offsetTimestampByAudioFrames(readPTS, count);
-
     // count == 0 is unlikely and not worth checking for explicitly; will be handled automatically
     ssize_t red = availableToRead();
     if (CC_UNLIKELY(red <= 0)) {
-        // Uh-oh, looks like we are underflowing.  Update the next read PTS and
-        // get out.
-        mPipe->updateFrontAndNRPTS(mPipe->mFront, nextReadPTS);
         return red;
     }
     if (CC_LIKELY((size_t) red > count)) {
@@ -80,7 +66,7 @@
                 memcpy((char *) buffer + (part1 * mFrameSize), mPipe->mBuffer, part2 * mFrameSize);
             }
         }
-        mPipe->updateFrontAndNRPTS(red + mPipe->mFront, nextReadPTS);
+        android_atomic_release_store(red + mPipe->mFront, &mPipe->mFront);
         mFramesRead += red;
     }
     return red;
diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp
index d641e74..1cb4410 100644
--- a/media/libnbaio/NBAIO.cpp
+++ b/media/libnbaio/NBAIO.cpp
@@ -97,8 +97,7 @@
 }
 
 // This is a default implementation; it is expected that subclasses will optimize this.
-ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user,
-                              int64_t readPTS, size_t block)
+ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, size_t block)
 {
     if (!mNegotiated) {
         return (ssize_t) NEGOTIATE;
@@ -117,11 +116,11 @@
         if (count > block) {
             count = block;
         }
-        ssize_t ret = read(buffer, count, readPTS);
+        ssize_t ret = read(buffer, count);
         if (ret > 0) {
             ALOG_ASSERT((size_t) ret <= count);
             size_t maxRet = ret;
-            ret = via(user, buffer, maxRet, readPTS);
+            ret = via(user, buffer, maxRet);
             if (ret > 0) {
                 ALOG_ASSERT((size_t) ret <= maxRet);
                 accumulator += ret;
diff --git a/media/libnbaio/PipeReader.cpp b/media/libnbaio/PipeReader.cpp
index c8e4953..b096903 100644
--- a/media/libnbaio/PipeReader.cpp
+++ b/media/libnbaio/PipeReader.cpp
@@ -59,7 +59,7 @@
     return avail;
 }
 
-ssize_t PipeReader::read(void *buffer, size_t count, int64_t readPTS __unused)
+ssize_t PipeReader::read(void *buffer, size_t count)
 {
     ssize_t avail = availableToRead();
     if (CC_UNLIKELY(avail <= 0)) {
diff --git a/media/libnbaio/SourceAudioBufferProvider.cpp b/media/libnbaio/SourceAudioBufferProvider.cpp
index e21ef48..dc01c0e 100644
--- a/media/libnbaio/SourceAudioBufferProvider.cpp
+++ b/media/libnbaio/SourceAudioBufferProvider.cpp
@@ -45,7 +45,7 @@
     free(mAllocated);
 }
 
-status_t SourceAudioBufferProvider::getNextBuffer(Buffer *buffer, int64_t pts)
+status_t SourceAudioBufferProvider::getNextBuffer(Buffer *buffer)
 {
     ALOG_ASSERT(buffer != NULL && buffer->frameCount > 0 && mGetCount == 0);
     // any leftover data available?
@@ -61,20 +61,30 @@
     // do we need to reallocate?
     if (buffer->frameCount > mSize) {
         free(mAllocated);
-        mAllocated = malloc(buffer->frameCount * mFrameSize);
+        // Android convention is to _not_ check the return value of malloc and friends.
+        // But in this case the calloc() can also fail due to integer overflow,
+        // so we check and recover.
+        mAllocated = calloc(buffer->frameCount, mFrameSize);
+        if (mAllocated == NULL) {
+            mSize = 0;
+            goto fail;
+        }
         mSize = buffer->frameCount;
     }
-    // read from source
-    ssize_t actual = mSource->read(mAllocated, buffer->frameCount, pts);
-    if (actual > 0) {
-        ALOG_ASSERT((size_t) actual <= buffer->frameCount);
-        mOffset = 0;
-        mRemaining = actual;
-        buffer->raw = mAllocated;
-        buffer->frameCount = actual;
-        mGetCount = actual;
-        return OK;
+    {
+        // read from source
+        ssize_t actual = mSource->read(mAllocated, buffer->frameCount);
+        if (actual > 0) {
+            ALOG_ASSERT((size_t) actual <= buffer->frameCount);
+            mOffset = 0;
+            mRemaining = actual;
+            buffer->raw = mAllocated;
+            buffer->frameCount = actual;
+            mGetCount = actual;
+            return OK;
+        }
     }
+fail:
     buffer->raw = NULL;
     buffer->frameCount = 0;
     mGetCount = 0;
diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
index 45e8a30..19efc53 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/libstagefright/AACExtractor.cpp
@@ -211,7 +211,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-sp<MediaSource> AACExtractor::getTrack(size_t index) {
+sp<IMediaSource> AACExtractor::getTrack(size_t index) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 9d90dbd..8b1e1c3 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -67,7 +67,7 @@
 }
 
 
-status_t AACWriter::addSource(const sp<MediaSource> &source) {
+status_t AACWriter::addSource(const sp<IMediaSource> &source) {
     if (mInitCheck != OK) {
         return mInitCheck;
     }
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 10734e4..5f13ebc 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -811,6 +811,10 @@
                     def.nBufferCountActual, bufSize, allottedSize, def.nBufferSize, asString(type),
                     portIndex == kPortIndexInput ? "input" : "output");
 
+            if (bufSize == 0 || def.nBufferCountActual > SIZE_MAX / bufSize) {
+                ALOGE("b/22885421");
+                return NO_MEMORY;
+            }
             size_t totalSize = def.nBufferCountActual * bufSize;
             mDealer[portIndex] = new MemoryDealer(totalSize, "ACodec");
 
@@ -830,8 +834,7 @@
                         ? kRequiresAllocateBufferOnInputPorts
                         : kRequiresAllocateBufferOnOutputPorts;
 
-                if ((portIndex == kPortIndexInput && (mFlags & kFlagIsSecure))
-                        || (portIndex == kPortIndexOutput && usingMetadataOnEncoderOutput())) {
+                if (portIndex == kPortIndexInput && (mFlags & kFlagIsSecure)) {
                     mem.clear();
 
                     void *ptr;
@@ -852,6 +855,7 @@
                     if (type == kMetadataBufferTypeANWBuffer) {
                         ((VideoNativeMetadata *)mem->pointer())->nFenceFd = -1;
                     }
+                    info.mMemRef = mem;
                 }
 
                 mBuffers[portIndex].push(info);
@@ -872,8 +876,7 @@
 
     for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
         const BufferInfo &info = mBuffers[portIndex][i];
-
-        desc->addBuffer(info.mBufferID, info.mData);
+        desc->addBuffer(info.mBufferID, info.mData, info.mMemRef);
     }
 
     notify->setObject("portDesc", desc);
@@ -1133,7 +1136,7 @@
         // we use useBuffer for metadata regardless of quirks
         err = mOMX->useBuffer(
                 mNode, kPortIndexOutput, mem, &info.mBufferID, mem->size());
-
+        info.mMemRef = mem;
         mBuffers[kPortIndexOutput].push(info);
 
         ALOGV("[%s] allocated meta buffer with ID %u (pointer = %p)",
@@ -1584,6 +1587,8 @@
             "video_decoder.vp9", "video_encoder.vp9" },
         { MEDIA_MIMETYPE_AUDIO_RAW,
             "audio_decoder.raw", "audio_encoder.raw" },
+        { MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
+            "video_decoder.dolby-vision", "video_encoder.dolby-vision" },
         { MEDIA_MIMETYPE_AUDIO_FLAC,
             "audio_decoder.flac", "audio_encoder.flac" },
         { MEDIA_MIMETYPE_AUDIO_MSGSM,
@@ -2236,6 +2241,102 @@
     return OK;
 }
 
+status_t ACodec::getIntraRefreshPeriod(uint32_t *intraRefreshPeriod) {
+    OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE params;
+    InitOMXParams(&params);
+    params.nPortIndex = kPortIndexOutput;
+    status_t err = mOMX->getConfig(
+            mNode, (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh, &params, sizeof(params));
+    if (err == OK) {
+        *intraRefreshPeriod = params.nRefreshPeriod;
+        return OK;
+    }
+
+    // Fallback to query through standard OMX index.
+    OMX_VIDEO_PARAM_INTRAREFRESHTYPE refreshParams;
+    InitOMXParams(&refreshParams);
+    refreshParams.nPortIndex = kPortIndexOutput;
+    refreshParams.eRefreshMode = OMX_VIDEO_IntraRefreshCyclic;
+    err = mOMX->getParameter(
+            mNode, OMX_IndexParamVideoIntraRefresh, &refreshParams, sizeof(refreshParams));
+    if (err != OK || refreshParams.nCirMBs == 0) {
+        *intraRefreshPeriod = 0;
+        return OK;
+    }
+
+    // Calculate period based on width and height
+    uint32_t width, height;
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+    OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+    def.nPortIndex = kPortIndexOutput;
+    err = mOMX->getParameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    if (err != OK) {
+        *intraRefreshPeriod = 0;
+        return err;
+    }
+    width = video_def->nFrameWidth;
+    height = video_def->nFrameHeight;
+    // Use H.264/AVC MacroBlock size 16x16
+    *intraRefreshPeriod = divUp((divUp(width, 16u) * divUp(height, 16u)), refreshParams.nCirMBs);
+
+    return OK;
+}
+
+status_t ACodec::setIntraRefreshPeriod(uint32_t intraRefreshPeriod, bool inConfigure) {
+    OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE params;
+    InitOMXParams(&params);
+    params.nPortIndex = kPortIndexOutput;
+    params.nRefreshPeriod = intraRefreshPeriod;
+    status_t err = mOMX->setConfig(
+            mNode, (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh, &params, sizeof(params));
+    if (err == OK) {
+        return OK;
+    }
+
+    // Only in configure state, a component could invoke setParameter.
+    if (!inConfigure) {
+        return INVALID_OPERATION;
+    } else {
+        ALOGI("[%s] try falling back to Cyclic", mComponentName.c_str());
+    }
+
+    OMX_VIDEO_PARAM_INTRAREFRESHTYPE refreshParams;
+    InitOMXParams(&refreshParams);
+    refreshParams.nPortIndex = kPortIndexOutput;
+    refreshParams.eRefreshMode = OMX_VIDEO_IntraRefreshCyclic;
+
+    if (intraRefreshPeriod == 0) {
+        // 0 means disable intra refresh.
+        refreshParams.nCirMBs = 0;
+    } else {
+        // Calculate macroblocks that need to be intra coded base on width and height
+        uint32_t width, height;
+        OMX_PARAM_PORTDEFINITIONTYPE def;
+        InitOMXParams(&def);
+        OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+        def.nPortIndex = kPortIndexOutput;
+        err = mOMX->getParameter(
+                mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+        if (err != OK) {
+            return err;
+        }
+        width = video_def->nFrameWidth;
+        height = video_def->nFrameHeight;
+        // Use H.264/AVC MacroBlock size 16x16
+        refreshParams.nCirMBs = divUp((divUp(width, 16u) * divUp(height, 16u)), intraRefreshPeriod);
+    }
+
+    err = mOMX->setParameter(mNode, OMX_IndexParamVideoIntraRefresh,
+                             &refreshParams, sizeof(refreshParams));
+    if (err != OK) {
+        return err;
+    }
+
+    return OK;
+}
+
 status_t ACodec::setMinBufferSize(OMX_U32 portIndex, size_t size) {
     OMX_PARAM_PORTDEFINITIONTYPE def;
     InitOMXParams(&def);
@@ -2861,6 +2962,7 @@
     { MEDIA_MIMETYPE_VIDEO_MPEG2, OMX_VIDEO_CodingMPEG2 },
     { MEDIA_MIMETYPE_VIDEO_VP8, OMX_VIDEO_CodingVP8 },
     { MEDIA_MIMETYPE_VIDEO_VP9, OMX_VIDEO_CodingVP9 },
+    { MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, OMX_VIDEO_CodingDolbyVision },
 };
 
 static status_t GetVideoCodingTypeFromMime(
@@ -3096,6 +3198,17 @@
         return err;
     }
 
+    int32_t intraRefreshPeriod = 0;
+    if (msg->findInt32("intra-refresh-period", &intraRefreshPeriod)
+            && intraRefreshPeriod >= 0) {
+        err = setIntraRefreshPeriod((uint32_t)intraRefreshPeriod, true);
+        if (err != OK) {
+            ALOGI("[%s] failed setIntraRefreshPeriod. Failure is fine since this key is optional",
+                    mComponentName.c_str());
+            err = OK;
+        }
+    }
+
     switch (compressionFormat) {
         case OMX_VIDEO_CodingMPEG4:
             err = setupMPEG4EncoderParameters(msg);
@@ -3546,8 +3659,8 @@
         hevcType.eProfile = static_cast<OMX_VIDEO_HEVCPROFILETYPE>(profile);
         hevcType.eLevel = static_cast<OMX_VIDEO_HEVCLEVELTYPE>(level);
     }
-
-    // TODO: Need OMX structure definition for setting iFrameInterval
+    // TODO: finer control?
+    hevcType.nKeyFrameInterval = setPFramesSpacing(iFrameInterval, frameRate);
 
     err = mOMX->setParameter(
             mNode, (OMX_INDEXTYPE)OMX_IndexParamVideoHevc, &hevcType, sizeof(hevcType));
@@ -3880,8 +3993,11 @@
         params.nSliceHeight = params.nFrameHeight;
     }
 
-    // we need stride and slice-height to be non-zero
-    if (params.nStride == 0 || params.nSliceHeight == 0) {
+    // we need stride and slice-height to be non-zero and sensible. These values were chosen to
+    // prevent integer overflows further down the line, and do not indicate support for
+    // 32kx32k video.
+    if (params.nStride == 0 || params.nSliceHeight == 0
+            || params.nStride > 32768 || params.nSliceHeight > 32768) {
         ALOGW("cannot describe color format 0x%x = %d with stride=%u and sliceHeight=%u",
                 fmt, fmt, params.nStride, params.nSliceHeight);
         return false;
@@ -4178,6 +4294,11 @@
                     } else {
                         notify->setString("mime", mime.c_str());
                     }
+                    uint32_t intraRefreshPeriod = 0;
+                    if (mIsEncoder && getIntraRefreshPeriod(&intraRefreshPeriod) == OK
+                            && intraRefreshPeriod > 0) {
+                        notify->setInt32("intra-refresh-period", intraRefreshPeriod);
+                    }
                     break;
                 }
             }
@@ -4525,9 +4646,10 @@
 }
 
 void ACodec::PortDescription::addBuffer(
-        IOMX::buffer_id id, const sp<ABuffer> &buffer) {
+        IOMX::buffer_id id, const sp<ABuffer> &buffer, const sp<RefBase> &memRef) {
     mBufferIDs.push_back(id);
     mBuffers.push_back(buffer);
+    mMemRefs.push_back(memRef);
 }
 
 size_t ACodec::PortDescription::countBuffers() {
@@ -4542,6 +4664,10 @@
     return mBuffers.itemAt(index);
 }
 
+sp<RefBase> ACodec::PortDescription::memRefAt(size_t index) const {
+    return mMemRefs.itemAt(index);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 ACodec::BaseState::BaseState(ACodec *codec, const sp<AState> &parentState)
@@ -5914,6 +6040,15 @@
 
         mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
 
+        mCodec->mOMX->sendCommand(
+                mCodec->mNode, OMX_CommandStateSet, OMX_StateLoaded);
+        if (mCodec->allYourBuffersAreBelongToUs(kPortIndexInput)) {
+            mCodec->freeBuffersOnPort(kPortIndexInput);
+        }
+        if (mCodec->allYourBuffersAreBelongToUs(kPortIndexOutput)) {
+            mCodec->freeBuffersOnPort(kPortIndexOutput);
+        }
+
         mCodec->changeState(mCodec->mLoadedState);
     }
 }
@@ -6367,6 +6502,17 @@
         }
     }
 
+    int32_t intraRefreshPeriod = 0;
+    if (params->findInt32("intra-refresh-period", &intraRefreshPeriod)
+            && intraRefreshPeriod > 0) {
+        status_t err = setIntraRefreshPeriod(intraRefreshPeriod, false);
+        if (err != OK) {
+            ALOGI("[%s] failed setIntraRefreshPeriod. Failure is fine since this key is optional",
+                    mComponentName.c_str());
+            err = OK;
+        }
+    }
+
     return OK;
 }
 
@@ -6403,7 +6549,8 @@
                 mCodec->freeOutputBuffersNotOwnedByComponent();
 
                 mCodec->changeState(mCodec->mOutputPortSettingsChangedState);
-            } else if (data2 == OMX_IndexConfigCommonOutputCrop) {
+            } else if (data2 == OMX_IndexConfigCommonOutputCrop
+                    || data2 == OMX_IndexConfigAndroidIntraRefresh) {
                 mCodec->mSentFormat = false;
 
                 if (mCodec->mTunneled) {
@@ -6984,6 +7131,34 @@
                         asString(portFormat.eColorFormat), portFormat.eColorFormat);
             }
         }
+    } else if (mime.equalsIgnoreCase(MEDIA_MIMETYPE_AUDIO_AAC)) {
+        // More audio codecs if they have profiles.
+        OMX_AUDIO_PARAM_ANDROID_PROFILETYPE param;
+        InitOMXParams(&param);
+        param.nPortIndex = isEncoder ? kPortIndexOutput : kPortIndexInput;
+        for (OMX_U32 index = 0; index <= kMaxIndicesToCheck; ++index) {
+            param.nProfileIndex = index;
+            status_t err = omx->getParameter(
+                    node, (OMX_INDEXTYPE)OMX_IndexParamAudioProfileQuerySupported,
+                    &param, sizeof(param));
+            if (err != OK) {
+                break;
+            }
+            // For audio, level is ignored.
+            builder->addProfileLevel(param.eProfile, 0 /* level */);
+
+            if (index == kMaxIndicesToCheck) {
+                ALOGW("[%s] stopping checking profiles after %u: %x",
+                        name.c_str(), index,
+                        param.eProfile);
+            }
+        }
+
+        // NOTE: Without Android extensions, OMX does not provide a way to query
+        // AAC profile support
+        if (param.nProfileIndex == 0) {
+            ALOGW("component %s doesn't support profile query.", name.c_str());
+        }
     }
 
     if (isVideo && !isEncoder) {
@@ -7002,6 +7177,18 @@
         }
     }
 
+    if (isVideo && isEncoder) {
+        OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE params;
+        InitOMXParams(&params);
+        params.nPortIndex = kPortIndexOutput;
+        // TODO: should we verify if fallback is supported?
+        if (omx->getConfig(
+                node, (OMX_INDEXTYPE)OMX_IndexConfigAndroidIntraRefresh,
+                &params, sizeof(params)) == OK) {
+            builder->addFlags(MediaCodecInfo::Capabilities::kFlagSupportsIntraRefresh);
+        }
+    }
+
     *caps = builder;
     omx->freeNode(node);
     client.disconnect();
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index a6fb3d8..1458802 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -180,7 +180,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-sp<MediaSource> AMRExtractor::getTrack(size_t index) {
+sp<IMediaSource> AMRExtractor::getTrack(size_t index) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -309,7 +309,13 @@
         buffer->release();
         buffer = NULL;
 
-        return ERROR_IO;
+        if (n < 0) {
+            return ERROR_IO;
+        } else {
+            // only partial frame is available, treat it as EOS.
+            mOffset += n;
+            return ERROR_END_OF_STREAM;
+        }
     }
 
     buffer->set_range(0, frameSize);
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index f53d7f0..961b57f 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -54,7 +54,7 @@
     return mInitCheck;
 }
 
-status_t AMRWriter::addSource(const sp<MediaSource> &source) {
+status_t AMRWriter::addSource(const sp<IMediaSource> &source) {
     if (mInitCheck != OK) {
         return mInitCheck;
     }
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index e361749..fd4ed58 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -22,13 +22,13 @@
         FLACExtractor.cpp                 \
         FrameRenderTracker.cpp            \
         HTTPBase.cpp                      \
+        HevcUtils.cpp                     \
         JPEGSource.cpp                    \
         MP3Extractor.cpp                  \
         MPEG2TSWriter.cpp                 \
         MPEG4Extractor.cpp                \
         MPEG4Writer.cpp                   \
         MediaAdapter.cpp                  \
-        MediaBuffer.cpp                   \
         MediaBufferGroup.cpp              \
         MediaClock.cpp                    \
         MediaCodec.cpp                    \
@@ -42,7 +42,6 @@
         http/MediaHTTP.cpp                \
         MediaMuxer.cpp                    \
         MediaSource.cpp                   \
-        MetaData.cpp                      \
         NuCachedSource2.cpp               \
         NuMediaExtractor.cpp              \
         OMXClient.cpp                     \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 68cac74..cb42847 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -66,7 +66,7 @@
     }
 }
 
-void AudioPlayer::setSource(const sp<MediaSource> &source) {
+void AudioPlayer::setSource(const sp<IMediaSource> &source) {
     CHECK(mSource == NULL);
     mSource = source;
 }
@@ -350,7 +350,7 @@
     // When offloading, the OMX component is not used so this hack
     // is not needed
     if (!useOffload()) {
-        wp<MediaSource> tmp = mSource;
+        wp<IMediaSource> tmp = mSource;
         mSource.clear();
         while (tmp.promote() != NULL) {
             usleep(1000);
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index e17fdf8..e6303ba 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -64,7 +64,7 @@
             mIDataSource->readAt(offset + totalNumRead, numToRead);
         // A negative return value represents an error. Pass it on.
         if (numRead < 0) {
-            return numRead;
+            return numRead == ERROR_END_OF_STREAM && totalNumRead > 0 ? totalNumRead : numRead;
         }
         // A zero return value signals EOS. Return the bytes read so far.
         if (numRead == 0) {
@@ -95,6 +95,10 @@
     return OK;
 }
 
+uint32_t CallbackDataSource::flags() {
+    return mIDataSource->getFlags();
+}
+
 TinyCacheSource::TinyCacheSource(const sp<DataSource>& source)
     : mSource(source), mCachedOffset(0), mCachedSize(0) {
 }
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 66280da..d302f82 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -22,6 +22,9 @@
 
 #include <OMX_Component.h>
 #include <binder/IPCThreadState.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
+#include <media/hardware/HardwareAPI.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/CameraSource.h>
 #include <media/stagefright/MediaDefs.h>
@@ -139,8 +142,8 @@
     size.height = -1;
 
     sp<ICamera> camera;
-    return new CameraSource(camera, NULL, 0, clientName, -1,
-            size, -1, NULL, false);
+    return new CameraSource(camera, NULL, 0, clientName, Camera::USE_CALLING_UID,
+            Camera::USE_CALLING_PID, size, -1, NULL, false);
 }
 
 // static
@@ -150,13 +153,14 @@
     int32_t cameraId,
     const String16& clientName,
     uid_t clientUid,
+    pid_t clientPid,
     Size videoSize,
     int32_t frameRate,
     const sp<IGraphicBufferProducer>& surface,
     bool storeMetaDataInVideoBuffers) {
 
     CameraSource *source = new CameraSource(camera, proxy, cameraId,
-            clientName, clientUid, videoSize, frameRate, surface,
+            clientName, clientUid, clientPid, videoSize, frameRate, surface,
             storeMetaDataInVideoBuffers);
     return source;
 }
@@ -167,6 +171,7 @@
     int32_t cameraId,
     const String16& clientName,
     uid_t clientUid,
+    pid_t clientPid,
     Size videoSize,
     int32_t frameRate,
     const sp<IGraphicBufferProducer>& surface,
@@ -190,7 +195,7 @@
     mVideoSize.height = -1;
 
     mInitCheck = init(camera, proxy, cameraId,
-                    clientName, clientUid,
+                    clientName, clientUid, clientPid,
                     videoSize, frameRate,
                     storeMetaDataInVideoBuffers);
     if (mInitCheck != OK) releaseCamera();
@@ -202,10 +207,10 @@
 
 status_t CameraSource::isCameraAvailable(
     const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
-    int32_t cameraId, const String16& clientName, uid_t clientUid) {
+    int32_t cameraId, const String16& clientName, uid_t clientUid, pid_t clientPid) {
 
     if (camera == 0) {
-        mCamera = Camera::connect(cameraId, clientName, clientUid);
+        mCamera = Camera::connect(cameraId, clientName, clientUid, clientPid);
         if (mCamera == 0) return -EBUSY;
         mCameraFlags &= ~FLAGS_HOT_CAMERA;
     } else {
@@ -489,6 +494,7 @@
         int32_t cameraId,
         const String16& clientName,
         uid_t clientUid,
+        pid_t clientPid,
         Size videoSize,
         int32_t frameRate,
         bool storeMetaDataInVideoBuffers) {
@@ -496,19 +502,91 @@
     ALOGV("init");
     status_t err = OK;
     int64_t token = IPCThreadState::self()->clearCallingIdentity();
-    err = initWithCameraAccess(camera, proxy, cameraId, clientName, clientUid,
+    err = initWithCameraAccess(camera, proxy, cameraId, clientName, clientUid, clientPid,
                                videoSize, frameRate,
                                storeMetaDataInVideoBuffers);
     IPCThreadState::self()->restoreCallingIdentity(token);
     return err;
 }
 
+status_t CameraSource::initBufferQueue(uint32_t width, uint32_t height,
+        uint32_t format, android_dataspace dataSpace, uint32_t bufferCount) {
+    ALOGV("initBufferQueue");
+
+    if (mVideoBufferConsumer != nullptr || mVideoBufferProducer != nullptr) {
+        ALOGE("%s: Buffer queue already exists", __FUNCTION__);
+        return ALREADY_EXISTS;
+    }
+
+    // Create a buffer queue.
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+
+    uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN;
+    if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+        usage = GRALLOC_USAGE_HW_VIDEO_ENCODER;
+    }
+
+    bufferCount += kConsumerBufferCount;
+
+    mVideoBufferConsumer = new BufferItemConsumer(consumer, usage, bufferCount);
+    mVideoBufferConsumer->setName(String8::format("StageFright-CameraSource"));
+    mVideoBufferProducer = producer;
+
+    status_t res = mVideoBufferConsumer->setDefaultBufferSize(width, height);
+    if (res != OK) {
+        ALOGE("%s: Could not set buffer dimensions %dx%d: %s (%d)", __FUNCTION__, width, height,
+                strerror(-res), res);
+        return res;
+    }
+
+    res = mVideoBufferConsumer->setDefaultBufferFormat(format);
+    if (res != OK) {
+        ALOGE("%s: Could not set buffer format %d: %s (%d)", __FUNCTION__, format,
+                strerror(-res), res);
+        return res;
+    }
+
+    res = mVideoBufferConsumer->setDefaultBufferDataSpace(dataSpace);
+    if (res != OK) {
+        ALOGE("%s: Could not set data space %d: %s (%d)", __FUNCTION__, dataSpace,
+                strerror(-res), res);
+        return res;
+    }
+
+    res = mCamera->setVideoTarget(mVideoBufferProducer);
+    if (res != OK) {
+        ALOGE("%s: Failed to set video target: %s (%d)", __FUNCTION__, strerror(-res), res);
+        return res;
+    }
+
+    // Create memory heap to store buffers as VideoNativeMetadata.
+    size_t bufferSize = sizeof(VideoNativeMetadata);
+    mMemoryHeapBase = new MemoryHeapBase(bufferSize * bufferCount, 0,
+            "StageFright-CameraSource-BufferHeap");
+    for (uint32_t i = 0; i < bufferCount; i++) {
+        mMemoryBases.push_back(new MemoryBase(mMemoryHeapBase, i * bufferSize, bufferSize));
+    }
+
+    mBufferQueueListener = new BufferQueueListener(mVideoBufferConsumer, this);
+    res = mBufferQueueListener->run("CameraSource-BufferQueueListener");
+    if (res != OK) {
+        ALOGE("%s: Could not run buffer queue listener thread: %s (%d)", __FUNCTION__,
+                strerror(-res), res);
+        return res;
+    }
+
+    return OK;
+}
+
 status_t CameraSource::initWithCameraAccess(
         const sp<ICamera>& camera,
         const sp<ICameraRecordingProxy>& proxy,
         int32_t cameraId,
         const String16& clientName,
         uid_t clientUid,
+        pid_t clientPid,
         Size videoSize,
         int32_t frameRate,
         bool storeMetaDataInVideoBuffers) {
@@ -516,7 +594,7 @@
     status_t err = OK;
 
     if ((err = isCameraAvailable(camera, proxy, cameraId,
-            clientName, clientUid)) != OK) {
+            clientName, clientUid, clientPid)) != OK) {
         ALOGE("Camera connection could not be established.");
         return err;
     }
@@ -551,12 +629,23 @@
         CHECK_EQ((status_t)OK, mCamera->setPreviewTarget(mSurface));
     }
 
-    // By default, do not store metadata in video buffers
-    mIsMetaDataStoredInVideoBuffers = false;
-    mCamera->storeMetaDataInBuffers(false);
+    // By default, store real data in video buffers.
+    mVideoBufferMode = ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV;
     if (storeMetaDataInVideoBuffers) {
-        if (OK == mCamera->storeMetaDataInBuffers(true)) {
-            mIsMetaDataStoredInVideoBuffers = true;
+        if (OK == mCamera->setVideoBufferMode(ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE)) {
+            mVideoBufferMode = ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE;
+        } else if (OK == mCamera->setVideoBufferMode(
+                ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA)) {
+            mVideoBufferMode = ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA;
+        }
+    }
+
+    if (mVideoBufferMode == ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV) {
+        err = mCamera->setVideoBufferMode(ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV);
+        if (err != OK) {
+            ALOGE("%s: Setting video buffer mode to VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV failed: "
+                    "%s (err=%d)", __FUNCTION__, strerror(-err), err);
+            return err;
         }
     }
 
@@ -596,28 +685,41 @@
     // will connect to the camera in ICameraRecordingProxy::startRecording.
     int64_t token = IPCThreadState::self()->clearCallingIdentity();
     status_t err;
-    if (mNumInputBuffers > 0) {
+
+    if (mVideoBufferMode == ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE) {
+        // Initialize buffer queue.
+        err = initBufferQueue(mVideoSize.width, mVideoSize.height, mEncoderFormat,
+                (android_dataspace_t)mEncoderDataSpace,
+                mNumInputBuffers > 0 ? mNumInputBuffers : 1);
+        if (err != OK) {
+            ALOGE("%s: Failed to initialize buffer queue: %s (err=%d)", __FUNCTION__,
+                    strerror(-err), err);
+            return err;
+        }
+    } else {
+        if (mNumInputBuffers > 0) {
+            err = mCamera->sendCommand(
+                CAMERA_CMD_SET_VIDEO_BUFFER_COUNT, mNumInputBuffers, 0);
+
+            // This could happen for CameraHAL1 clients; thus the failure is
+            // not a fatal error
+            if (err != OK) {
+                ALOGW("Failed to set video buffer count to %d due to %d",
+                    mNumInputBuffers, err);
+            }
+        }
+
         err = mCamera->sendCommand(
-            CAMERA_CMD_SET_VIDEO_BUFFER_COUNT, mNumInputBuffers, 0);
+            CAMERA_CMD_SET_VIDEO_FORMAT, mEncoderFormat, mEncoderDataSpace);
 
         // This could happen for CameraHAL1 clients; thus the failure is
         // not a fatal error
         if (err != OK) {
-            ALOGW("Failed to set video buffer count to %d due to %d",
-                mNumInputBuffers, err);
+            ALOGW("Failed to set video encoder format/dataspace to %d, %d due to %d",
+                    mEncoderFormat, mEncoderDataSpace, err);
         }
     }
 
-    err = mCamera->sendCommand(
-        CAMERA_CMD_SET_VIDEO_FORMAT, mEncoderFormat, mEncoderDataSpace);
-
-    // This could happen for CameraHAL1 clients; thus the failure is
-    // not a fatal error
-    if (err != OK) {
-        ALOGW("Failed to set video encoder format/dataspace to %d, %d due to %d",
-                mEncoderFormat, mEncoderDataSpace, err);
-    }
-
     err = OK;
     if (mCameraFlags & FLAGS_HOT_CAMERA) {
         mCamera->unlock();
@@ -771,6 +873,14 @@
         CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped);
     }
 
+    if (mBufferQueueListener != nullptr) {
+        mBufferQueueListener->requestExit();
+        mBufferQueueListener->join();
+        mBufferQueueListener.clear();
+    }
+
+    mVideoBufferConsumer.clear();
+    mVideoBufferProducer.clear();
     releaseCamera();
 
     ALOGD("reset: X");
@@ -779,7 +889,33 @@
 
 void CameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
     ALOGV("releaseRecordingFrame");
-    if (mCameraRecordingProxy != NULL) {
+
+    if (mVideoBufferMode == ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE) {
+        // Return the buffer to buffer queue in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
+        ssize_t offset;
+        size_t size;
+        sp<IMemoryHeap> heap = frame->getMemory(&offset, &size);
+        if (heap->getHeapID() != mMemoryHeapBase->getHeapID()) {
+            ALOGE("%s: Mismatched heap ID, ignoring release (got %x, expected %x)", __FUNCTION__,
+                    heap->getHeapID(), mMemoryHeapBase->getHeapID());
+            return;
+        }
+
+        VideoNativeMetadata *payload = reinterpret_cast<VideoNativeMetadata*>(
+                (uint8_t*)heap->getBase() + offset);
+
+        // Find the corresponding buffer item for the native window buffer.
+        ssize_t index = mReceivedBufferItemMap.indexOfKey(payload->pBuffer);
+        if (index == NAME_NOT_FOUND) {
+            ALOGE("%s: Couldn't find buffer item for %p", __FUNCTION__, payload->pBuffer);
+            return;
+        }
+
+        BufferItem buffer = mReceivedBufferItemMap.valueAt(index);
+        mReceivedBufferItemMap.removeItemsAt(index);
+        mVideoBufferConsumer->releaseBuffer(buffer);
+        mMemoryBases.push_back(frame);
+    } else if (mCameraRecordingProxy != NULL) {
         mCameraRecordingProxy->releaseRecordingFrame(frame);
     } else if (mCamera != NULL) {
         int64_t token = IPCThreadState::self()->clearCallingIdentity();
@@ -871,29 +1007,23 @@
     return OK;
 }
 
-void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
-        int32_t msgType __unused, const sp<IMemory> &data) {
-    ALOGV("dataCallbackTimestamp: timestamp %lld us", (long long)timestampUs);
-    Mutex::Autolock autoLock(mLock);
+bool CameraSource::shouldSkipFrameLocked(int64_t timestampUs) {
     if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) {
         ALOGV("Drop frame at %lld/%lld us", (long long)timestampUs, (long long)mStartTimeUs);
-        releaseOneRecordingFrame(data);
-        return;
+        return true;
     }
 
     // May need to skip frame or modify timestamp. Currently implemented
     // by the subclass CameraSourceTimeLapse.
     if (skipCurrentFrame(timestampUs)) {
-        releaseOneRecordingFrame(data);
-        return;
+        return true;
     }
 
     if (mNumFramesReceived > 0) {
         if (timestampUs <= mLastFrameTimestampUs) {
             ALOGW("Dropping frame with backward timestamp %lld (last %lld)",
                     (long long)timestampUs, (long long)mLastFrameTimestampUs);
-            releaseOneRecordingFrame(data);
-            return;
+            return true;
         }
         if (timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) {
             ++mNumGlitches;
@@ -908,12 +1038,25 @@
             if (timestampUs < mStartTimeUs) {
                 // Frame was captured before recording was started
                 // Drop it without updating the statistical data.
-                releaseOneRecordingFrame(data);
-                return;
+                return true;
             }
             mStartTimeUs = timestampUs - mStartTimeUs;
         }
     }
+
+    return false;
+}
+
+void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
+        int32_t msgType __unused, const sp<IMemory> &data) {
+    ALOGV("dataCallbackTimestamp: timestamp %lld us", (long long)timestampUs);
+    Mutex::Autolock autoLock(mLock);
+
+    if (shouldSkipFrameLocked(timestampUs)) {
+        releaseOneRecordingFrame(data);
+        return;
+    }
+
     ++mNumFramesReceived;
 
     CHECK(data != NULL && data->size() > 0);
@@ -925,9 +1068,97 @@
     mFrameAvailableCondition.signal();
 }
 
+CameraSource::BufferQueueListener::BufferQueueListener(const sp<BufferItemConsumer>& consumer,
+        const sp<CameraSource>& cameraSource) {
+    mConsumer = consumer;
+    mConsumer->setFrameAvailableListener(this);
+    mCameraSource = cameraSource;
+}
+
+void CameraSource::BufferQueueListener::onFrameAvailable(const BufferItem& /*item*/) {
+    ALOGV("%s: onFrameAvailable", __FUNCTION__);
+
+    Mutex::Autolock l(mLock);
+
+    if (!mFrameAvailable) {
+        mFrameAvailable = true;
+        mFrameAvailableSignal.signal();
+    }
+}
+
+bool CameraSource::BufferQueueListener::threadLoop() {
+    if (mConsumer == nullptr || mCameraSource == nullptr) {
+        return false;
+    }
+
+    {
+        Mutex::Autolock l(mLock);
+        while (!mFrameAvailable) {
+            if (mFrameAvailableSignal.waitRelative(mLock, kFrameAvailableTimeout) == TIMED_OUT) {
+                return true;
+            }
+        }
+        mFrameAvailable = false;
+    }
+
+    BufferItem buffer;
+    while (mConsumer->acquireBuffer(&buffer, 0) == OK) {
+        mCameraSource->processBufferQueueFrame(buffer);
+    }
+
+    return true;
+}
+
+void CameraSource::processBufferQueueFrame(const BufferItem& buffer) {
+    Mutex::Autolock autoLock(mLock);
+
+    int64_t timestampUs = buffer.mTimestamp / 1000;
+    if (shouldSkipFrameLocked(timestampUs)) {
+        mVideoBufferConsumer->releaseBuffer(buffer);
+        return;
+    }
+
+    if (mMemoryBases.empty()) {
+        ALOGW("%s: No available memory base. Dropping a recording frame.", __FUNCTION__);
+        mVideoBufferConsumer->releaseBuffer(buffer);
+        return;
+    }
+
+    ++mNumFramesReceived;
+
+    // Find a available memory slot to store the buffer as VideoNativeMetadata.
+    sp<IMemory> data = *mMemoryBases.begin();
+    mMemoryBases.erase(mMemoryBases.begin());
+
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap = data->getMemory(&offset, &size);
+    VideoNativeMetadata *payload = reinterpret_cast<VideoNativeMetadata*>(
+        (uint8_t*)heap->getBase() + offset);
+    memset(payload, 0, sizeof(VideoNativeMetadata));
+    payload->eType = kMetadataBufferTypeANWBuffer;
+    payload->pBuffer = buffer.mGraphicBuffer->getNativeBuffer();
+    payload->nFenceFd = -1;
+
+    // Add the mapping so we can find the corresponding buffer item to release to the buffer queue
+    // when the encoder returns the native window buffer.
+    mReceivedBufferItemMap.add(payload->pBuffer, buffer);
+
+    mFramesReceived.push_back(data);
+    int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs);
+    mFrameTimes.push_back(timeUs);
+    ALOGV("initial delay: %" PRId64 ", current time stamp: %" PRId64,
+        mStartTimeUs, timeUs);
+    mFrameAvailableCondition.signal();
+}
+
 bool CameraSource::isMetaDataStoredInVideoBuffers() const {
     ALOGV("isMetaDataStoredInVideoBuffers");
-    return mIsMetaDataStoredInVideoBuffers;
+
+    // Output buffers will contain metadata if camera sends us buffer in metadata mode or via
+    // buffer queue.
+    return (mVideoBufferMode == ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA ||
+            mVideoBufferMode == ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE);
 }
 
 CameraSource::ProxyListener::ProxyListener(const sp<CameraSource>& source) {
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 0acd9d0..202ec42 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -40,6 +40,7 @@
         int32_t cameraId,
         const String16& clientName,
         uid_t clientUid,
+        pid_t clientPid,
         Size videoSize,
         int32_t videoFrameRate,
         const sp<IGraphicBufferProducer>& surface,
@@ -48,7 +49,7 @@
 
     CameraSourceTimeLapse *source = new
             CameraSourceTimeLapse(camera, proxy, cameraId,
-                clientName, clientUid,
+                clientName, clientUid, clientPid,
                 videoSize, videoFrameRate, surface,
                 timeBetweenFrameCaptureUs,
                 storeMetaDataInVideoBuffers);
@@ -68,12 +69,13 @@
         int32_t cameraId,
         const String16& clientName,
         uid_t clientUid,
+        pid_t clientPid,
         Size videoSize,
         int32_t videoFrameRate,
         const sp<IGraphicBufferProducer>& surface,
         int64_t timeBetweenFrameCaptureUs,
         bool storeMetaDataInVideoBuffers)
-      : CameraSource(camera, proxy, cameraId, clientName, clientUid,
+      : CameraSource(camera, proxy, cameraId, clientName, clientUid, clientPid,
                 videoSize, videoFrameRate, surface,
                 storeMetaDataInVideoBuffers),
       mTimeBetweenTimeLapseVideoFramesUs(1E6/videoFrameRate),
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index 9cb6e86..255dcd0 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -35,7 +35,7 @@
 
 class DRMSource : public MediaSource {
 public:
-    DRMSource(const sp<MediaSource> &mediaSource,
+    DRMSource(const sp<IMediaSource> &mediaSource,
             const sp<DecryptHandle> &decryptHandle,
             DrmManagerClient *managerClient,
             int32_t trackId, DrmBuffer *ipmpBox);
@@ -50,7 +50,7 @@
     virtual ~DRMSource();
 
 private:
-    sp<MediaSource> mOriginalMediaSource;
+    sp<IMediaSource> mOriginalMediaSource;
     sp<DecryptHandle> mDecryptHandle;
     DrmManagerClient* mDrmManagerClient;
     size_t mTrackId;
@@ -64,7 +64,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-DRMSource::DRMSource(const sp<MediaSource> &mediaSource,
+DRMSource::DRMSource(const sp<IMediaSource> &mediaSource,
         const sp<DecryptHandle> &decryptHandle,
         DrmManagerClient *managerClient,
         int32_t trackId, DrmBuffer *ipmpBox)
@@ -247,8 +247,8 @@
     return mOriginalExtractor->countTracks();
 }
 
-sp<MediaSource> DRMExtractor::getTrack(size_t index) {
-    sp<MediaSource> originalMediaSource = mOriginalExtractor->getTrack(index);
+sp<IMediaSource> DRMExtractor::getTrack(size_t index) {
+    sp<IMediaSource> originalMediaSource = mOriginalExtractor->getTrack(index);
     originalMediaSource->getFormat()->setInt32(kKeyIsDRM, 1);
 
     int32_t trackID;
@@ -258,8 +258,9 @@
     ipmpBox.data = mOriginalExtractor->getDrmTrackInfo(trackID, &(ipmpBox.length));
     CHECK(ipmpBox.length > 0);
 
-    return new DRMSource(originalMediaSource, mDecryptHandle, mDrmManagerClient,
-            trackID, &ipmpBox);
+    return interface_cast<IMediaSource>(
+            new DRMSource(originalMediaSource, mDecryptHandle, mDrmManagerClient,
+            trackID, &ipmpBox));
 }
 
 sp<MetaData> DRMExtractor::getTrackMetaData(size_t index, uint32_t flags) {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 5020c6c..163a527 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -48,6 +48,8 @@
 
 #include <cutils/properties.h>
 
+#include <private/android_filesystem_config.h>
+
 namespace android {
 
 bool DataSource::getUInt16(off64_t offset, uint16_t *x) {
@@ -173,7 +175,10 @@
     RegisterSniffer_l(SniffMP3);
     RegisterSniffer_l(SniffAAC);
     RegisterSniffer_l(SniffMPEG2PS);
-    RegisterSniffer_l(SniffWVM);
+    if (getuid() == AID_MEDIA) {
+        // WVM only in the media server process
+        RegisterSniffer_l(SniffWVM);
+    }
     RegisterSniffer_l(SniffMidi);
 
     char value[PROPERTY_VALUE_MAX];
diff --git a/media/libstagefright/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp
index 89a91f7..6e99d02 100644
--- a/media/libstagefright/FLACExtractor.cpp
+++ b/media/libstagefright/FLACExtractor.cpp
@@ -807,7 +807,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-sp<MediaSource> FLACExtractor::getTrack(size_t index)
+sp<IMediaSource> FLACExtractor::getTrack(size_t index)
 {
     if (mInitCheck != OK || index > 0) {
         return NULL;
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index 37053ec..5d762d8 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -20,6 +20,7 @@
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/FileSource.h>
+#include <media/stagefright/Utils.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <sys/types.h>
@@ -38,6 +39,7 @@
       mDrmBufSize(0),
       mDrmBuf(NULL){
 
+    ALOGV("%s", filename);
     mFd = open(filename, O_LARGEFILE | O_RDONLY);
 
     if (mFd >= 0) {
@@ -56,6 +58,9 @@
       mDrmBufOffset(0),
       mDrmBufSize(0),
       mDrmBuf(NULL){
+    ALOGV("fd=%d (%s), offset=%lld, length=%lld",
+            fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
+
     CHECK(offset >= 0);
     CHECK(length >= 0);
 }
@@ -99,8 +104,8 @@
         if (offset >= mLength) {
             return 0;  // read beyond EOF.
         }
-        int64_t numAvailable = mLength - offset;
-        if ((int64_t)size > numAvailable) {
+        uint64_t numAvailable = mLength - offset;
+        if ((uint64_t)size > numAvailable) {
             size = numAvailable;
         }
     }
diff --git a/media/libstagefright/HevcUtils.cpp b/media/libstagefright/HevcUtils.cpp
new file mode 100644
index 0000000..087c903
--- /dev/null
+++ b/media/libstagefright/HevcUtils.cpp
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 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_NDEBUG 0
+#define LOG_TAG "HevcUtils"
+
+#include <cstring>
+
+#include "include/HevcUtils.h"
+#include "include/avc_utils.h"
+
+#include <media/stagefright/foundation/ABitReader.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+static const uint8_t kHevcNalUnitTypes[5] = {
+    kHevcNalUnitTypeVps,
+    kHevcNalUnitTypeSps,
+    kHevcNalUnitTypePps,
+    kHevcNalUnitTypePrefixSei,
+    kHevcNalUnitTypeSuffixSei,
+};
+
+HevcParameterSets::HevcParameterSets() {
+}
+
+status_t HevcParameterSets::addNalUnit(const uint8_t* data, size_t size) {
+    uint8_t nalUnitType = (data[0] >> 1) & 0x3f;
+    status_t err = OK;
+    switch (nalUnitType) {
+        case 32:  // VPS
+            err = parseVps(data + 2, size - 2);
+            break;
+        case 33:  // SPS
+            err = parseSps(data + 2, size - 2);
+            break;
+        case 34:  // PPS
+            err = parsePps(data + 2, size - 2);
+            break;
+        case 39:  // Prefix SEI
+        case 40:  // Suffix SEI
+            // Ignore
+            break;
+        default:
+            ALOGE("Unrecognized NAL unit type.");
+            return ERROR_MALFORMED;
+    }
+
+    if (err != OK) {
+        return err;
+    }
+
+    sp<ABuffer> buffer = ABuffer::CreateAsCopy(data, size);
+    buffer->setInt32Data(nalUnitType);
+    mNalUnits.push(buffer);
+    return OK;
+}
+
+template <typename T>
+static bool findParam(uint32_t key, T *param,
+        KeyedVector<uint32_t, uint64_t> &params) {
+    CHECK(param);
+    if (params.indexOfKey(key) < 0) {
+        return false;
+    }
+    *param = (T) params[key];
+    return true;
+}
+
+bool HevcParameterSets::findParam8(uint32_t key, uint8_t *param) {
+    return findParam(key, param, mParams);
+}
+
+bool HevcParameterSets::findParam16(uint32_t key, uint16_t *param) {
+    return findParam(key, param, mParams);
+}
+
+bool HevcParameterSets::findParam32(uint32_t key, uint32_t *param) {
+    return findParam(key, param, mParams);
+}
+
+bool HevcParameterSets::findParam64(uint32_t key, uint64_t *param) {
+    return findParam(key, param, mParams);
+}
+
+size_t HevcParameterSets::getNumNalUnitsOfType(uint8_t type) {
+    size_t num = 0;
+    for (size_t i = 0; i < mNalUnits.size(); ++i) {
+        if (getType(i) == type) {
+            ++num;
+        }
+    }
+    return num;
+}
+
+uint8_t HevcParameterSets::getType(size_t index) {
+    CHECK_LT(index, mNalUnits.size());
+    return mNalUnits[index]->int32Data();
+}
+
+size_t HevcParameterSets::getSize(size_t index) {
+    CHECK_LT(index, mNalUnits.size());
+    return mNalUnits[index]->size();
+}
+
+bool HevcParameterSets::write(size_t index, uint8_t* dest, size_t size) {
+    CHECK_LT(index, mNalUnits.size());
+    const sp<ABuffer>& nalUnit = mNalUnits[index];
+    if (size < nalUnit->size()) {
+        ALOGE("dest buffer size too small: %zu vs. %zu to be written",
+                size, nalUnit->size());
+        return false;
+    }
+    memcpy(dest, nalUnit->data(), nalUnit->size());
+    return true;
+}
+
+status_t HevcParameterSets::parseVps(const uint8_t* data, size_t size) {
+    // See Rec. ITU-T H.265 v3 (04/2015) Chapter 7.3.2.1 for reference
+    NALBitReader reader(data, size);
+    // Skip vps_video_parameter_set_id
+    reader.skipBits(4);
+    // Skip vps_base_layer_internal_flag
+    reader.skipBits(1);
+    // Skip vps_base_layer_available_flag
+    reader.skipBits(1);
+    // Skip vps_max_layers_minus_1
+    reader.skipBits(6);
+    // Skip vps_temporal_id_nesting_flags
+    reader.skipBits(1);
+    // Skip reserved
+    reader.skipBits(16);
+
+    mParams.add(kGeneralProfileSpace, reader.getBits(2));
+    mParams.add(kGeneralTierFlag, reader.getBits(1));
+    mParams.add(kGeneralProfileIdc, reader.getBits(5));
+    mParams.add(kGeneralProfileCompatibilityFlags, reader.getBits(32));
+    mParams.add(
+            kGeneralConstraintIndicatorFlags,
+            ((uint64_t)reader.getBits(16) << 32) | reader.getBits(32));
+    mParams.add(kGeneralLevelIdc, reader.getBits(8));
+    // 96 bits total for general profile.
+
+    return OK;
+}
+
+status_t HevcParameterSets::parseSps(const uint8_t* data, size_t size) {
+    // See Rec. ITU-T H.265 v3 (04/2015) Chapter 7.3.2.2 for reference
+    NALBitReader reader(data, size);
+    // Skip sps_video_parameter_set_id
+    reader.skipBits(4);
+    uint8_t maxSubLayersMinus1 = reader.getBits(3);
+    // Skip sps_temporal_id_nesting_flag;
+    reader.skipBits(1);
+    // Skip general profile
+    reader.skipBits(96);
+    if (maxSubLayersMinus1 > 0) {
+        bool subLayerProfilePresentFlag[8];
+        bool subLayerLevelPresentFlag[8];
+        for (int i = 0; i < maxSubLayersMinus1; ++i) {
+            subLayerProfilePresentFlag[i] = reader.getBits(1);
+            subLayerLevelPresentFlag[i] = reader.getBits(1);
+        }
+        // Skip reserved
+        reader.skipBits(2 * (8 - maxSubLayersMinus1));
+        for (int i = 0; i < maxSubLayersMinus1; ++i) {
+            if (subLayerProfilePresentFlag[i]) {
+                // Skip profile
+                reader.skipBits(88);
+            }
+            if (subLayerLevelPresentFlag[i]) {
+                // Skip sub_layer_level_idc[i]
+                reader.skipBits(8);
+            }
+        }
+    }
+    // Skip sps_seq_parameter_set_id
+    parseUE(&reader);
+    uint8_t chromaFormatIdc = parseUE(&reader);
+    mParams.add(kChromaFormatIdc, chromaFormatIdc);
+    if (chromaFormatIdc == 3) {
+        // Skip separate_colour_plane_flag
+        reader.skipBits(1);
+    }
+    // Skip pic_width_in_luma_samples
+    parseUE(&reader);
+    // Skip pic_height_in_luma_samples
+    parseUE(&reader);
+    if (reader.getBits(1) /* i.e. conformance_window_flag */) {
+        // Skip conf_win_left_offset
+        parseUE(&reader);
+        // Skip conf_win_right_offset
+        parseUE(&reader);
+        // Skip conf_win_top_offset
+        parseUE(&reader);
+        // Skip conf_win_bottom_offset
+        parseUE(&reader);
+    }
+    mParams.add(kBitDepthLumaMinus8, parseUE(&reader));
+    mParams.add(kBitDepthChromaMinus8, parseUE(&reader));
+
+    return OK;
+}
+
+status_t HevcParameterSets::parsePps(
+        const uint8_t* data __unused, size_t size __unused) {
+    return OK;
+}
+
+status_t HevcParameterSets::makeHvcc(uint8_t *hvcc, size_t *hvccSize,
+        size_t nalSizeLength) {
+    if (hvcc == NULL || hvccSize == NULL
+            || (nalSizeLength != 4 && nalSizeLength != 2)) {
+        return BAD_VALUE;
+    }
+    // ISO 14496-15: HEVC file format
+    size_t size = 23;  // 23 bytes in the header
+    size_t numOfArrays = 0;
+    const size_t numNalUnits = getNumNalUnits();
+    for (size_t i = 0; i < ARRAY_SIZE(kHevcNalUnitTypes); ++i) {
+        uint8_t type = kHevcNalUnitTypes[i];
+        size_t numNalus = getNumNalUnitsOfType(type);
+        if (numNalus == 0) {
+            continue;
+        }
+        ++numOfArrays;
+        size += 3;
+        for (size_t j = 0; j < numNalUnits; ++j) {
+            if (getType(j) != type) {
+                continue;
+            }
+            size += 2 + getSize(j);
+        }
+    }
+    uint8_t generalProfileSpace, generalTierFlag, generalProfileIdc;
+    if (!findParam8(kGeneralProfileSpace, &generalProfileSpace)
+            || !findParam8(kGeneralTierFlag, &generalTierFlag)
+            || !findParam8(kGeneralProfileIdc, &generalProfileIdc)) {
+        return ERROR_MALFORMED;
+    }
+    uint32_t compatibilityFlags;
+    uint64_t constraintIdcFlags;
+    if (!findParam32(kGeneralProfileCompatibilityFlags, &compatibilityFlags)
+            || !findParam64(kGeneralConstraintIndicatorFlags, &constraintIdcFlags)) {
+        return ERROR_MALFORMED;
+    }
+    uint8_t generalLevelIdc;
+    if (!findParam8(kGeneralLevelIdc, &generalLevelIdc)) {
+        return ERROR_MALFORMED;
+    }
+    uint8_t chromaFormatIdc, bitDepthLumaMinus8, bitDepthChromaMinus8;
+    if (!findParam8(kChromaFormatIdc, &chromaFormatIdc)
+            || !findParam8(kBitDepthLumaMinus8, &bitDepthLumaMinus8)
+            || !findParam8(kBitDepthChromaMinus8, &bitDepthChromaMinus8)) {
+        return ERROR_MALFORMED;
+    }
+    if (size > *hvccSize) {
+        return NO_MEMORY;
+    }
+    *hvccSize = size;
+
+    uint8_t *header = hvcc;
+    header[0] = 1;
+    header[1] = (kGeneralProfileSpace << 6) | (kGeneralTierFlag << 5) | kGeneralProfileIdc;
+    header[2] = (compatibilityFlags >> 24) & 0xff;
+    header[3] = (compatibilityFlags >> 16) & 0xff;
+    header[4] = (compatibilityFlags >> 8) & 0xff;
+    header[5] = compatibilityFlags & 0xff;
+    header[6] = (constraintIdcFlags >> 40) & 0xff;
+    header[7] = (constraintIdcFlags >> 32) & 0xff;
+    header[8] = (constraintIdcFlags >> 24) & 0xff;
+    header[9] = (constraintIdcFlags >> 16) & 0xff;
+    header[10] = (constraintIdcFlags >> 8) & 0xff;
+    header[11] = constraintIdcFlags & 0xff;
+    header[12] = generalLevelIdc;
+    // FIXME: parse min_spatial_segmentation_idc.
+    header[13] = 0xf0;
+    header[14] = 0;
+    // FIXME: derive parallelismType properly.
+    header[15] = 0xfc;
+    header[16] = 0xfc | chromaFormatIdc;
+    header[17] = 0xf8 | bitDepthLumaMinus8;
+    header[18] = 0xf8 | bitDepthChromaMinus8;
+    // FIXME: derive avgFrameRate
+    header[19] = 0;
+    header[20] = 0;
+    // constantFrameRate, numTemporalLayers, temporalIdNested all set to 0.
+    header[21] = nalSizeLength - 1;
+    header[22] = numOfArrays;
+    header += 23;
+    for (size_t i = 0; i < ARRAY_SIZE(kHevcNalUnitTypes); ++i) {
+        uint8_t type = kHevcNalUnitTypes[i];
+        size_t numNalus = getNumNalUnitsOfType(type);
+        if (numNalus == 0) {
+            continue;
+        }
+        // array_completeness set to 0.
+        header[0] = type;
+        header[1] = (numNalus >> 8) & 0xff;
+        header[2] = numNalus & 0xff;
+        header += 3;
+        for (size_t j = 0; j < numNalUnits; ++j) {
+            if (getType(j) != type) {
+                continue;
+            }
+            header[0] = (getSize(j) >> 8) & 0xff;
+            header[1] = getSize(j) & 0xff;
+            if (!write(j, header + 2, size - (header - (uint8_t *)hvcc))) {
+                return NO_MEMORY;
+            }
+            header += (2 + getSize(j));
+        }
+    }
+    CHECK_EQ(header - size, hvcc);
+
+    return OK;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 2e54e8c..7240e1a 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -400,7 +400,7 @@
     return mInitCheck != OK ? 0 : 1;
 }
 
-sp<MediaSource> MP3Extractor::getTrack(size_t index) {
+sp<IMediaSource> MP3Extractor::getTrack(size_t index) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index ef07aa0..a9e8846 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -35,7 +35,7 @@
 namespace android {
 
 struct MPEG2TSWriter::SourceInfo : public AHandler {
-    SourceInfo(const sp<MediaSource> &source);
+    SourceInfo(const sp<IMediaSource> &source);
 
     void start(const sp<AMessage> &notify);
     void stop();
@@ -69,7 +69,7 @@
         kWhatRead  = 'read',
     };
 
-    sp<MediaSource> mSource;
+    sp<IMediaSource> mSource;
     sp<ALooper> mLooper;
     sp<AMessage> mNotify;
 
@@ -93,7 +93,7 @@
     DISALLOW_EVIL_CONSTRUCTORS(SourceInfo);
 };
 
-MPEG2TSWriter::SourceInfo::SourceInfo(const sp<MediaSource> &source)
+MPEG2TSWriter::SourceInfo::SourceInfo(const sp<IMediaSource> &source)
     : mSource(source),
       mLooper(new ALooper),
       mEOSReceived(false),
@@ -523,7 +523,7 @@
     }
 }
 
-status_t MPEG2TSWriter::addSource(const sp<MediaSource> &source) {
+status_t MPEG2TSWriter::addSource(const sp<IMediaSource> &source) {
     CHECK(!mStarted);
 
     sp<MetaData> meta = source->getFormat();
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
old mode 100755
new mode 100644
index 13b6fce..6f4a65b
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -766,6 +766,11 @@
 
 status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
     ALOGV("entering parseChunk %lld/%d", (long long)*offset, depth);
+
+    if (*offset < 0) {
+        ALOGE("b/23540914");
+        return ERROR_MALFORMED;
+    }
     uint32_t hdr[2];
     if (mDataSource->readAt(*offset, hdr, 8) < 8) {
         return ERROR_IO;
@@ -831,7 +836,12 @@
 
     PathAdder autoAdder(&mPath, chunk_type);
 
-    off64_t chunk_data_size = *offset + chunk_size - data_offset;
+    // (data_offset - *offset) is either 8 or 16
+    off64_t chunk_data_size = chunk_size - (data_offset - *offset);
+    if (chunk_data_size < 0) {
+        ALOGE("b/23540914");
+        return ERROR_MALFORMED;
+    }
 
     if (chunk_type != FOURCC('c', 'p', 'r', 't')
             && chunk_type != FOURCC('c', 'o', 'v', 'r')
@@ -929,6 +939,11 @@
             }
 
             if (isTrack) {
+                int32_t trackId;
+                // There must be exact one track header per track.
+                if (!mLastTrack->meta->findInt32(kKeyTrackID, &trackId)) {
+                    mLastTrack->skipTrack = true;
+                }
                 if (mLastTrack->skipTrack) {
                     Track *cur = mFirstTrack;
 
@@ -2820,7 +2835,7 @@
     }
 }
 
-sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {
+sp<IMediaSource> MPEG4Extractor::getTrack(size_t index) {
     status_t err;
     if ((err = readMetaData()) != OK) {
         return NULL;
@@ -2851,10 +2866,46 @@
                 break;
             }
         }
+    } else {
+        ALOGE("b/21657957");
+        return NULL;
     }
 
     ALOGV("getTrack called, pssh: %zu", mPssh.size());
 
+    const char *mime;
+    if (!track->meta->findCString(kKeyMIMEType, &mime)) {
+        return NULL;
+    }
+
+    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+        uint32_t type;
+        const void *data;
+        size_t size;
+        if (!track->meta->findData(kKeyAVCC, &type, &data, &size)) {
+            return NULL;
+        }
+
+        const uint8_t *ptr = (const uint8_t *)data;
+
+        if (size < 7 || ptr[0] != 1) {  // configurationVersion == 1
+            return NULL;
+        }
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+        uint32_t type;
+        const void *data;
+        size_t size;
+        if (!track->meta->findData(kKeyHVCC, &type, &data, &size)) {
+            return NULL;
+        }
+
+        const uint8_t *ptr = (const uint8_t *)data;
+
+        if (size < 22 || ptr[0] != 1) {  // configurationVersion == 1
+            return NULL;
+        }
+    }
+
     return new MPEG4Source(this,
             track->meta, mDataSource, track->timescale, track->sampleTable,
             mSidxEntries, trex, mMoofOffset);
@@ -3310,7 +3361,7 @@
 
         const uint8_t *ptr = (const uint8_t *)data;
 
-        CHECK(size >= 7);
+        CHECK(size >= 22);
         CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
 
         mNALLengthSize = 1 + (ptr[14 + 7] & 3);
@@ -4545,7 +4596,15 @@
                     continue;
                 }
 
-                CHECK(dstOffset + 4 <= mBuffer->size());
+                if (dstOffset > SIZE_MAX - 4 ||
+                        dstOffset + 4 > SIZE_MAX - nalLength ||
+                        dstOffset + 4 + nalLength > mBuffer->size()) {
+                    ALOGE("b/26365349 : %zu %zu", dstOffset, mBuffer->size());
+                    android_errorWriteLog(0x534e4554, "26365349");
+                    mBuffer->release();
+                    mBuffer = NULL;
+                    return ERROR_MALFORMED;
+                }
 
                 dstData[dstOffset++] = 0;
                 dstData[dstOffset++] = 0;
@@ -4690,12 +4749,18 @@
                 // The smallest valid chunk is 16 bytes long in this case.
                 return false;
             }
+
         } else if (chunkSize < 8) {
             // The smallest valid chunk is 8 bytes long.
             return false;
         }
 
-        off64_t chunkDataSize = offset + chunkSize - chunkDataOffset;
+        // (data_offset - offset) is either 8 or 16
+        off64_t chunkDataSize = chunkSize - (chunkDataOffset - offset);
+        if (chunkDataSize < 0) {
+            ALOGE("b/23540914");
+            return ERROR_MALFORMED;
+        }
 
         char chunkstring[5];
         MakeFourCCString(chunkType, chunkstring);
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 78d4fb1..a5d9484 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -41,7 +41,7 @@
 #include <cutils/properties.h>
 
 #include "include/ESDS.h"
-
+#include "include/HevcUtils.h"
 
 #ifndef __predict_false
 #define __predict_false(exp) __builtin_expect((exp) != 0, 0)
@@ -70,12 +70,24 @@
 #endif
 static const char kMetaKey_CaptureFps[] = "com.android.capture.fps";
 
+static const uint8_t kMandatoryHevcNalUnitTypes[3] = {
+    kHevcNalUnitTypeVps,
+    kHevcNalUnitTypeSps,
+    kHevcNalUnitTypePps,
+};
+static const uint8_t kHevcNalUnitTypes[5] = {
+    kHevcNalUnitTypeVps,
+    kHevcNalUnitTypeSps,
+    kHevcNalUnitTypePps,
+    kHevcNalUnitTypePrefixSei,
+    kHevcNalUnitTypeSuffixSei,
+};
 /* uncomment to include model and build in meta */
 //#define SHOW_MODEL_BUILD 1
 
 class MPEG4Writer::Track {
 public:
-    Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId);
+    Track(MPEG4Writer *owner, const sp<IMediaSource> &source, size_t trackId);
 
     ~Track();
 
@@ -89,6 +101,7 @@
     void writeTrackHeader(bool use32BitOffset = true);
     void bufferChunk(int64_t timestampUs);
     bool isAvc() const { return mIsAvc; }
+    bool isHevc() const { return mIsHevc; }
     bool isAudio() const { return mIsAudio; }
     bool isMPEG4() const { return mIsMPEG4; }
     void addChunkOffset(off64_t offset);
@@ -228,12 +241,13 @@
 
     MPEG4Writer *mOwner;
     sp<MetaData> mMeta;
-    sp<MediaSource> mSource;
+    sp<IMediaSource> mSource;
     volatile bool mDone;
     volatile bool mPaused;
     volatile bool mResumed;
     volatile bool mStarted;
     bool mIsAvc;
+    bool mIsHevc;
     bool mIsAudio;
     bool mIsMPEG4;
     int32_t mTrackId;
@@ -299,10 +313,17 @@
     const uint8_t *parseParamSet(
         const uint8_t *data, size_t length, int type, size_t *paramSetLen);
 
+    status_t copyCodecSpecificData(const uint8_t *data, size_t size, size_t minLength = 0);
+
     status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size);
     status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size);
     status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size);
 
+    status_t makeHEVCCodecSpecificData(const uint8_t *data, size_t size);
+    status_t copyHEVCCodecSpecificData(const uint8_t *data, size_t size);
+    status_t parseHEVCCodecSpecificData(
+            const uint8_t *data, size_t size, HevcParameterSets &paramSets);
+
     // Track authoring progress status
     void trackProgressStatus(int64_t timeUs, status_t err = OK);
     void initTrackingProgressStatus(MetaData *params);
@@ -340,6 +361,7 @@
     void writeD263Box();
     void writePaspBox();
     void writeAvccBox();
+    void writeHvccBox();
     void writeUrlBox();
     void writeDrefBox();
     void writeDinfBox();
@@ -463,6 +485,8 @@
             return "s263";
         } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
             return "avc1";
+        } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
+            return "hvc1";
         }
     } else {
         ALOGE("Track (%s) other than video or audio is not supported", mime);
@@ -470,7 +494,7 @@
     return NULL;
 }
 
-status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
+status_t MPEG4Writer::addSource(const sp<IMediaSource> &source) {
     Mutex::Autolock l(mLock);
     if (mStarted) {
         ALOGE("Attempt to add source AFTER recording is started");
@@ -1436,7 +1460,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 MPEG4Writer::Track::Track(
-        MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId)
+        MPEG4Writer *owner, const sp<IMediaSource> &source, size_t trackId)
     : mOwner(owner),
       mMeta(source->getFormat()),
       mSource(source),
@@ -1465,6 +1489,7 @@
     const char *mime;
     mMeta->findCString(kKeyMIMEType, &mime);
     mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
+    mIsHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
     mIsAudio = !strncasecmp(mime, "audio/", 6);
     mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
                !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
@@ -1560,31 +1585,26 @@
     const char *mime;
     CHECK(mMeta->findCString(kKeyMIMEType, &mime));
 
+    uint32_t type;
+    const void *data = NULL;
+    size_t size = 0;
     if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
-        uint32_t type;
-        const void *data;
-        size_t size;
-        if (mMeta->findData(kKeyAVCC, &type, &data, &size)) {
-            mCodecSpecificData = malloc(size);
-            mCodecSpecificDataSize = size;
-            memcpy(mCodecSpecificData, data, size);
-            mGotAllCodecSpecificData = true;
-        }
+        mMeta->findData(kKeyAVCC, &type, &data, &size);
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+        mMeta->findData(kKeyHVCC, &type, &data, &size);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
             || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
-        uint32_t type;
-        const void *data;
-        size_t size;
         if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
             ESDS esds(data, size);
-            if (esds.getCodecSpecificInfo(&data, &size) == OK) {
-                mCodecSpecificData = malloc(size);
-                mCodecSpecificDataSize = size;
-                memcpy(mCodecSpecificData, data, size);
-                mGotAllCodecSpecificData = true;
+            if (esds.getCodecSpecificInfo(&data, &size) != OK) {
+                data = NULL;
+                size = 0;
             }
         }
     }
+    if (data != NULL && copyCodecSpecificData((uint8_t *)data, size) == OK) {
+        mGotAllCodecSpecificData = true;
+    }
 }
 
 MPEG4Writer::Track::~Track() {
@@ -1661,7 +1681,7 @@
     while (!chunk->mSamples.empty()) {
         List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
 
-        off64_t offset = chunk->mTrack->isAvc()
+        off64_t offset = (chunk->mTrack->isAvc() || chunk->mTrack->isHevc())
                                 ? addLengthPrefixedSample_l(*it)
                                 : addSample_l(*it);
 
@@ -1968,13 +1988,30 @@
 
     // 2 bytes for each of the parameter set length field
     // plus the 7 bytes for the header
-    if (size < 4 + 7) {
+    return copyCodecSpecificData(data, size, 4 + 7);
+}
+
+status_t MPEG4Writer::Track::copyHEVCCodecSpecificData(
+        const uint8_t *data, size_t size) {
+    ALOGV("copyHEVCCodecSpecificData");
+
+    // Min length of HEVC CSD is 23. (ISO/IEC 14496-15:2014 Chapter 8.3.3.1.2)
+    return copyCodecSpecificData(data, size, 23);
+}
+
+status_t MPEG4Writer::Track::copyCodecSpecificData(
+        const uint8_t *data, size_t size, size_t minLength) {
+    if (size < minLength) {
         ALOGE("Codec specific data length too short: %zu", size);
         return ERROR_MALFORMED;
     }
 
-    mCodecSpecificDataSize = size;
     mCodecSpecificData = malloc(size);
+    if (mCodecSpecificData == NULL) {
+        ALOGE("Failed allocating codec specific data");
+        return NO_MEMORY;
+    }
+    mCodecSpecificDataSize = size;
     memcpy(mCodecSpecificData, data, size);
     return OK;
 }
@@ -2097,6 +2134,11 @@
     // ISO 14496-15: AVC file format
     mCodecSpecificDataSize += 7;  // 7 more bytes in the header
     mCodecSpecificData = malloc(mCodecSpecificDataSize);
+    if (mCodecSpecificData == NULL) {
+        mCodecSpecificDataSize = 0;
+        ALOGE("Failed allocating codec specific data");
+        return NO_MEMORY;
+    }
     uint8_t *header = (uint8_t *)mCodecSpecificData;
     header[0] = 1;                     // version
     header[1] = mProfileIdc;           // profile indication
@@ -2145,6 +2187,96 @@
     return OK;
 }
 
+
+status_t MPEG4Writer::Track::parseHEVCCodecSpecificData(
+        const uint8_t *data, size_t size, HevcParameterSets &paramSets) {
+
+    ALOGV("parseHEVCCodecSpecificData");
+    const uint8_t *tmp = data;
+    const uint8_t *nextStartCode = data;
+    size_t bytesLeft = size;
+    while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
+        nextStartCode = findNextStartCode(tmp + 4, bytesLeft - 4);
+        if (nextStartCode == NULL) {
+            return ERROR_MALFORMED;
+        }
+        status_t err = paramSets.addNalUnit(tmp + 4, (nextStartCode - tmp) - 4);
+        if (err != OK) {
+            return ERROR_MALFORMED;
+        }
+
+        // Move on to find the next parameter set
+        bytesLeft -= nextStartCode - tmp;
+        tmp = nextStartCode;
+    }
+
+    size_t csdSize = 23;
+    const size_t numNalUnits = paramSets.getNumNalUnits();
+    for (size_t i = 0; i < ARRAY_SIZE(kMandatoryHevcNalUnitTypes); ++i) {
+        int type = kMandatoryHevcNalUnitTypes[i];
+        size_t numParamSets = paramSets.getNumNalUnitsOfType(type);
+        if (numParamSets == 0) {
+            ALOGE("Cound not find NAL unit of type %d", type);
+            return ERROR_MALFORMED;
+        }
+    }
+    for (size_t i = 0; i < ARRAY_SIZE(kHevcNalUnitTypes); ++i) {
+        int type = kHevcNalUnitTypes[i];
+        size_t numParamSets = paramSets.getNumNalUnitsOfType(type);
+        if (numParamSets > 0xffff) {
+            ALOGE("Too many seq parameter sets (%zu) found", numParamSets);
+            return ERROR_MALFORMED;
+        }
+        csdSize += 3;
+        for (size_t j = 0; j < numNalUnits; ++j) {
+            if (paramSets.getType(j) != type) {
+                continue;
+            }
+            csdSize += 2 + paramSets.getSize(j);
+        }
+    }
+    mCodecSpecificDataSize = csdSize;
+    return OK;
+}
+
+status_t MPEG4Writer::Track::makeHEVCCodecSpecificData(
+        const uint8_t *data, size_t size) {
+
+    if (mCodecSpecificData != NULL) {
+        ALOGE("Already have codec specific data");
+        return ERROR_MALFORMED;
+    }
+
+    if (size < 4) {
+        ALOGE("Codec specific data length too short: %zu", size);
+        return ERROR_MALFORMED;
+    }
+
+    // Data is in the form of HEVCCodecSpecificData
+    if (memcmp("\x00\x00\x00\x01", data, 4)) {
+        return copyHEVCCodecSpecificData(data, size);
+    }
+
+    HevcParameterSets paramSets;
+    if (parseHEVCCodecSpecificData(data, size, paramSets) != OK) {
+        return ERROR_MALFORMED;
+    }
+
+    mCodecSpecificData = malloc(mCodecSpecificDataSize);
+    if (mCodecSpecificData == NULL) {
+        mCodecSpecificDataSize = 0;
+        ALOGE("Failed allocating codec specific data");
+        return NO_MEMORY;
+    }
+    status_t err = paramSets.makeHvcc((uint8_t *)mCodecSpecificData,
+            &mCodecSpecificDataSize, mOwner->useNalLengthFour() ? 5 : 2);
+    if (err != OK) {
+        return err;
+    }
+
+    return OK;
+}
+
 /*
  * Updates the drift time from the audio track so that
  * the video track can get the updated drift time information
@@ -2228,13 +2360,15 @@
                             + buffer->range_offset(),
                         buffer->range_length());
                 CHECK_EQ((status_t)OK, err);
-            } else if (mIsMPEG4) {
-                mCodecSpecificDataSize = buffer->range_length();
-                mCodecSpecificData = malloc(mCodecSpecificDataSize);
-                memcpy(mCodecSpecificData,
+            } else if (mIsHevc) {
+                status_t err = makeHEVCCodecSpecificData(
                         (const uint8_t *)buffer->data()
                             + buffer->range_offset(),
-                       buffer->range_length());
+                        buffer->range_length());
+                CHECK_EQ((status_t)OK, err);
+            } else if (mIsMPEG4) {
+                copyCodecSpecificData((const uint8_t *)buffer->data() + buffer->range_offset(),
+                        buffer->range_length());
             }
 
             buffer->release();
@@ -2254,10 +2388,10 @@
         buffer->release();
         buffer = NULL;
 
-        if (mIsAvc) StripStartcode(copy);
+        if (mIsAvc || mIsHevc) StripStartcode(copy);
 
         size_t sampleSize = copy->range_length();
-        if (mIsAvc) {
+        if (mIsAvc || mIsHevc) {
             if (mOwner->useNalLengthFour()) {
                 sampleSize += 4;
             } else {
@@ -2457,7 +2591,7 @@
             trackProgressStatus(timestampUs);
         }
         if (!hasMultipleTracks) {
-            off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
+            off64_t offset = (mIsAvc || mIsHevc) ? mOwner->addLengthPrefixedSample_l(copy)
                                  : mOwner->addSample_l(copy);
 
             uint32_t count = (mOwner->use32BitFileOffset()
@@ -2709,7 +2843,8 @@
     CHECK(mMeta->findCString(kKeyMIMEType, &mime));
     if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
         !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
-        !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
+        !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime) ||
+        !strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
         if (!mCodecSpecificData ||
             mCodecSpecificDataSize <= 0) {
             ALOGE("Missing codec specific data");
@@ -2815,6 +2950,8 @@
         writeD263Box();
     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
         writeAvccBox();
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
+        writeHvccBox();
     }
 
     writePaspBox();
@@ -3070,6 +3207,20 @@
     mOwner->endBox();  // avcC
 }
 
+
+void MPEG4Writer::Track::writeHvccBox() {
+    CHECK(mCodecSpecificData);
+    CHECK_GE(mCodecSpecificDataSize, 5);
+
+    // Patch avcc's lengthSize field to match the number
+    // of bytes we use to indicate the size of a nal unit.
+    uint8_t *ptr = (uint8_t *)mCodecSpecificData;
+    ptr[21] = (ptr[21] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1);
+    mOwner->beginBox("hvcC");
+    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
+    mOwner->endBox();  // hvcC
+}
+
 void MPEG4Writer::Track::writeD263Box() {
     mOwner->beginBox("d263");
     mOwner->writeInt32(0);  // vendor
diff --git a/media/libstagefright/MediaClock.cpp b/media/libstagefright/MediaClock.cpp
index 2641e4e..3aa0061 100644
--- a/media/libstagefright/MediaClock.cpp
+++ b/media/libstagefright/MediaClock.cpp
@@ -25,6 +25,10 @@
 
 namespace android {
 
+// Maximum allowed time backwards from anchor change.
+// If larger than this threshold, it's treated as discontinuity.
+static const int64_t kAnchorFluctuationAllowedUs = 10000ll;
+
 MediaClock::MediaClock()
     : mAnchorTimeMediaUs(-1),
       mAnchorTimeRealUs(-1),
@@ -64,9 +68,20 @@
         ALOGW("reject anchor time since it leads to negative media time.");
         return;
     }
+
+    if (maxTimeMediaUs != -1) {
+        mMaxTimeMediaUs = maxTimeMediaUs;
+    }
+    if (mAnchorTimeRealUs != -1) {
+        int64_t oldNowMediaUs =
+            mAnchorTimeMediaUs + (nowUs - mAnchorTimeRealUs) * (double)mPlaybackRate;
+        if (nowMediaUs < oldNowMediaUs
+                && nowMediaUs > oldNowMediaUs - kAnchorFluctuationAllowedUs) {
+            return;
+        }
+    }
     mAnchorTimeRealUs = nowUs;
     mAnchorTimeMediaUs = nowMediaUs;
-    mMaxTimeMediaUs = maxTimeMediaUs;
 }
 
 void MediaClock::updateMaxTimeMedia(int64_t maxTimeMediaUs) {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 01b29fa..ce67d78 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -446,6 +446,13 @@
         if (!format->findInt32("rotation-degrees", &mRotationDegrees)) {
             mRotationDegrees = 0;
         }
+
+        // Prevent possible integer overflow in downstream code.
+        if (mInitIsEncoder
+                && (uint64_t)mVideoWidth * mVideoHeight > (uint64_t)INT32_MAX / 4) {
+            ALOGE("buffer size is too big, width=%d, height=%d", mVideoWidth, mVideoHeight);
+            return BAD_VALUE;
+        }
     }
 
     msg->setMessage("format", format);
@@ -704,6 +711,7 @@
         const uint8_t key[16],
         const uint8_t iv[16],
         CryptoPlugin::Mode mode,
+        const CryptoPlugin::Pattern &pattern,
         int64_t presentationTimeUs,
         uint32_t flags,
         AString *errorDetailMsg) {
@@ -719,6 +727,8 @@
     msg->setPointer("key", (void *)key);
     msg->setPointer("iv", (void *)iv);
     msg->setInt32("mode", mode);
+    msg->setInt32("encryptBlocks", pattern.mEncryptBlocks);
+    msg->setInt32("skipBlocks", pattern.mSkipBlocks);
     msg->setInt64("timeUs", presentationTimeUs);
     msg->setInt32("flags", flags);
     msg->setPointer("errorDetailMsg", errorDetailMsg);
@@ -896,33 +906,54 @@
         size_t portIndex, size_t index,
         sp<ABuffer> *buffer, sp<AMessage> *format) {
     // use mutex instead of a context switch
-
     if (mReleasedByResourceManager) {
+        ALOGE("getBufferAndFormat - resource already released");
         return DEAD_OBJECT;
     }
 
+    if (buffer == NULL) {
+        ALOGE("getBufferAndFormat - null ABuffer");
+        return INVALID_OPERATION;
+    }
+
+    if (format == NULL) {
+        ALOGE("getBufferAndFormat - null AMessage");
+        return INVALID_OPERATION;
+    }
+
     buffer->clear();
     format->clear();
+
     if (!isExecuting()) {
+        ALOGE("getBufferAndFormat - not executing");
         return INVALID_OPERATION;
     }
 
     // we do not want mPortBuffers to change during this section
     // we also don't want mOwnedByClient to change during this
     Mutex::Autolock al(mBufferLock);
+
     Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
-    if (index < buffers->size()) {
-        const BufferInfo &info = buffers->itemAt(index);
-        if (info.mOwnedByClient) {
-            // by the time buffers array is initialized, crypto is set
-            if (portIndex == kPortIndexInput && mCrypto != NULL) {
-                *buffer = info.mEncryptedData;
-            } else {
-                *buffer = info.mData;
-            }
-            *format = info.mFormat;
-        }
+    if (index >= buffers->size()) {
+        ALOGE("getBufferAndFormat - trying to get buffer with "
+              "bad index (index=%zu buffer_size=%zu)", index, buffers->size());
+        return INVALID_OPERATION;
     }
+
+    const BufferInfo &info = buffers->itemAt(index);
+    if (!info.mOwnedByClient) {
+        ALOGE("getBufferAndFormat - invalid operation "
+              "(the index %zu is not owned by client)", index);
+        return INVALID_OPERATION;
+    }
+
+    // by the time buffers array is initialized, crypto is set
+    *buffer = (portIndex == kPortIndexInput && mCrypto != NULL) ?
+                  info.mEncryptedData :
+                  info.mData;
+
+    *format = info.mFormat;
+
     return OK;
 }
 
@@ -1326,6 +1357,7 @@
                         info.mBufferID = portDesc->bufferIDAt(i);
                         info.mOwnedByClient = false;
                         info.mData = portDesc->bufferAt(i);
+                        info.mMemRef = portDesc->memRefAt(i);
 
                         if (portIndex == kPortIndexInput && mCrypto != NULL) {
                             sp<IMemory> mem = mDealer->allocate(info.mData->capacity());
@@ -1898,7 +1930,7 @@
             mCodec->initiateShutdown(
                     msg->what() == kWhatStop /* keepComponentAllocated */);
 
-            returnBuffersToCodec();
+            returnBuffersToCodec(reclaimed);
 
             if (mSoftRenderer != NULL && (mFlags & kFlagPushBlankBuffersOnShutdown)) {
                 pushBlankBuffersToNativeWindow(mSurface.get());
@@ -2223,6 +2255,9 @@
         if (!format->findBuffer(AStringPrintf("csd-%u", i).c_str(), &csd)) {
             break;
         }
+        if (csd->size() == 0) {
+            ALOGW("csd-%zu size is 0", i);
+        }
 
         mCSD.push_back(csd);
         ++i;
@@ -2301,12 +2336,12 @@
     updateBatteryStat();
 }
 
-void MediaCodec::returnBuffersToCodec() {
-    returnBuffersToCodecOnPort(kPortIndexInput);
-    returnBuffersToCodecOnPort(kPortIndexOutput);
+void MediaCodec::returnBuffersToCodec(bool isReclaim) {
+    returnBuffersToCodecOnPort(kPortIndexInput, isReclaim);
+    returnBuffersToCodecOnPort(kPortIndexOutput, isReclaim);
 }
 
-void MediaCodec::returnBuffersToCodecOnPort(int32_t portIndex) {
+void MediaCodec::returnBuffersToCodecOnPort(int32_t portIndex, bool isReclaim) {
     CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
     Mutex::Autolock al(mBufferLock);
 
@@ -2318,7 +2353,13 @@
         if (info->mNotify != NULL) {
             sp<AMessage> msg = info->mNotify;
             info->mNotify = NULL;
-            info->mOwnedByClient = false;
+            if (isReclaim && info->mOwnedByClient) {
+                ALOGD("port %d buffer %zu still owned by client when codec is reclaimed",
+                        portIndex, i);
+            } else {
+                info->mMemRef = NULL;
+                info->mOwnedByClient = false;
+            }
 
             if (portIndex == kPortIndexInput) {
                 /* no error, just returning buffers */
@@ -2380,6 +2421,7 @@
     // We allow the simpler queueInputBuffer API to be used even in
     // secure mode, by fabricating a single unencrypted subSample.
     CryptoPlugin::SubSample ss;
+    CryptoPlugin::Pattern pattern;
 
     if (msg->findSize("size", &size)) {
         if (mCrypto != NULL) {
@@ -2390,6 +2432,8 @@
             numSubSamples = 1;
             key = NULL;
             iv = NULL;
+            pattern.mEncryptBlocks = 0;
+            pattern.mSkipBlocks = 0;
         }
     } else {
         if (mCrypto == NULL) {
@@ -2400,6 +2444,8 @@
         CHECK(msg->findSize("numSubSamples", &numSubSamples));
         CHECK(msg->findPointer("key", (void **)&key));
         CHECK(msg->findPointer("iv", (void **)&iv));
+        CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
+        CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
 
         int32_t tmp;
         CHECK(msg->findInt32("mode", &tmp));
@@ -2452,6 +2498,7 @@
                 key,
                 iv,
                 mode,
+                pattern,
                 info->mSharedEncryptedBuffer,
                 offset,
                 subSamples,
@@ -2812,25 +2859,15 @@
 }
 
 void MediaCodec::updateBatteryStat() {
+    if (!mIsVideo) {
+        return;
+    }
+
     if (mState == CONFIGURED && !mBatteryStatNotified) {
-        BatteryNotifier& notifier(BatteryNotifier::getInstance());
-
-        if (mIsVideo) {
-            notifier.noteStartVideo();
-        } else {
-            notifier.noteStartAudio();
-        }
-
+        BatteryNotifier::getInstance().noteStartVideo();
         mBatteryStatNotified = true;
     } else if (mState == UNINITIALIZED && mBatteryStatNotified) {
-        BatteryNotifier& notifier(BatteryNotifier::getInstance());
-
-        if (mIsVideo) {
-            notifier.noteStopVideo();
-        } else {
-            notifier.noteStopAudio();
-        }
-
+        BatteryNotifier::getInstance().noteStopVideo();
         mBatteryStatNotified = false;
     }
 }
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index d526bc0..3a3a538 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -321,6 +321,12 @@
     return NULL;
 }
 
+void MediaCodecSource::setInputBufferTimeOffset(int64_t timeOffsetUs) {
+    sp<AMessage> msg = new AMessage(kWhatSetInputBufferTimeOffset, mReflector);
+    msg->setInt64("time-offset-us", timeOffsetUs);
+    postSynchronouslyAndReturnError(msg);
+}
+
 status_t MediaCodecSource::start(MetaData* params) {
     sp<AMessage> msg = new AMessage(kWhatStart, mReflector);
     msg->setObject("meta", params);
@@ -381,6 +387,7 @@
       mEncoderFormat(0),
       mEncoderDataSpace(0),
       mGraphicBufferConsumer(consumer),
+      mInputBufferTimeOffsetUs(0),
       mFirstSampleTimeUs(-1ll),
       mGeneration(0) {
     CHECK(mLooper != NULL);
@@ -615,6 +622,7 @@
 
         if (mbuf != NULL) {
             CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
+            timeUs += mInputBufferTimeOffsetUs;
 
             // push decoding time for video, or drift time for audio
             if (mIsVideo) {
@@ -785,6 +793,9 @@
                 if (mIsVideo) {
                     int64_t decodingTimeUs;
                     if (mFlags & FLAG_USE_SURFACE_INPUT) {
+                        // Time offset is not applied at
+                        // feedEncoderInputBuffer() in surface input case.
+                        timeUs += mInputBufferTimeOffsetUs;
                         // GraphicBufferSource is supposed to discard samples
                         // queued before start, and offset timeUs by start time
                         CHECK_GE(timeUs, 0ll);
@@ -920,6 +931,17 @@
         }
         break;
     }
+    case kWhatSetInputBufferTimeOffset:
+    {
+        sp<AReplyToken> replyID;
+        CHECK(msg->senderAwaitsResponse(&replyID));
+
+        CHECK(msg->findInt64("time-offset-us", &mInputBufferTimeOffsetUs));
+
+        sp<AMessage> response = new AMessage;
+        response->postReply(replyID);
+        break;
+    }
     default:
         TRESPASS();
     }
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 2a50692..845462b 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -28,6 +28,7 @@
 const char *MEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp";
 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_AUDIO_AMR_NB = "audio/3gpp";
 const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
@@ -62,6 +63,7 @@
 const char *MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
 const char *MEDIA_MIMETYPE_TEXT_VTT = "text/vtt";
 const char *MEDIA_MIMETYPE_TEXT_CEA_608 = "text/cea-608";
+const char *MEDIA_MIMETYPE_TEXT_CEA_708 = "text/cea-708";
 const char *MEDIA_MIMETYPE_DATA_TIMED_ID3 = "application/x-id3v4";
 
 }  // namespace android
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index e21fe6e..fe66a58 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -17,6 +17,8 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MediaExtractor"
 #include <utils/Log.h>
+#include <inttypes.h>
+#include <pwd.h>
 
 #include "include/AMRExtractor.h"
 #include "include/MP3Extractor.h"
@@ -33,15 +35,34 @@
 
 #include "matroska/MatroskaExtractor.h"
 
+#include <binder/IServiceManager.h>
+#include <binder/MemoryDealer.h>
+
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MetaData.h>
+#include <media/IMediaExtractorService.h>
+#include <cutils/properties.h>
 #include <utils/String8.h>
+#include <private/android_filesystem_config.h>
+
 
 namespace android {
 
+MediaExtractor::MediaExtractor():
+    mIsDrm(false) {
+    if (!LOG_NDEBUG) {
+        uid_t uid = getuid();
+        struct passwd *pw = getpwuid(uid);
+        ALOGI("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
+    }
+
+}
+
+
 sp<MetaData> MediaExtractor::getMetaData() {
     return new MetaData;
 }
@@ -50,9 +71,106 @@
     return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
 }
 
+
+
+class RemoteDataSource : public BnDataSource {
+public:
+    enum {
+        kBufferSize = 64 * 1024,
+    };
+
+    static sp<IDataSource> wrap(const sp<DataSource> &source);
+    virtual ~RemoteDataSource();
+
+    virtual sp<IMemory> getIMemory();
+    virtual ssize_t readAt(off64_t offset, size_t size);
+    virtual status_t getSize(off64_t* size);
+    virtual void close();
+    virtual uint32_t getFlags();
+
+private:
+    sp<IMemory> mMemory;
+    sp<DataSource> mSource;
+    RemoteDataSource(const sp<DataSource> &source);
+    DISALLOW_EVIL_CONSTRUCTORS(RemoteDataSource);
+};
+
+
+sp<IDataSource> RemoteDataSource::wrap(const sp<DataSource> &source) {
+    return new RemoteDataSource(source);
+}
+RemoteDataSource::RemoteDataSource(const sp<DataSource> &source) {
+    mSource = source;
+    sp<MemoryDealer> memoryDealer = new MemoryDealer(kBufferSize, "RemoteDataSource");
+    mMemory = memoryDealer->allocate(kBufferSize);
+    if (mMemory == NULL) {
+        ALOGE("Failed to allocate memory!");
+    }
+}
+RemoteDataSource::~RemoteDataSource() {
+    close();
+}
+sp<IMemory> RemoteDataSource::getIMemory() {
+    return mMemory;
+}
+ssize_t RemoteDataSource::readAt(off64_t offset, size_t size) {
+    ALOGV("readAt(%" PRId64 ", %zu)", offset, size);
+    return mSource->readAt(offset, mMemory->pointer(), size);
+}
+status_t RemoteDataSource::getSize(off64_t* size) {
+    return mSource->getSize(size);
+}
+void RemoteDataSource::close() {
+    mSource = NULL;
+}
+uint32_t RemoteDataSource::getFlags() {
+    return mSource->flags();
+}
+
 // static
-sp<MediaExtractor> MediaExtractor::Create(
+sp<IMediaExtractor> MediaExtractor::Create(
         const sp<DataSource> &source, const char *mime) {
+    ALOGV("MediaExtractor::Create %s", mime);
+
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.stagefright.extractremote", value, NULL)
+            && (!strcmp("0", value) || !strcasecmp("false", value))) {
+        // local extractor
+        ALOGW("creating media extractor in calling process");
+        return CreateFromService(source, mime);
+    } else {
+        // remote extractor
+        ALOGV("get service manager");
+        sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
+
+        // Check if it's WVM, since WVMExtractor needs to be created in the media server process,
+        // not the extractor process.
+        String8 mime8;
+        float confidence;
+        sp<AMessage> meta;
+        if (SniffWVM(source, &mime8, &confidence, &meta) &&
+                !strcasecmp(mime8, MEDIA_MIMETYPE_CONTAINER_WVM)) {
+            return new WVMExtractor(source);
+        }
+
+        if (binder != 0) {
+            sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
+            sp<IMediaExtractor> ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime);
+            return ex;
+        } else {
+            ALOGE("extractor service not running");
+            return NULL;
+        }
+    }
+    return NULL;
+}
+
+sp<MediaExtractor> MediaExtractor::CreateFromService(
+        const sp<DataSource> &source, const char *mime) {
+
+    ALOGV("MediaExtractor::CreateFromService %s", mime);
+    DataSource::RegisterDefaultSniffers();
+
     sp<AMessage> meta;
 
     String8 tmp;
@@ -110,7 +228,7 @@
         ret = new MatroskaExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
         ret = new MPEG2TSExtractor(source);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) {
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM) && getuid() == AID_MEDIA) {
         // Return now.  WVExtractor should not have the DrmFlag set in the block below.
         return new WVMExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
index 576471a..a17757a 100644
--- a/media/libstagefright/MediaSource.cpp
+++ b/media/libstagefright/MediaSource.cpp
@@ -22,56 +22,4 @@
 
 MediaSource::~MediaSource() {}
 
-////////////////////////////////////////////////////////////////////////////////
-
-MediaSource::ReadOptions::ReadOptions() {
-    reset();
-}
-
-void MediaSource::ReadOptions::reset() {
-    mOptions = 0;
-    mSeekTimeUs = 0;
-    mLatenessUs = 0;
-    mNonBlocking = false;
-}
-
-void MediaSource::ReadOptions::setNonBlocking() {
-    mNonBlocking = true;
-}
-
-void MediaSource::ReadOptions::clearNonBlocking() {
-    mNonBlocking = false;
-}
-
-bool MediaSource::ReadOptions::getNonBlocking() const {
-    return mNonBlocking;
-}
-
-void MediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
-    mOptions |= kSeekTo_Option;
-    mSeekTimeUs = time_us;
-    mSeekMode = mode;
-}
-
-void MediaSource::ReadOptions::clearSeekTo() {
-    mOptions &= ~kSeekTo_Option;
-    mSeekTimeUs = 0;
-    mSeekMode = SEEK_CLOSEST_SYNC;
-}
-
-bool MediaSource::ReadOptions::getSeekTo(
-        int64_t *time_us, SeekMode *mode) const {
-    *time_us = mSeekTimeUs;
-    *mode = mSeekMode;
-    return (mOptions & kSeekTo_Option) != 0;
-}
-
-void MediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
-    mLatenessUs = lateness_us;
-}
-
-int64_t MediaSource::ReadOptions::getLateBy() const {
-    return mLatenessUs;
-}
-
 }  // namespace android
diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp
index 3a45e25..6f2d868 100644
--- a/media/libstagefright/MediaSync.cpp
+++ b/media/libstagefright/MediaSync.cpp
@@ -635,7 +635,7 @@
 
     ALOGV("acquired buffer %#llx from input", (long long)bufferItem.mGraphicBuffer->getId());
 
-    status = mInput->detachBuffer(bufferItem.mBuf);
+    status = mInput->detachBuffer(bufferItem.mSlot);
     if (status != NO_ERROR) {
         ALOGE("detaching buffer from input failed (%d)", status);
         if (status == NO_INIT) {
@@ -677,7 +677,6 @@
             bufferItem.mCrop,
             static_cast<int32_t>(bufferItem.mScalingMode),
             bufferItem.mTransform,
-            bufferItem.mIsDroppable,
             bufferItem.mFence);
 
     // Attach and queue the buffer to the output.
diff --git a/media/libstagefright/MidiExtractor.cpp b/media/libstagefright/MidiExtractor.cpp
index f6b8c84..7525f57 100644
--- a/media/libstagefright/MidiExtractor.cpp
+++ b/media/libstagefright/MidiExtractor.cpp
@@ -281,7 +281,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-sp<MediaSource> MidiExtractor::getTrack(size_t index)
+sp<IMediaSource> MidiExtractor::getTrack(size_t index)
 {
     if (mInitCheck != OK || index > 0) {
         return NULL;
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 8c67618..dd7f6b9 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -130,6 +130,9 @@
 
 status_t NuMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
 
+    ALOGV("setDataSource fd=%d (%s), offset=%lld, length=%lld",
+            fd, nameForFd(fd).c_str(), (long long) offset, (long long) size);
+
     Mutex::Autolock autoLock(mLock);
 
     if (mImpl != NULL) {
@@ -187,6 +190,10 @@
 
     for (size_t i = 0; i < mImpl->countTracks(); ++i) {
         sp<MetaData> meta = mImpl->getTrackMetaData(i);
+        if (meta == NULL) {
+            ALOGW("no metadata for track %zu", i);
+            continue;
+        }
 
         int32_t bitrate;
         if (!meta->findInt32(kKeyBitRate, &bitrate)) {
@@ -279,7 +286,7 @@
         }
     }
 
-    sp<MediaSource> source = mImpl->getTrack(index);
+    sp<IMediaSource> source = mImpl->getTrack(index);
 
     CHECK_EQ((status_t)OK, source->start());
 
@@ -443,6 +450,59 @@
     return OK;
 }
 
+status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer) {
+    int32_t numPageSamples;
+    if (!info->mSample->meta_data()->findInt32(
+            kKeyValidSamples, &numPageSamples)) {
+        numPageSamples = -1;
+    }
+
+    memcpy((uint8_t *)buffer->data() + info->mSample->range_length(),
+           &numPageSamples,
+           sizeof(numPageSamples));
+
+    uint32_t type;
+    const void *data;
+    size_t size, size2;
+    if (info->mSample->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) {
+        // Signal numPageSamples (a plain int32_t) is appended at the end,
+        // i.e. sizeof(numPageSamples) plain bytes + 0 encrypted bytes
+        if (SIZE_MAX - size < sizeof(int32_t)) {
+            return -ENOMEM;
+        }
+
+        size_t newSize = size + sizeof(int32_t);
+        sp<ABuffer> abuf = new ABuffer(newSize);
+        uint8_t *adata = static_cast<uint8_t *>(abuf->data());
+        if (adata == NULL) {
+            return -ENOMEM;
+        }
+
+        // append 0 to encrypted sizes
+        int32_t zero = 0;
+        memcpy(adata, data, size);
+        memcpy(adata + size, &zero, sizeof(zero));
+        info->mSample->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize);
+
+        if (info->mSample->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) {
+            if (size2 != size) {
+                return ERROR_MALFORMED;
+            }
+            memcpy(adata, data, size);
+        } else {
+            // if sample meta data does not include plain size array, assume filled with zeros,
+            // i.e. entire buffer is encrypted
+            memset(adata, 0, size);
+        }
+        // append sizeof(numPageSamples) to plain sizes.
+        int32_t int32Size = sizeof(numPageSamples);
+        memcpy(adata + size, &int32Size, sizeof(int32Size));
+        info->mSample->meta_data()->setData(kKeyPlainSizes, type, adata, newSize);
+    }
+
+    return OK;
+}
+
 status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) {
     Mutex::Autolock autoLock(mLock);
 
@@ -472,21 +532,16 @@
 
     memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length());
 
+    status_t err = OK;
     if (info->mTrackFlags & kIsVorbis) {
-        int32_t numPageSamples;
-        if (!info->mSample->meta_data()->findInt32(
-                    kKeyValidSamples, &numPageSamples)) {
-            numPageSamples = -1;
-        }
-
-        memcpy((uint8_t *)buffer->data() + info->mSample->range_length(),
-               &numPageSamples,
-               sizeof(numPageSamples));
+        err = appendVorbisNumPageSamples(info, buffer);
     }
 
-    buffer->setRange(0, sampleSize);
+    if (err == OK) {
+        buffer->setRange(0, sampleSize);
+    }
 
-    return OK;
+    return err;
 }
 
 status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) {
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index d63ac96..9162f80 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -965,7 +965,7 @@
     mMeta->setInt32(kKeyChannelCount, mChannelCount);
     mMeta->setInt64(kKeyOpusSeekPreRoll /* ns */, kOpusSeekPreRollUs * 1000 /* = 80 ms*/);
     mMeta->setInt64(kKeyOpusCodecDelay /* ns */,
-            mCodecDelay /* sample/s */ * 1000000000 / kOpusSampleRate);
+            mCodecDelay /* sample/s */ * 1000000000ll / kOpusSampleRate);
 
     return OK;
 }
@@ -1265,17 +1265,17 @@
         return;
     }
 
-    descLen = U32_AT(&flac[8 + typeLen]);
+    if (flacSize < 32 || flacSize - 32 < typeLen) {
+        return;
+    }
 
-    if (flacSize < 32 ||
-        flacSize - 32 < typeLen ||
-        flacSize - 32 - typeLen < descLen) {
+    descLen = U32_AT(&flac[8 + typeLen]);
+    if (flacSize - 32 - typeLen < descLen) {
         return;
     }
 
     dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
 
-
     // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
     if (flacSize - 32 - typeLen - descLen < dataLen) {
         return;
@@ -1325,7 +1325,7 @@
     return mInitCheck != OK ? 0 : 1;
 }
 
-sp<MediaSource> OggExtractor::getTrack(size_t index) {
+sp<IMediaSource> OggExtractor::getTrack(size_t index) {
     if (index >= 1) {
         return NULL;
     }
diff --git a/media/libstagefright/ProcessInfo.cpp b/media/libstagefright/ProcessInfo.cpp
index b4172b3..353f108 100644
--- a/media/libstagefright/ProcessInfo.cpp
+++ b/media/libstagefright/ProcessInfo.cpp
@@ -32,19 +32,23 @@
     sp<IProcessInfoService> service = interface_cast<IProcessInfoService>(binder);
 
     size_t length = 1;
-    int32_t states;
-    status_t err = service->getProcessStatesFromPids(length, &pid, &states);
+    int32_t state;
+    static const int32_t INVALID_ADJ = -10000;
+    static const int32_t NATIVE_ADJ = -1000;
+    int32_t score = INVALID_ADJ;
+    status_t err = service->getProcessStatesAndOomScoresFromPids(length, &pid, &state, &score);
     if (err != OK) {
-        ALOGE("getProcessStatesFromPids failed");
+        ALOGE("getProcessStatesAndOomScoresFromPids failed");
         return false;
     }
-    ALOGV("pid %d states %d", pid, states);
-    if (states < 0) {
+    ALOGV("pid %d state %d score %d", pid, state, score);
+    if (score <= NATIVE_ADJ) {
+        ALOGE("pid %d invalid OOM adjustments value %d", pid, score);
         return false;
     }
 
-    // Use process state as the priority. Lower the value, higher the priority.
-    *priority = states;
+    // Use OOM adjustments value as the priority. Lower the value, higher the priority.
+    *priority = score;
     return true;
 }
 
diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
index 032bbb9..7bf3437 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/libstagefright/SampleIterator.cpp
@@ -84,6 +84,11 @@
 
     CHECK(sampleIndex < mStopChunkSampleIndex);
 
+    if (mSamplesPerChunk == 0) {
+        ALOGE("b/22802344");
+        return ERROR_MALFORMED;
+    }
+
     uint32_t chunk =
         (sampleIndex - mFirstChunkSampleIndex) / mSamplesPerChunk
         + mFirstChunk;
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 93cf055..39459e2 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -255,8 +255,11 @@
                 != (ssize_t)sizeof(buffer)) {
             return ERROR_IO;
         }
-
-        CHECK(U32_AT(buffer) >= 1);  // chunk index is 1 based in the spec.
+        // chunk index is 1 based in the spec.
+        if (U32_AT(buffer) < 1) {
+            ALOGE("b/23534160");
+            return ERROR_OUT_OF_RANGE;
+        }
 
         // We want the chunk index to be 0-based.
         mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
index d544e35..1b44a00 100644
--- a/media/libstagefright/SimpleDecodingSource.cpp
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -35,7 +35,7 @@
 
 //static
 sp<SimpleDecodingSource> SimpleDecodingSource::Create(
-        const sp<MediaSource> &source, uint32_t flags, const sp<ANativeWindow> &nativeWindow,
+        const sp<IMediaSource> &source, uint32_t flags, const sp<ANativeWindow> &nativeWindow,
         const char *desiredCodec) {
     sp<Surface> surface = static_cast<Surface*>(nativeWindow.get());
     const char *mime = NULL;
@@ -87,7 +87,7 @@
 }
 
 SimpleDecodingSource::SimpleDecodingSource(
-        const sp<MediaCodec> &codec, const sp<MediaSource> &source, const sp<ALooper> &looper,
+        const sp<MediaCodec> &codec, const sp<IMediaSource> &source, const sp<ALooper> &looper,
         bool usingSurface, const sp<AMessage> &format)
     : mCodec(codec),
       mSource(source),
@@ -199,7 +199,7 @@
     status_t res;
 
     // flush codec on seek
-    MediaSource::ReadOptions::SeekMode mode;
+    IMediaSource::ReadOptions::SeekMode mode;
     if (options != NULL && options->getSeekTo(&out_pts, &mode)) {
         me->mQueuedInputEOS = false;
         me->mGotOutputEOS = false;
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 08342cf..45fb785 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -138,7 +138,7 @@
 static VideoFrame *extractVideoFrame(
         const AString &componentName,
         const sp<MetaData> &trackMeta,
-        const sp<MediaSource> &source,
+        const sp<IMediaSource> &source,
         int64_t frameTimeUs,
         int seekMode) {
 
@@ -146,6 +146,7 @@
 
     sp<AMessage> videoFormat;
     if (convertMetaDataToMessage(trackMeta, &videoFormat) != OK) {
+        ALOGE("b/23680780");
         ALOGW("Failed to convert meta data to message");
         return NULL;
     }
@@ -457,7 +458,7 @@
     sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
             i, MediaExtractor::kIncludeExtensiveMetaData);
 
-    sp<MediaSource> source = mExtractor->getTrack(i);
+    sp<IMediaSource> source = mExtractor->getTrack(i);
 
     if (source.get() == NULL) {
         ALOGV("unable to instantiate video track.");
@@ -659,9 +660,12 @@
                 }
             } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
                 const char *lang;
-                trackMeta->findCString(kKeyMediaLanguage, &lang);
-                timedTextLang.append(String8(lang));
-                timedTextLang.append(String8(":"));
+                if (trackMeta->findCString(kKeyMediaLanguage, &lang)) {
+                    timedTextLang.append(String8(lang));
+                    timedTextLang.append(String8(":"));
+                } else {
+                    ALOGE("No language found for timed text");
+                }
             }
         }
     }
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index e8abf48..e4bf67a 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -308,9 +308,9 @@
 
             // First time seeing the buffer?  Added it to the SMS slot
             if (item.mGraphicBuffer != NULL) {
-                mSlots[item.mBuf].mGraphicBuffer = item.mGraphicBuffer;
+                mSlots[item.mSlot].mGraphicBuffer = item.mGraphicBuffer;
             }
-            mSlots[item.mBuf].mFrameNumber = item.mFrameNumber;
+            mSlots[item.mSlot].mFrameNumber = item.mFrameNumber;
 
             // check for the timing of this buffer
             if (mNumFramesReceived == 0 && !mUseAbsoluteTimestamps) {
@@ -320,7 +320,7 @@
                     if (item.mTimestamp < mStartTimeNs) {
                         // This frame predates start of record, discard
                         mConsumer->releaseBuffer(
-                                item.mBuf, item.mFrameNumber, EGL_NO_DISPLAY,
+                                item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY,
                                 EGL_NO_SYNC_KHR, Fence::NO_FENCE);
                         continue;
                     }
@@ -346,13 +346,13 @@
         return ERROR_END_OF_STREAM;
     }
 
-    mCurrentSlot = item.mBuf;
+    mCurrentSlot = item.mSlot;
 
     // First time seeing the buffer?  Added it to the SMS slot
     if (item.mGraphicBuffer != NULL) {
-        mSlots[item.mBuf].mGraphicBuffer = item.mGraphicBuffer;
+        mSlots[item.mSlot].mGraphicBuffer = item.mGraphicBuffer;
     }
-    mSlots[item.mBuf].mFrameNumber = item.mFrameNumber;
+    mSlots[item.mSlot].mFrameNumber = item.mFrameNumber;
 
     mCurrentBuffers.push_back(mSlots[mCurrentSlot].mGraphicBuffer);
     int64_t prevTimeStamp = mCurrentTimestamp;
diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
index 6b62e43..9940822 100644
--- a/media/libstagefright/SurfaceUtils.cpp
+++ b/media/libstagefright/SurfaceUtils.cpp
@@ -55,11 +55,17 @@
         return err;
     }
 
+    int consumerUsage = 0;
+    err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage);
+    if (err != NO_ERROR) {
+        ALOGW("failed to get consumer usage bits. ignoring");
+        err = NO_ERROR;
+    }
+
     // Make sure to check whether either Stagefright or the video decoder
     // requested protected buffers.
     if (usage & GRALLOC_USAGE_PROTECTED) {
-        // Verify that the ANativeWindow sends images directly to
-        // SurfaceFlinger.
+        // Check if the ANativeWindow sends images directly to SurfaceFlinger.
         int queuesToNativeWindow = 0;
         err = nativeWindow->query(
                 nativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &queuesToNativeWindow);
@@ -67,19 +73,14 @@
             ALOGE("error authenticating native window: %s (%d)", strerror(-err), -err);
             return err;
         }
-        if (queuesToNativeWindow != 1) {
+
+        // Check if the ANativeWindow uses hardware protected buffers.
+        if (queuesToNativeWindow != 1 && !(consumerUsage & GRALLOC_USAGE_PROTECTED)) {
             ALOGE("native window could not be authenticated");
             return PERMISSION_DENIED;
         }
     }
 
-    int consumerUsage = 0;
-    err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage);
-    if (err != NO_ERROR) {
-        ALOGW("failed to get consumer usage bits. ignoring");
-        err = NO_ERROR;
-    }
-
     int finalUsage = usage | consumerUsage;
     ALOGV("gralloc usage: %#x(producer) + %#x(consumer) = %#x", usage, consumerUsage, finalUsage);
     err = native_window_set_usage(nativeWindow, finalUsage);
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 17f0201..dcc29fe 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -18,8 +18,11 @@
 #define LOG_TAG "Utils"
 #include <utils/Log.h>
 #include <ctype.h>
+#include <stdio.h>
+#include <sys/stat.h>
 
 #include "include/ESDS.h"
+#include "include/HevcUtils.h"
 
 #include <arpa/inet.h>
 #include <cutils/properties.h>
@@ -89,10 +92,18 @@
 
 status_t convertMetaDataToMessage(
         const sp<MetaData> &meta, sp<AMessage> *format) {
+
     format->clear();
 
+    if (meta == NULL) {
+        ALOGE("convertMetaDataToMessage: NULL input");
+        return BAD_VALUE;
+    }
+
     const char *mime;
-    CHECK(meta->findCString(kKeyMIMEType, &mime));
+    if (!meta->findCString(kKeyMIMEType, &mime)) {
+        return BAD_VALUE;
+    }
 
     sp<AMessage> msg = new AMessage;
     msg->setString("mime", mime);
@@ -114,8 +125,10 @@
 
     if (!strncasecmp("video/", mime, 6)) {
         int32_t width, height;
-        CHECK(meta->findInt32(kKeyWidth, &width));
-        CHECK(meta->findInt32(kKeyHeight, &height));
+        if (!meta->findInt32(kKeyWidth, &width)
+                || !meta->findInt32(kKeyHeight, &height)) {
+            return BAD_VALUE;
+        }
 
         msg->setInt32("width", width);
         msg->setInt32("height", height);
@@ -147,8 +160,10 @@
         }
     } else if (!strncasecmp("audio/", mime, 6)) {
         int32_t numChannels, sampleRate;
-        CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
-        CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+        if (!meta->findInt32(kKeyChannelCount, &numChannels)
+                || !meta->findInt32(kKeySampleRate, &sampleRate)) {
+            return BAD_VALUE;
+        }
 
         msg->setInt32("channel-count", numChannels);
         msg->setInt32("sample-rate", sampleRate);
@@ -371,7 +386,9 @@
 
     } else if (meta->findData(kKeyESDS, &type, &data, &size)) {
         ESDS esds((const char *)data, size);
-        CHECK_EQ(esds.InitCheck(), (status_t)OK);
+        if (esds.InitCheck() != (status_t)OK) {
+            return BAD_VALUE;
+        }
 
         const void *codec_specific_data;
         size_t codec_specific_data_size;
@@ -453,6 +470,13 @@
         msg->setBuffer("csd-2", buffer);
     }
 
+    // TODO expose "crypto-key"/kKeyCryptoKey through public api
+    if (meta->findData(kKeyCryptoKey, &type, &data, &size)) {
+        sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
+        msg->setBuffer("crypto-key", buffer);
+        memcpy(buffer->data(), data, size);
+    }
+
     *format = msg;
 
     return OK;
@@ -567,6 +591,41 @@
 
 }
 
+static size_t reassembleHVCC(const sp<ABuffer> &csd0, uint8_t *hvcc, size_t hvccSize, size_t nalSizeLength) {
+    HevcParameterSets paramSets;
+    uint8_t* data = csd0->data();
+    if (csd0->size() < 4) {
+        ALOGE("csd0 too small");
+        return 0;
+    }
+    if (memcmp(data, "\x00\x00\x00\x01", 4) != 0) {
+        ALOGE("csd0 doesn't start with a start code");
+        return 0;
+    }
+    size_t prevNalOffset = 4;
+    status_t err = OK;
+    for (size_t i = 1; i < csd0->size() - 4; ++i) {
+        if (memcmp(&data[i], "\x00\x00\x00\x01", 4) != 0) {
+            continue;
+        }
+        err = paramSets.addNalUnit(&data[prevNalOffset], i - prevNalOffset);
+        if (err != OK) {
+            return 0;
+        }
+        prevNalOffset = i + 4;
+    }
+    err = paramSets.addNalUnit(&data[prevNalOffset], csd0->size() - prevNalOffset);
+    if (err != OK) {
+        return 0;
+    }
+    size_t size = hvccSize;
+    err = paramSets.makeHvcc(hvcc, &size, nalSizeLength);
+    if (err != OK) {
+        return 0;
+    }
+    return size;
+}
+
 void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
     AString mime;
     if (msg->findString("mime", &mime)) {
@@ -685,6 +744,10 @@
             // for transporting the CSD to muxers.
             reassembleESDS(csd0, esds);
             meta->setData(kKeyESDS, kKeyESDS, esds, sizeof(esds));
+        } else if (mime == MEDIA_MIMETYPE_VIDEO_HEVC) {
+            uint8_t hvcc[1024]; // that oughta be enough, right?
+            size_t outsize = reassembleHVCC(csd0, hvcc, 1024, 4);
+            meta->setData(kKeyHVCC, kKeyHVCC, hvcc, outsize);
         }
     }
 
@@ -1007,5 +1070,37 @@
     *sync = settings;
 }
 
+AString nameForFd(int fd) {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    AString result;
+    snprintf(buffer, SIZE, "/proc/%d/fd/%d", getpid(), fd);
+    struct stat s;
+    if (lstat(buffer, &s) == 0) {
+        if ((s.st_mode & S_IFMT) == S_IFLNK) {
+            char linkto[256];
+            int len = readlink(buffer, linkto, sizeof(linkto));
+            if(len > 0) {
+                if(len > 255) {
+                    linkto[252] = '.';
+                    linkto[253] = '.';
+                    linkto[254] = '.';
+                    linkto[255] = 0;
+                } else {
+                    linkto[len] = 0;
+                }
+                result.append(linkto);
+            }
+        } else {
+            result.append("unexpected type for ");
+            result.append(buffer);
+        }
+    } else {
+        result.append("couldn't open ");
+        result.append(buffer);
+    }
+    return result;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/VBRISeeker.cpp b/media/libstagefright/VBRISeeker.cpp
index 8a0fcac..58f2c60 100644
--- a/media/libstagefright/VBRISeeker.cpp
+++ b/media/libstagefright/VBRISeeker.cpp
@@ -149,7 +149,7 @@
 }
 
 bool VBRISeeker::getOffsetForTime(int64_t *timeUs, off64_t *pos) {
-    if (mDurationUs < 0) {
+    if (mDurationUs < 0 || mSegments.size() == 0) {
         return false;
     }
 
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 811929b..680c0c6 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -116,7 +116,7 @@
     return mInitCheck == OK ? 1 : 0;
 }
 
-sp<MediaSource> WAVExtractor::getTrack(size_t index) {
+sp<IMediaSource> WAVExtractor::getTrack(size_t index) {
     if (mInitCheck != OK || index > 0) {
         return NULL;
     }
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index bc48272..d1b2f54 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -95,7 +95,7 @@
     return (mImpl != NULL) ? mImpl->countTracks() : 0;
 }
 
-sp<MediaSource> WVMExtractor::getTrack(size_t index) {
+sp<IMediaSource> WVMExtractor::getTrack(size_t index) {
     if (mImpl == NULL) {
         return NULL;
     }
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index bebb9dc..9e596ff 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -30,7 +30,7 @@
 
 namespace android {
 
-AACEncoder::AACEncoder(const sp<MediaSource> &source, const sp<MetaData> &meta)
+AACEncoder::AACEncoder(const sp<IMediaSource> &source, const sp<MetaData> &meta)
     : mSource(source),
       mMeta(meta),
       mStarted(false),
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
index 35aa883..96e2f87 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
@@ -20,9 +20,11 @@
 
 #include "SoftAACEncoder2.h"
 #include <OMX_AudioExt.h>
+#include <OMX_IndexExt.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/hexdump.h>
+#include <utils/misc.h>
 
 namespace android {
 
@@ -35,6 +37,14 @@
     params->nVersion.s.nStep = 0;
 }
 
+static const OMX_U32 kSupportedProfiles[] = {
+    OMX_AUDIO_AACObjectLC,
+    OMX_AUDIO_AACObjectHE,
+    OMX_AUDIO_AACObjectHE_PS,
+    OMX_AUDIO_AACObjectLD,
+    OMX_AUDIO_AACObjectELD,
+};
+
 SoftAACEncoder2::SoftAACEncoder2(
         const char *name,
         const OMX_CALLBACKTYPE *callbacks,
@@ -117,7 +127,7 @@
 
 OMX_ERRORTYPE SoftAACEncoder2::internalGetParameter(
         OMX_INDEXTYPE index, OMX_PTR params) {
-    switch (index) {
+    switch ((OMX_U32) index) {
         case OMX_IndexParamAudioPortFormat:
         {
             OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
@@ -220,6 +230,25 @@
             return OMX_ErrorNone;
         }
 
+        case OMX_IndexParamAudioProfileQuerySupported:
+        {
+            OMX_AUDIO_PARAM_ANDROID_PROFILETYPE *profileParams =
+                (OMX_AUDIO_PARAM_ANDROID_PROFILETYPE *)params;
+
+            if (profileParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (profileParams->nProfileIndex >= NELEM(kSupportedProfiles)) {
+                return OMX_ErrorNoMore;
+            }
+
+            profileParams->eProfile =
+                kSupportedProfiles[profileParams->nProfileIndex];
+
+            return OMX_ErrorNone;
+        }
+
         default:
             return SimpleSoftOMXComponent::internalGetParameter(index, params);
     }
diff --git a/media/libstagefright/codecs/amrnb/common/Android.mk b/media/libstagefright/codecs/amrnb/common/Android.mk
index 3e4c8c7..15220a4 100644
--- a/media/libstagefright/codecs/amrnb/common/Android.mk
+++ b/media/libstagefright/codecs/amrnb/common/Android.mk
@@ -69,7 +69,8 @@
 
 LOCAL_CFLAGS += -Werror
 LOCAL_CLANG := true
-LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
+#addressing b/25409744
+#LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
 
 LOCAL_MODULE := libstagefright_amrnb_common
 
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk
index b966762..7967ec3 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.mk
+++ b/media/libstagefright/codecs/amrnb/dec/Android.mk
@@ -49,7 +49,7 @@
 
 LOCAL_CFLAGS += -Werror
 LOCAL_CLANG := true
-LOCAL_SANITIZE := signed-integer-overflow
+#LOCAL_SANITIZE := signed-integer-overflow
 
 LOCAL_MODULE := libstagefright_amrnbdec
 
@@ -74,7 +74,7 @@
 
 LOCAL_CFLAGS += -Werror
 LOCAL_CLANG := true
-LOCAL_SANITIZE := signed-integer-overflow
+#LOCAL_SANITIZE := signed-integer-overflow
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_amrnbdec libstagefright_amrwbdec
@@ -105,7 +105,7 @@
         libstagefright_amrnb_common libaudioutils liblog
 
 LOCAL_CLANG := true
-LOCAL_SANITIZE := signed-integer-overflow
+#LOCAL_SANITIZE := signed-integer-overflow
 
 LOCAL_MODULE := libstagefright_amrnbdec_test
 LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk
index 9216124..f8a41af 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.mk
+++ b/media/libstagefright/codecs/amrnb/enc/Android.mk
@@ -71,7 +71,8 @@
 
 LOCAL_CFLAGS += -Werror
 LOCAL_CLANG := true
-LOCAL_SANITIZE := signed-integer-overflow
+#addressing b/25409744
+#LOCAL_SANITIZE := signed-integer-overflow
 
 LOCAL_MODULE := libstagefright_amrnbenc
 
@@ -94,7 +95,8 @@
 
 LOCAL_CFLAGS += -Werror
 LOCAL_CLANG := true
-LOCAL_SANITIZE := signed-integer-overflow
+#addressing b/25409744
+#LOCAL_SANITIZE := signed-integer-overflow
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_amrnbenc
@@ -126,7 +128,8 @@
     libstagefright_amrnb_common
 
 LOCAL_CLANG := true
-LOCAL_SANITIZE := signed-integer-overflow
+#addressing b/25409744
+#LOCAL_SANITIZE := signed-integer-overflow
 
 LOCAL_MODULE := libstagefright_amrnbenc_test
 LOCAL_MODULE_TAGS := tests
diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
index d0ad4f8..e378a62 100644
--- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
+++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
@@ -28,6 +28,8 @@
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
+#include <OMX_IndexExt.h>
+#include <OMX_VideoExt.h>
 #include <ui/Rect.h>
 
 #include "ih264_typedefs.h"
@@ -1026,9 +1028,29 @@
     }
 }
 
+OMX_ERRORTYPE SoftAVC::getConfig(
+        OMX_INDEXTYPE index, OMX_PTR _params) {
+    switch ((int)index) {
+        case OMX_IndexConfigAndroidIntraRefresh:
+        {
+            OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *intraRefreshParams =
+                (OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *)_params;
+            if (intraRefreshParams->nPortIndex != kOutputPortIndex) {
+                return OMX_ErrorUndefined;
+            }
+
+            intraRefreshParams->nRefreshPeriod = mAIRRefreshPeriod;
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SoftVideoEncoderOMXComponent::getConfig(index, _params);
+    }
+}
+
 OMX_ERRORTYPE SoftAVC::setConfig(
         OMX_INDEXTYPE index, const OMX_PTR _params) {
-    switch (index) {
+    switch ((int)index) {
         case OMX_IndexConfigVideoIntraVOPRefresh:
         {
             OMX_CONFIG_INTRAREFRESHVOPTYPE *params =
@@ -1060,6 +1082,25 @@
             return OMX_ErrorNone;
         }
 
+        case OMX_IndexConfigAndroidIntraRefresh:
+        {
+            const OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *intraRefreshParams =
+                (const OMX_VIDEO_CONFIG_ANDROID_INTRAREFRESHTYPE *)_params;
+            if (intraRefreshParams->nPortIndex != kOutputPortIndex) {
+                return OMX_ErrorUndefined;
+            }
+
+            if (intraRefreshParams->nRefreshPeriod == 0) {
+                mAIRMode = IVE_AIR_MODE_NONE;
+                mAIRRefreshPeriod = 0;
+            } else if (intraRefreshParams->nRefreshPeriod > 0) {
+                mAIRMode = IVE_AIR_MODE_CYCLIC;
+                mAIRRefreshPeriod = intraRefreshParams->nRefreshPeriod;
+            }
+            mUpdateFlag |= kUpdateAIRMode;
+            return OMX_ErrorNone;
+        }
+
         default:
             return SimpleSoftOMXComponent::setConfig(index, _params);
     }
@@ -1299,6 +1340,11 @@
             if (mUpdateFlag & kRequestKeyFrame) {
                 setFrameType(IV_IDR_FRAME);
             }
+            if (mUpdateFlag & kUpdateAIRMode) {
+                setAirParams();
+                notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
+                        OMX_IndexConfigAndroidIntraRefresh, NULL);
+            }
             mUpdateFlag = 0;
         }
 
diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.h b/media/libstagefright/codecs/avcenc/SoftAVCEnc.h
index 6a3bc0f..232c6e0 100644
--- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.h
+++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.h
@@ -143,8 +143,9 @@
     };
 
     enum {
-      kUpdateBitrate            = 1 << 0,
-      kRequestKeyFrame          = 1 << 1,
+        kUpdateBitrate            = 1 << 0,
+        kRequestKeyFrame          = 1 << 1,
+        kUpdateAIRMode            = 1 << 2,
     };
 
     // OMX input buffer's timestamp and flags
@@ -219,6 +220,9 @@
     OMX_ERRORTYPE setConfig(
         OMX_INDEXTYPE index, const OMX_PTR _params);
 
+    OMX_ERRORTYPE getConfig(
+        OMX_INDEXTYPE index, const OMX_PTR _params);
+
     // Handles port definition changes.
     OMX_ERRORTYPE internalSetPortParams(
         const OMX_PARAM_PORTDEFINITIONTYPE *port);
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
index 8240f83..f2a4e65 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
@@ -37,6 +37,10 @@
 
 #include <inttypes.h>
 
+#ifndef INT32_MAX
+#define INT32_MAX   2147483647
+#endif
+
 namespace android {
 
 template<class T>
@@ -137,6 +141,11 @@
     if (mColorFormat != OMX_COLOR_FormatYUV420Planar || mInputDataIsMeta) {
         // Color conversion is needed.
         free(mInputFrameData);
+        mInputFrameData = NULL;
+        if (((uint64_t)mWidth * mHeight) > ((uint64_t)INT32_MAX / 3)) {
+            ALOGE("b/25812794, Buffer size is too big.");
+            return OMX_ErrorBadParameter;
+        }
         mInputFrameData =
             (uint8_t *) malloc((mWidth * mHeight * 3 ) >> 1);
         CHECK(mInputFrameData != NULL);
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
index cd6c3b1..7fafb6f 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
@@ -209,6 +209,8 @@
                     mEOSStatus == INPUT_EOS_SEEN) {
                 return;
             }
+            // Continue as outQueue may be empty now.
+            continue;
         }
 
         BufferInfo *inInfo = *inQueue.begin();
@@ -220,15 +222,23 @@
             EOSseen = true;
         }
 
-        if (inHeader->nFilledLen > 0 &&
-            vpx_codec_decode((vpx_codec_ctx_t *)mCtx,
-                              inHeader->pBuffer + inHeader->nOffset,
-                              inHeader->nFilledLen,
-                              &mTimeStamps[mTimeStampIdx], 0)) {
-            ALOGE("on2 decoder failed to decode frame.");
-            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
-            return;
+        if (inHeader->nFilledLen > 0) {
+            vpx_codec_err_t err = vpx_codec_decode(
+                    (vpx_codec_ctx_t *)mCtx, inHeader->pBuffer + inHeader->nOffset,
+                    inHeader->nFilledLen, &mTimeStamps[mTimeStampIdx], 0);
+            if (err == VPX_CODEC_OK) {
+                inInfo->mOwnedByUs = false;
+                inQueue.erase(inQueue.begin());
+                inInfo = NULL;
+                notifyEmptyBufferDone(inHeader);
+                inHeader = NULL;
+            } else {
+                ALOGE("on2 decoder failed to decode frame.");
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                return;
+            }
         }
+
         mTimeStampIdx = (mTimeStampIdx + 1) % kNumBuffers;
 
         if (!outputBuffers(
@@ -240,12 +250,6 @@
         if (portWillReset) {
             return;
         }
-
-        inInfo->mOwnedByUs = false;
-        inQueue.erase(inQueue.begin());
-        inInfo = NULL;
-        notifyEmptyBufferDone(inHeader);
-        inHeader = NULL;
     }
 }
 
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
index e654843..0f28e8d 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
@@ -26,6 +26,10 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaDefs.h>
 
+#ifndef INT32_MAX
+#define INT32_MAX   2147483647
+#endif
+
 namespace android {
 
 template<class T>
@@ -102,24 +106,24 @@
 
 status_t SoftVPXEncoder::initEncoder() {
     vpx_codec_err_t codec_return;
+    status_t result = UNKNOWN_ERROR;
 
-    mCodecContext = new vpx_codec_ctx_t;
-    mCodecConfiguration = new vpx_codec_enc_cfg_t;
     mCodecInterface = vpx_codec_vp8_cx();
-
     if (mCodecInterface == NULL) {
-        return UNKNOWN_ERROR;
+        goto CLEAN_UP;
     }
     ALOGD("VP8: initEncoder. BRMode: %u. TSLayers: %zu. KF: %u. QP: %u - %u",
           (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval,
           mMinQuantizer, mMaxQuantizer);
+
+    mCodecConfiguration = new vpx_codec_enc_cfg_t;
     codec_return = vpx_codec_enc_config_default(mCodecInterface,
                                                 mCodecConfiguration,
                                                 0);  // Codec specific flags
 
     if (codec_return != VPX_CODEC_OK) {
         ALOGE("Error populating default configuration for vpx encoder.");
-        return UNKNOWN_ERROR;
+        goto CLEAN_UP;
     }
 
     mCodecConfiguration->g_w = mWidth;
@@ -246,7 +250,7 @@
         default:
         {
             ALOGE("Wrong number of temporal layers %zu", mTemporalLayers);
-            return UNKNOWN_ERROR;
+            goto CLEAN_UP;
         }
     }
 
@@ -268,6 +272,7 @@
         mCodecConfiguration->rc_max_quantizer = mMaxQuantizer;
     }
 
+    mCodecContext = new vpx_codec_ctx_t;
     codec_return = vpx_codec_enc_init(mCodecContext,
                                       mCodecInterface,
                                       mCodecConfiguration,
@@ -275,7 +280,7 @@
 
     if (codec_return != VPX_CODEC_OK) {
         ALOGE("Error initializing vpx encoder");
-        return UNKNOWN_ERROR;
+        goto CLEAN_UP;
     }
 
     codec_return = vpx_codec_control(mCodecContext,
@@ -283,7 +288,7 @@
                                      mDCTPartitions);
     if (codec_return != VPX_CODEC_OK) {
         ALOGE("Error setting dct partitions for vpx encoder.");
-        return UNKNOWN_ERROR;
+        goto CLEAN_UP;
     }
 
     // Extra CBR settings
@@ -309,19 +314,28 @@
         }
         if (codec_return != VPX_CODEC_OK) {
             ALOGE("Error setting cbr parameters for vpx encoder.");
-            return UNKNOWN_ERROR;
+            goto CLEAN_UP;
         }
     }
 
     if (mColorFormat != OMX_COLOR_FormatYUV420Planar || mInputDataIsMeta) {
         free(mConversionBuffer);
+        mConversionBuffer = NULL;
+        if (((uint64_t)mWidth * mHeight) > ((uint64_t)INT32_MAX / 3)) {
+            ALOGE("b/25812794, Buffer size is too big, width=%d, height=%d.", mWidth, mHeight);
+            goto CLEAN_UP;
+        }
         mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2);
         if (mConversionBuffer == NULL) {
             ALOGE("Allocating conversion buffer failed.");
-            return UNKNOWN_ERROR;
+            goto CLEAN_UP;
         }
     }
     return OK;
+
+CLEAN_UP:
+    releaseEncoder();
+    return result;
 }
 
 
diff --git a/media/libstagefright/codecs/raw/SoftRaw.cpp b/media/libstagefright/codecs/raw/SoftRaw.cpp
index 9d514a6..9d3bab8 100644
--- a/media/libstagefright/codecs/raw/SoftRaw.cpp
+++ b/media/libstagefright/codecs/raw/SoftRaw.cpp
@@ -159,7 +159,16 @@
         }
 
         default:
-            return SimpleSoftOMXComponent::internalSetParameter(index, params);
+        {
+            OMX_ERRORTYPE err = SimpleSoftOMXComponent::internalSetParameter(
+                    index, params);
+            // In case inPort->mDef.nBufferSize changed, the output buffer size
+            // should match the input buffer size.
+            PortInfo *inPort = editPortInfo(0);
+            PortInfo *outPort = editPortInfo(1);
+            outPort->mDef.nBufferSize = inPort->mDef.nBufferSize;
+            return err;
+        }
     }
 }
 
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index c559682..3b1b2dc 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -56,6 +56,7 @@
       mNumFramesLeftOnPage(-1),
       mSawInputEos(false),
       mSignalledOutputEos(false),
+      mSignalledError(false),
       mOutputPortSettingsChange(NONE) {
     initPorts();
     CHECK_EQ(initDecoder(), (status_t)OK);
@@ -247,7 +248,7 @@
     List<BufferInfo *> &inQueue = getPortQueue(0);
     List<BufferInfo *> &outQueue = getPortQueue(1);
 
-    if (mOutputPortSettingsChange != NONE) {
+    if (mSignalledError || mOutputPortSettingsChange != NONE) {
         return;
     }
 
@@ -271,9 +272,19 @@
             mVi = new vorbis_info;
             vorbis_info_init(mVi);
 
-            CHECK_EQ(0, _vorbis_unpack_info(mVi, &bits));
+            int ret = _vorbis_unpack_info(mVi, &bits);
+            if (ret != 0) {
+                notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
+                mSignalledError = true;
+                return;
+            }
         } else {
-            CHECK_EQ(0, _vorbis_unpack_books(mVi, &bits));
+            int ret = _vorbis_unpack_books(mVi, &bits);
+            if (ret != 0) {
+                notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
+                mSignalledError = true;
+                return;
+            }
 
             CHECK(mState == NULL);
             mState = new vorbis_dsp_state;
@@ -418,6 +429,9 @@
         // depend on fragments from the last one decoded.
 
         mNumFramesOutput = 0;
+        mSawInputEos = false;
+        mSignalledOutputEos = false;
+        mNumFramesLeftOnPage = -1;
         vorbis_dsp_restart(mState);
     }
 }
@@ -439,6 +453,7 @@
 
     mSawInputEos = false;
     mSignalledOutputEos = false;
+    mSignalledError = false;
     mOutputPortSettingsChange = NONE;
 }
 
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
index 1d00816..30d137b 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
@@ -61,6 +61,7 @@
     int32_t mNumFramesLeftOnPage;
     bool mSawInputEos;
     bool mSignalledOutputEos;
+    bool mSignalledError;
 
     enum {
         NONE,
diff --git a/media/libstagefright/data/media_codecs_google_video.xml b/media/libstagefright/data/media_codecs_google_video.xml
index 81a6d00..b03c769 100644
--- a/media/libstagefright/data/media_codecs_google_video.xml
+++ b/media/libstagefright/data/media_codecs_google_video.xml
@@ -84,6 +84,7 @@
             <Limit name="block-size" value="16x16" />
             <Limit name="blocks-per-second" range="1-244800" />
             <Limit name="bitrate" range="1-12000000" />
+            <Feature name="intra-refresh" />
         </MediaCodec>
         <MediaCodec name="OMX.google.mpeg4.encoder" type="video/mp4v-es">
             <!-- profiles and levels:  ProfileCore : Level2 -->
diff --git a/media/libstagefright/filters/GraphicBufferListener.cpp b/media/libstagefright/filters/GraphicBufferListener.cpp
index a606315..c1aaa17 100644
--- a/media/libstagefright/filters/GraphicBufferListener.cpp
+++ b/media/libstagefright/filters/GraphicBufferListener.cpp
@@ -101,11 +101,11 @@
     if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
         // shouldn't happen, since we track num frames available
         ALOGE("frame was not available");
-        item.mBuf = -1;
+        item.mSlot = -1;
         return item;
     } else if (err != OK) {
         ALOGE("acquireBuffer returned err=%d", err);
-        item.mBuf = -1;
+        item.mSlot = -1;
         return item;
     }
 
@@ -119,8 +119,8 @@
     // If this is the first time we're seeing this buffer, add it to our
     // slot table.
     if (item.mGraphicBuffer != NULL) {
-        ALOGV("setting mBufferSlot %d", item.mBuf);
-        mBufferSlot[item.mBuf] = item.mGraphicBuffer;
+        ALOGV("setting mBufferSlot %d", item.mSlot);
+        mBufferSlot[item.mSlot] = item.mGraphicBuffer;
     }
 
     return item;
@@ -128,24 +128,24 @@
 
 sp<GraphicBuffer> GraphicBufferListener::getBuffer(BufferItem item) {
     sp<GraphicBuffer> buf;
-    if (item.mBuf < 0 || item.mBuf >= BufferQueue::NUM_BUFFER_SLOTS) {
-        ALOGE("getBuffer() received invalid BufferItem: mBuf==%d", item.mBuf);
+    if (item.mSlot < 0 || item.mSlot >= BufferQueue::NUM_BUFFER_SLOTS) {
+        ALOGE("getBuffer() received invalid BufferItem: mSlot==%d", item.mSlot);
         return buf;
     }
 
-    buf = mBufferSlot[item.mBuf];
+    buf = mBufferSlot[item.mSlot];
     CHECK(buf.get() != NULL);
 
     return buf;
 }
 
 status_t GraphicBufferListener::releaseBuffer(BufferItem item) {
-    if (item.mBuf < 0 || item.mBuf >= BufferQueue::NUM_BUFFER_SLOTS) {
-        ALOGE("getBuffer() received invalid BufferItem: mBuf==%d", item.mBuf);
+    if (item.mSlot < 0 || item.mSlot >= BufferQueue::NUM_BUFFER_SLOTS) {
+        ALOGE("getBuffer() received invalid BufferItem: mSlot==%d", item.mSlot);
         return ERROR_OUT_OF_RANGE;
     }
 
-    mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber,
+    mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
             EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
 
     return OK;
diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp
index 0cf6b06..cd69418 100644
--- a/media/libstagefright/filters/MediaFilter.cpp
+++ b/media/libstagefright/filters/MediaFilter.cpp
@@ -773,7 +773,7 @@
     convertRGBAToARGB(
             (uint8_t*)bufPtr, buf->getWidth(), buf->getHeight(),
             buf->getStride(), inputInfo->mData->data());
-    inputInfo->mBufferID = item.mBuf;
+    inputInfo->mBufferID = item.mSlot;
     inputInfo->mGeneration = mGeneration;
     inputInfo->mOutputFlags = 0;
     inputInfo->mStatus = BufferInfo::OWNED_BY_US;
diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp
index 5c2e9f9..9921636 100644
--- a/media/libstagefright/foundation/ALooper.cpp
+++ b/media/libstagefright/foundation/ALooper.cpp
@@ -234,31 +234,19 @@
 
 // to be called by AMessage::postAndAwaitResponse only
 status_t ALooper::awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response) {
-    {
-        Mutex::Autolock autoLock(mLock);
-        if (mThread == NULL) {
-            return -ENOENT;
-        }
-    }
-
     // return status in case we want to handle an interrupted wait
     Mutex::Autolock autoLock(mRepliesLock);
     CHECK(replyToken != NULL);
-    bool gotReply;
-    bool shouldContinue = true;
-    while (!(gotReply = replyToken->retrieveReply(response)) && shouldContinue) {
-        mRepliesCondition.wait(mRepliesLock);
-
+    while (!replyToken->retrieveReply(response)) {
         {
             Mutex::Autolock autoLock(mLock);
             if (mThread == NULL) {
-                shouldContinue = false;
-                // continue and try to get potential reply one more time before break the loop
+                return -ENOENT;
             }
         }
+        mRepliesCondition.wait(mRepliesLock);
     }
-
-    return gotReply ? OK : -ENOENT;
+    return OK;
 }
 
 status_t ALooper::postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &reply) {
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index 6c70e98..e17534f 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -15,6 +15,8 @@
     AString.cpp                   \
     AStringUtils.cpp              \
     AWakeLock.cpp                 \
+    MediaBuffer.cpp               \
+    MetaData.cpp                  \
     ParsedMessage.cpp             \
     base64.cpp                    \
     hexdump.cpp
@@ -32,6 +34,7 @@
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 LOCAL_CLANG := true
 LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
+
 LOCAL_MODULE:= libstagefright_foundation
 
 
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
similarity index 85%
rename from media/libstagefright/MediaBuffer.cpp
rename to media/libstagefright/foundation/MediaBuffer.cpp
index 1f80a47..d83a351 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/foundation/MediaBuffer.cpp
@@ -30,6 +30,9 @@
 
 namespace android {
 
+// allocations larger than this will use shared memory
+static const size_t kSharedMemThreshold = 64 * 1024;
+
 MediaBuffer::MediaBuffer(void *data, size_t size)
     : mObserver(NULL),
       mNextBuffer(NULL),
@@ -47,13 +50,29 @@
     : mObserver(NULL),
       mNextBuffer(NULL),
       mRefCount(0),
-      mData(malloc(size)),
+      mData(NULL),
       mSize(size),
       mRangeOffset(0),
       mRangeLength(size),
       mOwnsData(true),
       mMetaData(new MetaData),
       mOriginal(NULL) {
+    if (size < kSharedMemThreshold) {
+        mData = malloc(size);
+    } else {
+        sp<MemoryDealer> memoryDealer = new MemoryDealer(size, "MediaBuffer");
+        mMemory = memoryDealer->allocate(size);
+        if (mMemory == NULL) {
+            ALOGW("Failed to allocate shared memory, trying regular allocation!");
+            mData = malloc(size);
+            if (mData == NULL) {
+                ALOGE("Out of memory");
+            }
+        } else {
+            mData = mMemory->pointer();
+            ALOGV("Allocated shared mem buffer of size %zu @ %p", size, mData);
+        }
+    }
 }
 
 MediaBuffer::MediaBuffer(const sp<GraphicBuffer>& graphicBuffer)
@@ -158,7 +177,7 @@
 MediaBuffer::~MediaBuffer() {
     CHECK(mObserver == NULL);
 
-    if (mOwnsData && mData != NULL) {
+    if (mOwnsData && mData != NULL && mMemory == NULL) {
         free(mData);
         mData = NULL;
     }
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/foundation/MetaData.cpp
similarity index 84%
rename from media/libstagefright/MetaData.cpp
rename to media/libstagefright/foundation/MetaData.cpp
index 1a11c1e..b847eed 100644
--- a/media/libstagefright/MetaData.cpp
+++ b/media/libstagefright/foundation/MetaData.cpp
@@ -107,7 +107,7 @@
 }
 
 bool MetaData::findInt32(uint32_t key, int32_t *value) {
-    uint32_t type;
+    uint32_t type = 0;
     const void *data;
     size_t size;
     if (!findData(key, &type, &data, &size) || type != TYPE_INT32) {
@@ -122,7 +122,7 @@
 }
 
 bool MetaData::findInt64(uint32_t key, int64_t *value) {
-    uint32_t type;
+    uint32_t type = 0;
     const void *data;
     size_t size;
     if (!findData(key, &type, &data, &size) || type != TYPE_INT64) {
@@ -137,7 +137,7 @@
 }
 
 bool MetaData::findFloat(uint32_t key, float *value) {
-    uint32_t type;
+    uint32_t type = 0;
     const void *data;
     size_t size;
     if (!findData(key, &type, &data, &size) || type != TYPE_FLOAT) {
@@ -152,7 +152,7 @@
 }
 
 bool MetaData::findPointer(uint32_t key, void **value) {
-    uint32_t type;
+    uint32_t type = 0;
     const void *data;
     size_t size;
     if (!findData(key, &type, &data, &size) || type != TYPE_POINTER) {
@@ -170,7 +170,7 @@
         uint32_t key,
         int32_t *left, int32_t *top,
         int32_t *right, int32_t *bottom) {
-    uint32_t type;
+    uint32_t type = 0;
     const void *data;
     size_t size;
     if (!findData(key, &type, &data, &size) || type != TYPE_RECT) {
@@ -377,5 +377,57 @@
     }
 }
 
+status_t MetaData::writeToParcel(Parcel &parcel) {
+    size_t numItems = mItems.size();
+    parcel.writeUint32(uint32_t(numItems));
+    for (size_t i = 0; i < numItems; i++) {
+        int32_t key = mItems.keyAt(i);
+        const typed_data &item = mItems.valueAt(i);
+        uint32_t type;
+        const void *data;
+        size_t size;
+        item.getData(&type, &data, &size);
+        parcel.writeInt32(key);
+        parcel.writeUint32(type);
+        parcel.writeByteArray(size, (uint8_t*)data);
+    }
+    return OK;
+}
+
+status_t MetaData::updateFromParcel(const Parcel &parcel) {
+    uint32_t numItems;
+    if (parcel.readUint32(&numItems) == OK) {
+
+        for (size_t i = 0; i < numItems; i++) {
+            int32_t key;
+            uint32_t type;
+            uint32_t size;
+            status_t ret = parcel.readInt32(&key);
+            ret |= parcel.readUint32(&type);
+            ret |= parcel.readUint32(&size);
+            if (ret != OK) {
+                break;
+            }
+            // copy data directly from Parcel storage, then advance position
+            setData(key, type, parcel.readInplace(size), size);
+         }
+
+        return OK;
+    }
+    ALOGW("no metadata in parcel");
+    return UNKNOWN_ERROR;
+}
+
+
+/* static */
+sp<MetaData> MetaData::createFromParcel(const Parcel &parcel) {
+
+    sp<MetaData> meta = new MetaData();
+    meta->updateFromParcel(parcel);
+    return meta;
+}
+
+
+
 }  // namespace android
 
diff --git a/media/libstagefright/httplive/HTTPDownloader.cpp b/media/libstagefright/httplive/HTTPDownloader.cpp
index dff6b0b..861b85a 100644
--- a/media/libstagefright/httplive/HTTPDownloader.cpp
+++ b/media/libstagefright/httplive/HTTPDownloader.cpp
@@ -31,6 +31,7 @@
 #include <openssl/aes.h>
 #include <openssl/md5.h>
 #include <utils/Mutex.h>
+#include <inttypes.h>
 
 namespace android {
 
@@ -165,7 +166,10 @@
         size_t maxBytesToRead = bufferRemaining;
         if (range_length >= 0) {
             int64_t bytesLeftInRange = range_length - buffer->size();
-            if (bytesLeftInRange < (int64_t)maxBytesToRead) {
+            if (bytesLeftInRange < 0) {
+                ALOGE("range_length %" PRId64 " wrapped around", range_length);
+                return ERROR_OUT_OF_RANGE;
+            } else if (bytesLeftInRange < (int64_t)maxBytesToRead) {
                 maxBytesToRead = bytesLeftInRange;
 
                 if (bytesLeftInRange == 0) {
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 1557401..cebf95c 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -477,7 +477,7 @@
     sp<MetaData> meta = packetSource->getFormat();
 
     if (meta == NULL) {
-        return -EAGAIN;
+        return -EWOULDBLOCK;
     }
 
     if (stream == STREAMTYPE_AUDIO) {
diff --git a/media/libstagefright/include/AACEncoder.h b/media/libstagefright/include/AACEncoder.h
index 52beb0e..462e905 100644
--- a/media/libstagefright/include/AACEncoder.h
+++ b/media/libstagefright/include/AACEncoder.h
@@ -27,9 +27,9 @@
 
 class MediaBufferGroup;
 
-class AACEncoder: public MediaSource {
+class AACEncoder: public BnMediaSource {
     public:
-        AACEncoder(const sp<MediaSource> &source, const sp<MetaData> &meta);
+        AACEncoder(const sp<IMediaSource> &source, const sp<MetaData> &meta);
 
         virtual status_t start(MetaData *params);
         virtual status_t stop();
@@ -42,7 +42,7 @@
         virtual ~AACEncoder();
 
     private:
-        sp<MediaSource>   mSource;
+        sp<IMediaSource>   mSource;
         sp<MetaData>      mMeta;
         bool              mStarted;
         MediaBufferGroup *mBufferGroup;
diff --git a/media/libstagefright/include/AACExtractor.h b/media/libstagefright/include/AACExtractor.h
index e98ca82..e231e62 100644
--- a/media/libstagefright/include/AACExtractor.h
+++ b/media/libstagefright/include/AACExtractor.h
@@ -32,7 +32,7 @@
     AACExtractor(const sp<DataSource> &source, const sp<AMessage> &meta);
 
     virtual size_t countTracks();
-    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<IMediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/AMRExtractor.h b/media/libstagefright/include/AMRExtractor.h
index 4a1c827..0770397 100644
--- a/media/libstagefright/include/AMRExtractor.h
+++ b/media/libstagefright/include/AMRExtractor.h
@@ -32,7 +32,7 @@
     AMRExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
-    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<IMediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/CallbackDataSource.h b/media/libstagefright/include/CallbackDataSource.h
index 1a21dd3..8c6fd8f 100644
--- a/media/libstagefright/include/CallbackDataSource.h
+++ b/media/libstagefright/include/CallbackDataSource.h
@@ -36,6 +36,7 @@
     virtual status_t initCheck() const;
     virtual ssize_t readAt(off64_t offset, void *data, size_t size);
     virtual status_t getSize(off64_t *size);
+    virtual uint32_t flags();
 
 private:
     sp<IDataSource> mIDataSource;
diff --git a/media/libstagefright/include/DRMExtractor.h b/media/libstagefright/include/DRMExtractor.h
index b4e4afb..a035d8c 100644
--- a/media/libstagefright/include/DRMExtractor.h
+++ b/media/libstagefright/include/DRMExtractor.h
@@ -18,6 +18,7 @@
 
 #define DRM_EXTRACTOR_H_
 
+#include <media/IMediaSource.h>
 #include <media/stagefright/MediaExtractor.h>
 #include <drm/DrmManagerClient.h>
 
@@ -34,7 +35,7 @@
     DRMExtractor(const sp<DataSource> &source, const char *mime);
 
     virtual size_t countTracks();
-    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<IMediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
     virtual sp<MetaData> getMetaData();
 
@@ -44,7 +45,7 @@
 private:
     sp<DataSource> mDataSource;
 
-    sp<MediaExtractor> mOriginalExtractor;
+    sp<IMediaExtractor> mOriginalExtractor;
     sp<DecryptHandle> mDecryptHandle;
     DrmManagerClient* mDrmManagerClient;
 
diff --git a/media/libstagefright/include/FLACExtractor.h b/media/libstagefright/include/FLACExtractor.h
index ded91c2..a6e6c1d 100644
--- a/media/libstagefright/include/FLACExtractor.h
+++ b/media/libstagefright/include/FLACExtractor.h
@@ -32,7 +32,7 @@
     FLACExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
-    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<IMediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/HevcUtils.h b/media/libstagefright/include/HevcUtils.h
new file mode 100644
index 0000000..0d7bb2f
--- /dev/null
+++ b/media/libstagefright/include/HevcUtils.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 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 HEVC_UTILS_H_
+
+#define HEVC_UTILS_H_
+
+#include <stdint.h>
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+enum {
+    kHevcNalUnitTypeVps = 32,
+    kHevcNalUnitTypeSps = 33,
+    kHevcNalUnitTypePps = 34,
+    kHevcNalUnitTypePrefixSei = 39,
+    kHevcNalUnitTypeSuffixSei = 40,
+};
+
+enum {
+    // uint8_t
+    kGeneralProfileSpace,
+    // uint8_t
+    kGeneralTierFlag,
+    // uint8_t
+    kGeneralProfileIdc,
+    // uint32_t
+    kGeneralProfileCompatibilityFlags,
+    // uint64_t
+    kGeneralConstraintIndicatorFlags,
+    // uint8_t
+    kGeneralLevelIdc,
+    // uint8_t
+    kChromaFormatIdc,
+    // uint8_t
+    kBitDepthLumaMinus8,
+    // uint8_t
+    kBitDepthChromaMinus8,
+};
+
+class HevcParameterSets {
+public:
+    HevcParameterSets();
+
+    status_t addNalUnit(const uint8_t* data, size_t size);
+
+    bool findParam8(uint32_t key, uint8_t *param);
+    bool findParam16(uint32_t key, uint16_t *param);
+    bool findParam32(uint32_t key, uint32_t *param);
+    bool findParam64(uint32_t key, uint64_t *param);
+
+    inline size_t getNumNalUnits() { return mNalUnits.size(); }
+    size_t getNumNalUnitsOfType(uint8_t type);
+    uint8_t getType(size_t index);
+    size_t getSize(size_t index);
+    // Note that this method does not write the start code.
+    bool write(size_t index, uint8_t* dest, size_t size);
+    status_t makeHvcc(uint8_t *hvcc, size_t *hvccSize, size_t nalSizeLength);
+
+private:
+    status_t parseVps(const uint8_t* data, size_t size);
+    status_t parseSps(const uint8_t* data, size_t size);
+    status_t parsePps(const uint8_t* data, size_t size);
+
+    KeyedVector<uint32_t, uint64_t> mParams;
+    Vector<sp<ABuffer>> mNalUnits;
+
+    DISALLOW_EVIL_CONSTRUCTORS(HevcParameterSets);
+};
+
+}  // namespace android
+
+#endif  // HEVC_UTILS_H_
diff --git a/media/libstagefright/include/MP3Extractor.h b/media/libstagefright/include/MP3Extractor.h
index c83d9e8..2fd04f2 100644
--- a/media/libstagefright/include/MP3Extractor.h
+++ b/media/libstagefright/include/MP3Extractor.h
@@ -34,10 +34,11 @@
     MP3Extractor(const sp<DataSource> &source, const sp<AMessage> &meta);
 
     virtual size_t countTracks();
-    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<IMediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
+    virtual const char * name() { return "MP3Extractor"; }
 
 private:
     status_t mInitCheck;
diff --git a/media/libstagefright/include/MPEG2PSExtractor.h b/media/libstagefright/include/MPEG2PSExtractor.h
index 22cb02d..e815f0e 100644
--- a/media/libstagefright/include/MPEG2PSExtractor.h
+++ b/media/libstagefright/include/MPEG2PSExtractor.h
@@ -34,7 +34,7 @@
     MPEG2PSExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
-    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<IMediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
index 8eb8f6c..9907572 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/libstagefright/include/MPEG2TSExtractor.h
@@ -38,7 +38,7 @@
     MPEG2TSExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
-    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<IMediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index 3067c3d..cff976d 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -53,7 +53,7 @@
     MPEG4Extractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
-    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<IMediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/MidiExtractor.h b/media/libstagefright/include/MidiExtractor.h
index 9a2abc0..333277b 100644
--- a/media/libstagefright/include/MidiExtractor.h
+++ b/media/libstagefright/include/MidiExtractor.h
@@ -56,7 +56,7 @@
     MidiExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
-    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<IMediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index e7c4f6d..9f2e5e7 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -166,13 +166,13 @@
 
     Mutex mLock;
     OMXMaster *mMaster;
-    int32_t mNodeCounter;
+    size_t mNodeCounter;
 
     KeyedVector<wp<IBinder>, OMXNodeInstance *> mLiveNodes;
     KeyedVector<node_id, OMXNodeInstance *> mNodeIDToInstance;
     KeyedVector<node_id, sp<CallbackDispatcher> > mDispatchers;
 
-    node_id makeNodeID(OMXNodeInstance *instance);
+    node_id makeNodeID_l(OMXNodeInstance *instance);
     OMXNodeInstance *findInstance(node_id node);
     sp<CallbackDispatcher> findDispatcher(node_id node);
 
diff --git a/media/libstagefright/include/OggExtractor.h b/media/libstagefright/include/OggExtractor.h
index c647cbb..592c264 100644
--- a/media/libstagefright/include/OggExtractor.h
+++ b/media/libstagefright/include/OggExtractor.h
@@ -34,10 +34,11 @@
     OggExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
-    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<IMediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
+    virtual const char * name() { return "OggExtractor"; }
 
 protected:
     virtual ~OggExtractor();
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index 61bbf6c..b7ac718 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -18,6 +18,7 @@
 
 #define STAGEFRIGHT_METADATA_RETRIEVER_H_
 
+#include <media/IMediaExtractor.h>
 #include <media/MediaMetadataRetrieverInterface.h>
 
 #include <utils/KeyedVector.h>
@@ -45,7 +46,7 @@
 
 private:
     sp<DataSource> mSource;
-    sp<MediaExtractor> mExtractor;
+    sp<IMediaExtractor> mExtractor;
 
     bool mParsedMetaData;
     KeyedVector<int, String8> mMetaData;
diff --git a/media/libstagefright/include/WAVExtractor.h b/media/libstagefright/include/WAVExtractor.h
index c567ccd..91ee870 100644
--- a/media/libstagefright/include/WAVExtractor.h
+++ b/media/libstagefright/include/WAVExtractor.h
@@ -33,10 +33,11 @@
     WAVExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
-    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<IMediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
 
     virtual sp<MetaData> getMetaData();
+    virtual const char * name() { return "WAVExtractor"; }
 
 protected:
     virtual ~WAVExtractor();
diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h
index ab7e8b8..5b91072 100644
--- a/media/libstagefright/include/WVMExtractor.h
+++ b/media/libstagefright/include/WVMExtractor.h
@@ -46,7 +46,7 @@
     WVMExtractor(const sp<DataSource> &source);
 
     virtual size_t countTracks();
-    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<IMediaSource> getTrack(size_t index);
     virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
     virtual sp<MetaData> getMetaData();
     virtual void setUID(uid_t uid);
diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk
index 1e8c2b2..b0cbf08 100644
--- a/media/libstagefright/matroska/Android.mk
+++ b/media/libstagefright/matroska/Android.mk
@@ -7,9 +7,11 @@
 LOCAL_C_INCLUDES:= \
         $(TOP)/external/libvpx/libwebm \
         $(TOP)/frameworks/native/include/media/openmax \
+        $(TOP)/frameworks/av/media/libstagefright/include \
 
 LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
 LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
 
 LOCAL_MODULE:= libstagefright_matroska
 
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 09e6b9b..861bdc5 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -19,9 +19,11 @@
 #include <utils/Log.h>
 
 #include "MatroskaExtractor.h"
+#include "avc_utils.h"
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
@@ -144,12 +146,13 @@
     Type mType;
     bool mIsAudio;
     BlockIterator mBlockIter;
-    size_t mNALSizeLen;  // for type AVC
+    ssize_t mNALSizeLen;  // for type AVC
 
     List<MediaBuffer *> mPendingFrames;
 
     status_t advance();
 
+    status_t setWebmBlockCryptoInfo(MediaBuffer *mbuf);
     status_t readBlock();
     void clearPendingFrames();
 
@@ -213,7 +216,7 @@
       mBlockIter(mExtractor.get(),
                  mExtractor->mTracks.itemAt(index).mTrackNum,
                  index),
-      mNALSizeLen(0) {
+      mNALSizeLen(-1) {
     sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta;
 
     const char *mime;
@@ -227,13 +230,18 @@
         uint32_t dummy;
         const uint8_t *avcc;
         size_t avccSize;
-        CHECK(meta->findData(
-                    kKeyAVCC, &dummy, (const void **)&avcc, &avccSize));
-
-        CHECK_GE(avccSize, 5u);
-
-        mNALSizeLen = 1 + (avcc[4] & 3);
-        ALOGV("mNALSizeLen = %zu", mNALSizeLen);
+        int32_t nalSizeLen = 0;
+        if (meta->findInt32(kKeyNalLengthSize, &nalSizeLen)) {
+            if (nalSizeLen >= 0 && nalSizeLen <= 4) {
+                mNALSizeLen = nalSizeLen;
+            }
+        } else if (meta->findData(kKeyAVCC, &dummy, (const void **)&avcc, &avccSize)
+                && avccSize >= 5u) {
+            mNALSizeLen = 1 + (avcc[4] & 3);
+            ALOGV("mNALSizeLen = %zd", mNALSizeLen);
+        } else {
+            ALOGE("No mNALSizeLen");
+        }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
         mType = AAC;
     }
@@ -244,6 +252,10 @@
 }
 
 status_t MatroskaSource::start(MetaData * /* params */) {
+    if (mType == AVC && mNALSizeLen < 0) {
+        return ERROR_MALFORMED;
+    }
+
     mBlockIter.reset();
 
     return OK;
@@ -492,6 +504,9 @@
 }
 
 int64_t BlockIterator::blockTimeUs() const {
+    if (mCluster == NULL || mBlockEntry == NULL) {
+        return -1;
+    }
     return (mBlockEntry->GetBlock()->GetTime(mCluster) + 500ll) / 1000ll;
 }
 
@@ -511,6 +526,72 @@
     }
 }
 
+status_t MatroskaSource::setWebmBlockCryptoInfo(MediaBuffer *mbuf) {
+    if (mbuf->range_length() < 1 || mbuf->range_length() - 1 > INT32_MAX) {
+        // 1-byte signal
+        return ERROR_MALFORMED;
+    }
+
+    const uint8_t *data = (const uint8_t *)mbuf->data() + mbuf->range_offset();
+    bool blockEncrypted = data[0] & 0x1;
+    if (blockEncrypted && mbuf->range_length() < 9) {
+        // 1-byte signal + 8-byte IV
+        return ERROR_MALFORMED;
+    }
+
+    sp<MetaData> meta = mbuf->meta_data();
+    if (blockEncrypted) {
+        /*
+         *  0                   1                   2                   3
+         *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         *  |  Signal Byte  |                                               |
+         *  +-+-+-+-+-+-+-+-+             IV                                |
+         *  |                                                               |
+         *  |               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         *  |               |                                               |
+         *  |-+-+-+-+-+-+-+-+                                               |
+         *  :               Bytes 1..N of encrypted frame                   :
+         *  |                                                               |
+         *  |                                                               |
+         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         */
+        int32_t plainSizes[] = { 0 };
+        int32_t encryptedSizes[] = { static_cast<int32_t>(mbuf->range_length() - 9) };
+        uint8_t ctrCounter[16] = { 0 };
+        uint32_t type;
+        const uint8_t *keyId;
+        size_t keyIdSize;
+        sp<MetaData> trackMeta = mExtractor->mTracks.itemAt(mTrackIndex).mMeta;
+        CHECK(trackMeta->findData(kKeyCryptoKey, &type, (const void **)&keyId, &keyIdSize));
+        meta->setData(kKeyCryptoKey, 0, keyId, keyIdSize);
+        memcpy(ctrCounter, data + 1, 8);
+        meta->setData(kKeyCryptoIV, 0, ctrCounter, 16);
+        meta->setData(kKeyPlainSizes, 0, plainSizes, sizeof(plainSizes));
+        meta->setData(kKeyEncryptedSizes, 0, encryptedSizes, sizeof(encryptedSizes));
+        mbuf->set_range(9, mbuf->range_length() - 9);
+    } else {
+        /*
+         *  0                   1                   2                   3
+         *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         *  |  Signal Byte  |                                               |
+         *  +-+-+-+-+-+-+-+-+                                               |
+         *  :               Bytes 1..N of unencrypted frame                 :
+         *  |                                                               |
+         *  |                                                               |
+         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+         */
+        int32_t plainSizes[] = { static_cast<int32_t>(mbuf->range_length() - 1) };
+        int32_t encryptedSizes[] = { 0 };
+        meta->setData(kKeyPlainSizes, 0, plainSizes, sizeof(plainSizes));
+        meta->setData(kKeyEncryptedSizes, 0, encryptedSizes, sizeof(encryptedSizes));
+        mbuf->set_range(1, mbuf->range_length() - 1);
+    }
+
+    return OK;
+}
+
 status_t MatroskaSource::readBlock() {
     CHECK(mPendingFrames.empty());
 
@@ -529,13 +610,19 @@
         mbuf->meta_data()->setInt64(kKeyTime, timeUs);
         mbuf->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey());
 
-        long n = frame.Read(mExtractor->mReader, (unsigned char *)mbuf->data());
-        if (n != 0) {
+        status_t err = frame.Read(mExtractor->mReader, static_cast<uint8_t *>(mbuf->data()));
+        if (err == OK
+                && mExtractor->mIsWebm
+                && mExtractor->mTracks.itemAt(mTrackIndex).mEncrypted) {
+            err = setWebmBlockCryptoInfo(mbuf);
+        }
+
+        if (err != OK) {
             mPendingFrames.clear();
 
             mBlockIter.advance();
             mbuf->release();
-            return ERROR_IO;
+            return err;
         }
 
         mPendingFrames.push_back(mbuf);
@@ -582,7 +669,7 @@
     MediaBuffer *frame = *mPendingFrames.begin();
     mPendingFrames.erase(mPendingFrames.begin());
 
-    if (mType != AVC) {
+    if (mType != AVC || mNALSizeLen == 0) {
         if (targetSampleTimeUs >= 0ll) {
             frame->meta_data()->setInt64(
                     kKeyTargetTime, targetSampleTimeUs);
@@ -598,6 +685,9 @@
     // followed by a corresponding number of bytes containing the fragment.
     // We output all these fragments into a single large buffer separated
     // by startcodes (0x00 0x00 0x00 0x01).
+    //
+    // When mNALSizeLen is 0, we assume the data is already in the format
+    // desired.
 
     const uint8_t *srcPtr =
         (const uint8_t *)frame->data() + frame->range_offset();
@@ -772,7 +862,7 @@
     return mTracks.size();
 }
 
-sp<MediaSource> MatroskaExtractor::getTrack(size_t index) {
+sp<IMediaSource> MatroskaExtractor::getTrack(size_t index) {
     if (index >= mTracks.size()) {
         return NULL;
     }
@@ -939,6 +1029,35 @@
     return OK;
 }
 
+status_t MatroskaExtractor::synthesizeAVCC(TrackInfo *trackInfo, size_t index) {
+    BlockIterator iter(this, trackInfo->mTrackNum, index);
+    if (iter.eos()) {
+        return ERROR_MALFORMED;
+    }
+
+    const mkvparser::Block *block = iter.block();
+    if (block->GetFrameCount() <= 0) {
+        return ERROR_MALFORMED;
+    }
+
+    const mkvparser::Block::Frame &frame = block->GetFrame(0);
+    sp<ABuffer> abuf = new ABuffer(frame.len);
+    long n = frame.Read(mReader, abuf->data());
+    if (n != 0) {
+        return ERROR_MALFORMED;
+    }
+
+    sp<MetaData> avcMeta = MakeAVCCodecSpecificData(abuf);
+    if (avcMeta == NULL) {
+        return ERROR_MALFORMED;
+    }
+
+    // Override the synthesized nal length size, which is arbitrary
+    avcMeta->setInt32(kKeyNalLengthSize, 0);
+    trackInfo->mMeta = avcMeta;
+    return OK;
+}
+
 void MatroskaExtractor::addTracks() {
     const mkvparser::Tracks *tracks = mSegment->GetTracks();
 
@@ -1051,10 +1170,31 @@
         meta->setInt64(kKeyDuration, (durationNs + 500) / 1000);
 
         mTracks.push();
-        TrackInfo *trackInfo = &mTracks.editItemAt(mTracks.size() - 1);
+        size_t n = mTracks.size() - 1;
+        TrackInfo *trackInfo = &mTracks.editItemAt(n);
         trackInfo->mTrackNum = track->GetNumber();
         trackInfo->mMeta = meta;
         trackInfo->mExtractor = this;
+
+        trackInfo->mEncrypted = false;
+        for(size_t i = 0; i < track->GetContentEncodingCount() && !trackInfo->mEncrypted; i++) {
+            const mkvparser::ContentEncoding *encoding = track->GetContentEncodingByIndex(i);
+            for(size_t j = 0; j < encoding->GetEncryptionCount(); j++) {
+                const mkvparser::ContentEncoding::ContentEncryption *encryption;
+                encryption = encoding->GetEncryptionByIndex(j);
+                meta->setData(kKeyCryptoKey, 0, encryption->key_id, encryption->key_id_len);
+                trackInfo->mEncrypted = true;
+                break;
+            }
+        }
+
+        if (!strcmp("V_MPEG4/ISO/AVC", codecID) && codecPrivateSize == 0) {
+            // Attempt to recover from AVC track without codec private data
+            err = synthesizeAVCC(trackInfo, n);
+            if (err != OK) {
+                mTracks.pop();
+            }
+        }
     }
 }
 
diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h
index db36bf8..a1d6b00 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.h
+++ b/media/libstagefright/matroska/MatroskaExtractor.h
@@ -37,7 +37,7 @@
 
     virtual size_t countTracks();
 
-    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<IMediaSource> getTrack(size_t index);
 
     virtual sp<MetaData> getTrackMetaData(
             size_t index, uint32_t flags);
@@ -55,6 +55,7 @@
 
     struct TrackInfo {
         unsigned long mTrackNum;
+        bool mEncrypted;
         sp<MetaData> mMeta;
         const MatroskaExtractor *mExtractor;
         Vector<const mkvparser::CuePoint*> mCuePoints;
@@ -74,6 +75,7 @@
     bool mIsWebm;
     int64_t mSeekPreRollNs;
 
+    status_t synthesizeAVCC(TrackInfo *trackInfo, size_t index);
     void addTracks();
     void findThumbnails();
 
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index bec99a5..2790a0e 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -524,15 +524,10 @@
 }
 
 sp<MediaSource> ATSParser::Program::getSource(SourceType type) {
-    size_t index = (type == AUDIO) ? 0 : 0;
-
     for (size_t i = 0; i < mStreams.size(); ++i) {
         sp<MediaSource> source = mStreams.editValueAt(i)->getSource(type);
         if (source != NULL) {
-            if (index == 0) {
-                return source;
-            }
-            --index;
+            return source;
         }
     }
 
@@ -546,6 +541,8 @@
             return true;
         } else if (type == VIDEO && stream->isVideo()) {
             return true;
+        } else if (type == META && stream->isMeta()) {
+            return true;
         }
     }
 
@@ -1499,23 +1496,38 @@
 }
 
 sp<MediaSource> ATSParser::getSource(SourceType type) {
-    int which = -1;  // any
-
+    sp<MediaSource> firstSourceFound;
     for (size_t i = 0; i < mPrograms.size(); ++i) {
         const sp<Program> &program = mPrograms.editItemAt(i);
-
-        if (which >= 0 && (int)program->number() != which) {
+        sp<MediaSource> source = program->getSource(type);
+        if (source == NULL) {
             continue;
         }
+        if (firstSourceFound == NULL) {
+            firstSourceFound = source;
+        }
+        // Prefer programs with both audio/video
+        switch (type) {
+            case VIDEO: {
+                if (program->hasSource(AUDIO)) {
+                    return source;
+                }
+                break;
+            }
 
-        sp<MediaSource> source = program->getSource(type);
+            case AUDIO: {
+                if (program->hasSource(VIDEO)) {
+                    return source;
+                }
+                break;
+            }
 
-        if (source != NULL) {
-            return source;
+            default:
+                return source;
         }
     }
 
-    return NULL;
+    return firstSourceFound;
 }
 
 bool ATSParser::hasSource(SourceType type) const {
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index cabde32..4fcf7b5 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -216,6 +216,12 @@
             mediaBuffer->meta_data()->setData(kKeySEI, 0, sei->data(), sei->size());
         }
 
+        sp<ABuffer> mpegUserData;
+        if (buffer->meta()->findBuffer("mpegUserData", &mpegUserData) && mpegUserData != NULL) {
+            mediaBuffer->meta_data()->setData(
+                    kKeyMpegUserData, 0, mpegUserData->data(), mpegUserData->size());
+        }
+
         *out = mediaBuffer;
         return OK;
     }
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 36ec367..daf6b3d 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -1047,6 +1047,8 @@
     const uint8_t *data = mBuffer->data();
     size_t size = mBuffer->size();
 
+    Vector<size_t> userDataPositions;
+
     bool sawPictureStart = false;
     int pprevStartCode = -1;
     int prevStartCode = -1;
@@ -1121,11 +1123,19 @@
 
         if (mFormat != NULL && currentStartCode == 0xb8) {
             // GOP layer
+            if (offset + 7 >= size) {
+                ALOGE("Size too small");
+                return NULL;
+            }
             gopFound = true;
             isClosedGop = (data[offset + 7] & 0x40) != 0;
             brokenLink = (data[offset + 7] & 0x20) != 0;
         }
 
+        if (mFormat != NULL && currentStartCode == 0xb2) {
+            userDataPositions.add(offset);
+        }
+
         if (mFormat != NULL && currentStartCode == 0x00) {
             // Picture start
 
@@ -1159,6 +1169,19 @@
 
                 // hexdump(accessUnit->data(), accessUnit->size());
 
+                if (userDataPositions.size() > 0) {
+                    sp<ABuffer> mpegUserData =
+                        new ABuffer(userDataPositions.size() * sizeof(size_t));
+                    if (mpegUserData != NULL && mpegUserData->data() != NULL) {
+                        for (size_t i = 0; i < userDataPositions.size(); ++i) {
+                            memcpy(
+                                    mpegUserData->data() + i * sizeof(size_t),
+                                    &userDataPositions[i], sizeof(size_t));
+                        }
+                        accessUnit->meta()->setBuffer("mpegUserData", mpegUserData);
+                    }
+                }
+
                 return accessUnit;
             }
         }
diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
index 0f18fac..078a5f0 100644
--- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
@@ -125,7 +125,7 @@
     return mTracks.size();
 }
 
-sp<MediaSource> MPEG2PSExtractor::getTrack(size_t index) {
+sp<IMediaSource> MPEG2PSExtractor::getTrack(size_t index) {
     if (index >= mTracks.size()) {
         return NULL;
     }
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index cbe9673..0b456c3 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -120,7 +120,7 @@
     return mSourceImpls.size();
 }
 
-sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) {
+sp<IMediaSource> MPEG2TSExtractor::getTrack(size_t index) {
     if (index >= mSourceImpls.size()) {
         return NULL;
     }
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 1a7dc9d..acdc4b0 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -64,19 +64,19 @@
             return;
         }
 
-        err = consumer->detachBuffer(bi.mBuf);
+        err = consumer->detachBuffer(bi.mSlot);
         if (err != OK) {
             ALOGE("PersistentProxyListener: detachBuffer failed (%d)", err);
             return;
         }
 
-        err = consumer->attachBuffer(&bi.mBuf, bi.mGraphicBuffer);
+        err = consumer->attachBuffer(&bi.mSlot, bi.mGraphicBuffer);
         if (err != OK) {
             ALOGE("PersistentProxyListener: attachBuffer failed (%d)", err);
             return;
         }
 
-        err = consumer->releaseBuffer(bi.mBuf, 0,
+        err = consumer->releaseBuffer(bi.mSlot, 0,
                 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, bi.mFence);
         if (err != OK) {
             ALOGE("PersistentProxyListener: releaseBuffer failed (%d)", err);
@@ -382,7 +382,7 @@
     // Find matching entry in our cached copy of the BufferQueue slots.
     // If we find a match, release that slot.  If we don't, the BufferQueue
     // has dropped that GraphicBuffer, and there's nothing for us to release.
-    int id = codecBuffer.mBuf;
+    int id = codecBuffer.mSlot;
     sp<Fence> fence = new Fence(fenceFd);
     if (mBufferSlot[id] != NULL &&
         mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {
@@ -476,7 +476,7 @@
             ++mNumBufferAcquired;
             --mNumFramesAvailable;
 
-            releaseBuffer(item.mBuf, item.mFrameNumber,
+            releaseBuffer(item.mSlot, item.mFrameNumber,
                     item.mGraphicBuffer, item.mFence);
         }
         return;
@@ -530,8 +530,8 @@
     // If this is the first time we're seeing this buffer, add it to our
     // slot table.
     if (item.mGraphicBuffer != NULL) {
-        ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mBuf);
-        mBufferSlot[item.mBuf] = item.mGraphicBuffer;
+        ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mSlot);
+        mBufferSlot[item.mSlot] = item.mGraphicBuffer;
     }
 
     err = UNKNOWN_ERROR;
@@ -557,10 +557,10 @@
     }
 
     if (err != OK) {
-        ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf);
-        releaseBuffer(item.mBuf, item.mFrameNumber, item.mGraphicBuffer, item.mFence);
+        ALOGV("submitBuffer_l failed, releasing bq slot %d", item.mSlot);
+        releaseBuffer(item.mSlot, item.mFrameNumber, item.mGraphicBuffer, item.mFence);
     } else {
-        ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi);
+        ALOGV("buffer submitted (bq %d, cbi %d)", item.mSlot, cbi);
         setLatestBuffer_l(item, dropped);
     }
 
@@ -600,7 +600,7 @@
     }
 
     BufferItem item;
-    item.mBuf = mLatestBufferId;
+    item.mSlot = mLatestBufferId;
     item.mFrameNumber = mLatestBufferFrameNum;
     item.mTimestamp = mRepeatLastFrameTimestamp;
     item.mFence = mLatestBufferFence;
@@ -642,7 +642,7 @@
         }
     }
 
-    mLatestBufferId = item.mBuf;
+    mLatestBufferId = item.mSlot;
     mLatestBufferFrameNum = item.mFrameNumber;
     mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
 
@@ -754,8 +754,8 @@
     }
 
     CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
-    codecBuffer.mGraphicBuffer = mBufferSlot[item.mBuf];
-    codecBuffer.mBuf = item.mBuf;
+    codecBuffer.mGraphicBuffer = mBufferSlot[item.mSlot];
+    codecBuffer.mSlot = item.mSlot;
     codecBuffer.mFrameNumber = item.mFrameNumber;
 
     OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader;
@@ -880,11 +880,11 @@
             // If this is the first time we're seeing this buffer, add it to our
             // slot table.
             if (item.mGraphicBuffer != NULL) {
-                ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mBuf);
-                mBufferSlot[item.mBuf] = item.mGraphicBuffer;
+                ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mSlot);
+                mBufferSlot[item.mSlot] = item.mGraphicBuffer;
             }
 
-            releaseBuffer(item.mBuf, item.mFrameNumber,
+            releaseBuffer(item.mSlot, item.mFrameNumber,
                     item.mGraphicBuffer, item.mFence);
         }
         return;
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 2f929d9..7150684 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -195,7 +195,7 @@
         uint64_t mFrameNumber;
 
         // buffer producer's buffer slot for buffer
-        int mBuf;
+        int mSlot;
 
         sp<GraphicBuffer> mGraphicBuffer;
     };
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 7f357c9..b3625b4 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -38,6 +38,9 @@
 
 namespace android {
 
+// node ids are created by concatenating the pid with a 16-bit counter
+static size_t kMaxNodeInstances = (1 << 16);
+
 ////////////////////////////////////////////////////////////////////////////////
 
 // This provides the underlying Thread used by CallbackDispatcher.
@@ -237,6 +240,11 @@
 
     *node = 0;
 
+    if (mNodeIDToInstance.size() == kMaxNodeInstances) {
+        // all possible node IDs are in use
+        return NO_MEMORY;
+    }
+
     OMXNodeInstance *instance = new OMXNodeInstance(this, observer, name);
 
     OMX_COMPONENTTYPE *handle;
@@ -252,7 +260,7 @@
         return StatusFromOMXError(err);
     }
 
-    *node = makeNodeID(instance);
+    *node = makeNodeID_l(instance);
     mDispatchers.add(*node, new CallbackDispatcher(instance));
 
     instance->setHandle(*node, handle);
@@ -266,6 +274,10 @@
 status_t OMX::freeNode(node_id node) {
     OMXNodeInstance *instance = findInstance(node);
 
+    if (instance == NULL) {
+        return OK;
+    }
+
     {
         Mutex::Autolock autoLock(mLock);
         ssize_t index = mLiveNodes.indexOfKey(IInterface::asBinder(instance->observer()));
@@ -293,14 +305,26 @@
 
 status_t OMX::sendCommand(
         node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
-    return findInstance(node)->sendCommand(cmd, param);
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->sendCommand(cmd, param);
 }
 
 status_t OMX::getParameter(
         node_id node, OMX_INDEXTYPE index,
         void *params, size_t size) {
     ALOGV("getParameter(%u %#x %p %zd)", node, index, params, size);
-    return findInstance(node)->getParameter(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->getParameter(
             index, params, size);
 }
 
@@ -308,84 +332,162 @@
         node_id node, OMX_INDEXTYPE index,
         const void *params, size_t size) {
     ALOGV("setParameter(%u %#x %p %zd)", node, index, params, size);
-    return findInstance(node)->setParameter(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->setParameter(
             index, params, size);
 }
 
 status_t OMX::getConfig(
         node_id node, OMX_INDEXTYPE index,
         void *params, size_t size) {
-    return findInstance(node)->getConfig(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->getConfig(
             index, params, size);
 }
 
 status_t OMX::setConfig(
         node_id node, OMX_INDEXTYPE index,
         const void *params, size_t size) {
-    return findInstance(node)->setConfig(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->setConfig(
             index, params, size);
 }
 
 status_t OMX::getState(
         node_id node, OMX_STATETYPE* state) {
-    return findInstance(node)->getState(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->getState(
             state);
 }
 
 status_t OMX::enableGraphicBuffers(
         node_id node, OMX_U32 port_index, OMX_BOOL enable) {
-    return findInstance(node)->enableGraphicBuffers(port_index, enable);
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->enableGraphicBuffers(port_index, enable);
 }
 
 status_t OMX::getGraphicBufferUsage(
         node_id node, OMX_U32 port_index, OMX_U32* usage) {
-    return findInstance(node)->getGraphicBufferUsage(port_index, usage);
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->getGraphicBufferUsage(port_index, usage);
 }
 
 status_t OMX::storeMetaDataInBuffers(
         node_id node, OMX_U32 port_index, OMX_BOOL enable, MetadataBufferType *type) {
-    return findInstance(node)->storeMetaDataInBuffers(port_index, enable, type);
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->storeMetaDataInBuffers(port_index, enable, type);
 }
 
 status_t OMX::prepareForAdaptivePlayback(
         node_id node, OMX_U32 portIndex, OMX_BOOL enable,
         OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) {
-    return findInstance(node)->prepareForAdaptivePlayback(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->prepareForAdaptivePlayback(
             portIndex, enable, maxFrameWidth, maxFrameHeight);
 }
 
 status_t OMX::configureVideoTunnelMode(
         node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
         OMX_U32 audioHwSync, native_handle_t **sidebandHandle) {
-    return findInstance(node)->configureVideoTunnelMode(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->configureVideoTunnelMode(
             portIndex, tunneled, audioHwSync, sidebandHandle);
 }
 
 status_t OMX::useBuffer(
         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
         buffer_id *buffer, OMX_U32 allottedSize) {
-    return findInstance(node)->useBuffer(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->useBuffer(
             port_index, params, buffer, allottedSize);
 }
 
 status_t OMX::useGraphicBuffer(
         node_id node, OMX_U32 port_index,
         const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
-    return findInstance(node)->useGraphicBuffer(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->useGraphicBuffer(
             port_index, graphicBuffer, buffer);
 }
 
 status_t OMX::updateGraphicBufferInMeta(
         node_id node, OMX_U32 port_index,
         const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) {
-    return findInstance(node)->updateGraphicBufferInMeta(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->updateGraphicBufferInMeta(
             port_index, graphicBuffer, buffer);
 }
 
 status_t OMX::createInputSurface(
         node_id node, OMX_U32 port_index,
         sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) {
-    return findInstance(node)->createInputSurface(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->createInputSurface(
             port_index, bufferProducer, type);
 }
 
@@ -399,35 +501,71 @@
 status_t OMX::setInputSurface(
         node_id node, OMX_U32 port_index,
         const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type) {
-    return findInstance(node)->setInputSurface(port_index, bufferConsumer, type);
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->setInputSurface(port_index, bufferConsumer, type);
 }
 
 
 status_t OMX::signalEndOfInputStream(node_id node) {
-    return findInstance(node)->signalEndOfInputStream();
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->signalEndOfInputStream();
 }
 
 status_t OMX::allocateBuffer(
         node_id node, OMX_U32 port_index, size_t size,
         buffer_id *buffer, void **buffer_data) {
-    return findInstance(node)->allocateBuffer(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->allocateBuffer(
             port_index, size, buffer, buffer_data);
 }
 
 status_t OMX::allocateBufferWithBackup(
         node_id node, OMX_U32 port_index, const sp<IMemory> &params,
         buffer_id *buffer, OMX_U32 allottedSize) {
-    return findInstance(node)->allocateBufferWithBackup(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->allocateBufferWithBackup(
             port_index, params, buffer, allottedSize);
 }
 
 status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
-    return findInstance(node)->freeBuffer(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->freeBuffer(
             port_index, buffer);
 }
 
 status_t OMX::fillBuffer(node_id node, buffer_id buffer, int fenceFd) {
-    return findInstance(node)->fillBuffer(buffer, fenceFd);
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->fillBuffer(buffer, fenceFd);
 }
 
 status_t OMX::emptyBuffer(
@@ -435,7 +573,13 @@
         buffer_id buffer,
         OMX_U32 range_offset, OMX_U32 range_length,
         OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
-    return findInstance(node)->emptyBuffer(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->emptyBuffer(
             buffer, range_offset, range_length, flags, timestamp, fenceFd);
 }
 
@@ -443,7 +587,13 @@
         node_id node,
         const char *parameter_name,
         OMX_INDEXTYPE *index) {
-    return findInstance(node)->getExtensionIndex(
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->getExtensionIndex(
             parameter_name, index);
 }
 
@@ -453,7 +603,13 @@
         InternalOptionType type,
         const void *data,
         size_t size) {
-    return findInstance(node)->setInternalOption(port_index, type, data, size);
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return NAME_NOT_FOUND;
+    }
+
+    return instance->setInternalOption(port_index, type, data, size);
 }
 
 OMX_ERRORTYPE OMX::OnEvent(
@@ -463,9 +619,14 @@
         OMX_IN OMX_U32 nData2,
         OMX_IN OMX_PTR pEventData) {
     ALOGV("OnEvent(%d, %" PRIu32", %" PRIu32 ")", eEvent, nData1, nData2);
+    OMXNodeInstance *instance = findInstance(node);
+
+    if (instance == NULL) {
+        return OMX_ErrorComponentNotFound;
+    }
 
     // Forward to OMXNodeInstance.
-    findInstance(node)->onEvent(eEvent, nData1, nData2);
+    instance->onEvent(eEvent, nData1, nData2);
 
     sp<OMX::CallbackDispatcher> dispatcher = findDispatcher(node);
 
@@ -537,10 +698,17 @@
     return OMX_ErrorNone;
 }
 
-OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
+OMX::node_id OMX::makeNodeID_l(OMXNodeInstance *instance) {
     // mLock is already held.
 
-    node_id node = (node_id)++mNodeCounter;
+    node_id prefix = node_id(getpid() << 16);
+    node_id node = 0;
+    do  {
+        if (++mNodeCounter >= kMaxNodeInstances) {
+            mNodeCounter = 0; // OK to use because we're combining with the pid
+        }
+        node = node_id(prefix | mNodeCounter);
+    } while (mNodeIDToInstance.indexOfKey(node) >= 0);
     mNodeIDToInstance.add(node, instance);
 
     return node;
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index ae3cb33..6132a2c 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -23,6 +23,7 @@
 #include "SoftOMXPlugin.h"
 
 #include <dlfcn.h>
+#include <fcntl.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 
@@ -30,6 +31,29 @@
 
 OMXMaster::OMXMaster()
     : mVendorLibHandle(NULL) {
+
+    mProcessName[0] = 0;
+    if (mProcessName[0] == 0) {
+        pid_t pid = getpid();
+        char filename[20];
+        snprintf(filename, sizeof(filename), "/proc/%d/comm", pid);
+        int fd = open(filename, O_RDONLY);
+        if (fd < 0) {
+            ALOGW("couldn't determine process name");
+            sprintf(mProcessName, "<unknown>");
+        } else {
+            ssize_t len = read(fd, mProcessName, sizeof(mProcessName));
+            if (len < 2) {
+                ALOGW("couldn't determine process name");
+                sprintf(mProcessName, "<unknown>");
+            } else {
+                // the name is newline terminated, so erase the newline
+                mProcessName[len - 1] = 0;
+            }
+            close(fd);
+        }
+    }
+
     addVendorPlugin();
     addPlugin(new SoftOMXPlugin);
 }
@@ -123,6 +147,7 @@
         const OMX_CALLBACKTYPE *callbacks,
         OMX_PTR appData,
         OMX_COMPONENTTYPE **component) {
+    ALOGI("makeComponentInstance(%s) in %s process", name, mProcessName);
     Mutex::Autolock autoLock(mLock);
 
     *component = NULL;
diff --git a/media/libstagefright/omx/OMXMaster.h b/media/libstagefright/omx/OMXMaster.h
index 6069741..3f9c0ca 100644
--- a/media/libstagefright/omx/OMXMaster.h
+++ b/media/libstagefright/omx/OMXMaster.h
@@ -50,6 +50,7 @@
             Vector<String8> *roles);
 
 private:
+    char mProcessName[16];
     Mutex mLock;
     List<OMXPluginBase *> mPlugins;
     KeyedVector<String8, OMXPluginBase *> mPluginByComponentName;
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index a1485f0..9ae238a 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -655,6 +655,11 @@
 status_t OMXNodeInstance::useBuffer(
         OMX_U32 portIndex, const sp<IMemory> &params,
         OMX::buffer_id *buffer, OMX_U32 allottedSize) {
+    if (params == NULL || buffer == NULL) {
+        ALOGE("b/25884056");
+        return BAD_VALUE;
+    }
+
     Mutex::Autolock autoLock(mLock);
     if (allottedSize > params->size()) {
         return BAD_VALUE;
@@ -699,6 +704,10 @@
 status_t OMXNodeInstance::useGraphicBuffer2_l(
         OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
         OMX::buffer_id *buffer) {
+    if (graphicBuffer == NULL || buffer == NULL) {
+        ALOGE("b/25884056");
+        return BAD_VALUE;
+    }
 
     // port definition
     OMX_PARAM_PORTDEFINITIONTYPE def;
@@ -751,6 +760,10 @@
 status_t OMXNodeInstance::useGraphicBuffer(
         OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
         OMX::buffer_id *buffer) {
+    if (graphicBuffer == NULL || buffer == NULL) {
+        ALOGE("b/25884056");
+        return BAD_VALUE;
+    }
     Mutex::Autolock autoLock(mLock);
 
     // See if the newer version of the extension is present.
@@ -811,6 +824,12 @@
 status_t OMXNodeInstance::updateGraphicBufferInMeta_l(
         OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
         OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header) {
+    // No need to check |graphicBuffer| since NULL is valid for it as below.
+    if (header == NULL) {
+        ALOGE("b/25884056");
+        return BAD_VALUE;
+    }
+
     if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
         return BAD_VALUE;
     }
@@ -911,6 +930,11 @@
 
 status_t OMXNodeInstance::createInputSurface(
         OMX_U32 portIndex, sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) {
+    if (bufferProducer == NULL) {
+        ALOGE("b/25884056");
+        return BAD_VALUE;
+    }
+
     Mutex::Autolock autolock(mLock);
     status_t err = createGraphicBufferSource(portIndex, NULL /* bufferConsumer */, type);
 
@@ -926,6 +950,10 @@
 status_t OMXNodeInstance::createPersistentInputSurface(
         sp<IGraphicBufferProducer> *bufferProducer,
         sp<IGraphicBufferConsumer> *bufferConsumer) {
+    if (bufferProducer == NULL || bufferConsumer == NULL) {
+        ALOGE("b/25884056");
+        return BAD_VALUE;
+    }
     String8 name("GraphicBufferSource");
 
     sp<IGraphicBufferProducer> producer;
@@ -971,6 +999,11 @@
 status_t OMXNodeInstance::allocateBuffer(
         OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
         void **buffer_data) {
+    if (buffer == NULL || buffer_data == NULL) {
+        ALOGE("b/25884056");
+        return BAD_VALUE;
+    }
+
     Mutex::Autolock autoLock(mLock);
 
     BufferMeta *buffer_meta = new BufferMeta(size);
@@ -1009,6 +1042,11 @@
 status_t OMXNodeInstance::allocateBufferWithBackup(
         OMX_U32 portIndex, const sp<IMemory> &params,
         OMX::buffer_id *buffer, OMX_U32 allottedSize) {
+    if (params == NULL || buffer == NULL) {
+        ALOGE("b/25884056");
+        return BAD_VALUE;
+    }
+
     Mutex::Autolock autoLock(mLock);
     if (allottedSize > params->size()) {
         return BAD_VALUE;
@@ -1056,6 +1094,10 @@
     removeActiveBuffer(portIndex, buffer);
 
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
+    if (header == NULL) {
+        ALOGE("b/25884056");
+        return BAD_VALUE;
+    }
     BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
 
     OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
@@ -1072,6 +1114,10 @@
     Mutex::Autolock autoLock(mLock);
 
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
+    if (header == NULL) {
+        ALOGE("b/25884056");
+        return BAD_VALUE;
+    }
     header->nFilledLen = 0;
     header->nOffset = 0;
     header->nFlags = 0;
@@ -1105,6 +1151,10 @@
     Mutex::Autolock autoLock(mLock);
 
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
+    if (header == NULL) {
+        ALOGE("b/25884056");
+        return BAD_VALUE;
+    }
     BufferMeta *buffer_meta =
         static_cast<BufferMeta *>(header->pAppPrivate);
     sp<ABuffer> backup = buffer_meta->getBuffer(header, true /* backup */, false /* limit */);
@@ -1256,6 +1306,11 @@
 status_t OMXNodeInstance::emptyGraphicBuffer(
         OMX_BUFFERHEADERTYPE *header, const sp<GraphicBuffer> &graphicBuffer,
         OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
+    if (header == NULL) {
+        ALOGE("b/25884056");
+        return BAD_VALUE;
+    }
+
     Mutex::Autolock autoLock(mLock);
     OMX::buffer_id buffer = findBufferID(header);
     status_t err = updateGraphicBufferInMeta_l(kPortIndexInput, graphicBuffer, buffer, header);
@@ -1385,6 +1440,10 @@
     if (msg.type == omx_message::FILL_BUFFER_DONE) {
         OMX_BUFFERHEADERTYPE *buffer =
             findBufferHeader(msg.u.extended_buffer_data.buffer);
+        if (buffer == NULL) {
+            ALOGE("b/25884056");
+            return BAD_VALUE;
+        }
 
         {
             Mutex::Autolock _l(mDebugLock);
@@ -1523,6 +1582,10 @@
         OMX_IN OMX_U32 nData1,
         OMX_IN OMX_U32 nData2,
         OMX_IN OMX_PTR pEventData) {
+    if (pAppData == NULL) {
+        ALOGE("b/25884056");
+        return OMX_ErrorBadParameter;
+    }
     OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
     if (instance->mDying) {
         return OMX_ErrorNone;
@@ -1536,6 +1599,10 @@
         OMX_IN OMX_HANDLETYPE /* hComponent */,
         OMX_IN OMX_PTR pAppData,
         OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+    if (pAppData == NULL) {
+        ALOGE("b/25884056");
+        return OMX_ErrorBadParameter;
+    }
     OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
     if (instance->mDying) {
         return OMX_ErrorNone;
@@ -1550,6 +1617,10 @@
         OMX_IN OMX_HANDLETYPE /* hComponent */,
         OMX_IN OMX_PTR pAppData,
         OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+    if (pAppData == NULL) {
+        ALOGE("b/25884056");
+        return OMX_ErrorBadParameter;
+    }
     OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
     if (instance->mDying) {
         return OMX_ErrorNone;
@@ -1590,7 +1661,7 @@
 void OMXNodeInstance::freeActiveBuffers() {
     // Make sure to count down here, as freeBuffer will in turn remove
     // the active buffer from the vector...
-    for (size_t i = mActiveBuffers.size(); i;) {
+    for (size_t i = mActiveBuffers.size(); i > 0;) {
         i--;
         freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
     }
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index 4ce165b..e1f4125 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -388,6 +388,14 @@
             uint32_t oldHeight = def->format.video.nFrameHeight;
             uint32_t newWidth = video_def->nFrameWidth;
             uint32_t newHeight = video_def->nFrameHeight;
+            // We need width, height, stride and slice-height to be non-zero and sensible.
+            // These values were chosen to prevent integer overflows further down the line, and do
+            // not indicate support for 32kx32k video.
+            if (newWidth > 32768 || newHeight > 32768
+                    || video_def->nStride > 32768 || video_def->nSliceHeight > 32768) {
+                ALOGE("b/22885421");
+                return OMX_ErrorBadParameter;
+            }
             if (newWidth != oldWidth || newHeight != oldHeight) {
                 bool outputPort = (newParams->nPortIndex == kOutputPortIndex);
                 if (outputPort) {
diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
index a770f49..72823e2 100644
--- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
@@ -23,7 +23,6 @@
 
 #include "include/SoftVideoEncoderOMXComponent.h"
 
-#include <hardware/gralloc.h>
 #include <media/hardware/HardwareAPI.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -71,7 +70,6 @@
       mBitrate(192000),
       mFramerate(30 << 16), // Q16 format
       mColorFormat(OMX_COLOR_FormatYUV420Planar),
-      mGrallocModule(NULL),
       mMinOutputBufferSize(384), // arbitrary, using one uncompressed macroblock
       mMinCompressionRatio(1),   // max output size is normally the input size
       mComponentRole(componentRole),
@@ -500,13 +498,6 @@
         return NULL;
     }
 
-    if (mGrallocModule == NULL) {
-        CHECK_EQ(0, hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule));
-    }
-
-    const gralloc_module_t *grmodule =
-        (const gralloc_module_t *)mGrallocModule;
-
     buffer_handle_t handle;
     int format;
     size_t srcStride;
@@ -564,19 +555,21 @@
         return NULL;
     }
 
+    auto& mapper = GraphicBufferMapper::get();
+
     void *bits = NULL;
     struct android_ycbcr ycbcr;
     status_t res;
     if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-        res = grmodule->lock_ycbcr(
-                 grmodule, handle,
+        res = mapper.lockYCbCr(
+                 handle,
                  GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
-                 0, 0, width, height, &ycbcr);
+                 Rect(width, height), &ycbcr);
     } else {
-        res = grmodule->lock(
-                 grmodule, handle,
+        res = mapper.lock(
+                 handle,
                  GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
-                 0, 0, width, height, &bits);
+                 Rect(width, height), &bits);
     }
     if (res != OK) {
         ALOGE("Unable to lock image buffer %p for access", handle);
@@ -620,7 +613,7 @@
             break;
     }
 
-    if (grmodule->unlock(grmodule, handle) != OK) {
+    if (mapper.unlock(handle) != OK) {
         ALOGE("Unable to unlock image buffer %p for access", handle);
     }
 
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 9a4e867..c0ccb35 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -27,7 +27,7 @@
 #include <binder/IServiceManager.h>
 #include <binder/MemoryDealer.h>
 #include <media/IMediaHTTPService.h>
-#include <media/IMediaPlayerService.h>
+#include <media/IMediaCodecService.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/DataSource.h>
@@ -57,8 +57,8 @@
 
 status_t Harness::initOMX() {
     sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> binder = sm->getService(String16("media.player"));
-    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+    sp<IBinder> binder = sm->getService(String16("media.codec"));
+    sp<IMediaCodecService> service = interface_cast<IMediaCodecService>(binder);
     mOMX = service->getOMX();
 
     return mOMX != 0 ? OK : NO_INIT;
@@ -244,7 +244,7 @@
     NodeReaper &operator=(const NodeReaper &);
 };
 
-static sp<MediaExtractor> CreateExtractorFromURI(const char *uri) {
+static sp<IMediaExtractor> CreateExtractorFromURI(const char *uri) {
     sp<DataSource> source =
         DataSource::CreateFromURI(NULL /* httpService */, uri);
 
@@ -492,14 +492,14 @@
     return NULL;
 }
 
-static sp<MediaSource> CreateSourceForMime(const char *mime) {
+static sp<IMediaSource> CreateSourceForMime(const char *mime) {
     const char *url = GetURLForMime(mime);
 
     if (url == NULL) {
         return NULL;
     }
 
-    sp<MediaExtractor> extractor = CreateExtractorFromURI(url);
+    sp<IMediaExtractor> extractor = CreateExtractorFromURI(url);
 
     if (extractor == NULL) {
         return NULL;
@@ -559,7 +559,7 @@
         return OK;
     }
 
-    sp<MediaSource> source = CreateSourceForMime(mime);
+    sp<IMediaSource> source = CreateSourceForMime(mime);
 
     if (source == NULL) {
         printf("  * Unable to open test content for type '%s', "
@@ -569,14 +569,14 @@
         return OK;
     }
 
-    sp<MediaSource> seekSource = CreateSourceForMime(mime);
+    sp<IMediaSource> seekSource = CreateSourceForMime(mime);
     if (source == NULL || seekSource == NULL) {
         return UNKNOWN_ERROR;
     }
 
     CHECK_EQ(seekSource->start(), (status_t)OK);
 
-    sp<MediaSource> codec = SimpleDecodingSource::Create(
+    sp<IMediaSource> codec = SimpleDecodingSource::Create(
             source, 0 /* flags */, NULL /* nativeWindow */, componentName);
 
     CHECK(codec != NULL);
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index d7c3bd6..576a0a4 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -116,8 +116,15 @@
     // to the highest sequence number (extended to 32 bits) received so far.
 
     uint32_t seq1 = seqNum | (mHighestSeqNumber & 0xffff0000);
-    uint32_t seq2 = seqNum | ((mHighestSeqNumber & 0xffff0000) + 0x10000);
-    uint32_t seq3 = seqNum | ((mHighestSeqNumber & 0xffff0000) - 0x10000);
+
+    // non-overflowing version of:
+    // uint32_t seq2 = seqNum | ((mHighestSeqNumber & 0xffff0000) + 0x10000);
+    uint32_t seq2 = seqNum | (((mHighestSeqNumber >> 16) + 1) << 16);
+
+    // non-underflowing version of:
+    // uint32_t seq2 = seqNum | ((mHighestSeqNumber & 0xffff0000) - 0x10000);
+    uint32_t seq3 = seqNum | ((((mHighestSeqNumber >> 16) | 0x10000) - 1) << 16);
+
     uint32_t diff1 = AbsDiff(seq1, mHighestSeqNumber);
     uint32_t diff2 = AbsDiff(seq2, mHighestSeqNumber);
     uint32_t diff3 = AbsDiff(seq3, mHighestSeqNumber);
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 56c4aa6..1f6b6f7 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -104,7 +104,7 @@
     mFd = -1;
 }
 
-status_t ARTPWriter::addSource(const sp<MediaSource> &source) {
+status_t ARTPWriter::addSource(const sp<IMediaSource> &source) {
     mSource = source;
     return OK;
 }
diff --git a/media/libstagefright/rtsp/ARTPWriter.h b/media/libstagefright/rtsp/ARTPWriter.h
index be8bc13..62abd0a 100644
--- a/media/libstagefright/rtsp/ARTPWriter.h
+++ b/media/libstagefright/rtsp/ARTPWriter.h
@@ -37,7 +37,7 @@
 struct ARTPWriter : public MediaWriter {
     ARTPWriter(int fd);
 
-    virtual status_t addSource(const sp<MediaSource> &source);
+    virtual status_t addSource(const sp<IMediaSource> &source);
     virtual bool reachedEOS();
     virtual status_t start(MetaData *params);
     virtual status_t stop();
@@ -72,7 +72,7 @@
     int mRTCPFd;
 #endif
 
-    sp<MediaSource> mSource;
+    sp<IMediaSource> mSource;
     sp<ALooper> mLooper;
     sp<AHandlerReflector<ARTPWriter> > mReflector;
 
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index 4f76d16..bdda19c 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -33,7 +33,7 @@
 
 LOCAL_CFLAGS += -Werror -Wall
 LOCAL_CLANG := true
-LOCAL_SANITIZE := signed-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 0d0baf3..eedbb42 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -1131,10 +1131,11 @@
                 int32_t result;
                 CHECK(msg->findInt32("result", &result));
 
-                ALOGI("PLAY completed with result %d (%s)",
+                ALOGI("PLAY (for resume) completed with result %d (%s)",
                      result, strerror(-result));
 
                 mCheckPending = false;
+                ++mCheckGeneration;
                 postAccessUnitTimeoutCheck();
 
                 if (result == OK) {
@@ -1282,10 +1283,11 @@
                 int32_t result;
                 CHECK(msg->findInt32("result", &result));
 
-                ALOGI("PLAY completed with result %d (%s)",
+                ALOGI("PLAY (for seek) completed with result %d (%s)",
                      result, strerror(-result));
 
                 mCheckPending = false;
+                ++mCheckGeneration;
                 postAccessUnitTimeoutCheck();
 
                 if (result == OK) {
diff --git a/media/libstagefright/webm/WebmElement.cpp b/media/libstagefright/webm/WebmElement.cpp
index a008cab..f454bf6 100644
--- a/media/libstagefright/webm/WebmElement.cpp
+++ b/media/libstagefright/webm/WebmElement.cpp
@@ -338,6 +338,7 @@
 }
 
 sp<WebmElement> WebmElement::VideoTrackEntry(
+        const char *codec,
         uint64_t width,
         uint64_t height,
         uint64_t uid,
@@ -353,7 +354,7 @@
             uid,
             lacing,
             lang,
-            "V_VP8",
+            codec,
             kVideoType,
             trackEntryFields);
 
diff --git a/media/libstagefright/webm/WebmElement.h b/media/libstagefright/webm/WebmElement.h
index f19933e..456c3c7 100644
--- a/media/libstagefright/webm/WebmElement.h
+++ b/media/libstagefright/webm/WebmElement.h
@@ -57,6 +57,7 @@
             const char *lang = "und");
 
     static sp<WebmElement> VideoTrackEntry(
+            const char *codec,
             uint64_t width,
             uint64_t height,
             uint64_t uid = 0,
diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp
index a4b8a42..7eb4745 100644
--- a/media/libstagefright/webm/WebmFrameThread.cpp
+++ b/media/libstagefright/webm/WebmFrameThread.cpp
@@ -246,7 +246,7 @@
 }
 
 WebmFrameMediaSourceThread::WebmFrameMediaSourceThread(
-        const sp<MediaSource>& source,
+        const sp<IMediaSource>& source,
         int type,
         LinkedBlockingQueue<const sp<WebmFrame> >& sink,
         uint64_t timeCodeScale,
diff --git a/media/libstagefright/webm/WebmFrameThread.h b/media/libstagefright/webm/WebmFrameThread.h
index d65d9b7..528984f 100644
--- a/media/libstagefright/webm/WebmFrameThread.h
+++ b/media/libstagefright/webm/WebmFrameThread.h
@@ -123,7 +123,7 @@
 class WebmFrameMediaSourceThread: public WebmFrameSourceThread {
 public:
     WebmFrameMediaSourceThread(
-            const sp<MediaSource>& source,
+            const sp<IMediaSource>& source,
             int type,
             LinkedBlockingQueue<const sp<WebmFrame> >& sink,
             uint64_t timeCodeScale,
@@ -142,7 +142,7 @@
     }
 
 private:
-    const sp<MediaSource> mSource;
+    const sp<IMediaSource> mSource;
     const uint64_t mTimeCodeScale;
     uint64_t mStartTimeUs;
 
diff --git a/media/libstagefright/webm/WebmWriter.cpp b/media/libstagefright/webm/WebmWriter.cpp
index 737f144..511260a 100644
--- a/media/libstagefright/webm/WebmWriter.cpp
+++ b/media/libstagefright/webm/WebmWriter.cpp
@@ -83,9 +83,25 @@
 // static
 sp<WebmElement> WebmWriter::videoTrack(const sp<MetaData>& md) {
     int32_t width, height;
+    const char *mimeType;
     CHECK(md->findInt32(kKeyWidth, &width));
     CHECK(md->findInt32(kKeyHeight, &height));
-    return WebmElement::VideoTrackEntry(width, height);
+    CHECK(md->findCString(kKeyMIMEType, &mimeType));
+    const char *codec;
+    if (!strncasecmp(
+            mimeType,
+            MEDIA_MIMETYPE_VIDEO_VP8,
+            strlen(MEDIA_MIMETYPE_VIDEO_VP8))) {
+        codec = "V_VP8";
+    } else if (!strncasecmp(
+            mimeType,
+            MEDIA_MIMETYPE_VIDEO_VP9,
+            strlen(MEDIA_MIMETYPE_VIDEO_VP9))) {
+        codec = "V_VP9";
+    } else {
+        CHECK(!"Unsupported codec");
+    }
+    return WebmElement::VideoTrackEntry(codec, width, height);
 }
 
 // static
@@ -328,7 +344,7 @@
     return err;
 }
 
-status_t WebmWriter::addSource(const sp<MediaSource> &source) {
+status_t WebmWriter::addSource(const sp<IMediaSource> &source) {
     Mutex::Autolock l(mLock);
     if (mStarted) {
         ALOGE("Attempt to add source AFTER recording is started");
@@ -348,15 +364,18 @@
     const char *mime;
     source->getFormat()->findCString(kKeyMIMEType, &mime);
     const char *vp8 = MEDIA_MIMETYPE_VIDEO_VP8;
+    const char *vp9 = MEDIA_MIMETYPE_VIDEO_VP9;
     const char *vorbis = MEDIA_MIMETYPE_AUDIO_VORBIS;
 
     size_t streamIndex;
-    if (!strncasecmp(mime, vp8, strlen(vp8))) {
+    if (!strncasecmp(mime, vp8, strlen(vp8)) ||
+        !strncasecmp(mime, vp9, strlen(vp9))) {
         streamIndex = kVideoIndex;
     } else if (!strncasecmp(mime, vorbis, strlen(vorbis))) {
         streamIndex = kAudioIndex;
     } else {
-        ALOGE("Track (%s) other than %s or %s is not supported", mime, vp8, vorbis);
+        ALOGE("Track (%s) other than %s, %s or %s is not supported",
+              mime, vp8, vp9, vorbis);
         return ERROR_UNSUPPORTED;
     }
 
diff --git a/media/libstagefright/webm/WebmWriter.h b/media/libstagefright/webm/WebmWriter.h
index 4ad770e..4a7f506 100644
--- a/media/libstagefright/webm/WebmWriter.h
+++ b/media/libstagefright/webm/WebmWriter.h
@@ -40,7 +40,7 @@
     ~WebmWriter() { reset(); }
 
 
-    virtual status_t addSource(const sp<MediaSource> &source);
+    virtual status_t addSource(const sp<IMediaSource> &source);
     virtual status_t start(MetaData *param = NULL);
     virtual status_t stop();
     virtual status_t pause();
@@ -85,7 +85,7 @@
         const char *mName;
         sp<WebmElement> (*mMakeTrack)(const sp<MetaData>&);
 
-        sp<MediaSource> mSource;
+        sp<IMediaSource> mSource;
         sp<WebmElement> mTrackEntry;
         sp<WebmFrameSourceThread> mThread;
         LinkedBlockingQueue<const sp<WebmFrame> > mSink;
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index 580d8c1..ee99a26 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -14,22 +14,15 @@
 	main_mediaserver.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libaudioflinger \
-	libaudiopolicyservice \
 	libcamera_metadata\
 	libcameraservice \
-	libicuuc \
 	libmedialogservice \
 	libresourcemanagerservice \
 	libcutils \
-	libnbaio \
 	libmedia \
 	libmediaplayerservice \
 	libutils \
-	liblog \
 	libbinder \
-	libsoundtriggerservice \
-	libradioservice
 
 LOCAL_STATIC_LIBRARIES := \
         libicuandroid_utils \
@@ -37,18 +30,8 @@
 
 LOCAL_C_INCLUDES := \
     frameworks/av/media/libmediaplayerservice \
-    frameworks/av/services/medialog \
-    frameworks/av/services/audioflinger \
-    frameworks/av/services/audiopolicy \
-    frameworks/av/services/audiopolicy/common/managerdefinitions/include \
-    frameworks/av/services/audiopolicy/common/include \
-    frameworks/av/services/audiopolicy/engine/interface \
     frameworks/av/services/camera/libcameraservice \
     frameworks/av/services/mediaresourcemanager \
-    $(call include-path-for, audio-utils) \
-    frameworks/av/services/soundtrigger \
-    frameworks/av/services/radio \
-    external/sonic
 
 LOCAL_MODULE:= mediaserver
 LOCAL_32_BIT_ONLY := true
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 315aff4..e006e89 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -18,130 +18,29 @@
 #define LOG_TAG "mediaserver"
 //#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 <cutils/properties.h>
 #include <utils/Log.h>
 #include "RegisterExtensions.h"
 
 // from LOCAL_C_INCLUDES
-#include "AudioFlinger.h"
 #include "CameraService.h"
-#include "IcuUtils.h"
-#include "MediaLogService.h"
 #include "MediaPlayerService.h"
 #include "ResourceManagerService.h"
-#include "service/AudioPolicyService.h"
-#include "SoundTriggerHwService.h"
-#include "RadioService.h"
 
 using namespace android;
 
-int main(int argc __unused, char** argv)
+int main(int argc __unused, char **argv __unused)
 {
     signal(SIGPIPE, SIG_IGN);
-    char value[PROPERTY_VALUE_MAX];
-    bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
-    pid_t childPid;
-    // FIXME The advantage of making the process containing media.log service the parent process of
-    // the process that contains all the other real services, is that it allows us to collect more
-    // detailed information such as signal numbers, stop and continue, resource usage, etc.
-    // But it is also more complex.  Consider replacing this by independent processes, and using
-    // binder on death notification instead.
-    if (doLog && (childPid = fork()) != 0) {
-        // media.log service
-        //prctl(PR_SET_NAME, (unsigned long) "media.log", 0, 0, 0);
-        // unfortunately ps ignores PR_SET_NAME for the main thread, so use this ugly hack
-        strcpy(argv[0], "media.log");
-        sp<ProcessState> proc(ProcessState::self());
-        MediaLogService::instantiate();
-        ProcessState::self()->startThreadPool();
-        for (;;) {
-            siginfo_t info;
-            int ret = waitid(P_PID, childPid, &info, WEXITED | WSTOPPED | WCONTINUED);
-            if (ret == EINTR) {
-                continue;
-            }
-            if (ret < 0) {
-                break;
-            }
-            char buffer[32];
-            const char *code;
-            switch (info.si_code) {
-            case CLD_EXITED:
-                code = "CLD_EXITED";
-                break;
-            case CLD_KILLED:
-                code = "CLD_KILLED";
-                break;
-            case CLD_DUMPED:
-                code = "CLD_DUMPED";
-                break;
-            case CLD_STOPPED:
-                code = "CLD_STOPPED";
-                break;
-            case CLD_TRAPPED:
-                code = "CLD_TRAPPED";
-                break;
-            case CLD_CONTINUED:
-                code = "CLD_CONTINUED";
-                break;
-            default:
-                snprintf(buffer, sizeof(buffer), "unknown (%d)", info.si_code);
-                code = buffer;
-                break;
-            }
-            struct rusage usage;
-            getrusage(RUSAGE_CHILDREN, &usage);
-            ALOG(LOG_ERROR, "media.log", "pid %d status %d code %s user %ld.%03lds sys %ld.%03lds",
-                    info.si_pid, info.si_status, code,
-                    usage.ru_utime.tv_sec, usage.ru_utime.tv_usec / 1000,
-                    usage.ru_stime.tv_sec, usage.ru_stime.tv_usec / 1000);
-            sp<IServiceManager> sm = defaultServiceManager();
-            sp<IBinder> binder = sm->getService(String16("media.log"));
-            if (binder != 0) {
-                Vector<String16> args;
-                binder->dump(-1, args);
-            }
-            switch (info.si_code) {
-            case CLD_EXITED:
-            case CLD_KILLED:
-            case CLD_DUMPED: {
-                ALOG(LOG_INFO, "media.log", "exiting");
-                _exit(0);
-                // not reached
-                }
-            default:
-                break;
-            }
-        }
-    } else {
-        // all other services
-        if (doLog) {
-            prctl(PR_SET_PDEATHSIG, SIGKILL);   // if parent media.log dies before me, kill me also
-            setpgid(0, 0);                      // but if I die first, don't kill my parent
-        }
-#ifndef __BRILLO__
-        // Brillo is headless and very resource constrained. As such, it doesn't
-        // need an internationalization library for now.
-        InitializeIcuOrDie();
-#endif
-        sp<ProcessState> proc(ProcessState::self());
-        sp<IServiceManager> sm = defaultServiceManager();
-        ALOGI("ServiceManager: %p", sm.get());
-        AudioFlinger::instantiate();
-        MediaPlayerService::instantiate();
-        ResourceManagerService::instantiate();
-        CameraService::instantiate();
-        AudioPolicyService::instantiate();
-        SoundTriggerHwService::instantiate();
-        RadioService::instantiate();
-        registerExtensions();
-        ProcessState::self()->startThreadPool();
-        IPCThreadState::self()->joinThreadPool();
-    }
+
+    sp<ProcessState> proc(ProcessState::self());
+    sp<IServiceManager> sm(defaultServiceManager());
+    ALOGI("ServiceManager: %p", sm.get());
+    MediaPlayerService::instantiate();
+    ResourceManagerService::instantiate();
+    registerExtensions();
+    ProcessState::self()->startThreadPool();
+    IPCThreadState::self()->joinThreadPool();
 }
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 052b700..d0ec2a6 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -25,8 +25,6 @@
 #include "MtpDataPacket.h"
 #include "MtpStringBuffer.h"
 
-#define MTP_BUFFER_SIZE 16384
-
 namespace android {
 
 MtpDataPacket::MtpDataPacket()
@@ -525,16 +523,9 @@
 int MtpDataPacket::write(struct usb_request *request) {
     MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
     MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
-
-    // send header separately from data
     request->buffer = mBuffer;
-    request->buffer_length = MTP_CONTAINER_HEADER_SIZE;
+    request->buffer_length = mPacketSize;
     int ret = transfer(request);
-    if (ret == MTP_CONTAINER_HEADER_SIZE) {
-        request->buffer = mBuffer + MTP_CONTAINER_HEADER_SIZE;
-        request->buffer_length = mPacketSize - MTP_CONTAINER_HEADER_SIZE;
-        ret = transfer(request);
-    }
     return (ret < 0 ? ret : 0);
 }
 
@@ -547,17 +538,17 @@
 
 #endif // MTP_HOST
 
-void* MtpDataPacket::getData(int& outLength) const {
+void* MtpDataPacket::getData(int* outLength) const {
     int length = mPacketSize - MTP_CONTAINER_HEADER_SIZE;
     if (length > 0) {
         void* result = malloc(length);
         if (result) {
             memcpy(result, mBuffer + MTP_CONTAINER_HEADER_SIZE, length);
-            outLength = length;
+            *outLength = length;
             return result;
         }
     }
-    outLength = 0;
+    *outLength = 0;
     return NULL;
 }
 
diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h
index 13d3bd9..6240f28 100644
--- a/media/mtp/MtpDataPacket.h
+++ b/media/mtp/MtpDataPacket.h
@@ -117,7 +117,7 @@
 
     inline bool         hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; }
     inline uint32_t     getContainerLength() const { return MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET); }
-    void*               getData(int& outLength) const;
+    void*               getData(int* outLength) const;
 };
 
 }; // namespace android
diff --git a/media/mtp/MtpDebug.cpp b/media/mtp/MtpDebug.cpp
index 9f3037d..1c04bcf 100644
--- a/media/mtp/MtpDebug.cpp
+++ b/media/mtp/MtpDebug.cpp
@@ -101,6 +101,7 @@
     { "MTP_FORMAT_TIFF_IT",                         0x380E },
     { "MTP_FORMAT_JP2",                             0x380F },
     { "MTP_FORMAT_JPX",                             0x3810 },
+    { "MTP_FORMAT_DNG",                             0x3811 },
     { "MTP_FORMAT_UNDEFINED_FIRMWARE",              0xB802 },
     { "MTP_FORMAT_WINDOWS_IMAGE_FORMAT",            0xB881 },
     { "MTP_FORMAT_UNDEFINED_AUDIO",                 0xB900 },
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 3eafd6f..7d7ea13 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -19,6 +19,7 @@
 #include "MtpDebug.h"
 #include "MtpDevice.h"
 #include "MtpDeviceInfo.h"
+#include "MtpEventPacket.h"
 #include "MtpObjectInfo.h"
 #include "MtpProperty.h"
 #include "MtpStorageInfo.h"
@@ -50,6 +51,19 @@
 }
 #endif
 
+namespace {
+
+bool writeToFd(void* data, uint32_t /* unused_offset */, uint32_t length, void* clientData) {
+    const int fd = *static_cast<int*>(clientData);
+    const ssize_t result = write(fd, data, length);
+    if (result < 0) {
+        return false;
+    }
+    return static_cast<uint32_t>(result) == length;
+}
+
+}  // namespace
+
 MtpDevice* MtpDevice::open(const char* deviceName, int fd) {
     struct usb_device *device = usb_device_new(deviceName, fd);
     if (!device) {
@@ -123,6 +137,10 @@
                     printf("no MTP string\n");
                 }
             }
+#else
+            else {
+                continue;
+            }
 #endif
             // if we got here, then we have a likely MTP or PTP device
 
@@ -163,7 +181,13 @@
                 return NULL;
             }
 
-            if (usb_device_claim_interface(device, interface->bInterfaceNumber)) {
+            int ret = usb_device_claim_interface(device, interface->bInterfaceNumber);
+            if (ret && errno == EBUSY) {
+                // disconnect kernel driver and try again
+                usb_device_connect_kernel_driver(device, interface->bInterfaceNumber, false);
+                ret = usb_device_claim_interface(device, interface->bInterfaceNumber);
+            }
+            if (ret) {
                 ALOGE("usb_device_claim_interface failed errno: %d\n", errno);
                 usb_device_close(device);
                 return NULL;
@@ -194,7 +218,9 @@
         mDeviceInfo(NULL),
         mSessionID(0),
         mTransactionID(0),
-        mReceivedResponse(false)
+        mReceivedResponse(false),
+        mProcessingEvent(false),
+        mCurrentEventHandle(0)
 {
     mRequestIn1 = usb_request_new(device, ep_in);
     mRequestIn2 = usb_request_new(device, ep_in);
@@ -414,7 +440,7 @@
     if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
         MtpResponseCode ret = readResponse();
         if (ret == MTP_RESPONSE_OK) {
-            return mData.getData(outLength);
+            return mData.getData(&outLength);
         }
     }
     outLength = 0;
@@ -430,8 +456,9 @@
         parent = MTP_PARENT_ROOT;
 
     mRequest.setParameter(1, info->mStorageID);
-    mRequest.setParameter(2, info->mParent);
+    mRequest.setParameter(2, parent);
 
+    mData.reset();
     mData.putUInt32(info->mStorageID);
     mData.putUInt16(info->mFormat);
     mData.putUInt16(info->mProtectionStatus);
@@ -472,17 +499,18 @@
     return (MtpObjectHandle)-1;
 }
 
-bool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) {
+bool MtpDevice::sendObject(MtpObjectHandle handle, int size, int srcFD) {
     Mutex::Autolock autoLock(mMutex);
 
-    int remaining = info->mCompressedSize;
+    int remaining = size;
     mRequest.reset();
-    mRequest.setParameter(1, info->mHandle);
+    mRequest.setParameter(1, handle);
     if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
         // send data header
         writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
 
-        char buffer[65536];
+        // USB writes greater than 16K don't work
+        char buffer[MTP_BUFFER_SIZE];
         while (remaining > 0) {
             int count = read(srcFD, buffer, sizeof(buffer));
             if (count > 0) {
@@ -592,97 +620,12 @@
 }
 
 bool MtpDevice::readObject(MtpObjectHandle handle,
-        bool (* callback)(void* data, int offset, int length, void* clientData),
-        size_t objectSize, void* clientData) {
-    Mutex::Autolock autoLock(mMutex);
-    bool result = false;
-
-    mRequest.reset();
-    mRequest.setParameter(1, handle);
-    if (sendRequest(MTP_OPERATION_GET_OBJECT)
-            && mData.readDataHeader(mRequestIn1)) {
-        uint32_t length = mData.getContainerLength();
-        if (length - MTP_CONTAINER_HEADER_SIZE != objectSize) {
-            ALOGE("readObject error objectSize: %d, length: %d",
-                    objectSize, length);
-            goto fail;
-        }
-        length -= MTP_CONTAINER_HEADER_SIZE;
-        uint32_t remaining = length;
-        int offset = 0;
-
-        int initialDataLength = 0;
-        void* initialData = mData.getData(initialDataLength);
-        if (initialData) {
-            if (initialDataLength > 0) {
-                if (!callback(initialData, 0, initialDataLength, clientData))
-                    goto fail;
-                remaining -= initialDataLength;
-                offset += initialDataLength;
-            }
-            free(initialData);
-        }
-
-        // USB reads greater than 16K don't work
-        char buffer1[16384], buffer2[16384];
-        mRequestIn1->buffer = buffer1;
-        mRequestIn2->buffer = buffer2;
-        struct usb_request* req = mRequestIn1;
-        void* writeBuffer = NULL;
-        int writeLength = 0;
-
-        while (remaining > 0 || writeBuffer) {
-            if (remaining > 0) {
-                // queue up a read request
-                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
-                if (mData.readDataAsync(req)) {
-                    ALOGE("readDataAsync failed");
-                    goto fail;
-                }
-            } else {
-                req = NULL;
-            }
-
-            if (writeBuffer) {
-                // write previous buffer
-                if (!callback(writeBuffer, offset, writeLength, clientData)) {
-                    ALOGE("write failed");
-                    // wait for pending read before failing
-                    if (req)
-                        mData.readDataWait(mDevice);
-                    goto fail;
-                }
-                offset += writeLength;
-                writeBuffer = NULL;
-            }
-
-            // wait for read to complete
-            if (req) {
-                int read = mData.readDataWait(mDevice);
-                if (read < 0)
-                    goto fail;
-
-                if (read > 0) {
-                    writeBuffer = req->buffer;
-                    writeLength = read;
-                    remaining -= read;
-                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
-                } else {
-                    writeBuffer = NULL;
-                }
-            }
-        }
-
-        MtpResponseCode response = readResponse();
-        if (response == MTP_RESPONSE_OK)
-            result = true;
-    }
-
-fail:
-    return result;
+                           ReadObjectCallback callback,
+                           uint32_t expectedLength,
+                           void* clientData) {
+    return readObjectInternal(handle, callback, &expectedLength, clientData);
 }
 
-
 // reads the object's data and writes it to the specified file path
 bool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
     ALOGD("readObject: %s", destPath);
@@ -698,89 +641,176 @@
     fchmod(fd, perm);
     umask(mask);
 
+    bool result = readObject(handle, fd);
+    ::close(fd);
+    return result;
+}
+
+bool MtpDevice::readObject(MtpObjectHandle handle, int fd) {
+    ALOGD("readObject: %d", fd);
+    return readObjectInternal(handle, writeToFd, NULL /* expected size */, &fd);
+}
+
+bool MtpDevice::readObjectInternal(MtpObjectHandle handle,
+                                   ReadObjectCallback callback,
+                                   const uint32_t* expectedLength,
+                                   void* clientData) {
     Mutex::Autolock autoLock(mMutex);
-    bool result = false;
 
     mRequest.reset();
     mRequest.setParameter(1, handle);
-    if (sendRequest(MTP_OPERATION_GET_OBJECT)
-            && mData.readDataHeader(mRequestIn1)) {
-        uint32_t length = mData.getContainerLength();
-        if (length < MTP_CONTAINER_HEADER_SIZE)
-            goto fail;
-        length -= MTP_CONTAINER_HEADER_SIZE;
-        uint32_t remaining = length;
+    if (!sendRequest(MTP_OPERATION_GET_OBJECT)) {
+        ALOGE("Failed to send a read request.");
+        return false;
+    }
 
+    return readData(callback, expectedLength, nullptr, clientData);
+}
+
+bool MtpDevice::readData(ReadObjectCallback callback,
+                            const uint32_t* expectedLength,
+                            uint32_t* writtenSize,
+                            void* clientData) {
+    if (!mData.readDataHeader(mRequestIn1)) {
+        ALOGE("Failed to read header.");
+        return false;
+    }
+
+    if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
+        mResponse.copyFrom(mData);
+        return mResponse.getResponseCode() == MTP_RESPONSE_OK ? 0 : -1;
+    }
+
+    // If object size 0 byte, the remote device can reply response packet
+    // without sending any data packets.
+    if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
+        mResponse.copyFrom(mData);
+        return mResponse.getResponseCode() == MTP_RESPONSE_OK;
+    }
+
+    const uint32_t fullLength = mData.getContainerLength();
+    if (fullLength < MTP_CONTAINER_HEADER_SIZE) {
+        ALOGE("fullLength is too short: %d", fullLength);
+        return false;
+    }
+    const uint32_t length = fullLength - MTP_CONTAINER_HEADER_SIZE;
+    if (expectedLength && length != *expectedLength) {
+        ALOGE("readObject error length: %d", fullLength);
+        return false;
+    }
+
+    uint32_t offset = 0;
+    bool writingError = false;
+
+    {
         int initialDataLength = 0;
-        void* initialData = mData.getData(initialDataLength);
+        void* const initialData = mData.getData(&initialDataLength);
         if (initialData) {
             if (initialDataLength > 0) {
-                if (write(fd, initialData, initialDataLength) != initialDataLength) {
-                    free(initialData);
-                    goto fail;
+                if (!callback(initialData, offset, initialDataLength, clientData)) {
+                    ALOGE("Failed to write initial data.");
+                    writingError = true;
                 }
-                remaining -= initialDataLength;
+                offset += initialDataLength;
             }
             free(initialData);
         }
+    }
 
-        // USB reads greater than 16K don't work
-        char buffer1[16384], buffer2[16384];
-        mRequestIn1->buffer = buffer1;
-        mRequestIn2->buffer = buffer2;
-        struct usb_request* req = mRequestIn1;
+    // USB reads greater than 16K don't work.
+    char buffer1[MTP_BUFFER_SIZE], buffer2[MTP_BUFFER_SIZE];
+    mRequestIn1->buffer = buffer1;
+    mRequestIn2->buffer = buffer2;
+    struct usb_request* req = NULL;
+
+    while (offset < length) {
+        // Wait for previous read to complete.
         void* writeBuffer = NULL;
         int writeLength = 0;
-
-        while (remaining > 0 || writeBuffer) {
-            if (remaining > 0) {
-                // queue up a read request
-                req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
-                if (mData.readDataAsync(req)) {
-                    ALOGE("readDataAsync failed");
-                    goto fail;
-                }
-            } else {
-                req = NULL;
+        if (req) {
+            const int read = mData.readDataWait(mDevice);
+            if (read < 0) {
+                ALOGE("readDataWait failed.");
+                return false;
             }
+            writeBuffer = req->buffer;
+            writeLength = read;
+        }
 
-            if (writeBuffer) {
-                // write previous buffer
-                if (write(fd, writeBuffer, writeLength) != writeLength) {
-                    ALOGE("write failed");
-                    // wait for pending read before failing
-                    if (req)
-                        mData.readDataWait(mDevice);
-                    goto fail;
-                }
-                writeBuffer = NULL;
-            }
-
-            // wait for read to complete
-            if (req) {
-                int read = mData.readDataWait(mDevice);
-                if (read < 0)
-                    goto fail;
-
-                if (read > 0) {
-                    writeBuffer = req->buffer;
-                    writeLength = read;
-                    remaining -= read;
-                    req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
-                } else {
-                    writeBuffer = NULL;
-                }
+        // Request to read next chunk.
+        const uint32_t nextOffset = offset + writeLength;
+        if (nextOffset < length) {
+            // Queue up a read request.
+            const size_t remaining = length - nextOffset;
+            req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
+            req->buffer_length = remaining > MTP_BUFFER_SIZE ?
+                    static_cast<size_t>(MTP_BUFFER_SIZE) : remaining;
+            if (mData.readDataAsync(req) != 0) {
+                ALOGE("readDataAsync failed");
+                return false;
             }
         }
 
-        MtpResponseCode response = readResponse();
-        if (response == MTP_RESPONSE_OK)
-            result = true;
+        // Write previous buffer.
+        if (writeBuffer && !writingError) {
+            if (!callback(writeBuffer, offset, writeLength, clientData)) {
+                ALOGE("write failed");
+                writingError = true;
+            }
+        }
+        offset = nextOffset;
     }
 
-fail:
-    ::close(fd);
-    return result;
+    if (writtenSize) {
+        *writtenSize = length;
+    }
+
+    return readResponse() == MTP_RESPONSE_OK;
+}
+
+bool MtpDevice::readPartialObject(MtpObjectHandle handle,
+                                  uint32_t offset,
+                                  uint32_t size,
+                                  uint32_t *writtenSize,
+                                  ReadObjectCallback callback,
+                                  void* clientData) {
+    Mutex::Autolock autoLock(mMutex);
+
+    mRequest.reset();
+    mRequest.setParameter(1, handle);
+    mRequest.setParameter(2, offset);
+    mRequest.setParameter(3, size);
+    if (!sendRequest(MTP_OPERATION_GET_PARTIAL_OBJECT)) {
+        ALOGE("Failed to send a read request.");
+        return false;
+    }
+    // The expected size is null because it requires the exact number of bytes to read though
+    // MTP_OPERATION_GET_PARTIAL_OBJECT allows devices to return shorter length of bytes than
+    // requested. Destination's buffer length should be checked in |callback|.
+    return readData(callback, nullptr /* expected size */, writtenSize, clientData);
+}
+
+bool MtpDevice::readPartialObject64(MtpObjectHandle handle,
+                                    uint64_t offset,
+                                    uint32_t size,
+                                    uint32_t *writtenSize,
+                                    ReadObjectCallback callback,
+                                    void* clientData) {
+    Mutex::Autolock autoLock(mMutex);
+
+    mRequest.reset();
+    mRequest.setParameter(1, handle);
+    mRequest.setParameter(2, 0xffffffff & offset);
+    mRequest.setParameter(3, 0xffffffff & (offset >> 32));
+    mRequest.setParameter(4, size);
+    if (!sendRequest(MTP_OPERATION_GET_PARTIAL_OBJECT_64)) {
+        ALOGE("Failed to send a read request.");
+        return false;
+    }
+    // The expected size is null because it requires the exact number of bytes to read though
+    // MTP_OPERATION_GET_PARTIAL_OBJECT_64 allows devices to return shorter length of bytes than
+    // requested. Destination's buffer length should be checked in |callback|.
+    return readData(callback, nullptr /* expected size */, writtenSize, clientData);
 }
 
 bool MtpDevice::sendRequest(MtpOperationCode operation) {
@@ -800,7 +830,7 @@
     mData.setTransactionID(mRequest.getTransactionID());
     int ret = mData.write(mRequestOut);
     mData.dump();
-    return (ret > 0);
+    return (ret >= 0);
 }
 
 bool MtpDevice::readData() {
@@ -851,4 +881,44 @@
     }
 }
 
+int MtpDevice::submitEventRequest() {
+    if (mEventMutex.tryLock()) {
+        // An event is being reaped on another thread.
+        return -1;
+    }
+    if (mProcessingEvent) {
+        // An event request was submitted, but no reapEventRequest called so far.
+        return -1;
+    }
+    Mutex::Autolock autoLock(mEventMutexForInterrupt);
+    mEventPacket.sendRequest(mRequestIntr);
+    const int currentHandle = ++mCurrentEventHandle;
+    mProcessingEvent = true;
+    mEventMutex.unlock();
+    return currentHandle;
+}
+
+int MtpDevice::reapEventRequest(int handle, uint32_t (*parameters)[3]) {
+    Mutex::Autolock autoLock(mEventMutex);
+    if (!mProcessingEvent || mCurrentEventHandle != handle || !parameters) {
+        return -1;
+    }
+    mProcessingEvent = false;
+    const int readSize = mEventPacket.readResponse(mRequestIntr->dev);
+    const int result = mEventPacket.getEventCode();
+    // MTP event has three parameters.
+    (*parameters)[0] = mEventPacket.getParameter(1);
+    (*parameters)[1] = mEventPacket.getParameter(2);
+    (*parameters)[2] = mEventPacket.getParameter(3);
+    return readSize != 0 ? result : 0;
+}
+
+void MtpDevice::discardEventRequest(int handle) {
+    Mutex::Autolock autoLock(mEventMutexForInterrupt);
+    if (mCurrentEventHandle != handle) {
+        return;
+    }
+    usb_request_cancel(mRequestIntr);
+}
+
 }  // namespace android
diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h
index 9b0acbf..ce60811 100644
--- a/media/mtp/MtpDevice.h
+++ b/media/mtp/MtpDevice.h
@@ -17,8 +17,9 @@
 #ifndef _MTP_DEVICE_H
 #define _MTP_DEVICE_H
 
-#include "MtpRequestPacket.h"
+#include "MtpEventPacket.h"
 #include "MtpDataPacket.h"
+#include "MtpRequestPacket.h"
 #include "MtpResponsePacket.h"
 #include "MtpTypes.h"
 
@@ -31,6 +32,7 @@
 namespace android {
 
 class MtpDeviceInfo;
+class MtpEventPacket;
 class MtpObjectInfo;
 class MtpStorageInfo;
 
@@ -53,17 +55,27 @@
     MtpRequestPacket        mRequest;
     MtpDataPacket           mData;
     MtpResponsePacket       mResponse;
+    MtpEventPacket          mEventPacket;
+
     // set to true if we received a response packet instead of a data packet
     bool                    mReceivedResponse;
+    bool                    mProcessingEvent;
+    int                     mCurrentEventHandle;
 
     // to ensure only one MTP transaction at a time
     Mutex                   mMutex;
+    Mutex                   mEventMutex;
+    Mutex                   mEventMutexForInterrupt;
 
 public:
-                            MtpDevice(struct usb_device* device, int interface,
-                                    const struct usb_endpoint_descriptor *ep_in,
-                                    const struct usb_endpoint_descriptor *ep_out,
-                                    const struct usb_endpoint_descriptor *ep_intr);
+    typedef bool (*ReadObjectCallback)
+            (void* data, uint32_t offset, uint32_t length, void* clientData);
+
+    MtpDevice(struct usb_device* device,
+              int interface,
+              const struct usb_endpoint_descriptor *ep_in,
+              const struct usb_endpoint_descriptor *ep_out,
+              const struct usb_endpoint_descriptor *ep_intr);
 
     static MtpDevice*       open(const char* deviceName, int fd);
 
@@ -85,7 +97,7 @@
     MtpObjectInfo*          getObjectInfo(MtpObjectHandle handle);
     void*                   getThumbnail(MtpObjectHandle handle, int& outLength);
     MtpObjectHandle         sendObjectInfo(MtpObjectInfo* info);
-    bool                    sendObject(MtpObjectInfo* info, int srcFD);
+    bool                    sendObject(MtpObjectHandle handle, int size, int srcFD);
     bool                    deleteObject(MtpObjectHandle handle);
     MtpObjectHandle         getParent(MtpObjectHandle handle);
     MtpObjectHandle         getStorageID(MtpObjectHandle handle);
@@ -95,20 +107,53 @@
     MtpProperty*            getDevicePropDesc(MtpDeviceProperty code);
     MtpProperty*            getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format);
 
-    bool                    readObject(MtpObjectHandle handle,
-                                    bool (* callback)(void* data, int offset,
-                                            int length, void* clientData),
-                                    size_t objectSize, void* clientData);
+    bool                    readObject(MtpObjectHandle handle, ReadObjectCallback callback,
+                                    uint32_t objectSize, void* clientData);
     bool                    readObject(MtpObjectHandle handle, const char* destPath, int group,
                                     int perm);
+    bool                    readObject(MtpObjectHandle handle, int fd);
+    bool                    readPartialObject(MtpObjectHandle handle,
+                                              uint32_t offset,
+                                              uint32_t size,
+                                              uint32_t *writtenSize,
+                                              ReadObjectCallback callback,
+                                              void* clientData);
+    bool                    readPartialObject64(MtpObjectHandle handle,
+                                                uint64_t offset,
+                                                uint32_t size,
+                                                uint32_t *writtenSize,
+                                                ReadObjectCallback callback,
+                                                void* clientData);
+    // Starts a request to read MTP event from MTP device. It returns a request handle that
+    // can be used for blocking read or cancel. If other thread has already been processing an
+    // event returns -1.
+    int                     submitEventRequest();
+    // Waits for MTP event from the device and returns MTP event code. It blocks the current thread
+    // until it receives an event from the device. |handle| should be a request handle returned
+    // by |submitEventRequest|. The function writes event parameters to |parameters|. Returns 0 for
+    // cancellations. Returns -1 for errors.
+    int                     reapEventRequest(int handle, uint32_t (*parameters)[3]);
+    // Cancels an event request. |handle| should be request handle returned by
+    // |submitEventRequest|. If there is a thread blocked by |reapEventRequest| with the same
+    // |handle|, the thread will resume.
+    void                    discardEventRequest(int handle);
 
 private:
+    // If |objectSize| is not NULL, it checks object size before reading data bytes.
+    bool                    readObjectInternal(MtpObjectHandle handle,
+                                               ReadObjectCallback callback,
+                                               const uint32_t* objectSize,
+                                               void* clientData);
+    // If |objectSize| is not NULL, it checks object size before reading data bytes.
+    bool                    readData(ReadObjectCallback callback,
+                                     const uint32_t* objectSize,
+                                     uint32_t* writtenData,
+                                     void* clientData);
     bool                    sendRequest(MtpOperationCode operation);
     bool                    sendData();
     bool                    readData();
     bool                    writeDataHeader(MtpOperationCode operation, int dataLength);
     MtpResponseCode         readResponse();
-
 };
 
 }; // namespace android
diff --git a/media/mtp/MtpEventPacket.cpp b/media/mtp/MtpEventPacket.cpp
index d2fca42..8e13ea9 100644
--- a/media/mtp/MtpEventPacket.cpp
+++ b/media/mtp/MtpEventPacket.cpp
@@ -54,17 +54,26 @@
 #endif
 
 #ifdef MTP_HOST
-int MtpEventPacket::read(struct usb_request *request) {
+int MtpEventPacket::sendRequest(struct usb_request *request) {
     request->buffer = mBuffer;
     request->buffer_length = mBufferSize;
-    int ret = transfer(request);
-     if (ret >= 0)
-        mPacketSize = ret;
-    else
-        mPacketSize = 0;
-    return ret;
+    mPacketSize = 0;
+    if (usb_request_queue(request)) {
+        ALOGE("usb_endpoint_queue failed, errno: %d", errno);
+        return -1;
+    }
+    return 0;
+}
+
+int MtpEventPacket::readResponse(struct usb_device *device) {
+    struct usb_request* const req = usb_request_wait(device);
+    if (req) {
+        mPacketSize = req->actual_length;
+        return req->actual_length;
+    } else {
+        return -1;
+    }
 }
 #endif
 
 }  // namespace android
-
diff --git a/media/mtp/MtpEventPacket.h b/media/mtp/MtpEventPacket.h
index 660baad..a8779fd 100644
--- a/media/mtp/MtpEventPacket.h
+++ b/media/mtp/MtpEventPacket.h
@@ -35,7 +35,8 @@
 
 #ifdef MTP_HOST
     // read our buffer with the given request
-    int                 read(struct usb_request *request);
+    int                 sendRequest(struct usb_request *request);
+    int                 readResponse(struct usb_device *device);
 #endif
 
     inline MtpEventCode     getEventCode() const { return getContainerCode(); }
diff --git a/media/mtp/MtpPacket.h b/media/mtp/MtpPacket.h
index 037722a..0e96309 100644
--- a/media/mtp/MtpPacket.h
+++ b/media/mtp/MtpPacket.h
@@ -19,6 +19,7 @@
 
 #include "MtpTypes.h"
 
+struct usb_device;
 struct usb_request;
 
 namespace android {
diff --git a/media/mtp/mtp.h b/media/mtp/mtp.h
index d270df5..adfb102 100644
--- a/media/mtp/mtp.h
+++ b/media/mtp/mtp.h
@@ -37,6 +37,9 @@
 #define MTP_CONTAINER_PARAMETER_OFFSET          12
 #define MTP_CONTAINER_HEADER_SIZE               12
 
+// Maximum buffer size for a MTP packet.
+#define MTP_BUFFER_SIZE 16384
+
 // MTP Data Types
 #define MTP_TYPE_UNDEFINED      0x0000          // Undefined
 #define MTP_TYPE_INT8           0x0001          // Signed 8-bit integer
@@ -90,6 +93,7 @@
 #define MTP_FORMAT_TIFF_IT                              0x380E   // Tag Image File Format for Information Technology (graphic arts)
 #define MTP_FORMAT_JP2                                  0x380F   // JPEG2000 Baseline File Format
 #define MTP_FORMAT_JPX                                  0x3810   // JPEG2000 Extended File Format
+#define MTP_FORMAT_DNG                                  0x3811   // Digital Negative
 #define MTP_FORMAT_UNDEFINED_FIRMWARE                   0xB802
 #define MTP_FORMAT_WINDOWS_IMAGE_FORMAT                 0xB881
 #define MTP_FORMAT_UNDEFINED_AUDIO                      0xB900
diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk
index 8f795cd..8dbb291 100644
--- a/media/ndk/Android.mk
+++ b/media/ndk/Android.mk
@@ -27,13 +27,16 @@
                   NdkMediaFormat.cpp                    \
                   NdkMediaMuxer.cpp                     \
                   NdkMediaDrm.cpp                       \
+                  NdkImage.cpp                          \
+                  NdkImageReader.cpp                    \
 
 LOCAL_MODULE:= libmediandk
 
 LOCAL_C_INCLUDES := \
     bionic/libc/private \
     frameworks/base/core/jni \
-    frameworks/av/include/ndk
+    frameworks/av/include/ndk \
+    system/media/camera/include
 
 LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
 
@@ -44,8 +47,11 @@
     libstagefright_foundation \
     liblog \
     libutils \
+    libcutils \
     libandroid_runtime \
     libbinder \
+    libgui \
+    libui \
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp
new file mode 100644
index 0000000..40900ad
--- /dev/null
+++ b/media/ndk/NdkImage.cpp
@@ -0,0 +1,631 @@
+/*
+ * 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.
+ */
+
+#include <inttypes.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NdkImage"
+
+#include "NdkImagePriv.h"
+#include "NdkImageReaderPriv.h"
+
+#include <utils/Log.h>
+#include "hardware/camera3.h"
+
+using namespace android;
+
+#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
+
+AImage::AImage(AImageReader* reader, int32_t format,
+        CpuConsumer::LockedBuffer* buffer, int64_t timestamp,
+        int32_t width, int32_t height, int32_t numPlanes) :
+        mReader(reader), mFormat(format),
+        mBuffer(buffer), mTimestamp(timestamp),
+        mWidth(width), mHeight(height), mNumPlanes(numPlanes) {
+}
+
+// Can only be called by free() with mLock hold
+AImage::~AImage() {
+    if (!mIsClosed) {
+        LOG_ALWAYS_FATAL(
+                "Error: AImage %p is deleted before returning buffer to AImageReader!", this);
+    }
+}
+
+bool
+AImage::isClosed() const {
+    Mutex::Autolock _l(mLock);
+    return mIsClosed;
+}
+
+void
+AImage::close() {
+    Mutex::Autolock _l(mLock);
+    if (mIsClosed) {
+        return;
+    }
+    sp<AImageReader> reader = mReader.promote();
+    if (reader == nullptr) {
+        LOG_ALWAYS_FATAL("Error: AImage not closed before AImageReader close!");
+        return;
+    }
+    reader->releaseImageLocked(this);
+    // Should have been set to nullptr in releaseImageLocked
+    // Set to nullptr here for extra safety only
+    mBuffer = nullptr;
+    mIsClosed = true;
+}
+
+void
+AImage::free() {
+    if (!isClosed()) {
+        ALOGE("Cannot free AImage before close!");
+        return;
+    }
+    Mutex::Autolock _l(mLock);
+    delete this;
+}
+
+void
+AImage::lockReader() const {
+    sp<AImageReader> reader = mReader.promote();
+    if (reader == nullptr) {
+        // Reader has been closed
+        return;
+    }
+    reader->mLock.lock();
+}
+
+void
+AImage::unlockReader() const {
+    sp<AImageReader> reader = mReader.promote();
+    if (reader == nullptr) {
+        // Reader has been closed
+        return;
+    }
+    reader->mLock.unlock();
+}
+
+media_status_t
+AImage::getWidth(int32_t* width) const {
+    if (width == nullptr) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    *width = -1;
+    if (isClosed()) {
+        ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+    *width = mWidth;
+    return AMEDIA_OK;
+}
+
+media_status_t
+AImage::getHeight(int32_t* height) const {
+    if (height == nullptr) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    *height = -1;
+    if (isClosed()) {
+        ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+    *height = mHeight;
+    return AMEDIA_OK;
+}
+
+media_status_t
+AImage::getFormat(int32_t* format) const {
+    if (format == nullptr) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    *format = -1;
+    if (isClosed()) {
+        ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+    *format = mFormat;
+    return AMEDIA_OK;
+}
+
+media_status_t
+AImage::getNumPlanes(int32_t* numPlanes) const {
+    if (numPlanes == nullptr) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    *numPlanes = -1;
+    if (isClosed()) {
+        ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+    *numPlanes = mNumPlanes;
+    return AMEDIA_OK;
+}
+
+media_status_t
+AImage::getTimestamp(int64_t* timestamp) const {
+    if (timestamp == nullptr) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    *timestamp = -1;
+    if (isClosed()) {
+        ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+    *timestamp = mTimestamp;
+    return AMEDIA_OK;
+}
+
+media_status_t
+AImage::getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const {
+    if (planeIdx < 0 || planeIdx >= mNumPlanes) {
+        ALOGE("Error: planeIdx %d out of bound [0,%d]",
+                planeIdx, mNumPlanes - 1);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    if (pixelStride == nullptr) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    if (isClosed()) {
+        ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+    int32_t fmt = mBuffer->flexFormat;
+    switch (fmt) {
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+            *pixelStride = (planeIdx == 0) ? 1 : mBuffer->chromaStep;
+            return AMEDIA_OK;
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            *pixelStride = (planeIdx == 0) ? 1 : 2;
+            return AMEDIA_OK;
+        case HAL_PIXEL_FORMAT_Y8:
+            *pixelStride = 1;
+            return AMEDIA_OK;
+        case HAL_PIXEL_FORMAT_YV12:
+            *pixelStride = 1;
+            return AMEDIA_OK;
+        case HAL_PIXEL_FORMAT_Y16:
+        case HAL_PIXEL_FORMAT_RAW16:
+        case HAL_PIXEL_FORMAT_RGB_565:
+            // Single plane 16bpp data.
+            *pixelStride = 2;
+            return AMEDIA_OK;
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+            *pixelStride = 4;
+            return AMEDIA_OK;
+        case HAL_PIXEL_FORMAT_RGB_888:
+            // Single plane, 24bpp.
+            *pixelStride = 3;
+            return AMEDIA_OK;
+        case HAL_PIXEL_FORMAT_BLOB:
+        case HAL_PIXEL_FORMAT_RAW10:
+        case HAL_PIXEL_FORMAT_RAW12:
+        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+            // Blob is used for JPEG data, RAW10 and RAW12 is used for 10-bit and 12-bit raw data,
+            // those are single plane data without pixel stride defined
+            return AMEDIA_ERROR_UNSUPPORTED;
+        default:
+            ALOGE("Pixel format: 0x%x is unsupported", fmt);
+            return AMEDIA_ERROR_UNSUPPORTED;
+    }
+}
+
+media_status_t
+AImage::getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const {
+    if (planeIdx < 0 || planeIdx >= mNumPlanes) {
+        ALOGE("Error: planeIdx %d out of bound [0,%d]",
+                planeIdx, mNumPlanes - 1);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    if (rowStride == nullptr) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    if (isClosed()) {
+        ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+    int32_t fmt = mBuffer->flexFormat;
+    switch (fmt) {
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+            *rowStride = (planeIdx == 0) ? mBuffer->stride : mBuffer->chromaStride;
+            return AMEDIA_OK;
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            *rowStride = mBuffer->width;
+            return AMEDIA_OK;
+        case HAL_PIXEL_FORMAT_YV12:
+            if (mBuffer->stride % 16) {
+                ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
+                return AMEDIA_ERROR_UNKNOWN;
+            }
+            *rowStride = (planeIdx == 0) ? mBuffer->stride : ALIGN(mBuffer->stride / 2, 16);
+            return AMEDIA_OK;
+        case HAL_PIXEL_FORMAT_RAW10:
+        case HAL_PIXEL_FORMAT_RAW12:
+            // RAW10 and RAW12 are used for 10-bit and 12-bit raw data, they are single plane
+            *rowStride = mBuffer->stride;
+            return AMEDIA_OK;
+        case HAL_PIXEL_FORMAT_Y8:
+            if (mBuffer->stride % 16) {
+                ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
+                return AMEDIA_ERROR_UNKNOWN;
+            }
+            *rowStride = mBuffer->stride;
+            return AMEDIA_OK;
+        case HAL_PIXEL_FORMAT_Y16:
+        case HAL_PIXEL_FORMAT_RAW16:
+            // In native side, strides are specified in pixels, not in bytes.
+            // Single plane 16bpp bayer data. even width/height,
+            // row stride multiple of 16 pixels (32 bytes)
+            if (mBuffer->stride % 16) {
+                ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
+                return AMEDIA_ERROR_UNKNOWN;
+            }
+            *rowStride = mBuffer->stride * 2;
+            return AMEDIA_OK;
+        case HAL_PIXEL_FORMAT_RGB_565:
+            *rowStride = mBuffer->stride * 2;
+            return AMEDIA_OK;
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+            *rowStride = mBuffer->stride * 4;
+            return AMEDIA_OK;
+        case HAL_PIXEL_FORMAT_RGB_888:
+            // Single plane, 24bpp.
+            *rowStride = mBuffer->stride * 3;
+            return AMEDIA_OK;
+        case HAL_PIXEL_FORMAT_BLOB:
+        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+            // Blob is used for JPEG/Raw opaque data. It is single plane and has 0 row stride and
+            // no row stride defined
+            return AMEDIA_ERROR_UNSUPPORTED;
+        default:
+            ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt);
+          return AMEDIA_ERROR_UNSUPPORTED;
+    }
+}
+
+uint32_t
+AImage::getJpegSize() const {
+    if (mBuffer == nullptr) {
+        LOG_ALWAYS_FATAL("Error: buffer is null");
+    }
+
+    uint32_t size = 0;
+    uint32_t width = mBuffer->width;
+    uint8_t* jpegBuffer = mBuffer->data;
+
+    // First check for JPEG transport header at the end of the buffer
+    uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
+    struct camera3_jpeg_blob* blob = (struct camera3_jpeg_blob*)(header);
+    if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
+        size = blob->jpeg_size;
+        ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
+    }
+
+    // failed to find size, default to whole buffer
+    if (size == 0) {
+        /*
+         * This is a problem because not including the JPEG header
+         * means that in certain rare situations a regular JPEG blob
+         * will be misidentified as having a header, in which case
+         * we will get a garbage size value.
+         */
+        ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
+                __FUNCTION__, width);
+        size = width;
+    }
+
+    return size;
+}
+
+media_status_t
+AImage::getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const {
+    if (planeIdx < 0 || planeIdx >= mNumPlanes) {
+        ALOGE("Error: planeIdx %d out of bound [0,%d]",
+                planeIdx, mNumPlanes - 1);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    if (data == nullptr || dataLength == nullptr) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    if (isClosed()) {
+        ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+
+    uint32_t dataSize, ySize, cSize, cStride;
+    uint8_t* cb = nullptr;
+    uint8_t* cr = nullptr;
+    uint8_t* pData = nullptr;
+    int bytesPerPixel = 0;
+    int32_t fmt = mBuffer->flexFormat;
+
+    switch (fmt) {
+        case HAL_PIXEL_FORMAT_YCbCr_420_888:
+            pData = (planeIdx == 0) ? mBuffer->data :
+                    (planeIdx == 1) ? mBuffer->dataCb : mBuffer->dataCr;
+            // only map until last pixel
+            if (planeIdx == 0) {
+                dataSize = mBuffer->stride * (mBuffer->height - 1) + mBuffer->width;
+            } else {
+                dataSize = mBuffer->chromaStride * (mBuffer->height / 2 - 1) +
+                        mBuffer->chromaStep * (mBuffer->width / 2 - 1) + 1;
+            }
+            break;
+        // NV21
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            cr = mBuffer->data + (mBuffer->stride * mBuffer->height);
+            cb = cr + 1;
+            // only map until last pixel
+            ySize = mBuffer->width * (mBuffer->height - 1) + mBuffer->width;
+            cSize = mBuffer->width * (mBuffer->height / 2 - 1) + mBuffer->width - 1;
+
+            pData = (planeIdx == 0) ? mBuffer->data :
+                    (planeIdx == 1) ? cb : cr;
+            dataSize = (planeIdx == 0) ? ySize : cSize;
+            break;
+        case HAL_PIXEL_FORMAT_YV12:
+            // Y and C stride need to be 16 pixel aligned.
+            if (mBuffer->stride % 16) {
+                ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
+                return AMEDIA_ERROR_UNKNOWN;
+            }
+
+            ySize = mBuffer->stride * mBuffer->height;
+            cStride = ALIGN(mBuffer->stride / 2, 16);
+            cr = mBuffer->data + ySize;
+            cSize = cStride * mBuffer->height / 2;
+            cb = cr + cSize;
+
+            pData = (planeIdx == 0) ? mBuffer->data :
+                    (planeIdx == 1) ? cb : cr;
+            dataSize = (planeIdx == 0) ? ySize : cSize;
+            break;
+        case HAL_PIXEL_FORMAT_Y8:
+            // Single plane, 8bpp.
+
+            pData = mBuffer->data;
+            dataSize = mBuffer->stride * mBuffer->height;
+            break;
+        case HAL_PIXEL_FORMAT_Y16:
+            bytesPerPixel = 2;
+
+            pData = mBuffer->data;
+            dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+            break;
+        case HAL_PIXEL_FORMAT_BLOB:
+            // Used for JPEG data, height must be 1, width == size, single plane.
+            if (mBuffer->height != 1) {
+                ALOGE("Jpeg should have height value one but got %d", mBuffer->height);
+                return AMEDIA_ERROR_UNKNOWN;
+            }
+
+            pData = mBuffer->data;
+            dataSize = getJpegSize();
+            break;
+        case HAL_PIXEL_FORMAT_RAW16:
+            // Single plane 16bpp bayer data.
+            bytesPerPixel = 2;
+            pData = mBuffer->data;
+            dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+            break;
+        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+            // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
+            if (mBuffer->height != 1) {
+                ALOGE("RAW_OPAQUE should have height value one but got %d", mBuffer->height);
+                return AMEDIA_ERROR_UNKNOWN;
+            }
+            pData = mBuffer->data;
+            dataSize = mBuffer->width;
+            break;
+        case HAL_PIXEL_FORMAT_RAW10:
+            // Single plane 10bpp bayer data.
+            if (mBuffer->width % 4) {
+                ALOGE("Width is not multiple of 4 %d", mBuffer->width);
+                return AMEDIA_ERROR_UNKNOWN;
+            }
+            if (mBuffer->height % 2) {
+                ALOGE("Height is not multiple of 2 %d", mBuffer->height);
+                return AMEDIA_ERROR_UNKNOWN;
+            }
+            if (mBuffer->stride < (mBuffer->width * 10 / 8)) {
+                ALOGE("stride (%d) should be at least %d",
+                        mBuffer->stride, mBuffer->width * 10 / 8);
+                return AMEDIA_ERROR_UNKNOWN;
+            }
+            pData = mBuffer->data;
+            dataSize = mBuffer->stride * mBuffer->height;
+            break;
+        case HAL_PIXEL_FORMAT_RAW12:
+            // Single plane 10bpp bayer data.
+            if (mBuffer->width % 4) {
+                ALOGE("Width is not multiple of 4 %d", mBuffer->width);
+                return AMEDIA_ERROR_UNKNOWN;
+            }
+            if (mBuffer->height % 2) {
+                ALOGE("Height is not multiple of 2 %d", mBuffer->height);
+                return AMEDIA_ERROR_UNKNOWN;
+            }
+            if (mBuffer->stride < (mBuffer->width * 12 / 8)) {
+                ALOGE("stride (%d) should be at least %d",
+                        mBuffer->stride, mBuffer->width * 12 / 8);
+                return AMEDIA_ERROR_UNKNOWN;
+            }
+            pData = mBuffer->data;
+            dataSize = mBuffer->stride * mBuffer->height;
+            break;
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGBX_8888:
+            // Single plane, 32bpp.
+            bytesPerPixel = 4;
+            pData = mBuffer->data;
+            dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+            break;
+        case HAL_PIXEL_FORMAT_RGB_565:
+            // Single plane, 16bpp.
+            bytesPerPixel = 2;
+            pData = mBuffer->data;
+            dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+            break;
+        case HAL_PIXEL_FORMAT_RGB_888:
+            // Single plane, 24bpp.
+            bytesPerPixel = 3;
+            pData = mBuffer->data;
+            dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+            break;
+        default:
+            ALOGE("Pixel format: 0x%x is unsupported", fmt);
+            return AMEDIA_ERROR_UNSUPPORTED;
+    }
+
+    *data = pData;
+    *dataLength = dataSize;
+    return AMEDIA_OK;
+}
+
+EXPORT
+void AImage_delete(AImage* image) {
+    ALOGV("%s", __FUNCTION__);
+    if (image != nullptr) {
+        image->lockReader();
+        image->close();
+        image->unlockReader();
+        if (!image->isClosed()) {
+            LOG_ALWAYS_FATAL("Image close failed!");
+        }
+        image->free();
+    }
+    return;
+}
+
+EXPORT
+media_status_t AImage_getWidth(const AImage* image, /*out*/int32_t* width) {
+    ALOGV("%s", __FUNCTION__);
+    if (image == nullptr || width == nullptr) {
+        ALOGE("%s: bad argument. image %p width %p",
+                __FUNCTION__, image, width);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    return image->getWidth(width);
+}
+
+EXPORT
+media_status_t AImage_getHeight(const AImage* image, /*out*/int32_t* height) {
+    ALOGV("%s", __FUNCTION__);
+    if (image == nullptr || height == nullptr) {
+        ALOGE("%s: bad argument. image %p height %p",
+                __FUNCTION__, image, height);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    return image->getHeight(height);
+}
+
+EXPORT
+media_status_t AImage_getFormat(const AImage* image, /*out*/int32_t* format) {
+    ALOGV("%s", __FUNCTION__);
+    if (image == nullptr || format == nullptr) {
+        ALOGE("%s: bad argument. image %p format %p",
+                __FUNCTION__, image, format);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    return image->getFormat(format);
+}
+
+EXPORT
+media_status_t AImage_getCropRect(const AImage* image, /*out*/AImageCropRect* rect) {
+    ALOGV("%s", __FUNCTION__);
+    if (image == nullptr || rect == nullptr) {
+        ALOGE("%s: bad argument. image %p rect %p",
+                __FUNCTION__, image, rect);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    // For now AImage only supports camera outputs where cropRect is always full window
+    int32_t width = -1;
+    media_status_t ret = image->getWidth(&width);
+    if (ret != AMEDIA_OK) {
+        return ret;
+    }
+    int32_t height = -1;
+    ret = image->getHeight(&height);
+    if (ret != AMEDIA_OK) {
+        return ret;
+    }
+    rect->left = 0;
+    rect->top = 0;
+    rect->right = width;
+    rect->bottom = height;
+    return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AImage_getTimestamp(const AImage* image, /*out*/int64_t* timestampNs) {
+    ALOGV("%s", __FUNCTION__);
+    if (image == nullptr || timestampNs == nullptr) {
+        ALOGE("%s: bad argument. image %p timestampNs %p",
+                __FUNCTION__, image, timestampNs);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    return image->getTimestamp(timestampNs);
+}
+
+EXPORT
+media_status_t AImage_getNumberOfPlanes(const AImage* image, /*out*/int32_t* numPlanes) {
+    ALOGV("%s", __FUNCTION__);
+    if (image == nullptr || numPlanes == nullptr) {
+        ALOGE("%s: bad argument. image %p numPlanes %p",
+                __FUNCTION__, image, numPlanes);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    return image->getNumPlanes(numPlanes);
+}
+
+EXPORT
+media_status_t AImage_getPlanePixelStride(
+        const AImage* image, int planeIdx, /*out*/int32_t* pixelStride) {
+    ALOGV("%s", __FUNCTION__);
+    if (image == nullptr || pixelStride == nullptr) {
+        ALOGE("%s: bad argument. image %p pixelStride %p",
+                __FUNCTION__, image, pixelStride);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    return image->getPlanePixelStride(planeIdx, pixelStride);
+}
+
+EXPORT
+media_status_t AImage_getPlaneRowStride(
+        const AImage* image, int planeIdx, /*out*/int32_t* rowStride) {
+    ALOGV("%s", __FUNCTION__);
+    if (image == nullptr || rowStride == nullptr) {
+        ALOGE("%s: bad argument. image %p rowStride %p",
+                __FUNCTION__, image, rowStride);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    return image->getPlaneRowStride(planeIdx, rowStride);
+}
+
+EXPORT
+media_status_t AImage_getPlaneData(
+        const AImage* image, int planeIdx,
+        /*out*/uint8_t** data, /*out*/int* dataLength) {
+    ALOGV("%s", __FUNCTION__);
+    if (image == nullptr || data == nullptr || dataLength == nullptr) {
+        ALOGE("%s: bad argument. image %p data %p dataLength %p",
+                __FUNCTION__, image, data, dataLength);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    return image->getPlaneData(planeIdx, data, dataLength);
+}
diff --git a/media/ndk/NdkImagePriv.h b/media/ndk/NdkImagePriv.h
new file mode 100644
index 0000000..89d2b7c
--- /dev/null
+++ b/media/ndk/NdkImagePriv.h
@@ -0,0 +1,81 @@
+/*
+ * 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 _NDK_IMAGE_PRIV_H
+#define _NDK_IMAGE_PRIV_H
+
+#include <inttypes.h>
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
+
+#include <gui/CpuConsumer.h>
+
+#include "NdkImageReaderPriv.h"
+#include "NdkImage.h"
+
+
+using namespace android;
+
+// TODO: this only supports ImageReader
+struct AImage {
+    AImage(AImageReader* reader, int32_t format,
+            CpuConsumer::LockedBuffer* buffer, int64_t timestamp,
+            int32_t width, int32_t height, int32_t numPlanes);
+
+    // free all resources while keeping object alive. Caller must obtain reader lock
+    void close();
+
+    // Remove from object memory. Must be called after close
+    void free();
+
+    bool isClosed() const ;
+
+    // only For AImage to grab reader lock
+    // Always grab reader lock before grabbing image lock
+    void lockReader() const;
+    void unlockReader() const;
+
+    media_status_t getWidth(/*out*/int32_t* width) const;
+    media_status_t getHeight(/*out*/int32_t* height) const;
+    media_status_t getFormat(/*out*/int32_t* format) const;
+    media_status_t getNumPlanes(/*out*/int32_t* numPlanes) const;
+    media_status_t getTimestamp(/*out*/int64_t* timestamp) const;
+
+    media_status_t getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const;
+    media_status_t getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const;
+    media_status_t getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const;
+
+  private:
+    // AImage should be deleted through free() API.
+    ~AImage();
+
+    friend struct AImageReader; // for reader to access mBuffer
+
+    uint32_t getJpegSize() const;
+
+    // When reader is close, AImage will only accept close API call
+    wp<AImageReader>           mReader;
+    const int32_t              mFormat;
+    CpuConsumer::LockedBuffer* mBuffer;
+    const int64_t              mTimestamp;
+    const int32_t              mWidth;
+    const int32_t              mHeight;
+    const int32_t              mNumPlanes;
+    bool                       mIsClosed = false;
+    mutable Mutex              mLock;
+};
+
+#endif // _NDK_IMAGE_PRIV_H
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
new file mode 100644
index 0000000..d57a86e
--- /dev/null
+++ b/media/ndk/NdkImageReader.cpp
@@ -0,0 +1,581 @@
+/*
+ * 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.
+ */
+
+#include <inttypes.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NdkImageReader"
+
+#include "NdkImagePriv.h"
+#include "NdkImageReaderPriv.h"
+
+#include <utils/Log.h>
+#include <android_runtime/android_view_Surface.h>
+
+using namespace android;
+
+namespace {
+    // Get an ID that's unique within this process.
+    static int32_t createProcessUniqueId() {
+        static volatile int32_t globalCounter = 0;
+        return android_atomic_inc(&globalCounter);
+    }
+}
+
+const char* AImageReader::kCallbackFpKey = "Callback";
+const char* AImageReader::kContextKey    = "Context";
+
+bool
+AImageReader::isSupportedFormat(int32_t format) {
+    switch (format) {
+        case AIMAGE_FORMAT_YUV_420_888:
+        case AIMAGE_FORMAT_JPEG:
+        case AIMAGE_FORMAT_RAW16:
+        case AIMAGE_FORMAT_RAW_PRIVATE:
+        case AIMAGE_FORMAT_RAW10:
+        case AIMAGE_FORMAT_RAW12:
+        case AIMAGE_FORMAT_DEPTH16:
+        case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
+            return true;
+        default:
+            return false;
+    }
+}
+
+int
+AImageReader::getNumPlanesForFormat(int32_t format) {
+    switch (format) {
+        case AIMAGE_FORMAT_YUV_420_888:
+            return 3;
+        case AIMAGE_FORMAT_JPEG:
+        case AIMAGE_FORMAT_RAW16:
+        case AIMAGE_FORMAT_RAW_PRIVATE:
+        case AIMAGE_FORMAT_RAW10:
+        case AIMAGE_FORMAT_RAW12:
+        case AIMAGE_FORMAT_DEPTH16:
+        case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
+            return 1;
+        default:
+            return -1;
+    }
+}
+
+void
+AImageReader::FrameListener::onFrameAvailable(const BufferItem& /*item*/) {
+    Mutex::Autolock _l(mLock);
+    sp<AImageReader> reader = mReader.promote();
+    if (reader == nullptr) {
+        ALOGW("A frame is available after AImageReader closed!");
+        return; // reader has been closed
+    }
+    if (mListener.onImageAvailable == nullptr) {
+        return; // No callback registered
+    }
+
+    sp<AMessage> msg = new AMessage(AImageReader::kWhatImageAvailable, reader->mHandler);
+    msg->setPointer(AImageReader::kCallbackFpKey, (void *) mListener.onImageAvailable);
+    msg->setPointer(AImageReader::kContextKey, mListener.context);
+    msg->post();
+}
+
+media_status_t
+AImageReader::FrameListener::setImageListener(AImageReader_ImageListener* listener) {
+    Mutex::Autolock _l(mLock);
+    if (listener == nullptr) {
+        ALOGE("AImageReader: listener is null!");
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    mListener = *listener;
+    return AMEDIA_OK;
+}
+
+media_status_t
+AImageReader::setImageListenerLocked(AImageReader_ImageListener* listener) {
+    return mFrameListener->setImageListener(listener);
+}
+
+media_status_t
+AImageReader::setImageListener(AImageReader_ImageListener* listener) {
+    Mutex::Autolock _l(mLock);
+    return setImageListenerLocked(listener);
+}
+
+void AImageReader::CallbackHandler::onMessageReceived(
+        const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatImageAvailable:
+        {
+            AImageReader_ImageCallback onImageAvailable;
+            void* context;
+            bool found = msg->findPointer(kCallbackFpKey, (void**) &onImageAvailable);
+            if (!found || onImageAvailable == nullptr) {
+                ALOGE("%s: Cannot find onImageAvailable callback fp!", __FUNCTION__);
+                return;
+            }
+            found = msg->findPointer(kContextKey, &context);
+            if (!found) {
+                ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+                return;
+            }
+            (*onImageAvailable)(context, mReader);
+            break;
+        }
+        default:
+            ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
+            break;
+    }
+}
+
+AImageReader::AImageReader(int32_t width, int32_t height, int32_t format, int32_t maxImages) :
+        mWidth(width), mHeight(height), mFormat(format), mMaxImages(maxImages),
+        mNumPlanes(getNumPlanesForFormat(format)),
+        mFrameListener(new FrameListener(this)) {}
+
+media_status_t
+AImageReader::init() {
+    PublicFormat publicFormat = static_cast<PublicFormat>(mFormat);
+    mHalFormat = android_view_Surface_mapPublicFormatToHalFormat(publicFormat);
+    mHalDataSpace = android_view_Surface_mapPublicFormatToHalDataspace(publicFormat);
+
+    sp<IGraphicBufferProducer> gbProducer;
+    sp<IGraphicBufferConsumer> gbConsumer;
+    BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
+
+    sp<CpuConsumer> cpuConsumer;
+    String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
+            mWidth, mHeight, mFormat, mMaxImages, getpid(),
+            createProcessUniqueId());
+
+    cpuConsumer = new CpuConsumer(gbConsumer, mMaxImages, /*controlledByApp*/true);
+    if (cpuConsumer == nullptr) {
+        ALOGE("Failed to allocate CpuConsumer");
+        return AMEDIA_ERROR_UNKNOWN;
+    }
+
+    mCpuConsumer = cpuConsumer;
+    mCpuConsumer->setName(consumerName);
+    mProducer = gbProducer;
+
+    sp<ConsumerBase> consumer = cpuConsumer;
+    consumer->setFrameAvailableListener(mFrameListener);
+
+    status_t res;
+    res = cpuConsumer->setDefaultBufferSize(mWidth, mHeight);
+    if (res != OK) {
+        ALOGE("Failed to set CpuConsumer buffer size");
+        return AMEDIA_ERROR_UNKNOWN;
+    }
+    res = cpuConsumer->setDefaultBufferFormat(mHalFormat);
+    if (res != OK) {
+        ALOGE("Failed to set CpuConsumer buffer format");
+        return AMEDIA_ERROR_UNKNOWN;
+    }
+    res = cpuConsumer->setDefaultBufferDataSpace(mHalDataSpace);
+    if (res != OK) {
+        ALOGE("Failed to set CpuConsumer buffer dataSpace");
+        return AMEDIA_ERROR_UNKNOWN;
+    }
+
+    mSurface = new Surface(mProducer, /*controlledByApp*/true);
+    if (mSurface == nullptr) {
+        ALOGE("Failed to create surface");
+        return AMEDIA_ERROR_UNKNOWN;
+    }
+    mWindow = static_cast<ANativeWindow*>(mSurface.get());
+
+    for (int i = 0; i < mMaxImages; i++) {
+        CpuConsumer::LockedBuffer* buffer = new CpuConsumer::LockedBuffer;
+        mBuffers.push_back(buffer);
+    }
+
+    mCbLooper = new ALooper;
+    mCbLooper->setName(consumerName.string());
+    status_t ret = mCbLooper->start(
+            /*runOnCallingThread*/false,
+            /*canCallJava*/       true,
+            PRIORITY_DEFAULT);
+    mHandler = new CallbackHandler(this);
+    mCbLooper->registerHandler(mHandler);
+
+    return AMEDIA_OK;
+}
+
+AImageReader::~AImageReader() {
+    Mutex::Autolock _l(mLock);
+    AImageReader_ImageListener nullListener = {nullptr, nullptr};
+    setImageListenerLocked(&nullListener);
+
+    if (mCbLooper != nullptr) {
+        mCbLooper->unregisterHandler(mHandler->id());
+        mCbLooper->stop();
+    }
+    mCbLooper.clear();
+    mHandler.clear();
+
+    // Close all previously acquired images
+    for (auto it = mAcquiredImages.begin();
+              it != mAcquiredImages.end(); it++) {
+        AImage* image = *it;
+        image->close();
+    }
+
+    // Delete LockedBuffers
+    for (auto it = mBuffers.begin();
+              it != mBuffers.end(); it++) {
+        delete *it;
+    }
+
+    if (mCpuConsumer != nullptr) {
+        mCpuConsumer->abandon();
+        mCpuConsumer->setFrameAvailableListener(nullptr);
+    }
+}
+
+media_status_t
+AImageReader::acquireCpuConsumerImageLocked(/*out*/AImage** image) {
+    *image = nullptr;
+    CpuConsumer::LockedBuffer* buffer = getLockedBufferLocked();
+    if (buffer == nullptr) {
+        ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
+            " maxImages buffers");
+        return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
+    }
+
+    status_t res = mCpuConsumer->lockNextBuffer(buffer);
+    if (res != NO_ERROR) {
+        returnLockedBufferLocked(buffer);
+        if (res != BAD_VALUE /*no buffers*/) {
+            if (res == NOT_ENOUGH_DATA) {
+                return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
+            } else {
+                ALOGE("%s Fail to lockNextBuffer with error: %d ",
+                      __FUNCTION__, res);
+                return AMEDIA_ERROR_UNKNOWN;
+            }
+        }
+        return AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE;
+    }
+
+    if (buffer->flexFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
+        ALOGE("NV21 format is not supported by AImageReader");
+        return AMEDIA_ERROR_UNSUPPORTED;
+    }
+
+    // Check if the left-top corner of the crop rect is origin, we currently assume this point is
+    // zero, will revist this once this assumption turns out problematic.
+    Point lt = buffer->crop.leftTop();
+    if (lt.x != 0 || lt.y != 0) {
+        ALOGE("crop left top corner [%d, %d] need to be at origin", lt.x, lt.y);
+        return AMEDIA_ERROR_UNKNOWN;
+    }
+
+    // Check if the producer buffer configurations match what ImageReader configured.
+    int outputWidth = getBufferWidth(buffer);
+    int outputHeight = getBufferHeight(buffer);
+
+    int readerFmt = mHalFormat;
+    int readerWidth = mWidth;
+    int readerHeight = mHeight;
+
+    if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) && (readerFmt != HAL_PIXEL_FORMAT_BLOB) &&
+            (readerWidth != outputWidth || readerHeight != outputHeight)) {
+        ALOGW("%s: Producer buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
+                __FUNCTION__, outputWidth, outputHeight, readerWidth, readerHeight);
+    }
+
+    int bufFmt = buffer->format;
+    if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+        bufFmt = buffer->flexFormat;
+    }
+
+    if (readerFmt != bufFmt) {
+        if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && (bufFmt ==
+                HAL_PIXEL_FORMAT_YCrCb_420_SP || bufFmt == HAL_PIXEL_FORMAT_YV12)) {
+            // Special casing for when producer switches to a format compatible with flexible YUV
+            // (HAL_PIXEL_FORMAT_YCbCr_420_888).
+            mHalFormat = bufFmt;
+            ALOGD("%s: Overriding buffer format YUV_420_888 to %x.", __FUNCTION__, bufFmt);
+        } else {
+            // Return the buffer to the queue.
+            mCpuConsumer->unlockBuffer(*buffer);
+            returnLockedBufferLocked(buffer);
+
+            ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x",
+                    buffer->format, readerFmt);
+
+            return AMEDIA_ERROR_UNKNOWN;
+        }
+    }
+
+    if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
+        *image = new AImage(this, mFormat, buffer, buffer->timestamp,
+                            readerWidth, readerHeight, mNumPlanes);
+    } else {
+        *image = new AImage(this, mFormat, buffer, buffer->timestamp,
+                            outputWidth, outputHeight, mNumPlanes);
+    }
+    mAcquiredImages.push_back(*image);
+    return AMEDIA_OK;
+}
+
+CpuConsumer::LockedBuffer*
+AImageReader::getLockedBufferLocked() {
+    if (mBuffers.empty()) {
+        return nullptr;
+    }
+    // Return a LockedBuffer pointer and remove it from the list
+    auto it = mBuffers.begin();
+    CpuConsumer::LockedBuffer* buffer = *it;
+    mBuffers.erase(it);
+    return buffer;
+}
+
+void
+AImageReader::returnLockedBufferLocked(CpuConsumer::LockedBuffer* buffer) {
+    mBuffers.push_back(buffer);
+}
+
+void
+AImageReader::releaseImageLocked(AImage* image) {
+    CpuConsumer::LockedBuffer* buffer = image->mBuffer;
+    if (buffer == nullptr) {
+        // This should not happen, but is not fatal
+        ALOGW("AImage %p has no buffer!", image);
+        return;
+    }
+
+    mCpuConsumer->unlockBuffer(*buffer);
+    returnLockedBufferLocked(buffer);
+    image->mBuffer = nullptr;
+
+    bool found = false;
+    // cleanup acquired image list
+    for (auto it = mAcquiredImages.begin();
+              it != mAcquiredImages.end(); it++) {
+        AImage* readerCopy = *it;
+        if (readerCopy == image) {
+            found = true;
+            mAcquiredImages.erase(it);
+            break;
+        }
+    }
+    if (!found) {
+        ALOGE("Error: AImage %p is not generated by AImageReader %p",
+                image, this);
+    }
+}
+
+int
+AImageReader::getBufferWidth(CpuConsumer::LockedBuffer* buffer) {
+    if (buffer == nullptr) return -1;
+
+    if (!buffer->crop.isEmpty()) {
+        return buffer->crop.getWidth();
+    }
+    return buffer->width;
+}
+
+int
+AImageReader::getBufferHeight(CpuConsumer::LockedBuffer* buffer) {
+    if (buffer == nullptr) return -1;
+
+    if (!buffer->crop.isEmpty()) {
+        return buffer->crop.getHeight();
+    }
+    return buffer->height;
+}
+
+media_status_t
+AImageReader::acquireNextImage(/*out*/AImage** image) {
+    Mutex::Autolock _l(mLock);
+    return acquireCpuConsumerImageLocked(image);
+}
+
+media_status_t
+AImageReader::acquireLatestImage(/*out*/AImage** image) {
+    if (image == nullptr) {
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    Mutex::Autolock _l(mLock);
+    *image = nullptr;
+    AImage* prevImage = nullptr;
+    AImage* nextImage = nullptr;
+    media_status_t ret = acquireCpuConsumerImageLocked(&prevImage);
+    if (prevImage == nullptr) {
+        return ret;
+    }
+    for (;;) {
+        ret = acquireCpuConsumerImageLocked(&nextImage);
+        if (nextImage == nullptr) {
+            *image = prevImage;
+            return AMEDIA_OK;
+        }
+        prevImage->close();
+        prevImage->free();
+        prevImage = nextImage;
+        nextImage = nullptr;
+    }
+}
+
+EXPORT
+media_status_t AImageReader_new(
+        int32_t width, int32_t height, int32_t format, int32_t maxImages,
+        /*out*/AImageReader** reader) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (width < 1 || height < 1) {
+        ALOGE("%s: image dimension must be positive: w:%d h:%d",
+                __FUNCTION__, width, height);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+
+    if (maxImages < 1) {
+        ALOGE("%s: max outstanding image count must be at least 1 (%d)",
+                __FUNCTION__, maxImages);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+
+    if (!AImageReader::isSupportedFormat(format)) {
+        ALOGE("%s: format %d is not supported by AImageReader",
+                __FUNCTION__, format);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+
+    if (reader == nullptr) {
+        ALOGE("%s: reader argument is null", __FUNCTION__);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+
+    //*reader = new AImageReader(width, height, format, maxImages);
+    AImageReader* tmpReader = new AImageReader(width, height, format, maxImages);
+    if (tmpReader == nullptr) {
+        ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
+        return AMEDIA_ERROR_UNKNOWN;
+    }
+    media_status_t ret = tmpReader->init();
+    if (ret != AMEDIA_OK) {
+        ALOGE("%s: AImageReader initialization failed!", __FUNCTION__);
+        delete tmpReader;
+        return ret;
+    }
+    *reader = tmpReader;
+    (*reader)->incStrong((void*) AImageReader_new);
+    return AMEDIA_OK;
+}
+
+EXPORT
+void AImageReader_delete(AImageReader* reader) {
+    ALOGV("%s", __FUNCTION__);
+    if (reader != nullptr) {
+        reader->decStrong((void*) AImageReader_delete);
+    }
+    return;
+}
+
+EXPORT
+media_status_t AImageReader_getWindow(AImageReader* reader, /*out*/ANativeWindow** window) {
+    ALOGE("%s", __FUNCTION__);
+    if (reader == nullptr || window == nullptr) {
+        ALOGE("%s: invalid argument. reader %p, window %p",
+                __FUNCTION__, reader, window);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    *window = reader->getWindow();
+    return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AImageReader_getWidth(const AImageReader* reader, /*out*/int32_t* width) {
+    ALOGV("%s", __FUNCTION__);
+    if (reader == nullptr || width == nullptr) {
+        ALOGE("%s: invalid argument. reader %p, width %p",
+                __FUNCTION__, reader, width);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    *width = reader->getWidth();
+    return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AImageReader_getHeight(const AImageReader* reader, /*out*/int32_t* height) {
+    ALOGV("%s", __FUNCTION__);
+    if (reader == nullptr || height == nullptr) {
+        ALOGE("%s: invalid argument. reader %p, height %p",
+                __FUNCTION__, reader, height);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    *height = reader->getHeight();
+    return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AImageReader_getFormat(const AImageReader* reader, /*out*/int32_t* format) {
+    ALOGV("%s", __FUNCTION__);
+    if (reader == nullptr || format == nullptr) {
+        ALOGE("%s: invalid argument. reader %p, format %p",
+                __FUNCTION__, reader, format);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    *format = reader->getFormat();
+    return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AImageReader_getMaxImages(const AImageReader* reader, /*out*/int32_t* maxImages) {
+    ALOGV("%s", __FUNCTION__);
+    if (reader == nullptr || maxImages == nullptr) {
+        ALOGE("%s: invalid argument. reader %p, maxImages %p",
+                __FUNCTION__, reader, maxImages);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    *maxImages = reader->getMaxImages();
+    return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
+    ALOGV("%s", __FUNCTION__);
+    if (reader == nullptr || image == nullptr) {
+        ALOGE("%s: invalid argument. reader %p, maxImages %p",
+                __FUNCTION__, reader, image);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    return reader->acquireNextImage(image);
+}
+
+EXPORT
+media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
+    ALOGV("%s", __FUNCTION__);
+    if (reader == nullptr || image == nullptr) {
+        ALOGE("%s: invalid argument. reader %p, maxImages %p",
+                __FUNCTION__, reader, image);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+    return reader->acquireLatestImage(image);
+}
+
+EXPORT
+media_status_t AImageReader_setImageListener(
+        AImageReader* reader, AImageReader_ImageListener* listener) {
+    ALOGV("%s", __FUNCTION__);
+    if (reader == nullptr || listener == nullptr) {
+        ALOGE("%s: invalid argument! read %p listener %p", __FUNCTION__, reader, listener);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+
+    reader->setImageListener(listener);
+    return AMEDIA_OK;
+}
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
new file mode 100644
index 0000000..48f0953
--- /dev/null
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -0,0 +1,141 @@
+/*
+ * 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 _NDK_IMAGE_READER_PRIV_H
+#define _NDK_IMAGE_READER_PRIV_H
+
+#include <inttypes.h>
+
+#include "NdkImageReader.h"
+
+#include <utils/List.h>
+#include <utils/Mutex.h>
+#include <utils/StrongPointer.h>
+
+#include <gui/CpuConsumer.h>
+#include <gui/Surface.h>
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+using namespace android;
+
+namespace {
+    enum {
+        IMAGE_READER_MAX_NUM_PLANES = 3,
+    };
+
+    enum {
+        ACQUIRE_SUCCESS = 0,
+        ACQUIRE_NO_BUFFERS = 1,
+        ACQUIRE_MAX_IMAGES = 2,
+    };
+}
+
+struct AImageReader : public RefBase {
+  public:
+
+    static bool isSupportedFormat(int32_t format);
+    static int getNumPlanesForFormat(int32_t format);
+
+    AImageReader(int32_t width, int32_t height, int32_t format, int32_t maxImages);
+    ~AImageReader();
+
+    // Inintialize AImageReader, uninitialized or failed to initialize AImageReader
+    // should never be passed to application
+    media_status_t init();
+
+    media_status_t setImageListener(AImageReader_ImageListener* listener);
+
+    media_status_t acquireNextImage(/*out*/AImage** image);
+    media_status_t acquireLatestImage(/*out*/AImage** image);
+
+    ANativeWindow* getWindow()    const { return mWindow.get(); };
+    int32_t        getWidth()     const { return mWidth; };
+    int32_t        getHeight()    const { return mHeight; };
+    int32_t        getFormat()    const { return mFormat; };
+    int32_t        getMaxImages() const { return mMaxImages; };
+
+
+  private:
+
+    friend struct AImage; // for grabing reader lock
+
+    media_status_t acquireCpuConsumerImageLocked(/*out*/AImage** image);
+    CpuConsumer::LockedBuffer* getLockedBufferLocked();
+    void returnLockedBufferLocked(CpuConsumer::LockedBuffer* buffer);
+
+    // Called by AImage to close image
+    void releaseImageLocked(AImage* image);
+
+    static int getBufferWidth(CpuConsumer::LockedBuffer* buffer);
+    static int getBufferHeight(CpuConsumer::LockedBuffer* buffer);
+
+    media_status_t setImageListenerLocked(AImageReader_ImageListener* listener);
+
+    // definition of handler and message
+    enum {
+        kWhatImageAvailable
+    };
+    static const char* kCallbackFpKey;
+    static const char* kContextKey;
+    class CallbackHandler : public AHandler {
+      public:
+        CallbackHandler(AImageReader* reader) : mReader(reader) {}
+        void onMessageReceived(const sp<AMessage> &msg) override;
+      private:
+        AImageReader* mReader;
+    };
+    sp<CallbackHandler> mHandler;
+    sp<ALooper>         mCbLooper; // Looper thread where callbacks actually happen on
+
+    List<CpuConsumer::LockedBuffer*> mBuffers;
+    const int32_t mWidth;
+    const int32_t mHeight;
+    const int32_t mFormat;
+    const int32_t mMaxImages;
+    const int32_t mNumPlanes;
+
+    struct FrameListener : public ConsumerBase::FrameAvailableListener {
+      public:
+        FrameListener(AImageReader* parent) : mReader(parent) {}
+
+        void onFrameAvailable(const BufferItem& item) override;
+
+        media_status_t setImageListener(AImageReader_ImageListener* listener);
+
+      private:
+        AImageReader_ImageListener mListener = {nullptr, nullptr};
+        wp<AImageReader>           mReader;
+        Mutex                      mLock;
+    };
+    sp<FrameListener> mFrameListener;
+
+    int mHalFormat;
+    android_dataspace mHalDataSpace;
+
+    sp<IGraphicBufferProducer> mProducer;
+    sp<Surface>                mSurface;
+    sp<CpuConsumer>            mCpuConsumer;
+    sp<ANativeWindow>          mWindow;
+
+    List<AImage*>              mAcquiredImages;
+
+    Mutex                      mLock;
+};
+
+#endif // _NDK_IMAGE_READER_PRIV_H
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index cd0c462..5bb2dcd 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -359,6 +359,15 @@
     return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx, timestampNs));
 }
 
+EXPORT
+media_status_t AMediaCodec_setOutputSurface(AMediaCodec *mData, ANativeWindow* window) {
+    sp<Surface> surface = NULL;
+    if (window != NULL) {
+        surface = (Surface*) window;
+    }
+    return translate_error(mData->mCodec->setSurface(surface));
+}
+
 //EXPORT
 media_status_t AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback,
         void *userdata) {
@@ -372,6 +381,7 @@
         uint8_t key[16];
         uint8_t iv[16];
         cryptoinfo_mode_t mode;
+        cryptoinfo_pattern_t pattern;
         size_t *clearbytes;
         size_t *encryptedbytes;
 } AMediaCodecCryptoInfo;
@@ -391,6 +401,10 @@
         subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i];
     }
 
+    CryptoPlugin::Pattern pattern;
+    pattern.mEncryptBlocks = crypto->pattern.encryptBlocks;
+    pattern.mSkipBlocks = crypto->pattern.skipBlocks;
+
     AString errormsg;
     status_t err  = codec->mCodec->queueSecureInputBuffer(idx,
             offset,
@@ -398,7 +412,8 @@
             crypto->numsubsamples,
             crypto->key,
             crypto->iv,
-            (CryptoPlugin::Mode) crypto->mode,
+            (CryptoPlugin::Mode)crypto->mode,
+            pattern,
             time,
             flags,
             &errormsg);
@@ -410,6 +425,12 @@
 }
 
 
+EXPORT
+void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info,
+        cryptoinfo_pattern_t *pattern) {
+    info->pattern.encryptBlocks = pattern->encryptBlocks;
+    info->pattern.skipBlocks = pattern->skipBlocks;
+}
 
 EXPORT
 AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
@@ -431,6 +452,8 @@
     memcpy(ret->key, key, 16);
     memcpy(ret->iv, iv, 16);
     ret->mode = mode;
+    ret->pattern.encryptBlocks = 0;
+    ret->pattern.skipBlocks = 0;
 
     // clearbytes and encryptedbytes point at the actual data, which follows
     ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp
index 1cc2f1a..af8ffea 100644
--- a/media/ndk/NdkMediaCrypto.cpp
+++ b/media/ndk/NdkMediaCrypto.cpp
@@ -23,10 +23,12 @@
 #include "NdkMediaFormatPriv.h"
 
 
+#include <cutils/properties.h>
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
 #include <binder/IServiceManager.h>
 #include <media/ICrypto.h>
+#include <media/IMediaDrmService.h>
 #include <media/IMediaPlayerService.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_util_Binder.h>
@@ -46,19 +48,30 @@
 
 static sp<ICrypto> makeCrypto() {
     sp<IServiceManager> sm = defaultServiceManager();
+    sp<ICrypto> crypto;
 
-    sp<IBinder> binder =
-        sm->getService(String16("media.player"));
-
-    sp<IMediaPlayerService> service =
-        interface_cast<IMediaPlayerService>(binder);
-
-    if (service == NULL) {
-        return NULL;
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.mediadrmservice.enable", value, NULL)
+        && (!strcmp("1", value) || !strcasecmp("true", value))) {
+        sp<IBinder> binder =
+            sm->getService(String16("media.drm"));
+        sp<IMediaDrmService> service =
+            interface_cast<IMediaDrmService>(binder);
+        if (service == NULL) {
+            return NULL;
+        }
+        crypto = service->makeCrypto();
+    } else {
+        sp<IBinder> binder =
+            sm->getService(String16("media.player"));
+        sp<IMediaPlayerService> service =
+            interface_cast<IMediaPlayerService>(binder);
+        if (service == NULL) {
+            return NULL;
+        }
+        crypto = service->makeCrypto();
     }
 
-    sp<ICrypto> crypto = service->makeCrypto();
-
     if (crypto == NULL || (crypto->initCheck() != OK && crypto->initCheck() != NO_INIT)) {
         return NULL;
     }
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 83a5ba1..ea47d57 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -19,6 +19,7 @@
 
 #include "NdkMediaDrm.h"
 
+#include <cutils/properties.h>
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
 #include <gui/Surface.h>
@@ -27,6 +28,7 @@
 #include <media/IDrmClient.h>
 #include <media/stagefright/MediaErrors.h>
 #include <binder/IServiceManager.h>
+#include <media/IMediaDrmService.h>
 #include <media/IMediaPlayerService.h>
 #include <ndk/NdkMediaCrypto.h>
 
@@ -148,19 +150,30 @@
 
 static sp<IDrm> CreateDrm() {
     sp<IServiceManager> sm = defaultServiceManager();
+    sp<IDrm> drm;
 
-    sp<IBinder> binder =
-        sm->getService(String16("media.player"));
-
-    sp<IMediaPlayerService> service =
-        interface_cast<IMediaPlayerService>(binder);
-
-    if (service == NULL) {
-        return NULL;
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("media.mediadrmservice.enable", value, NULL)
+        && (!strcmp("1", value) || !strcasecmp("true", value))) {
+        sp<IBinder> binder =
+            sm->getService(String16("media.drm"));
+        sp<IMediaDrmService> service =
+            interface_cast<IMediaDrmService>(binder);
+        if (service == NULL) {
+            return NULL;
+        }
+        drm = service->makeDrm();
+    } else {
+        sp<IBinder> binder =
+            sm->getService(String16("media.player"));
+        sp<IMediaPlayerService> service =
+            interface_cast<IMediaPlayerService>(binder);
+        if (service == NULL) {
+            return NULL;
+        }
+        drm = service->makeDrm();
     }
 
-    sp<IDrm> drm = service->makeDrm();
-
     if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
         return NULL;
     }
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index 0ecd64f..b869c54 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -243,15 +243,27 @@
     while (len > 0) {
         numentries++;
 
+        if (len < 16) {
+            ALOGE("invalid PSSH data");
+            return NULL;
+        }
         // skip uuid
         data += 16;
         len -= 16;
 
         // get data length
+        if (len < 4) {
+            ALOGE("invalid PSSH data");
+            return NULL;
+        }
         uint32_t datalen = *((uint32_t*)data);
         data += 4;
         len -= 4;
 
+        if (len < datalen) {
+            ALOGE("invalid PSSH data");
+            return NULL;
+        }
         // skip the data
         data += datalen;
         len -= datalen;
@@ -265,6 +277,10 @@
     // extra pointer for each entry, and an extra size_t for the entire PsshInfo.
     size_t newsize = buffer->size() - (sizeof(uint32_t) * numentries) + sizeof(size_t)
             + ((sizeof(void*) + sizeof(size_t)) * numentries);
+    if (newsize <= buffer->size()) {
+        ALOGE("invalid PSSH data");
+        return NULL;
+    }
     ex->mPsshBuf = new ABuffer(newsize);
     ex->mPsshBuf->setRange(0, newsize);
 
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index a354d58..5598d5d 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -46,6 +46,10 @@
     ALOGV("private ctor");
     AMediaFormat* mData = new AMediaFormat();
     mData->mFormat = *((sp<AMessage>*)data);
+    if (mData->mFormat == NULL) {
+        ALOGW("got NULL format");
+        mData->mFormat = new AMessage;
+    }
     return mData;
 }
 
diff --git a/media/utils/BatteryNotifier.cpp b/media/utils/BatteryNotifier.cpp
index 7f9cd7a..341d391 100644
--- a/media/utils/BatteryNotifier.cpp
+++ b/media/utils/BatteryNotifier.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "BatteryNotifier"
+//#define LOG_NDEBUG 0
+
 #include "include/mediautils/BatteryNotifier.h"
 
 #include <binder/IServiceManager.h>
@@ -64,7 +67,7 @@
     sp<IBatteryStats> batteryService = getBatteryService_l();
     mVideoRefCount = 0;
     if (batteryService != nullptr) {
-        batteryService->noteResetAudio();
+        batteryService->noteResetVideo();
     }
 }
 
@@ -72,7 +75,7 @@
     Mutex::Autolock _l(mLock);
     sp<IBatteryStats> batteryService = getBatteryService_l();
     if (mAudioRefCount == 0 && batteryService != nullptr) {
-        batteryService->noteStartAudio(AID_MEDIA);
+        batteryService->noteStartAudio(AID_AUDIOSERVER);
     }
     mAudioRefCount++;
 }
@@ -88,7 +91,7 @@
 
     mAudioRefCount--;
     if (mAudioRefCount == 0 && batteryService != nullptr) {
-        batteryService->noteStopAudio(AID_MEDIA);
+        batteryService->noteStopAudio(AID_AUDIOSERVER);
     }
 }
 
@@ -190,20 +193,25 @@
         const String16 name("batterystats");
         mBatteryStatService = interface_cast<IBatteryStats>(sm->checkService(name));
         if (mBatteryStatService == nullptr) {
-            ALOGE("batterystats service unavailable!");
+            // this may occur normally during the init sequence as mediaserver
+            // and audioserver start before the batterystats service is available.
+            ALOGW("batterystats service unavailable!");
             return nullptr;
         }
 
         mDeathNotifier = new DeathNotifier();
         IInterface::asBinder(mBatteryStatService)->linkToDeath(mDeathNotifier);
 
-        // Notify start now if media already started
+        // Notify start now if mediaserver or audioserver is already started.
+        // 1) mediaserver and audioserver is started before batterystats service
+        // 2) batterystats server may have crashed.
         if (mVideoRefCount > 0) {
             mBatteryStatService->noteStartVideo(AID_MEDIA);
         }
         if (mAudioRefCount > 0) {
-            mBatteryStatService->noteStartAudio(AID_MEDIA);
+            mBatteryStatService->noteStartAudio(AID_AUDIOSERVER);
         }
+        // TODO: Notify for camera and flashlight state as well?
     }
     return mBatteryStatService;
 }
diff --git a/radio/IRadioService.cpp b/radio/IRadioService.cpp
index 8c2b3ef..81acf9e 100644
--- a/radio/IRadioService.cpp
+++ b/radio/IRadioService.cpp
@@ -87,7 +87,8 @@
         data.writeInterfaceToken(IRadioService::getInterfaceDescriptor());
         data.writeInt32(handle);
         data.writeStrongBinder(IInterface::asBinder(client));
-        ALOGV("attach() config %p withAudio %d region %d type %d", config, withAudio, config->region, config->band.type);
+        ALOGV("attach() config %p withAudio %d region %d type %d",
+              config == NULL ? 0 : config, withAudio, config->region, config->band.type);
         if (config == NULL) {
             data.writeInt32(0);
         } else {
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 9b4ba79..6e3eb83 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -41,12 +41,12 @@
     libaudioresampler \
     libaudiospdif \
     libaudioutils \
-    libcommon_time_client \
     libcutils \
     libutils \
     liblog \
     libbinder \
     libmedia \
+    libmediautils \
     libnbaio \
     libhardware \
     libhardware_legacy \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index fab1ef5..4ee8d6c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -56,13 +56,12 @@
 
 #include <powermanager/PowerManager.h>
 
-#include <common_time/cc_helper.h>
-
 #include <media/IMediaLogService.h>
 
 #include <media/nbaio/Pipe.h>
 #include <media/nbaio/PipeReader.h>
 #include <media/AudioParameter.h>
+#include <mediautils/BatteryNotifier.h>
 #include <private/android_filesystem_config.h>
 
 // ----------------------------------------------------------------------------
@@ -108,7 +107,7 @@
 // ----------------------------------------------------------------------------
 
 const char *formatToString(audio_format_t format) {
-    switch (format & AUDIO_FORMAT_MAIN_MASK) {
+    switch (audio_get_main_format(format)) {
     case AUDIO_FORMAT_PCM:
         switch (format) {
         case AUDIO_FORMAT_PCM_16_BIT: return "pcm16";
@@ -131,6 +130,7 @@
     case AUDIO_FORMAT_OPUS: return "opus";
     case AUDIO_FORMAT_AC3: return "ac-3";
     case AUDIO_FORMAT_E_AC3: return "e-ac-3";
+    case AUDIO_FORMAT_IEC61937: return "iec61937";
     default:
         break;
     }
@@ -184,13 +184,18 @@
       mSystemReady(false)
 {
     getpid_cached = getpid();
-    char value[PROPERTY_VALUE_MAX];
-    bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
+    // disable media.log until the service is reenabled, see b/26306954
+    const bool doLog = false; // property_get_bool("ro.test_harness", false);
     if (doLog) {
         mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters",
                 MemoryHeapBase::READ_ONLY);
     }
 
+    // reset battery stats.
+    // if the audio service has crashed, battery stats could be left
+    // in bad state, reset the state upon service start.
+    BatteryNotifier::getInstance().noteResetAudio();
+
 #ifdef TEE_SINK
     (void) property_get("ro.debuggable", value, "0");
     int debuggable = atoi(value);
@@ -255,16 +260,17 @@
     }
 
     // Tell media.log service about any old writers that still need to be unregistered
-    sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
-    if (binder != 0) {
-        sp<IMediaLogService> mediaLogService(interface_cast<IMediaLogService>(binder));
-        for (size_t count = mUnregisteredWriters.size(); count > 0; count--) {
-            sp<IMemory> iMemory(mUnregisteredWriters.top()->getIMemory());
-            mUnregisteredWriters.pop();
-            mediaLogService->unregisterWriter(iMemory);
+    if (mLogMemoryDealer != 0) {
+        sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
+        if (binder != 0) {
+            sp<IMediaLogService> mediaLogService(interface_cast<IMediaLogService>(binder));
+            for (size_t count = mUnregisteredWriters.size(); count > 0; count--) {
+                sp<IMemory> iMemory(mUnregisteredWriters.top()->getIMemory());
+                mUnregisteredWriters.pop();
+                mediaLogService->unregisterWriter(iMemory);
+            }
         }
     }
-
 }
 
 static const char * const audio_interfaces[] = {
@@ -1156,7 +1162,9 @@
     if (ret != NO_ERROR) {
         return 0;
     }
-    if (!audio_is_valid_format(format) || !audio_is_linear_pcm(format)) {
+    if ((sampleRate == 0) ||
+            !audio_is_valid_format(format) || !audio_has_proportional_frames(format) ||
+            !audio_is_input_channel(channelMask)) {
         return 0;
     }
 
@@ -1352,8 +1360,7 @@
 AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
     :   RefBase(),
         mAudioFlinger(audioFlinger),
-        mPid(pid),
-        mTimedTrackCount(0)
+        mPid(pid)
 {
     size_t heapSize = kClientSharedHeapSizeBytes;
     // Increase heap size on non low ram devices to limit risk of reconnection failure for
@@ -1375,31 +1382,6 @@
     return mMemoryDealer;
 }
 
-// Reserve one of the limited slots for a timed audio track associated
-// with this client
-bool AudioFlinger::Client::reserveTimedTrack()
-{
-    const int kMaxTimedTracksPerClient = 4;
-
-    Mutex::Autolock _l(mTimedTrackLock);
-
-    if (mTimedTrackCount >= kMaxTimedTracksPerClient) {
-        ALOGW("can not create timed track - pid %d has exceeded the limit",
-             mPid);
-        return false;
-    }
-
-    mTimedTrackCount++;
-    return true;
-}
-
-// Release a slot for a timed audio track
-void AudioFlinger::Client::releaseTimedTrack()
-{
-    Mutex::Autolock _l(mTimedTrackLock);
-    mTimedTrackCount--;
-}
-
 // ----------------------------------------------------------------------------
 
 AudioFlinger::NotificationClient::NotificationClient(const sp<AudioFlinger>& audioFlinger,
@@ -1451,8 +1433,15 @@
     cblk.clear();
     buffers.clear();
 
+    const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+    if (!isTrustedCallingUid(callingUid)) {
+        ALOGW_IF((uid_t)clientUid != callingUid,
+                "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, clientUid);
+        clientUid = callingUid;
+    }
+
     // check calling permissions
-    if (!recordingAllowed(opPackageName)) {
+    if (!recordingAllowed(opPackageName, tid, clientUid)) {
         ALOGE("openRecord() permission denied: recording not allowed");
         lStatus = PERMISSION_DENIED;
         goto Exit;
@@ -1502,7 +1491,6 @@
         }
         ALOGV("openRecord() lSessionId: %d input %d", lSessionId, input);
 
-        // TODO: the uid should be passed in as a parameter to openRecord
         recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask,
                                                   frameCount, lSessionId, notificationFrames,
                                                   clientUid, flags, tid, &lStatus);
@@ -2585,7 +2573,7 @@
 
         // check recording permission for visualizer
         if ((memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) &&
-            !recordingAllowed(opPackageName)) {
+            !recordingAllowed(opPackageName, pid, IPCThreadState::self()->getCallingUid())) {
             lStatus = PERMISSION_DENIED;
             goto Exit;
         }
@@ -2966,8 +2954,7 @@
             void *buffer = malloc(TEE_SINK_READ * frameSize);
             for (;;) {
                 size_t count = TEE_SINK_READ;
-                ssize_t actual = teeSource->read(buffer, count,
-                        AudioBufferProvider::kInvalidPTS);
+                ssize_t actual = teeSource->read(buffer, count);
                 bool wasFirstRead = firstRead;
                 firstRead = false;
                 if (actual <= 0) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 08fa70d..f2f11e3 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -23,8 +23,6 @@
 #include <sys/types.h>
 #include <limits.h>
 
-#include <common_time/cc_helper.h>
-
 #include <cutils/compiler.h>
 
 #include <media/IAudioFlinger.h>
@@ -59,6 +57,7 @@
 #include "AudioStreamOut.h"
 #include "SpdifStreamOut.h"
 #include "AudioHwDevice.h"
+#include "LinearMap.h"
 
 #include <powermanager/IPowerManager.h>
 
@@ -78,14 +77,6 @@
 
 // ----------------------------------------------------------------------------
 
-// The macro FCC_2 highlights some (but not all) places where there are are 2-channel assumptions.
-// This is typically due to legacy implementation of stereo input or output.
-// Search also for "2", "left", "right", "[0]", "[1]", ">> 16", "<< 16", etc.
-#define FCC_2 2     // FCC_2 = Fixed Channel Count 2
-// The macro FCC_8 highlights places where there are 8-channel assumptions.
-// This is typically due to audio mixer and resampler limitations.
-#define FCC_8 8     // FCC_8 = Fixed Channel Count 8
-
 static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3);
 
 
@@ -422,18 +413,12 @@
         pid_t               pid() const { return mPid; }
         sp<AudioFlinger>    audioFlinger() const { return mAudioFlinger; }
 
-        bool reserveTimedTrack();
-        void releaseTimedTrack();
-
     private:
                             Client(const Client&);
                             Client& operator = (const Client&);
         const sp<AudioFlinger> mAudioFlinger;
               sp<MemoryDealer> mMemoryDealer;
         const pid_t         mPid;
-
-        Mutex               mTimedTrackLock;
-        int                 mTimedTrackCount;
     };
 
     // --- Notification Client ---
@@ -504,12 +489,6 @@
         virtual void        flush();
         virtual void        pause();
         virtual status_t    attachAuxEffect(int effectId);
-        virtual status_t    allocateTimedBuffer(size_t size,
-                                                sp<IMemory>* buffer);
-        virtual status_t    queueTimedBuffer(const sp<IMemory>& buffer,
-                                             int64_t pts);
-        virtual status_t    setMediaTimeTransform(const LinearTransform& xform,
-                                                  int target);
         virtual status_t    setParameters(const String8& keyValuePairs);
         virtual status_t    getTimestamp(AudioTimestamp& timestamp);
         virtual void        signal(); // signal playback thread for a change in control block
diff --git a/services/audioflinger/AudioHwDevice.cpp b/services/audioflinger/AudioHwDevice.cpp
index 3191598..7494930 100644
--- a/services/audioflinger/AudioHwDevice.cpp
+++ b/services/audioflinger/AudioHwDevice.cpp
@@ -68,7 +68,7 @@
             status);
 
         // If the data is encoded then try again using wrapped PCM.
-        bool wrapperNeeded = !audio_is_linear_pcm(originalConfig.format)
+        bool wrapperNeeded = !audio_has_proportional_frames(originalConfig.format)
                 && ((flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0)
                 && ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0);
 
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 8a9a837..aea6b67 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -36,8 +36,6 @@
 
 #include <audio_utils/primitives.h>
 #include <audio_utils/format.h>
-#include <common_time/local_clock.h>
-#include <common_time/cc_helper.h>
 
 #include "AudioMixerOps.h"
 #include "AudioMixer.h"
@@ -786,7 +784,6 @@
                         mMixerInFormat,
                         resamplerChannelCount,
                         devSampleRate, quality);
-                resampler->setLocalTimeFreq(sLocalTimeFreq);
             }
             return true;
         }
@@ -906,13 +903,13 @@
 }
 
 
-void AudioMixer::process(int64_t pts)
+void AudioMixer::process()
 {
-    mState.hook(&mState, pts);
+    mState.hook(&mState);
 }
 
 
-void AudioMixer::process__validate(state_t* state, int64_t pts)
+void AudioMixer::process__validate(state_t* state)
 {
     ALOGW_IF(!state->needsChanged,
         "in process__validate() but nothing's invalid");
@@ -1042,7 +1039,7 @@
         countActiveTracks, state->enabledTracks,
         all16BitsStereoNoResample, resampling, volumeRamp);
 
-   state->hook(state, pts);
+   state->hook(state);
 
     // Now that the volume ramp has been done, set optimal state and
     // track hooks for subsequent mixer process
@@ -1367,7 +1364,7 @@
 }
 
 // no-op case
-void AudioMixer::process__nop(state_t* state, int64_t pts)
+void AudioMixer::process__nop(state_t* state)
 {
     ALOGVV("process__nop\n");
     uint32_t e0 = state->enabledTracks;
@@ -1401,9 +1398,7 @@
                 size_t outFrames = state->frameCount;
                 while (outFrames) {
                     t3.buffer.frameCount = outFrames;
-                    int64_t outputPTS = calculateOutputPTS(
-                        t3, pts, state->frameCount - outFrames);
-                    t3.bufferProvider->getNextBuffer(&t3.buffer, outputPTS);
+                    t3.bufferProvider->getNextBuffer(&t3.buffer);
                     if (t3.buffer.raw == NULL) break;
                     outFrames -= t3.buffer.frameCount;
                     t3.bufferProvider->releaseBuffer(&t3.buffer);
@@ -1414,7 +1409,7 @@
 }
 
 // generic code without resampling
-void AudioMixer::process__genericNoResampling(state_t* state, int64_t pts)
+void AudioMixer::process__genericNoResampling(state_t* state)
 {
     ALOGVV("process__genericNoResampling\n");
     int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
@@ -1427,7 +1422,7 @@
         e0 &= ~(1<<i);
         track_t& t = state->tracks[i];
         t.buffer.frameCount = state->frameCount;
-        t.bufferProvider->getNextBuffer(&t.buffer, pts);
+        t.bufferProvider->getNextBuffer(&t.buffer);
         t.frameCount = t.buffer.frameCount;
         t.in = t.buffer.raw;
     }
@@ -1486,9 +1481,7 @@
                         t.bufferProvider->releaseBuffer(&t.buffer);
                         t.buffer.frameCount = (state->frameCount - numFrames) -
                                 (BLOCKSIZE - outFrames);
-                        int64_t outputPTS = calculateOutputPTS(
-                            t, pts, numFrames + (BLOCKSIZE - outFrames));
-                        t.bufferProvider->getNextBuffer(&t.buffer, outputPTS);
+                        t.bufferProvider->getNextBuffer(&t.buffer);
                         t.in = t.buffer.raw;
                         if (t.in == NULL) {
                             enabledTracks &= ~(1<<i);
@@ -1522,7 +1515,7 @@
 
 
 // generic code with resampling
-void AudioMixer::process__genericResampling(state_t* state, int64_t pts)
+void AudioMixer::process__genericResampling(state_t* state)
 {
     ALOGVV("process__genericResampling\n");
     // this const just means that local variable outTemp doesn't change
@@ -1561,7 +1554,6 @@
             // acquire/release the buffers because it's done by
             // the resampler.
             if (t.needs & NEEDS_RESAMPLE) {
-                t.resampler->setPTS(pts);
                 t.hook(&t, outTemp, numFrames, state->resampleTemp, aux);
             } else {
 
@@ -1569,8 +1561,7 @@
 
                 while (outFrames < numFrames) {
                     t.buffer.frameCount = numFrames - outFrames;
-                    int64_t outputPTS = calculateOutputPTS(t, pts, outFrames);
-                    t.bufferProvider->getNextBuffer(&t.buffer, outputPTS);
+                    t.bufferProvider->getNextBuffer(&t.buffer);
                     t.in = t.buffer.raw;
                     // t.in == NULL can happen if the track was flushed just after having
                     // been enabled for mixing.
@@ -1592,8 +1583,7 @@
 }
 
 // one track, 16 bits stereo without resampling is the most common case
-void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state,
-                                                           int64_t pts)
+void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state)
 {
     ALOGVV("process__OneTrack16BitsStereoNoResampling\n");
     // This method is only called when state->enabledTracks has exactly
@@ -1615,8 +1605,7 @@
     const uint32_t vrl = t.volumeRL;
     while (numFrames) {
         b.frameCount = numFrames;
-        int64_t outputPTS = calculateOutputPTS(t, pts, out - t.mainBuffer);
-        t.bufferProvider->getNextBuffer(&b, outputPTS);
+        t.bufferProvider->getNextBuffer(&b);
         const int16_t *in = b.i16;
 
         // in == NULL can happen if the track was flushed just after having
@@ -1677,24 +1666,10 @@
     }
 }
 
-int64_t AudioMixer::calculateOutputPTS(const track_t& t, int64_t basePTS,
-                                       int outputFrameIndex)
-{
-    if (AudioBufferProvider::kInvalidPTS == basePTS) {
-        return AudioBufferProvider::kInvalidPTS;
-    }
-
-    return basePTS + ((outputFrameIndex * sLocalTimeFreq) / t.sampleRate);
-}
-
-/*static*/ uint64_t AudioMixer::sLocalTimeFreq;
 /*static*/ pthread_once_t AudioMixer::sOnceControl = PTHREAD_ONCE_INIT;
 
 /*static*/ void AudioMixer::sInitRoutine()
 {
-    LocalClock lc;
-    sLocalTimeFreq = lc.getLocalFreq(); // for the resampler
-
     DownmixerBufferProvider::init(); // for the downmixer
 }
 
@@ -1836,7 +1811,7 @@
  * TA: int32_t (Q4.27)
  */
 template <int MIXTYPE, typename TO, typename TI, typename TA>
-void AudioMixer::process_NoResampleOneTrack(state_t* state, int64_t pts)
+void AudioMixer::process_NoResampleOneTrack(state_t* state)
 {
     ALOGVV("process_NoResampleOneTrack\n");
     // CLZ is faster than CTZ on ARM, though really not sure if true after 31 - clz.
@@ -1852,8 +1827,7 @@
         AudioBufferProvider::Buffer& b(t->buffer);
         // get input buffer
         b.frameCount = numFrames;
-        const int64_t outputPTS = calculateOutputPTS(*t, pts, state->frameCount - numFrames);
-        t->bufferProvider->getNextBuffer(&b, outputPTS);
+        t->bufferProvider->getNextBuffer(&b);
         const TI *in = reinterpret_cast<TI*>(b.raw);
 
         // in == NULL can happen if the track was flushed just after having
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 7165c6c..e788ac3 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -126,7 +126,7 @@
     void        setParameter(int name, int target, int param, void *value);
 
     void        setBufferProvider(int name, AudioBufferProvider* bufferProvider);
-    void        process(int64_t pts);
+    void        process();
 
     uint32_t    trackNames() const { return mTrackNames; }
 
@@ -278,7 +278,7 @@
         void        reconfigureBufferProviders();
     };
 
-    typedef void (*process_hook_t)(state_t* state, int64_t pts);
+    typedef void (*process_hook_t)(state_t* state);
 
     // pad to 32-bytes to fill cache line
     struct state_t {
@@ -328,17 +328,12 @@
     static void volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp,
             int32_t* aux);
 
-    static void process__validate(state_t* state, int64_t pts);
-    static void process__nop(state_t* state, int64_t pts);
-    static void process__genericNoResampling(state_t* state, int64_t pts);
-    static void process__genericResampling(state_t* state, int64_t pts);
-    static void process__OneTrack16BitsStereoNoResampling(state_t* state,
-                                                          int64_t pts);
+    static void process__validate(state_t* state);
+    static void process__nop(state_t* state);
+    static void process__genericNoResampling(state_t* state);
+    static void process__genericResampling(state_t* state);
+    static void process__OneTrack16BitsStereoNoResampling(state_t* state);
 
-    static int64_t calculateOutputPTS(const track_t& t, int64_t basePTS,
-                                      int outputFrameIndex);
-
-    static uint64_t         sLocalTimeFreq;
     static pthread_once_t   sOnceControl;
     static void             sInitRoutine();
 
@@ -359,7 +354,7 @@
 
     // multi-format process hooks
     template <int MIXTYPE, typename TO, typename TI, typename TA>
-    static void process_NoResampleOneTrack(state_t* state, int64_t pts);
+    static void process_NoResampleOneTrack(state_t* state);
 
     // multi-format track hooks
     template <int MIXTYPE, typename TO, typename TI, typename TA>
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index e49b7b1..7c20478 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -261,8 +261,8 @@
         int32_t sampleRate, src_quality quality) :
         mChannelCount(inChannelCount),
         mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0),
-        mPhaseFraction(0), mLocalTimeFreq(0),
-        mPTS(AudioBufferProvider::kInvalidPTS), mQuality(quality) {
+        mPhaseFraction(0),
+        mQuality(quality) {
 
     const int maxChannels = quality < DYN_LOW_QUALITY ? 2 : 8;
     if (inChannelCount < 1
@@ -304,23 +304,6 @@
     mVolume[1] = u4_12_from_float(clampFloatVol(right));
 }
 
-void AudioResampler::setLocalTimeFreq(uint64_t freq) {
-    mLocalTimeFreq = freq;
-}
-
-void AudioResampler::setPTS(int64_t pts) {
-    mPTS = pts;
-}
-
-int64_t AudioResampler::calculateOutputPTS(int outputFrameIndex) {
-
-    if (mPTS == AudioBufferProvider::kInvalidPTS) {
-        return AudioBufferProvider::kInvalidPTS;
-    } else {
-        return mPTS + ((outputFrameIndex * mLocalTimeFreq) / mSampleRate);
-    }
-}
-
 void AudioResampler::reset() {
     mInputIndex = 0;
     mPhaseFraction = 0;
@@ -368,8 +351,7 @@
         // buffer is empty, fetch a new one
         while (mBuffer.frameCount == 0) {
             mBuffer.frameCount = inFrameCount;
-            provider->getNextBuffer(&mBuffer,
-                                    calculateOutputPTS(outputIndex / 2));
+            provider->getNextBuffer(&mBuffer);
             if (mBuffer.raw == NULL) {
                 goto resampleStereo16_exit;
             }
@@ -465,8 +447,7 @@
         // buffer is empty, fetch a new one
         while (mBuffer.frameCount == 0) {
             mBuffer.frameCount = inFrameCount;
-            provider->getNextBuffer(&mBuffer,
-                                    calculateOutputPTS(outputIndex / 2));
+            provider->getNextBuffer(&mBuffer);
             if (mBuffer.raw == NULL) {
                 mInputIndex = inputIndex;
                 mPhaseFraction = phaseFraction;
diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h
index a8e3e6f..c4627e8 100644
--- a/services/audioflinger/AudioResampler.h
+++ b/services/audioflinger/AudioResampler.h
@@ -59,10 +59,6 @@
     virtual void init() = 0;
     virtual void setSampleRate(int32_t inSampleRate);
     virtual void setVolume(float left, float right);
-    virtual void setLocalTimeFreq(uint64_t freq);
-
-    // set the PTS of the next buffer output by the resampler
-    virtual void setPTS(int64_t pts);
 
     // Resample int16_t samples from provider and accumulate into 'out'.
     // A mono provider delivers a sequence of samples.
@@ -103,8 +99,6 @@
     AudioResampler(const AudioResampler&);
     AudioResampler& operator=(const AudioResampler&);
 
-    int64_t calculateOutputPTS(int outputFrameIndex);
-
     const int32_t mChannelCount;
     const int32_t mSampleRate;
     int32_t mInSampleRate;
@@ -117,8 +111,6 @@
     size_t mInputIndex;
     int32_t mPhaseIncrement;
     uint32_t mPhaseFraction;
-    uint64_t mLocalTimeFreq;
-    int64_t mPTS;
 
     // returns the inFrameCount required to generate outFrameCount frames.
     //
diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp
index 172c2a5..6a324ad 100644
--- a/services/audioflinger/AudioResamplerCubic.cpp
+++ b/services/audioflinger/AudioResamplerCubic.cpp
@@ -66,7 +66,7 @@
     // fetch first buffer
     if (mBuffer.frameCount == 0) {
         mBuffer.frameCount = inFrameCount;
-        provider->getNextBuffer(&mBuffer, mPTS);
+        provider->getNextBuffer(&mBuffer);
         if (mBuffer.raw == NULL) {
             return 0;
         }
@@ -97,8 +97,7 @@
                 inputIndex = 0;
                 provider->releaseBuffer(&mBuffer);
                 mBuffer.frameCount = inFrameCount;
-                provider->getNextBuffer(&mBuffer,
-                                        calculateOutputPTS(outputIndex / 2));
+                provider->getNextBuffer(&mBuffer);
                 if (mBuffer.raw == NULL) {
                     goto save_state;  // ugly, but efficient
                 }
@@ -135,7 +134,7 @@
     // fetch first buffer
     if (mBuffer.frameCount == 0) {
         mBuffer.frameCount = inFrameCount;
-        provider->getNextBuffer(&mBuffer, mPTS);
+        provider->getNextBuffer(&mBuffer);
         if (mBuffer.raw == NULL) {
             return 0;
         }
@@ -166,8 +165,7 @@
                 inputIndex = 0;
                 provider->releaseBuffer(&mBuffer);
                 mBuffer.frameCount = inFrameCount;
-                provider->getNextBuffer(&mBuffer,
-                                        calculateOutputPTS(outputIndex / 2));
+                provider->getNextBuffer(&mBuffer);
                 if (mBuffer.raw == NULL) {
                     goto save_state;  // ugly, but efficient
                 }
diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/services/audioflinger/AudioResamplerDyn.cpp
index 6481b85..618b56c 100644
--- a/services/audioflinger/AudioResamplerDyn.cpp
+++ b/services/audioflinger/AudioResamplerDyn.cpp
@@ -527,8 +527,7 @@
         // We may not fetch a new buffer if the existing data is sufficient.
         while (mBuffer.frameCount == 0 && inFrameCount > 0) {
             mBuffer.frameCount = inFrameCount;
-            provider->getNextBuffer(&mBuffer,
-                    calculateOutputPTS(outputIndex / OUTPUT_CHANNELS));
+            provider->getNextBuffer(&mBuffer);
             if (mBuffer.raw == NULL) {
                 goto resample_exit;
             }
diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp
index 41730ee..e93c064 100644
--- a/services/audioflinger/AudioResamplerSinc.cpp
+++ b/services/audioflinger/AudioResamplerSinc.cpp
@@ -301,8 +301,7 @@
         // buffer is empty, fetch a new one
         while (mBuffer.frameCount == 0) {
             mBuffer.frameCount = inFrameCount;
-            provider->getNextBuffer(&mBuffer,
-                                    calculateOutputPTS(outputIndex / 2));
+            provider->getNextBuffer(&mBuffer);
             if (mBuffer.raw == NULL) {
                 goto resample_exit;
             }
diff --git a/services/audioflinger/AudioStreamOut.cpp b/services/audioflinger/AudioStreamOut.cpp
index b6d1be7..6026bbb 100644
--- a/services/audioflinger/AudioStreamOut.cpp
+++ b/services/audioflinger/AudioStreamOut.cpp
@@ -35,7 +35,7 @@
         , mFramesWrittenAtStandby(0)
         , mRenderPosition(0)
         , mRateMultiplier(1)
-        , mHalFormatIsLinearPcm(false)
+        , mHalFormatHasProportionalFrames(false)
         , mHalFrameSize(0)
 {
 }
@@ -96,7 +96,7 @@
 
     // Adjust for standby using HAL rate frames.
     // Only apply this correction if the HAL is getting PCM frames.
-    if (mHalFormatIsLinearPcm) {
+    if (mHalFormatHasProportionalFrames) {
         uint64_t adjustedPosition = (halPosition <= mFramesWrittenAtStandby) ?
                 0 : (halPosition - mFramesWrittenAtStandby);
         // Scale from HAL sample rate to application rate.
@@ -116,16 +116,21 @@
         const char *address)
 {
     audio_stream_out_t *outStream;
+
+    audio_output_flags_t customFlags = (config->format == AUDIO_FORMAT_IEC61937)
+                ? (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)
+                : flags;
+
     int status = hwDev()->open_output_stream(
             hwDev(),
             handle,
             devices,
-            flags,
+            customFlags,
             config,
             &outStream,
             address);
-    ALOGV("AudioStreamOut::open(), HAL open_output_stream returned "
-            " %p, sampleRate %d, Format %#x, "
+    ALOGV("AudioStreamOut::open(), HAL returned "
+            " stream %p, sampleRate %d, Format %#x, "
             "channelMask %#x, status %d",
             outStream,
             config->sample_rate,
@@ -133,10 +138,26 @@
             config->channel_mask,
             status);
 
+    // Some HALs may not recognize AUDIO_FORMAT_IEC61937. But if we declare
+    // it as PCM then it will probably work.
+    if (status != NO_ERROR && config->format == AUDIO_FORMAT_IEC61937) {
+        struct audio_config customConfig = *config;
+        customConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+
+        status = hwDev()->open_output_stream(
+                hwDev(),
+                handle,
+                devices,
+                customFlags,
+                &customConfig,
+                &outStream,
+                address);
+        ALOGV("AudioStreamOut::open(), treat IEC61937 as PCM, status = %d", status);
+    }
+
     if (status == NO_ERROR) {
         stream = outStream;
-        mHalFormatIsLinearPcm = audio_is_linear_pcm(config->format);
-        ALOGI("AudioStreamOut::open(), mHalFormatIsLinearPcm = %d", (int)mHalFormatIsLinearPcm);
+        mHalFormatHasProportionalFrames = audio_has_proportional_frames(config->format);
         mHalFrameSize = audio_stream_out_frame_size(stream);
     }
 
diff --git a/services/audioflinger/AudioStreamOut.h b/services/audioflinger/AudioStreamOut.h
index 06a2277..768f537 100644
--- a/services/audioflinger/AudioStreamOut.h
+++ b/services/audioflinger/AudioStreamOut.h
@@ -106,7 +106,7 @@
     uint64_t             mFramesWrittenAtStandby;
     uint64_t             mRenderPosition; // reset by flush or standby
     int                  mRateMultiplier;
-    bool                 mHalFormatIsLinearPcm;
+    bool                 mHalFormatHasProportionalFrames;
     size_t               mHalFrameSize;
 };
 
diff --git a/services/audioflinger/BufferProviders.cpp b/services/audioflinger/BufferProviders.cpp
index a8be206..2ca2cac 100644
--- a/services/audioflinger/BufferProviders.cpp
+++ b/services/audioflinger/BufferProviders.cpp
@@ -70,13 +70,12 @@
     free(mLocalBufferData);
 }
 
-status_t CopyBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer,
-        int64_t pts)
+status_t CopyBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer)
 {
-    //ALOGV("CopyBufferProvider(%p)::getNextBuffer(%p (%zu), %lld)",
-    //        this, pBuffer, pBuffer->frameCount, pts);
+    //ALOGV("CopyBufferProvider(%p)::getNextBuffer(%p (%zu))",
+    //        this, pBuffer, pBuffer->frameCount);
     if (mLocalBufferFrameCount == 0) {
-        status_t res = mTrackBufferProvider->getNextBuffer(pBuffer, pts);
+        status_t res = mTrackBufferProvider->getNextBuffer(pBuffer);
         if (res == OK) {
             copyFrames(pBuffer->raw, pBuffer->raw, pBuffer->frameCount);
         }
@@ -84,7 +83,7 @@
     }
     if (mBuffer.frameCount == 0) {
         mBuffer.frameCount = pBuffer->frameCount;
-        status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts);
+        status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer);
         // At one time an upstream buffer provider had
         // res == OK and mBuffer.frameCount == 0, doesn't seem to happen now 7/18/2014.
         //
@@ -356,13 +355,13 @@
 }
 
 status_t TimestretchBufferProvider::getNextBuffer(
-        AudioBufferProvider::Buffer *pBuffer, int64_t pts)
+        AudioBufferProvider::Buffer *pBuffer)
 {
-    ALOGV("TimestretchBufferProvider(%p)::getNextBuffer(%p (%zu), %lld)",
-            this, pBuffer, pBuffer->frameCount, pts);
+    ALOGV("TimestretchBufferProvider(%p)::getNextBuffer(%p (%zu))",
+            this, pBuffer, pBuffer->frameCount);
 
     // BYPASS
-    //return mTrackBufferProvider->getNextBuffer(pBuffer, pts);
+    //return mTrackBufferProvider->getNextBuffer(pBuffer);
 
     // check if previously processed data is sufficient.
     if (pBuffer->frameCount <= mRemaining) {
@@ -391,7 +390,7 @@
         mBuffer.frameCount = mPlaybackRate.mSpeed == AUDIO_TIMESTRETCH_SPEED_NORMAL
                 ? outputDesired : outputDesired * mPlaybackRate.mSpeed + 1;
 
-        status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts);
+        status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer);
 
         ALOG_ASSERT(res == OK || mBuffer.frameCount == 0);
         if (res != OK || mBuffer.frameCount == 0) { // not needed by API spec, but to be safe.
diff --git a/services/audioflinger/BufferProviders.h b/services/audioflinger/BufferProviders.h
index 4bc895c..abd43c6 100644
--- a/services/audioflinger/BufferProviders.h
+++ b/services/audioflinger/BufferProviders.h
@@ -64,7 +64,7 @@
     virtual ~CopyBufferProvider();
 
     // Overrides AudioBufferProvider methods
-    virtual status_t getNextBuffer(Buffer *buffer, int64_t pts);
+    virtual status_t getNextBuffer(Buffer *buffer);
     virtual void releaseBuffer(Buffer *buffer);
 
     // Overrides PassthruBufferProvider
@@ -156,7 +156,7 @@
     virtual ~TimestretchBufferProvider();
 
     // Overrides AudioBufferProvider methods
-    virtual status_t getNextBuffer(Buffer* buffer, int64_t pts);
+    virtual status_t getNextBuffer(Buffer* buffer);
     virtual void releaseBuffer(Buffer* buffer);
 
     // Overrides PassthruBufferProvider
diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp
index 1bba5f6..bb83858 100644
--- a/services/audioflinger/FastCapture.cpp
+++ b/services/audioflinger/FastCapture.cpp
@@ -166,8 +166,7 @@
         ALOG_ASSERT(mReadBuffer != NULL);
         dumpState->mReadSequence++;
         ATRACE_BEGIN("read");
-        ssize_t framesRead = mInputSource->read(mReadBuffer, frameCount,
-                AudioBufferProvider::kInvalidPTS);
+        ssize_t framesRead = mInputSource->read(mReadBuffer, frameCount);
         ATRACE_END();
         dumpState->mReadSequence++;
         if (framesRead >= 0) {
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 45c68b5..1446d19 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -37,12 +37,11 @@
 #include <cpustats/ThreadCpuUsage.h>
 #endif
 #endif
+#include <audio_utils/conversion.h>
 #include <audio_utils/format.h>
 #include "AudioMixer.h"
 #include "FastMixer.h"
 
-#define FCC_2                       2   // fixed channel count assumption
-
 namespace android {
 
 /*static*/ const FastMixerState FastMixer::sInitial;
@@ -66,7 +65,8 @@
     mFastTracksGen(0),
     mTotalNativeFramesWritten(0),
     // timestamp
-    mNativeFramesWrittenButNotPresented(0)   // the = 0 is to silence the compiler
+    mNativeFramesWrittenButNotPresented(0),   // the = 0 is to silence the compiler
+    mMasterMono(false)
 {
     // FIXME pass sInitial as parameter to base class constructor, and make it static local
     mPrevious = &sInitial;
@@ -402,13 +402,8 @@
             ftDump->mFramesReady = framesReady;
         }
 
-        int64_t pts;
-        if (mOutputSink == NULL || (OK != mOutputSink->getNextWriteTimestamp(&pts))) {
-            pts = AudioBufferProvider::kInvalidPTS;
-        }
-
         // process() is CPU-bound
-        mMixer->process(pts);
+        mMixer->process();
         mMixerBufferState = MIXED;
     } else if (mMixerBufferState == MIXED) {
         mMixerBufferState = UNDEFINED;
@@ -419,6 +414,10 @@
             memset(mMixerBuffer, 0, mMixerBufferSize);
             mMixerBufferState = ZEROED;
         }
+
+        if (mMasterMono.load()) {  // memory_order_seq_cst
+            mono_blend(mMixerBuffer, mMixerBufferFormat, Format_channelCount(mFormat), frameCount, true /*limit*/);
+        }
         // prepare the buffer used to write to sink
         void *buffer = mSinkBuffer != NULL ? mSinkBuffer : mMixerBuffer;
         if (mFormat.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 06a68fb..e38878e 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_AUDIO_FAST_MIXER_H
 #define ANDROID_AUDIO_FAST_MIXER_H
 
+#include <atomic>
 #include "FastThread.h"
 #include "StateQueue.h"
 #include "FastMixerState.h"
@@ -36,6 +37,8 @@
 
             FastMixerStateQueue* sq();
 
+    virtual void setMasterMono(bool mono) { mMasterMono.store(mono); /* memory_order_seq_cst */ }
+
 private:
             FastMixerStateQueue mSQ;
 
@@ -82,6 +85,8 @@
     AudioTimestamp  mTimestamp;
     uint32_t        mNativeFramesWrittenButNotPresented;
 
+    // accessed without lock between multiple threads.
+    std::atomic_bool mMasterMono;
 };  // class FastMixer
 
 }   // namespace android
diff --git a/services/audioflinger/LinearMap.h b/services/audioflinger/LinearMap.h
new file mode 100644
index 0000000..fca14dd
--- /dev/null
+++ b/services/audioflinger/LinearMap.h
@@ -0,0 +1,366 @@
+/*
+ * 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 ANDROID_LINEAR_MAP_H
+#define ANDROID_LINEAR_MAP_H
+
+#include <stdint.h>
+
+namespace android {
+
+/*
+A general purpose lookup utility that defines a mapping between X and Y as a
+continuous set of line segments with shared (x, y) end-points.
+The (x, y) points must be added in order, monotonically increasing in both x and y;
+a log warning is emitted if this does not happen (See general usage notes below).
+
+A limited history of (x, y) points is kept for space reasons (See general usage notes).
+
+In AudioFlinger, we use the LinearMap to associate track frames to
+sink frames.  When we want to obtain a client track timestamp, we first
+get a timestamp from the sink.  The sink timestamp's position (mPosition)
+corresponds to the sink frames written. We use LinearMap to figure out which track frame
+the sink frame corresponds to. This allows us to substitute a track frame for the
+the sink frame (keeping the mTime identical) and return that timestamp back to the client.
+
+The method findX() can be used to retrieve an x value from a given y value and is
+used for timestamps, similarly for findY() which is provided for completeness.
+
+We update the (track frame, sink frame) points in the LinearMap each time we write data
+to the sink by the AudioFlinger PlaybackThread (MixerThread).
+
+
+AudioFlinger Timestamp Notes:
+
+1) Example: Obtaining a track timestamp during playback.  In this case, the LinearMap
+looks something like this:
+
+Track Frame    Sink Frame
+(track start)
+0              50000  (track starts here, the sink may already be running)
+1000           51000
+2000           52000
+
+When we request a track timestamp, we call the sink getTimestamp() and get for example
+mPosition = 51020.  Using the LinearMap, we find we have played to track frame 1020.
+We substitute the sink mPosition of 51020 with the track position 1020,
+and return that timestamp to the app.
+
+2) Example: Obtaining a track timestamp duing pause. In this case, the LinearMap
+looks something like this:
+
+Track Frame    Sink Frame
+... (some time has gone by)
+15000          30000
+16000          31000
+17000          32000
+(pause here)
+(suppose we call sink getTimestamp() here and get sink mPosition = 31100; that means
+        we have played to track frame 16100.  The track timestamp mPosition will
+        continue to advance until the sink timestamp returns a value of mPosition
+        greater than 32000, corresponding to track frame 17000 when the pause was called).
+17000          33000
+17000          34000
+...
+
+3) If the track underruns, it appears as if a pause was called on that track.
+
+4) If there is an underrun in the HAL layer, then it may be possible that
+the sink getTimestamp() will return a value greater than the number of frames written
+(it should always be less). This should be rare, if not impossible by some
+HAL implementations of the sink getTimestamp. In that case, timing is lost
+and we will return the most recent track frame written.
+
+5) When called with no points in the map, findX() returns the start value (default 0).
+This is consistent with starting after a stop() or flush().
+
+6) Resuming after Track standby will be similar to coming out of pause, as the HAL ensures
+framesWritten() and getTimestamp() are contiguous for non-offloaded/direct tracks.
+
+7) LinearMap works for different speeds and sample rates as it uses
+linear interpolation. Since AudioFlinger only updates speed and sample rate
+exactly at the sample points pushed into the LinearMap, the returned values
+from findX() and findY() are accurate regardless of how many speed or sample
+rate changes are made, so long as the coordinate looked up is within the
+sample history.
+
+General usage notes:
+
+1) In order for the LinearMap to work reliably, you cannot look backwards more
+than the size of its circular buffer history, set upon creation (typically 16).
+If you look back further, the position is extrapolated either from a passed in
+extrapolation parameter or from the oldest line segment.
+
+2) Points must monotonically increase in x and y. The increment between adjacent
+points cannot be greater than signed 32 bits. Wrap in the x, y coordinates are supported,
+since we use differences in our computation.
+
+3) If the frame data is discontinuous (due to stop or flush) call reset() to clear
+the sample counter.
+
+4) If (x, y) are not strictly monotonic increasing, i.e. (x2 > x1) and (y2 > y1),
+then one or both of the inverses y = f(x) or x = g(y) may have multiple solutions.
+In that case, the most recent solution is returned by findX() or findY().  We
+do not warn if (x2 == x1) or (y2 == y1), but we do logcat warn if (x2 < x1) or
+(y2 < y1).
+
+5) Due to rounding it is possible x != findX(findY(x)) or y != findY(findX(y))
+even when the inverse exists. Nevertheless, the values should be close.
+
+*/
+
+template <typename T>
+class LinearMap {
+public:
+    // This enumeration describes the reliability of the findX() or findY() estimation
+    // in descending order.
+    enum FindMethod {
+        FIND_METHOD_INTERPOLATION,           // High reliability (errors due to rounding)
+        FIND_METHOD_FORWARD_EXTRAPOLATION,   // Reliability based on no future speed changes
+        FIND_METHOD_BACKWARD_EXTRAPOLATION,  // Reliability based on prior estimated speed
+        FIND_METHOD_START_VALUE,             // No samples in history, using start value
+    };
+
+    LinearMap(size_t size)
+            : mSize(size),
+              mPos(0), // a circular buffer, so could start anywhere. the first sample is at 1.
+              mSamples(0),
+              // mStepValid(false),      // only valid if mSamples > 1
+              // mExtrapolateTail(false), // only valid if mSamples > 0
+              mX(new T[size]),
+              mY(new T[size]) { }
+
+    ~LinearMap() {
+        delete[] mX;
+        delete[] mY;
+    }
+
+    // Add a new sample point to the linear map.
+    //
+    // The difference between the new sample and the previous sample
+    // in the x or y coordinate must be less than INT32_MAX for purposes
+    // of the linear interpolation or extrapolation.
+    //
+    // The value should be monotonic increasing (e.g. diff >= 0);
+    // logcat warnings are issued if they are not.
+    __attribute__((no_sanitize("integer")))
+    void push(T x, T y) {
+        // Assumption: we assume x, y are monotonic increasing values,
+        // which (can) wrap in precision no less than 32 bits and have
+        // "step" or differences between adjacent points less than 32 bits.
+
+        if (mSamples > 0) {
+            const bool lastStepValid = mStepValid;
+            int32_t xdiff;
+            int32_t ydiff;
+            // check difference assumption here
+            mStepValid = checkedDiff(&xdiff, x, mX[mPos], "x")
+                    & /* bitwise AND to always warn for ydiff, though logical AND is also OK */
+                    checkedDiff(&ydiff, y, mY[mPos], "y");
+
+            // Optimization: do not add a new sample if the line segment would
+            // simply extend the previous line segment.  This extends the useful
+            // history by removing redundant points.
+            if (mSamples > 1 && mStepValid && lastStepValid) {
+                const size_t prev = previousPosition();
+                const int32_t xdiff2 = x - mX[prev];
+                const int32_t ydiff2 = y - mY[prev];
+
+                // if both current step and previous step are valid (non-negative and
+                // less than INT32_MAX for precision greater than 4 bytes)
+                // then the sum of the two steps is valid when the
+                // int32_t difference is non-negative.
+                if (xdiff2 >= 0 && ydiff2 >= 0
+                        && (int64_t)xdiff2 * ydiff == (int64_t)ydiff2 * xdiff) {
+                    // ALOGD("reusing sample! (%u, %u) sample depth %zd", x, y, mSamples);
+                    mX[mPos] = x;
+                    mY[mPos] = y;
+                    return;
+                }
+            }
+        }
+        if (++mPos >= mSize) {
+            mPos = 0;
+        }
+        if (mSamples < mSize) {
+            mExtrapolateTail = false;
+            ++mSamples;
+        } else {
+            // we enable extrapolation beyond the oldest sample
+            // if the sample buffers are completely full and we
+            // no longer know the full history.
+            mExtrapolateTail = true;
+        }
+        mX[mPos] = x;
+        mY[mPos] = y;
+    }
+
+    // clear all samples from the circular array
+    void reset() {
+        // no need to reset mPos, we use a circular buffer.
+        // computed values such as mStepValid are set after a subsequent push().
+        mSamples = 0;
+    }
+
+    // returns true if LinearMap contains at least one sample.
+    bool hasData() const {
+        return mSamples != 0;
+    }
+
+    // find the corresponding X point from a Y point.
+    // See findU for details.
+    __attribute__((no_sanitize("integer")))
+    T findX(T y, FindMethod *method = NULL, double extrapolation = 0.0, T startValue = 0) const {
+        return findU(y, mX, mY, method, extrapolation, startValue);
+    }
+
+    // find the corresponding Y point from a X point.
+    // See findU for details.
+    __attribute__((no_sanitize("integer")))
+    T findY(T x, FindMethod *method = NULL, double extrapolation = 0.0, T startValue = 0) const {
+        return findU(x, mY, mX, method, extrapolation, startValue);
+    }
+
+protected:
+
+    // returns false if the diff is out of int32_t bounds or negative.
+    __attribute__((no_sanitize("integer")))
+    static inline bool checkedDiff(int32_t *diff, T x2, T x1, const char *coord) {
+        if (sizeof(T) >= 8) {
+            const int64_t diff64 = x2 - x1;
+            *diff = (int32_t)diff64;  // intentionally lose precision
+            if (diff64 > INT32_MAX) {
+                ALOGW("LinearMap: %s overflow diff(%lld) from %llu - %llu exceeds INT32_MAX",
+                        coord, (long long)diff64,
+                        (unsigned long long)x2, (unsigned long long)x1);
+                return false;
+            } else if (diff64 < 0) {
+                ALOGW("LinearMap: %s negative diff(%lld) from %llu - %llu",
+                        coord, (long long)diff64,
+                        (unsigned long long)x2, (unsigned long long)x1);
+                return false;
+            }
+            return true;
+        }
+        // for 32 bit integers we cannot detect overflow (it
+        // shows up as a negative difference).
+        *diff = x2 - x1;
+        if (*diff < 0) {
+            ALOGW("LinearMap: %s negative diff(%d) from %u - %u",
+                    coord, *diff, (unsigned)x2, (unsigned)x1);
+            return false;
+        }
+        return true;
+    }
+
+    // Returns the previous position in the mSamples array
+    // going backwards back steps.
+    //
+    // Parameters:
+    //   back: number of backward steps, cannot be less than zero or greater than mSamples.
+    //
+    __attribute__((no_sanitize("integer")))
+    size_t previousPosition(ssize_t back = 1) const {
+        LOG_ALWAYS_FATAL_IF(back < 0 || (size_t)back > mSamples, "Invalid back(%zd)", back);
+        ssize_t position = mPos - back;
+        if (position < 0) position += mSize;
+        return (size_t)position;
+    }
+
+    // A generic implementation of finding the "other coordinate" with coordinates
+    // (u, v) = (x, y) or (u, v) = (y, x).
+    //
+    // Parameters:
+    //   uArray: the u axis samples.
+    //   vArray: the v axis samples.
+    //   method: [out] how the returned value was computed.
+    //   extrapolation: the slope used when extrapolating from the
+    //     first sample value or the last sample value in the history.
+    //     If mExtrapolateTail is set, the slope of the last line segment
+    //     is used if the extrapolation parameter is zero to continue the tail of history.
+    //     At this time, we do not use a different value for forward extrapolation from the
+    //     head of history from backward extrapolation from the tail of history.
+    //     TODO: back extrapolation value could be stored along with mX, mY in history.
+    //   startValue: used only when there are no samples in history. One can detect
+    //     whether there are samples in history by the method hasData().
+    //
+    __attribute__((no_sanitize("integer")))
+    T findU(T v, T *uArray, T *vArray, FindMethod *method,
+            double extrapolation, T startValue) const {
+        if (mSamples == 0) {
+            if (method != NULL) {
+                *method = FIND_METHOD_START_VALUE;
+            }
+            return startValue;  // nothing yet
+        }
+        ssize_t previous = 0;
+        int32_t diff = 0;
+        for (ssize_t i = 0; i < (ssize_t)mSamples; ++i) {
+            size_t current = previousPosition(i);
+
+            // Assumption: even though the type "T" may have precision greater
+            // than 32 bits, the difference between adjacent points is limited to 32 bits.
+            diff = v - vArray[current];
+            if (diff >= 0 ||
+                    (i == (ssize_t)mSamples - 1 && mExtrapolateTail && extrapolation == 0.0)) {
+                // ALOGD("depth = %zd out of %zd", i, limit);
+                if (i == 0) {
+                    if (method != NULL) {
+                        *method = FIND_METHOD_FORWARD_EXTRAPOLATION;
+                    }
+                    return uArray[current] + diff * extrapolation;
+                }
+                // interpolate / extrapolate: For this computation, we
+                // must use differentials here otherwise we have inconsistent
+                // values on modulo wrap. previous is always valid here since
+                // i > 0.  we also perform rounding with the assumption
+                // that uStep, vStep, and diff are non-negative.
+                int32_t uStep = uArray[previous] - uArray[current]; // non-negative
+                int32_t vStep = vArray[previous] - vArray[current]; // positive
+                T u = uStep <= 0 || vStep <= 0 ?  // we do not permit negative ustep or vstep
+                        uArray[current]
+                      : ((int64_t)diff * uStep + (vStep >> 1)) / vStep + uArray[current];
+                // ALOGD("u:%u  diff:%d  uStep:%d  vStep:%d  u_current:%d",
+                //         u, diff, uStep, vStep, uArray[current]);
+                if (method != NULL) {
+                    *method = (diff >= 0) ?
+                            FIND_METHOD_INTERPOLATION : FIND_METHOD_BACKWARD_EXTRAPOLATION;
+                }
+                return u;
+            }
+            previous = current;
+        }
+        // previous is always valid here.
+        if (method != NULL) {
+            *method = FIND_METHOD_BACKWARD_EXTRAPOLATION;
+        }
+        return uArray[previous] + diff * extrapolation;
+    }
+
+private:
+    const size_t    mSize;      // Size of mX and mY arrays (history).
+    size_t          mPos;       // Index in mX and mY of last pushed data;
+                                // (incremented after push) [0, mSize - 1].
+    size_t          mSamples;   // Number of valid samples in the array [0, mSize].
+    bool            mStepValid; // Last sample step was valid (non-negative)
+    bool            mExtrapolateTail; // extrapolate tail using oldest line segment
+    T * const       mX;         // History of X values as a circular array.
+    T * const       mY;         // History of Y values as a circular array.
+};
+
+} // namespace android
+
+#endif // ANDROID_LINEAR_MAP_H
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index f6078a2..a6cb9c0 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -152,7 +152,8 @@
         return BAD_VALUE;
     }
     if (patch->num_sources == 0 || patch->num_sources > AUDIO_PATCH_PORTS_MAX ||
-            patch->num_sinks == 0 || patch->num_sinks > AUDIO_PATCH_PORTS_MAX) {
+            (patch->num_sinks == 0 && patch->num_sources != 2) ||
+            patch->num_sinks > AUDIO_PATCH_PORTS_MAX) {
         return BAD_VALUE;
     }
     // limit number of sources to 1 for now or 2 sources for special cross hw module case.
@@ -203,18 +204,18 @@
             }
 
             // manage patches requiring a software bridge
+            // - special patch request with 2 sources (reuse one existing output mix) OR
             // - Device to device AND
             //    - source HW module != destination HW module OR
             //    - audio HAL version < 3.0
-            //    - special patch request with 2 sources (reuse one existing output mix)
-            if ((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
-                    ((patch->sinks[0].ext.device.hw_module != srcModule) ||
-                    (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) ||
-                    (patch->num_sources == 2))) {
+            if ((patch->num_sources == 2) ||
+                ((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
+                 ((patch->sinks[0].ext.device.hw_module != srcModule) ||
+                  (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0)))) {
                 if (patch->num_sources == 2) {
                     if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX ||
-                            patch->sinks[0].ext.device.hw_module !=
-                                    patch->sources[1].ext.mix.hw_module) {
+                            (patch->num_sinks != 0 && patch->sinks[0].ext.device.hw_module !=
+                                    patch->sources[1].ext.mix.hw_module)) {
                         ALOGW("createAudioPatch() invalid source combination");
                         status = INVALID_OPERATION;
                         goto exit;
@@ -379,12 +380,16 @@
     }
 
     // create patch from playback thread output to sink device
-    patch->mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]);
-    subPatch.sinks[0] = audioPatch->sinks[0];
-    status = createAudioPatch(&subPatch, &patch->mPlaybackPatchHandle);
-    if (status != NO_ERROR) {
+    if (audioPatch->num_sinks != 0) {
+        patch->mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]);
+        subPatch.sinks[0] = audioPatch->sinks[0];
+        status = createAudioPatch(&subPatch, &patch->mPlaybackPatchHandle);
+        if (status != NO_ERROR) {
+            patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+            return status;
+        }
+    } else {
         patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-        return status;
     }
 
     // use a pseudo LCM between input and output framecount
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 7bc6f0c..fe3cc53 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -83,13 +83,13 @@
                         Track& operator = (const Track&);
 
     // AudioBufferProvider interface
-    virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer,
-                                   int64_t pts = kInvalidPTS);
+    virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
     // releaseBuffer() not overridden
 
     // ExtendedAudioBufferProvider interface
     virtual size_t framesReady() const;
     virtual size_t framesReleased() const;
+    virtual void onTimestamp(const AudioTimestamp &timestamp);
 
     bool isPausing() const { return mState == PAUSING; }
     bool isPaused() const { return mState == PAUSED; }
@@ -101,6 +101,8 @@
     void flushAck();
     bool isResumePending();
     void resumeAck();
+    void updateTrackFrameInfo(uint32_t trackFramesReleased, uint32_t sinkFramesWritten,
+            AudioTimestamp *timeStamp = NULL);
 
     sp<IMemory> sharedBuffer() const { return mSharedBuffer; }
 
@@ -138,6 +140,12 @@
     size_t              mPresentationCompleteFrames; // number of frames written to the
                                     // audio HAL when this track will be fully rendered
                                     // zero means not monitoring
+
+    // access these three variables only when holding thread lock.
+    LinearMap<uint32_t> mFrameMap;           // track frame to server frame mapping
+    bool                mSinkTimestampValid; // valid cached timestamp
+    AudioTimestamp      mSinkTimestamp;
+
 private:
     // The following fields are only for fast tracks, and should be in a subclass
     int                 mFastIndex; // index within FastMixerState::mFastTracks[];
@@ -158,92 +166,6 @@
 
 };  // end of Track
 
-class TimedTrack : public Track {
-  public:
-    static sp<TimedTrack> create(PlaybackThread *thread,
-                                 const sp<Client>& client,
-                                 audio_stream_type_t streamType,
-                                 uint32_t sampleRate,
-                                 audio_format_t format,
-                                 audio_channel_mask_t channelMask,
-                                 size_t frameCount,
-                                 const sp<IMemory>& sharedBuffer,
-                                 int sessionId,
-                                 int uid);
-    virtual ~TimedTrack();
-
-    class TimedBuffer {
-      public:
-        TimedBuffer();
-        TimedBuffer(const sp<IMemory>& buffer, int64_t pts);
-        const sp<IMemory>& buffer() const { return mBuffer; }
-        int64_t pts() const { return mPTS; }
-        uint32_t position() const { return mPosition; }
-        void setPosition(uint32_t pos) { mPosition = pos; }
-      private:
-        sp<IMemory> mBuffer;
-        int64_t     mPTS;
-        uint32_t    mPosition;
-    };
-
-    // Mixer facing methods.
-    virtual size_t framesReady() const;
-
-    // AudioBufferProvider interface
-    virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer,
-                                   int64_t pts);
-    virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
-
-    // Client/App facing methods.
-    status_t    allocateTimedBuffer(size_t size,
-                                    sp<IMemory>* buffer);
-    status_t    queueTimedBuffer(const sp<IMemory>& buffer,
-                                 int64_t pts);
-    status_t    setMediaTimeTransform(const LinearTransform& xform,
-                                      TimedAudioTrack::TargetTimeline target);
-
-  private:
-    TimedTrack(PlaybackThread *thread,
-               const sp<Client>& client,
-               audio_stream_type_t streamType,
-               uint32_t sampleRate,
-               audio_format_t format,
-               audio_channel_mask_t channelMask,
-               size_t frameCount,
-               const sp<IMemory>& sharedBuffer,
-               int sessionId,
-               int uid);
-
-    void timedYieldSamples_l(AudioBufferProvider::Buffer* buffer);
-    void timedYieldSilence_l(uint32_t numFrames,
-                             AudioBufferProvider::Buffer* buffer);
-    void trimTimedBufferQueue_l();
-    void trimTimedBufferQueueHead_l(const char* logTag);
-    void updateFramesPendingAfterTrim_l(const TimedBuffer& buf,
-                                        const char* logTag);
-
-    uint64_t            mLocalTimeFreq;
-    LinearTransform     mLocalTimeToSampleTransform;
-    LinearTransform     mMediaTimeToSampleTransform;
-    sp<MemoryDealer>    mTimedMemoryDealer;
-
-    Vector<TimedBuffer> mTimedBufferQueue;
-    bool                mQueueHeadInFlight;
-    bool                mTrimQueueHeadOnRelease;
-    uint32_t            mFramesPendingInQueue;
-
-    uint8_t*            mTimedSilenceBuffer;
-    uint32_t            mTimedSilenceBufferSize;
-    mutable Mutex       mTimedBufferQueueLock;
-    bool                mTimedAudioOutputOnTime;
-    CCHelper            mCCHelper;
-
-    Mutex               mMediaTimeTransformLock;
-    LinearTransform     mMediaTimeTransform;
-    bool                mMediaTimeTransformValid;
-    TimedAudioTrack::TargetTimeline mMediaTimeTransformTarget;
-};
-
 
 // playback track, used by DuplicatingThread
 class OutputTrack : public Track {
@@ -303,8 +225,7 @@
     virtual             ~PatchTrack();
 
     // AudioBufferProvider interface
-    virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer,
-                                   int64_t pts);
+    virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
     virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
 
     // PatchProxyBufferProvider interface
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 25d6d95..5f70479 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -54,6 +54,10 @@
             void        handleSyncStartEvent(const sp<SyncEvent>& event);
             void        clearSyncStartEvent();
 
+            void        updateTrackFrameInfo(int64_t trackFramesReleased,
+                                             int64_t sourceFramesRead,
+                                             uint32_t halSampleRate,
+                                             const ExtendedTimestamp &timestamp);
 private:
     friend class AudioFlinger;  // for mState
 
@@ -61,8 +65,7 @@
                         RecordTrack& operator = (const RecordTrack&);
 
     // AudioBufferProvider interface
-    virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer,
-                                   int64_t pts = kInvalidPTS);
+    virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
     // releaseBuffer() not overridden
 
     bool                mOverflow;  // overflow on most recent attempt to fill client buffer
@@ -73,6 +76,8 @@
             // be dropped and therefore not read by the application.
             sp<SyncEvent>                       mSyncStartEvent;
 
+            AudioRecordServerProxy             *mAudioRecordServerProxy;
+
             // number of captured frames to drop after the start sync event has been received.
             // when < 0, maximum frames to drop before starting capture even if sync event is
             // not received
@@ -99,8 +104,7 @@
     virtual             ~PatchRecord();
 
     // AudioBufferProvider interface
-    virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer,
-                                   int64_t pts);
+    virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
     virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
 
     // PatchProxyBufferProvider interface
diff --git a/services/audioflinger/ServiceUtilities.cpp b/services/audioflinger/ServiceUtilities.cpp
index 2e68dad..afc2440 100644
--- a/services/audioflinger/ServiceUtilities.cpp
+++ b/services/audioflinger/ServiceUtilities.cpp
@@ -32,29 +32,37 @@
 
 // Not valid until initialized by AudioFlinger constructor.  It would have to be
 // re-initialized if the process containing AudioFlinger service forks (which it doesn't).
+// This is often used to validate binder interface calls within audioserver
+// (e.g. AudioPolicyManager to AudioFlinger).
 pid_t getpid_cached;
 
-bool recordingAllowed(const String16& opPackageName) {
-    // Note: We are getting the UID from the calling IPC thread state because all
-    // clients that perform recording create AudioRecord in their own processes
-    // and the system does not create AudioRecord objects on behalf of apps. This
-    // differs from playback where in some situations the system recreates AudioTrack
-    // instances associated with a client's MediaPlayer on behalf of this client.
-    // In the latter case we have to store the client UID and pass in along for
-    // security checks.
+// A trusted calling UID may specify the client UID as part of a binder interface call.
+// otherwise the calling UID must be equal to the client UID.
+bool isTrustedCallingUid(uid_t uid) {
+    switch (uid) {
+    case AID_MEDIA:
+    case AID_AUDIOSERVER:
+        return true;
+    default:
+        return false;
+    }
+}
 
+bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid) {
+    // we're always OK.
     if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
+
     static const String16 sRecordAudio("android.permission.RECORD_AUDIO");
 
+    // We specify a pid and uid here as mediaserver (aka MediaRecorder or StageFrightRecorder)
+    // may open a record track on behalf of a client.  Note that pid may be a tid.
     // IMPORTANT: Don't use PermissionCache - a runtime permission and may change.
-    const bool ok = checkCallingPermission(sRecordAudio);
+    const bool ok = checkPermission(sRecordAudio, pid, uid);
     if (!ok) {
         ALOGE("Request requires android.permission.RECORD_AUDIO");
         return false;
     }
 
-    const uid_t uid = IPCThreadState::self()->getCallingUid();
-
     // To permit command-line native tests
     if (uid == AID_ROOT) return true;
 
diff --git a/services/audioflinger/ServiceUtilities.h b/services/audioflinger/ServiceUtilities.h
index fba6dce..1e79553 100644
--- a/services/audioflinger/ServiceUtilities.h
+++ b/services/audioflinger/ServiceUtilities.h
@@ -19,8 +19,8 @@
 namespace android {
 
 extern pid_t getpid_cached;
-
-bool recordingAllowed(const String16& opPackageName);
+bool isTrustedCallingUid(uid_t uid);
+bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid);
 bool captureAudioOutputAllowed();
 bool captureHotwordAllowed();
 bool settingsAllowed();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 71fc498..5aff394 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -36,6 +36,7 @@
 #include <hardware/audio.h>
 #include <audio_effects/effect_ns.h>
 #include <audio_effects/effect_aec.h>
+#include <audio_utils/conversion.h>
 #include <audio_utils/primitives.h>
 #include <audio_utils/format.h>
 #include <audio_utils/minifloat.h>
@@ -48,12 +49,10 @@
 #include <media/nbaio/Pipe.h>
 #include <media/nbaio/PipeReader.h>
 #include <media/nbaio/SourceAudioBufferProvider.h>
+#include <mediautils/BatteryNotifier.h>
 
 #include <powermanager/PowerManager.h>
 
-#include <common_time/cc_helper.h>
-#include <common_time/local_clock.h>
-
 #include "AudioFlinger.h"
 #include "AudioMixer.h"
 #include "BufferProviders.h"
@@ -221,6 +220,94 @@
 }
 #endif
 
+// Track the CLOCK_BOOTTIME versus CLOCK_MONOTONIC timebase offset
+struct {
+    // call when you acquire a partial wakelock
+    void acquire(const sp<IBinder> &wakeLockToken) {
+        pthread_mutex_lock(&mLock);
+        if (wakeLockToken.get() == nullptr) {
+            adjustTimebaseOffset(&mBoottimeOffset, ExtendedTimestamp::TIMEBASE_BOOTTIME);
+        } else {
+            if (mCount == 0) {
+                adjustTimebaseOffset(&mBoottimeOffset, ExtendedTimestamp::TIMEBASE_BOOTTIME);
+            }
+            ++mCount;
+        }
+        pthread_mutex_unlock(&mLock);
+    }
+
+    // call when you release a partial wakelock.
+    void release(const sp<IBinder> &wakeLockToken) {
+        if (wakeLockToken.get() == nullptr) {
+            return;
+        }
+        pthread_mutex_lock(&mLock);
+        if (--mCount < 0) {
+            ALOGE("negative wakelock count");
+            mCount = 0;
+        }
+        pthread_mutex_unlock(&mLock);
+    }
+
+    // retrieves the boottime timebase offset from monotonic.
+    int64_t getBoottimeOffset() {
+        pthread_mutex_lock(&mLock);
+        int64_t boottimeOffset = mBoottimeOffset;
+        pthread_mutex_unlock(&mLock);
+        return boottimeOffset;
+    }
+
+    // Adjusts the timebase offset between TIMEBASE_MONOTONIC
+    // and the selected timebase.
+    // Currently only TIMEBASE_BOOTTIME is allowed.
+    //
+    // This only needs to be called upon acquiring the first partial wakelock
+    // after all other partial wakelocks are released.
+    //
+    // We do an empirical measurement of the offset rather than parsing
+    // /proc/timer_list since the latter is not a formal kernel ABI.
+    static void adjustTimebaseOffset(int64_t *offset, ExtendedTimestamp::Timebase timebase) {
+        int clockbase;
+        switch (timebase) {
+        case ExtendedTimestamp::TIMEBASE_BOOTTIME:
+            clockbase = SYSTEM_TIME_BOOTTIME;
+            break;
+        default:
+            LOG_ALWAYS_FATAL("invalid timebase %d", timebase);
+            break;
+        }
+        // try three times to get the clock offset, choose the one
+        // with the minimum gap in measurements.
+        const int tries = 3;
+        nsecs_t bestGap, measured;
+        for (int i = 0; i < tries; ++i) {
+            const nsecs_t tmono = systemTime(SYSTEM_TIME_MONOTONIC);
+            const nsecs_t tbase = systemTime(clockbase);
+            const nsecs_t tmono2 = systemTime(SYSTEM_TIME_MONOTONIC);
+            const nsecs_t gap = tmono2 - tmono;
+            if (i == 0 || gap < bestGap) {
+                bestGap = gap;
+                measured = tbase - ((tmono + tmono2) >> 1);
+            }
+        }
+
+        // to avoid micro-adjusting, we don't change the timebase
+        // unless it is significantly different.
+        //
+        // Assumption: It probably takes more than toleranceNs to
+        // suspend and resume the device.
+        static int64_t toleranceNs = 10000; // 10 us
+        if (llabs(*offset - measured) > toleranceNs) {
+            ALOGV("Adjusting timebase offset old: %lld  new: %lld",
+                    (long long)*offset, (long long)measured);
+            *offset = measured;
+        }
+    }
+
+    pthread_mutex_t mLock;
+    int32_t mCount;
+    int64_t mBoottimeOffset;
+} gBoottime = { PTHREAD_MUTEX_INITIALIZER, 0, 0 }; // static, so use POD initialization
 
 // ----------------------------------------------------------------------------
 //      CPU Stats
@@ -357,54 +444,54 @@
         audio_devices_t mDevices;
         const char *    mString;
     } mappingsOut[] = {
-        AUDIO_DEVICE_OUT_EARPIECE,          "EARPIECE",
-        AUDIO_DEVICE_OUT_SPEAKER,           "SPEAKER",
-        AUDIO_DEVICE_OUT_WIRED_HEADSET,     "WIRED_HEADSET",
-        AUDIO_DEVICE_OUT_WIRED_HEADPHONE,   "WIRED_HEADPHONE",
-        AUDIO_DEVICE_OUT_BLUETOOTH_SCO,     "BLUETOOTH_SCO",
-        AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,     "BLUETOOTH_SCO_HEADSET",
-        AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT,      "BLUETOOTH_SCO_CARKIT",
-        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,            "BLUETOOTH_A2DP",
-        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, "BLUETOOTH_A2DP_HEADPHONES",
-        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,    "BLUETOOTH_A2DP_SPEAKER",
-        AUDIO_DEVICE_OUT_AUX_DIGITAL,       "AUX_DIGITAL",
-        AUDIO_DEVICE_OUT_HDMI,              "HDMI",
-        AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET, "ANLG_DOCK_HEADSET",
-        AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, "DGTL_DOCK_HEADSET",
-        AUDIO_DEVICE_OUT_USB_ACCESSORY,     "USB_ACCESSORY",
-        AUDIO_DEVICE_OUT_USB_DEVICE,        "USB_DEVICE",
-        AUDIO_DEVICE_OUT_TELEPHONY_TX,      "TELEPHONY_TX",
-        AUDIO_DEVICE_OUT_LINE,              "LINE",
-        AUDIO_DEVICE_OUT_HDMI_ARC,          "HDMI_ARC",
-        AUDIO_DEVICE_OUT_SPDIF,             "SPDIF",
-        AUDIO_DEVICE_OUT_FM,                "FM",
-        AUDIO_DEVICE_OUT_AUX_LINE,          "AUX_LINE",
-        AUDIO_DEVICE_OUT_SPEAKER_SAFE,      "SPEAKER_SAFE",
-        AUDIO_DEVICE_OUT_IP,                "IP",
-        AUDIO_DEVICE_NONE,                  "NONE",         // must be last
+        {AUDIO_DEVICE_OUT_EARPIECE,         "EARPIECE"},
+        {AUDIO_DEVICE_OUT_SPEAKER,          "SPEAKER"},
+        {AUDIO_DEVICE_OUT_WIRED_HEADSET,    "WIRED_HEADSET"},
+        {AUDIO_DEVICE_OUT_WIRED_HEADPHONE,  "WIRED_HEADPHONE"},
+        {AUDIO_DEVICE_OUT_BLUETOOTH_SCO,    "BLUETOOTH_SCO"},
+        {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,    "BLUETOOTH_SCO_HEADSET"},
+        {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT,     "BLUETOOTH_SCO_CARKIT"},
+        {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,           "BLUETOOTH_A2DP"},
+        {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"BLUETOOTH_A2DP_HEADPHONES"},
+        {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,   "BLUETOOTH_A2DP_SPEAKER"},
+        {AUDIO_DEVICE_OUT_AUX_DIGITAL,      "AUX_DIGITAL"},
+        {AUDIO_DEVICE_OUT_HDMI,             "HDMI"},
+        {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET,"ANLG_DOCK_HEADSET"},
+        {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET,"DGTL_DOCK_HEADSET"},
+        {AUDIO_DEVICE_OUT_USB_ACCESSORY,    "USB_ACCESSORY"},
+        {AUDIO_DEVICE_OUT_USB_DEVICE,       "USB_DEVICE"},
+        {AUDIO_DEVICE_OUT_TELEPHONY_TX,     "TELEPHONY_TX"},
+        {AUDIO_DEVICE_OUT_LINE,             "LINE"},
+        {AUDIO_DEVICE_OUT_HDMI_ARC,         "HDMI_ARC"},
+        {AUDIO_DEVICE_OUT_SPDIF,            "SPDIF"},
+        {AUDIO_DEVICE_OUT_FM,               "FM"},
+        {AUDIO_DEVICE_OUT_AUX_LINE,         "AUX_LINE"},
+        {AUDIO_DEVICE_OUT_SPEAKER_SAFE,     "SPEAKER_SAFE"},
+        {AUDIO_DEVICE_OUT_IP,               "IP"},
+        {AUDIO_DEVICE_NONE,                 "NONE"},       // must be last
     }, mappingsIn[] = {
-        AUDIO_DEVICE_IN_COMMUNICATION,      "COMMUNICATION",
-        AUDIO_DEVICE_IN_AMBIENT,            "AMBIENT",
-        AUDIO_DEVICE_IN_BUILTIN_MIC,        "BUILTIN_MIC",
-        AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,  "BLUETOOTH_SCO_HEADSET",
-        AUDIO_DEVICE_IN_WIRED_HEADSET,      "WIRED_HEADSET",
-        AUDIO_DEVICE_IN_AUX_DIGITAL,        "AUX_DIGITAL",
-        AUDIO_DEVICE_IN_VOICE_CALL,         "VOICE_CALL",
-        AUDIO_DEVICE_IN_TELEPHONY_RX,       "TELEPHONY_RX",
-        AUDIO_DEVICE_IN_BACK_MIC,           "BACK_MIC",
-        AUDIO_DEVICE_IN_REMOTE_SUBMIX,      "REMOTE_SUBMIX",
-        AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET,  "ANLG_DOCK_HEADSET",
-        AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET,  "DGTL_DOCK_HEADSET",
-        AUDIO_DEVICE_IN_USB_ACCESSORY,      "USB_ACCESSORY",
-        AUDIO_DEVICE_IN_USB_DEVICE,         "USB_DEVICE",
-        AUDIO_DEVICE_IN_FM_TUNER,           "FM_TUNER",
-        AUDIO_DEVICE_IN_TV_TUNER,           "TV_TUNER",
-        AUDIO_DEVICE_IN_LINE,               "LINE",
-        AUDIO_DEVICE_IN_SPDIF,              "SPDIF",
-        AUDIO_DEVICE_IN_BLUETOOTH_A2DP,     "BLUETOOTH_A2DP",
-        AUDIO_DEVICE_IN_LOOPBACK,           "LOOPBACK",
-        AUDIO_DEVICE_IN_IP,                 "IP",
-        AUDIO_DEVICE_NONE,                  "NONE",         // must be last
+        {AUDIO_DEVICE_IN_COMMUNICATION,     "COMMUNICATION"},
+        {AUDIO_DEVICE_IN_AMBIENT,           "AMBIENT"},
+        {AUDIO_DEVICE_IN_BUILTIN_MIC,       "BUILTIN_MIC"},
+        {AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "BLUETOOTH_SCO_HEADSET"},
+        {AUDIO_DEVICE_IN_WIRED_HEADSET,     "WIRED_HEADSET"},
+        {AUDIO_DEVICE_IN_AUX_DIGITAL,       "AUX_DIGITAL"},
+        {AUDIO_DEVICE_IN_VOICE_CALL,        "VOICE_CALL"},
+        {AUDIO_DEVICE_IN_TELEPHONY_RX,      "TELEPHONY_RX"},
+        {AUDIO_DEVICE_IN_BACK_MIC,          "BACK_MIC"},
+        {AUDIO_DEVICE_IN_REMOTE_SUBMIX,     "REMOTE_SUBMIX"},
+        {AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET, "ANLG_DOCK_HEADSET"},
+        {AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET, "DGTL_DOCK_HEADSET"},
+        {AUDIO_DEVICE_IN_USB_ACCESSORY,     "USB_ACCESSORY"},
+        {AUDIO_DEVICE_IN_USB_DEVICE,        "USB_DEVICE"},
+        {AUDIO_DEVICE_IN_FM_TUNER,          "FM_TUNER"},
+        {AUDIO_DEVICE_IN_TV_TUNER,          "TV_TUNER"},
+        {AUDIO_DEVICE_IN_LINE,              "LINE"},
+        {AUDIO_DEVICE_IN_SPDIF,             "SPDIF"},
+        {AUDIO_DEVICE_IN_BLUETOOTH_A2DP,    "BLUETOOTH_A2DP"},
+        {AUDIO_DEVICE_IN_LOOPBACK,          "LOOPBACK"},
+        {AUDIO_DEVICE_IN_IP,                "IP"},
+        {AUDIO_DEVICE_NONE,                 "NONE"},        // must be last
     };
     String8 result;
     audio_devices_t allDevices = AUDIO_DEVICE_NONE;
@@ -442,9 +529,11 @@
         audio_input_flags_t     mFlag;
         const char *            mString;
     } mappings[] = {
-        AUDIO_INPUT_FLAG_FAST,              "FAST",
-        AUDIO_INPUT_FLAG_HW_HOTWORD,        "HW_HOTWORD",
-        AUDIO_INPUT_FLAG_NONE,              "NONE",         // must be last
+        {AUDIO_INPUT_FLAG_FAST,             "FAST"},
+        {AUDIO_INPUT_FLAG_HW_HOTWORD,       "HW_HOTWORD"},
+        {AUDIO_INPUT_FLAG_RAW,              "RAW"},
+        {AUDIO_INPUT_FLAG_SYNC,             "SYNC"},
+        {AUDIO_INPUT_FLAG_NONE,             "NONE"},        // must be last
     };
     String8 result;
     audio_input_flags_t allFlags = AUDIO_INPUT_FLAG_NONE;
@@ -476,14 +565,17 @@
         audio_output_flags_t    mFlag;
         const char *            mString;
     } mappings[] = {
-        AUDIO_OUTPUT_FLAG_DIRECT,           "DIRECT",
-        AUDIO_OUTPUT_FLAG_PRIMARY,          "PRIMARY",
-        AUDIO_OUTPUT_FLAG_FAST,             "FAST",
-        AUDIO_OUTPUT_FLAG_DEEP_BUFFER,      "DEEP_BUFFER",
-        AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD, "COMPRESS_OFFLOAD",
-        AUDIO_OUTPUT_FLAG_NON_BLOCKING,     "NON_BLOCKING",
-        AUDIO_OUTPUT_FLAG_HW_AV_SYNC,       "HW_AV_SYNC",
-        AUDIO_OUTPUT_FLAG_NONE,             "NONE",         // must be last
+        {AUDIO_OUTPUT_FLAG_DIRECT,          "DIRECT"},
+        {AUDIO_OUTPUT_FLAG_PRIMARY,         "PRIMARY"},
+        {AUDIO_OUTPUT_FLAG_FAST,            "FAST"},
+        {AUDIO_OUTPUT_FLAG_DEEP_BUFFER,     "DEEP_BUFFER"},
+        {AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD,"COMPRESS_OFFLOAD"},
+        {AUDIO_OUTPUT_FLAG_NON_BLOCKING,    "NON_BLOCKING"},
+        {AUDIO_OUTPUT_FLAG_HW_AV_SYNC,      "HW_AV_SYNC"},
+        {AUDIO_OUTPUT_FLAG_RAW,             "RAW"},
+        {AUDIO_OUTPUT_FLAG_SYNC,            "SYNC"},
+        {AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO, "IEC958_NONAUDIO"},
+        {AUDIO_OUTPUT_FLAG_NONE,            "NONE"},        // must be last
     };
     String8 result;
     audio_output_flags_t allFlags = AUDIO_OUTPUT_FLAG_NONE;
@@ -521,6 +613,7 @@
     case AUDIO_SOURCE_VOICE_RECOGNITION:    return "voice recognition";
     case AUDIO_SOURCE_VOICE_COMMUNICATION:  return "voice communication";
     case AUDIO_SOURCE_REMOTE_SUBMIX:        return "remote submix";
+    case AUDIO_SOURCE_UNPROCESSED:          return "unprocessed";
     case AUDIO_SOURCE_FM_TUNER:             return "FM tuner";
     case AUDIO_SOURCE_HOTWORD:              return "hotword";
     default:                                return "unknown";
@@ -541,7 +634,8 @@
         mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
         // mName will be set by concrete (non-virtual) subclass
         mDeathRecipient(new PMDeathRecipient(this)),
-        mSystemReady(systemReady)
+        mSystemReady(systemReady),
+        mNotifiedBatteryStart(false)
 {
     memset(&mPatch, 0, sizeof(struct audio_patch));
 }
@@ -662,7 +756,19 @@
 // sendSetParameterConfigEvent_l() must be called with ThreadBase::mLock held
 status_t AudioFlinger::ThreadBase::sendSetParameterConfigEvent_l(const String8& keyValuePair)
 {
-    sp<ConfigEvent> configEvent = (ConfigEvent *)new SetParameterConfigEvent(keyValuePair);
+    sp<ConfigEvent> configEvent;
+    AudioParameter param(keyValuePair);
+    int value;
+    if (param.getInt(String8(AUDIO_PARAMETER_MONO_OUTPUT), value) == NO_ERROR) {
+        setMasterMono_l(value != 0);
+        if (param.size() == 1) {
+            return NO_ERROR; // should be a solo parameter - we don't pass down
+        }
+        param.remove(String8(AUDIO_PARAMETER_MONO_OUTPUT));
+        configEvent = new SetParameterConfigEvent(param.toString());
+    } else {
+        configEvent = new SetParameterConfigEvent(keyValuePair);
+    }
     return sendConfigEvent_l(configEvent);
 }
 
@@ -832,8 +938,8 @@
     dprintf(fd, "  Channel count: %u\n", mChannelCount);
     dprintf(fd, "  Channel mask: 0x%08x (%s)\n", mChannelMask,
             channelMaskToString(mChannelMask, mType != RECORD).string());
-    dprintf(fd, "  Format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
-    dprintf(fd, "  Frame size: %zu bytes\n", mFrameSize);
+    dprintf(fd, "  Processing format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
+    dprintf(fd, "  Processing frame size: %zu bytes\n", mFrameSize);
     dprintf(fd, "  Pending config events:");
     size_t numConfig = mConfigEvents.size();
     if (numConfig) {
@@ -907,14 +1013,14 @@
             status = mPowerManager->acquireWakeLockWithUid(POWERMANAGER_PARTIAL_WAKE_LOCK,
                     binder,
                     getWakeLockTag(),
-                    String16("media"),
+                    String16("audioserver"),
                     uid,
                     true /* FIXME force oneway contrary to .aidl */);
         } else {
             status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
                     binder,
                     getWakeLockTag(),
-                    String16("media"),
+                    String16("audioserver"),
                     true /* FIXME force oneway contrary to .aidl */);
         }
         if (status == NO_ERROR) {
@@ -922,6 +1028,12 @@
         }
         ALOGV("acquireWakeLock_l() %s status %d", mThreadName, status);
     }
+
+    if (!mNotifiedBatteryStart) {
+        BatteryNotifier::getInstance().noteStartAudio();
+        mNotifiedBatteryStart = true;
+    }
+    gBoottime.acquire(mWakeLockToken);
 }
 
 void AudioFlinger::ThreadBase::releaseWakeLock()
@@ -932,6 +1044,7 @@
 
 void AudioFlinger::ThreadBase::releaseWakeLock_l()
 {
+    gBoottime.release(mWakeLockToken);
     if (mWakeLockToken != 0) {
         ALOGV("releaseWakeLock_l() %s", mThreadName);
         if (mPowerManager != 0) {
@@ -940,6 +1053,11 @@
         }
         mWakeLockToken.clear();
     }
+
+    if (mNotifiedBatteryStart) {
+        BatteryNotifier::getInstance().noteStopAudio();
+        mNotifiedBatteryStart = false;
+    }
 }
 
 void AudioFlinger::ThreadBase::updateWakeLockUids(const SortedVector<int> &uids) {
@@ -963,8 +1081,12 @@
 
 void AudioFlinger::ThreadBase::updateWakeLockUids_l(const SortedVector<int> &uids) {
     getPowerManager_l();
-    if (mWakeLockToken == NULL) {
-        ALOGE("no wake lock to update!");
+    if (mWakeLockToken == NULL) { // token may be NULL if AudioFlinger::systemReady() not called.
+        if (mSystemReady) {
+            ALOGE("no wake lock to update, but system ready!");
+        } else {
+            ALOGW("no wake lock to update, system not ready yet");
+        }
         return;
     }
     if (mPowerManager != 0) {
@@ -1457,9 +1579,7 @@
         mScreenState(AudioFlinger::mScreenState),
         // index 0 is reserved for normal mixer's submix
         mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1),
-        mHwSupportsPause(false), mHwPaused(false), mFlushPending(false),
-        // mLatchD, mLatchQ,
-        mLatchDValid(false), mLatchQValid(false)
+        mHwSupportsPause(false), mHwPaused(false), mFlushPending(false)
 {
     snprintf(mThreadName, kThreadNameLength, "AudioOut_%X", id);
     mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
@@ -1589,6 +1709,7 @@
     dprintf(fd, "  Mixer buffer: %p\n", mMixerBuffer);
     dprintf(fd, "  Effect buffer: %p\n", mEffectBuffer);
     dprintf(fd, "  Fast track availMask=%#x\n", mFastTrackAvailMask);
+    dprintf(fd, "  Standby delay ns=%lld\n", (long long)mStandbyDelayNs);
     AudioStreamOut *output = mOutput;
     audio_output_flags_t flags = output != NULL ? output->flags : AUDIO_OUTPUT_FLAG_NONE;
     String8 flagsAsString = outputFlagsToString(flags);
@@ -1630,13 +1751,9 @@
     sp<Track> track;
     status_t lStatus;
 
-    bool isTimed = (*flags & IAudioFlinger::TRACK_TIMED) != 0;
-
     // client expresses a preference for FAST, but we get the final say
     if (*flags & IAudioFlinger::TRACK_FAST) {
       if (
-            // not timed
-            (!isTimed) &&
             // either of these use cases:
             (
               // use case 1: shared buffer with any frame count
@@ -1680,11 +1797,11 @@
         ALOGV("AUDIO_OUTPUT_FLAG_FAST accepted: frameCount=%d mFrameCount=%d",
                 frameCount, mFrameCount);
       } else {
-        ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: isTimed=%d sharedBuffer=%p frameCount=%d "
+        ALOGV("AUDIO_OUTPUT_FLAG_FAST denied: sharedBuffer=%p frameCount=%d "
                 "mFrameCount=%d format=%#x mFormat=%#x isLinear=%d channelMask=%#x "
                 "sampleRate=%u mSampleRate=%u "
                 "hasFastMixer=%d tid=%d fastTrackAvailMask=%#x",
-                isTimed, sharedBuffer.get(), frameCount, mFrameCount, format, mFormat,
+                sharedBuffer.get(), frameCount, mFrameCount, format, mFormat,
                 audio_is_linear_pcm(format),
                 channelMask, sampleRate, mSampleRate, hasFastMixer(), tid, mFastTrackAvailMask);
         *flags &= ~IAudioFlinger::TRACK_FAST;
@@ -1696,7 +1813,7 @@
     // This is probably too conservative, but legacy application code may depend on it.
     // If you change this calculation, also review the start threshold which is related.
     if (!(*flags & IAudioFlinger::TRACK_FAST)
-            && audio_is_linear_pcm(format) && sharedBuffer == 0) {
+            && audio_has_proportional_frames(format) && sharedBuffer == 0) {
         // this must match AudioTrack.cpp calculateMinFrameCount().
         // TODO: Move to a common library
         uint32_t latencyMs = mOutput->stream->get_latency(mOutput->stream);
@@ -1719,7 +1836,7 @@
     switch (mType) {
 
     case DIRECT:
-        if (audio_is_linear_pcm(format)) {
+        if (audio_is_linear_pcm(format)) { // TODO maybe use audio_has_proportional_frames()?
             if (sampleRate != mSampleRate || format != mFormat || channelMask != mChannelMask) {
                 ALOGE("createTrack_l() Bad parameter: sampleRate %u format %#x, channelMask 0x%08x "
                         "for output %p with format %#x",
@@ -1783,17 +1900,10 @@
             }
         }
 
-        if (!isTimed) {
-            track = new Track(this, client, streamType, sampleRate, format,
-                              channelMask, frameCount, NULL, sharedBuffer,
-                              sessionId, uid, *flags, TrackBase::TYPE_DEFAULT);
-        } else {
-            track = TimedTrack::create(this, client, streamType, sampleRate, format,
-                    channelMask, frameCount, sharedBuffer, sessionId, uid);
-        }
+        track = new Track(this, client, streamType, sampleRate, format,
+                          channelMask, frameCount, NULL, sharedBuffer,
+                          sessionId, uid, *flags, TrackBase::TYPE_DEFAULT);
 
-        // new Track always returns non-NULL,
-        // but TimedTrack::create() is a factory that could fail by returning NULL
         lStatus = track != 0 ? track->initCheck() : (status_t) NO_MEMORY;
         if (lStatus != NO_ERROR) {
             ALOGE("createTrack_l() initCheck failed %d; no control block?", lStatus);
@@ -2442,16 +2552,6 @@
         } else {
             bytesWritten = framesWritten;
         }
-        mLatchDValid = false;
-        status_t status = mNormalSink->getTimestamp(mLatchD.mTimestamp);
-        if (status == NO_ERROR) {
-            size_t totalFramesWritten = mNormalSink->framesWritten();
-            if (totalFramesWritten >= mLatchD.mTimestamp.mPosition) {
-                mLatchD.mUnpresentedFrames = totalFramesWritten - mLatchD.mTimestamp.mPosition;
-                // mLatchD.mFramesReleased is set immediately before D is clocked into Q
-                mLatchDValid = true;
-            }
-        }
     // otherwise use the HAL / AudioStreamOut directly
     } else {
         // Direct output and offload threads
@@ -2513,7 +2613,8 @@
  - mSinkBufferSize from frame count * frame size
  - mActiveSleepTimeUs from activeSleepTimeUs()
  - mIdleSleepTimeUs from idleSleepTimeUs()
- - mStandbyDelayNs from mActiveSleepTimeUs (DIRECT only)
+ - mStandbyDelayNs from mActiveSleepTimeUs (DIRECT only) or forced to at least
+   kDefaultStandbyTimeInNsecs when connected to an A2DP device.
  - maxPeriod from frame count and sample rate (MIXER only)
 
 The parameters that affect these derived values are:
@@ -2532,6 +2633,15 @@
     mSinkBufferSize = mNormalFrameCount * mFrameSize;
     mActiveSleepTimeUs = activeSleepTimeUs();
     mIdleSleepTimeUs = idleSleepTimeUs();
+
+    // make sure standby delay is not too short when connected to an A2DP sink to avoid
+    // truncating audio when going to standby.
+    mStandbyDelayNs = AudioFlinger::mStandbyTimeInNsecs;
+    if ((mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) {
+        if (mStandbyDelayNs < kDefaultStandbyTimeInNsecs) {
+            mStandbyDelayNs = kDefaultStandbyTimeInNsecs;
+        }
+    }
 }
 
 void AudioFlinger::PlaybackThread::invalidateTracks(audio_stream_type_t streamType)
@@ -2543,7 +2653,7 @@
     size_t size = mTracks.size();
     for (size_t i = 0; i < size; i++) {
         sp<Track> t = mTracks[i];
-        if (t->streamType() == streamType) {
+        if (t->streamType() == streamType && t->isExternalTrack()) {
             t->invalidate();
         }
     }
@@ -2747,21 +2857,47 @@
             }
 
             // Gather the framesReleased counters for all active tracks,
-            // and latch them atomically with the timestamp.
-            // FIXME We're using raw pointers as indices. A unique track ID would be a better index.
-            mLatchD.mFramesReleased.clear();
-            size_t size = mActiveTracks.size();
-            for (size_t i = 0; i < size; i++) {
-                sp<Track> t = mActiveTracks[i].promote();
-                if (t != 0) {
-                    mLatchD.mFramesReleased.add(t.get(),
-                            t->mAudioTrackServerProxy->framesReleased());
+            // and associate with the sink frames written out.  We need
+            // this to convert the sink timestamp to the track timestamp.
+            if (mNormalSink != 0) {
+                bool updateTracks = true;
+                bool cacheTimestamp = false;
+                AudioTimestamp timeStamp;
+                // FIXME: Use a 64 bit mNormalSink->framesWritten() counter.
+                // At this time, we must always use cached timestamps even when
+                // going through mPipeSink (which is non-blocking). The reason is that
+                // the track may be removed from the active list for many hours and
+                // the mNormalSink->framesWritten() will wrap making the linear
+                // mapping fail.
+                //
+                // (Also mAudioTrackServerProxy->framesReleased() needs to be
+                // updated to 64 bits for 64 bit frame position.)
+                //
+                if (true /* see comment above, should be: mNormalSink == mOutputSink */) {
+                    // If we use a hardware device, we must cache the sink timestamp now.
+                    // hardware devices can block timestamp access during data writes.
+                    if (mNormalSink->getTimestamp(timeStamp) == NO_ERROR) {
+                        cacheTimestamp = true;
+                    } else {
+                        updateTracks = false;
+                    }
                 }
-            }
-            if (mLatchDValid) {
-                mLatchQ = mLatchD;
-                mLatchDValid = false;
-                mLatchQValid = true;
+                if (updateTracks) {
+                    // sinkFramesWritten for non-offloaded tracks are contiguous
+                    // even after standby() is called. This is useful for the track frame
+                    // to sink frame mapping.
+                    const uint32_t sinkFramesWritten = mNormalSink->framesWritten();
+                    const size_t size = mActiveTracks.size();
+                    for (size_t i = 0; i < size; ++i) {
+                        sp<Track> t = mActiveTracks[i].promote();
+                        if (t != 0 && !t->isFastTrack()) {
+                            t->updateTrackFrameInfo(
+                                    t->mAudioTrackServerProxy->framesReleased(),
+                                    sinkFramesWritten,
+                                    cacheTimestamp ? &timeStamp : NULL);
+                        }
+                    }
+                }
             }
 
             saveOutputTracks();
@@ -2882,6 +3018,13 @@
                 void *buffer = mEffectBufferValid ? mEffectBuffer : mSinkBuffer;
                 audio_format_t format = mEffectBufferValid ? mEffectBufferFormat : mFormat;
 
+                // mono blend occurs for mixer threads only (not direct or offloaded)
+                // and is handled here if we're going directly to the sink.
+                if (requireMonoBlend() && !mEffectBufferValid) {
+                    mono_blend(mMixerBuffer, mMixerBufferFormat, mChannelCount, mNormalFrameCount,
+                               true /*limit*/);
+                }
+
                 memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat,
                         mNormalFrameCount * mChannelCount);
             }
@@ -2917,6 +3060,12 @@
         // TODO use mSleepTimeUs == 0 as an additional condition.
         if (mEffectBufferValid) {
             //ALOGV("writing effect buffer to sink buffer format %#x", mFormat);
+
+            if (requireMonoBlend()) {
+                mono_blend(mEffectBuffer, mEffectBufferFormat, mChannelCount, mNormalFrameCount,
+                           true /*limit*/);
+            }
+
             memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat,
                     mNormalFrameCount * mChannelCount);
         }
@@ -3259,7 +3408,8 @@
     :   PlaybackThread(audioFlinger, output, id, device, type, systemReady),
         // mAudioMixer below
         // mFastMixer below
-        mFastMixerFutex(0)
+        mFastMixerFutex(0),
+        mMasterMono(false)
         // mOutputSink below
         // mPipeSink below
         // mNormalSink below
@@ -3581,22 +3731,8 @@
 
 void AudioFlinger::MixerThread::threadLoop_mix()
 {
-    // obtain the presentation timestamp of the next output buffer
-    int64_t pts;
-    status_t status = INVALID_OPERATION;
-
-    if (mNormalSink != 0) {
-        status = mNormalSink->getNextWriteTimestamp(&pts);
-    } else {
-        status = mOutputSink->getNextWriteTimestamp(&pts);
-    }
-
-    if (status != NO_ERROR) {
-        pts = AudioBufferProvider::kInvalidPTS;
-    }
-
     // mix buffers...
-    mAudioMixer->process(pts);
+    mAudioMixer->process();
     mCurrentWriteLength = mSinkBufferSize;
     // increase sleep time progressively when application underrun condition clears.
     // Only increase sleep time if the mixer is ready for two consecutive times to avoid
@@ -3729,6 +3865,8 @@
                     recentUnderruns > 0) {
                 // FIXME fast mixer will pull & mix partial buffers, but we count as a full underrun
                 track->mAudioTrackServerProxy->tallyUnderrunFrames(recentUnderruns * mFrameCount);
+            } else {
+                track->mAudioTrackServerProxy->tallyUnderrunFrames(0);
             }
 
             // This is similar to the state machine for normal tracks,
@@ -3838,7 +3976,10 @@
                     // because we're about to decrement the last sp<> on those tracks.
                     block = FastMixerStateQueue::BLOCK_UNTIL_ACKED;
                 } else {
-                    LOG_ALWAYS_FATAL("fast track %d should have been active", j);
+                    LOG_ALWAYS_FATAL("fast track %d should have been active; "
+                            "mState=%d, mTrackMask=%#x, recentUnderruns=%u, isShared=%d",
+                            j, track->mState, state->mTrackMask, recentUnderruns,
+                            track->sharedBuffer() != 0);
                 }
                 tracksToRemove->add(track);
                 // Avoids a misleading display in dumpsys
@@ -4095,7 +4236,10 @@
                 ALOGV("track(%p) underrun,  framesReady(%zu) < framesDesired(%zd)",
                         track, framesReady, desiredFrames);
                 track->mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
+            } else {
+                track->mAudioTrackServerProxy->tallyUnderrunFrames(0);
             }
+
             // clear effect chain input buffer if an active track underruns to avoid sending
             // previous audio buffer again to effects
             chain = getEffectChain_l(track->sessionId());
@@ -4248,6 +4392,7 @@
                                                        status_t& status)
 {
     bool reconfig = false;
+    bool a2dpDeviceChanged = false;
 
     status = NO_ERROR;
 
@@ -4324,6 +4469,8 @@
         // forward device change to effects that have requested to be
         // aware of attached audio device.
         if (value != AUDIO_DEVICE_NONE) {
+            a2dpDeviceChanged =
+                    (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != (value & AUDIO_DEVICE_OUT_ALL_A2DP);
             mOutDevice = value;
             for (size_t i = 0; i < mEffectChains.size(); i++) {
                 mEffectChains[i]->setDevice_l(mOutDevice);
@@ -4367,7 +4514,7 @@
         sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
     }
 
-    return reconfig;
+    return reconfig || a2dpDeviceChanged;
 }
 
 
@@ -4380,10 +4527,15 @@
     PlaybackThread::dumpInternals(fd, args);
     dprintf(fd, "  Thread throttle time (msecs): %u\n", mThreadThrottleTimeMs);
     dprintf(fd, "  AudioMixer tracks: 0x%08x\n", mAudioMixer->trackNames());
+    dprintf(fd, "  Master mono: %s\n", mMasterMono ? "on" : "off");
 
     // Make a non-atomic copy of fast mixer dump state so it won't change underneath us
-    const FastMixerDumpState copy(mFastMixerDumpState);
-    copy.dump(fd);
+    // while we are dumping it.  It may be inconsistent, but it won't mutate!
+    // This is a large object so we place it on the heap.
+    // FIXME 25972958: Need an intelligent copy constructor that does not touch unused pages.
+    const FastMixerDumpState *copy = new FastMixerDumpState(mFastMixerDumpState);
+    copy->dump(fd);
+    delete copy;
 
 #ifdef STATE_QUEUE_DUMP
     // Similar for state queue
@@ -4577,7 +4729,7 @@
         // Do not use a high threshold for compressed audio.
         uint32_t minFrames;
         if ((track->sharedBuffer() == 0) && !track->isStopping_1() && !track->isPausing()
-            && (track->mRetryCount > 1) && audio_is_linear_pcm(mFormat)) {
+            && (track->mRetryCount > 1) && audio_has_proportional_frames(mFormat)) {
             minFrames = mNormalFrameCount;
         } else {
             minFrames = 1;
@@ -4638,7 +4790,7 @@
                 // We have consumed all the buffers of this track.
                 // Remove it from the list of active tracks.
                 size_t audioHALFrames;
-                if (audio_is_linear_pcm(mFormat)) {
+                if (audio_has_proportional_frames(mFormat)) {
                     audioHALFrames = (latency_l() * mSampleRate) / 1000;
                 } else {
                     audioHALFrames = 0;
@@ -4746,7 +4898,7 @@
         } else {
             mSleepTimeUs = mIdleSleepTimeUs;
         }
-    } else if (mBytesWritten != 0 && audio_is_linear_pcm(mFormat)) {
+    } else if (mBytesWritten != 0 && audio_has_proportional_frames(mFormat)) {
         memset(mSinkBuffer, 0, mFrameCount * mFrameSize);
         mSleepTimeUs = 0;
     }
@@ -4803,6 +4955,7 @@
                                                               status_t& status)
 {
     bool reconfig = false;
+    bool a2dpDeviceChanged = false;
 
     status = NO_ERROR;
 
@@ -4812,6 +4965,8 @@
         // forward device change to effects that have requested to be
         // aware of attached audio device.
         if (value != AUDIO_DEVICE_NONE) {
+            a2dpDeviceChanged =
+                    (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != (value & AUDIO_DEVICE_OUT_ALL_A2DP);
             mOutDevice = value;
             for (size_t i = 0; i < mEffectChains.size(); i++) {
                 mEffectChains[i]->setDevice_l(mOutDevice);
@@ -4844,13 +4999,13 @@
         }
     }
 
-    return reconfig;
+    return reconfig || a2dpDeviceChanged;
 }
 
 uint32_t AudioFlinger::DirectOutputThread::activeSleepTimeUs() const
 {
     uint32_t time;
-    if (audio_is_linear_pcm(mFormat)) {
+    if (audio_has_proportional_frames(mFormat)) {
         time = PlaybackThread::activeSleepTimeUs();
     } else {
         time = 10000;
@@ -4861,7 +5016,7 @@
 uint32_t AudioFlinger::DirectOutputThread::idleSleepTimeUs() const
 {
     uint32_t time;
-    if (audio_is_linear_pcm(mFormat)) {
+    if (audio_has_proportional_frames(mFormat)) {
         time = (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000) / 2;
     } else {
         time = 10000;
@@ -4872,7 +5027,7 @@
 uint32_t AudioFlinger::DirectOutputThread::suspendSleepTimeUs() const
 {
     uint32_t time;
-    if (audio_is_linear_pcm(mFormat)) {
+    if (audio_has_proportional_frames(mFormat)) {
         time = (uint32_t)(((mFrameCount * 1000) / mSampleRate) * 1000);
     } else {
         time = 10000;
@@ -4889,7 +5044,7 @@
     // no delay on outputs with HW A/V sync
     if (usesHwAvSync()) {
         mStandbyDelayNs = 0;
-    } else if ((mType == OFFLOAD) && !audio_is_linear_pcm(mFormat)) {
+    } else if ((mType == OFFLOAD) && !audio_has_proportional_frames(mFormat)) {
         mStandbyDelayNs = kOffloadStandbyDelayNs;
     } else {
         mStandbyDelayNs = microseconds(mActiveSleepTimeUs*2);
@@ -5291,7 +5446,7 @@
 {
     // mix buffers...
     if (outputsReady(outputTracks)) {
-        mAudioMixer->process(AudioBufferProvider::kInvalidPTS);
+        mAudioMixer->process();
     } else {
         if (mMixerBufferValid) {
             memset(mMixerBuffer, 0, mMixerBufferSize);
@@ -5634,6 +5789,9 @@
         }
     }
 
+    mTimestamp.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_BOOTTIME] =
+            gBoottime.getBoottimeOffset();
+
     // used to request a deferred sleep, to be executed later while mutex is unlocked
     uint32_t sleepUs = 0;
 
@@ -5831,7 +5989,7 @@
         if (mPipeSource != 0) {
             size_t framesToRead = mBufferSize / mFrameSize;
             framesRead = mPipeSource->read((uint8_t*)mRsmpInBuffer + rear * mFrameSize,
-                    framesToRead, AudioBufferProvider::kInvalidPTS);
+                    framesToRead);
             if (framesRead == 0) {
                 // since pipe is non-blocking, simulate blocking input
                 sleepUs = (framesToRead * 1000000LL) / mSampleRate;
@@ -5847,6 +6005,28 @@
             }
         }
 
+        // Update server timestamp with server stats
+        // systemTime() is optional if the hardware supports timestamps.
+        mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER] += framesRead;
+        mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = systemTime();
+
+        // Update server timestamp with kernel stats
+        if (mInput->stream->get_capture_position != nullptr) {
+            int64_t position, time;
+            int ret = mInput->stream->get_capture_position(mInput->stream, &position, &time);
+            if (ret == NO_ERROR) {
+                mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = position;
+                mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] = time;
+                // Note: In general record buffers should tend to be empty in
+                // a properly running pipeline.
+                //
+                // Also, it is not advantageous to call get_presentation_position during the read
+                // as the read obtains a lock, preventing the timestamp call from executing.
+            }
+        }
+        // Use this to track timestamp information
+        // ALOGD("%s", mTimestamp.toString().c_str());
+
         if (framesRead < 0 || (framesRead == 0 && mPipeSource == 0)) {
             ALOGE("read failed: framesRead=%d", framesRead);
             // Force input into standby so that it tries to recover at next read attempt
@@ -5975,6 +6155,11 @@
                 break;
             }
 
+            // update frame information and push timestamp out
+            activeTrack->updateTrackFrameInfo(
+                    activeTrack->mAudioRecordServerProxy->framesReleased(),
+                    mTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER],
+                    mSampleRate, mTimestamp);
         }
 
 unlock:
@@ -6356,9 +6541,13 @@
     dprintf(fd, "  Fast capture thread: %s\n", hasFastCapture() ? "yes" : "no");
     dprintf(fd, "  Fast track available: %s\n", mFastTrackAvail ? "yes" : "no");
 
-    //  Make a non-atomic copy of fast capture dump state so it won't change underneath us
-    const FastCaptureDumpState copy(mFastCaptureDumpState);
-    copy.dump(fd);
+    // Make a non-atomic copy of fast capture dump state so it won't change underneath us
+    // while we are dumping it.  It may be inconsistent, but it won't mutate!
+    // This is a large object so we place it on the heap.
+    // FIXME 25972958: Need an intelligent copy constructor that does not touch unused pages.
+    const FastCaptureDumpState *copy = new FastCaptureDumpState(mFastCaptureDumpState);
+    copy->dump(fd);
+    delete copy;
 }
 
 void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args __unused)
@@ -6449,7 +6638,7 @@
 
 // AudioBufferProvider interface
 status_t AudioFlinger::RecordThread::ResamplerBufferProvider::getNextBuffer(
-        AudioBufferProvider::Buffer* buffer, int64_t pts __unused)
+        AudioBufferProvider::Buffer* buffer)
 {
     sp<ThreadBase> threadBase = mRecordTrack->mThread.promote();
     if (threadBase == 0) {
@@ -6550,7 +6739,7 @@
         AudioBufferProvider::Buffer buffer;
         for (size_t i = frames; i > 0; ) {
             buffer.frameCount = i;
-            status_t status = provider->getNextBuffer(&buffer, 0);
+            status_t status = provider->getNextBuffer(&buffer);
             if (status != OK || buffer.frameCount == 0) {
                 frames -= i; // cannot fill request.
                 break;
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 46ac300..7c92c1c 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -400,6 +400,8 @@
                 String16 getWakeLockTag();
 
     virtual     void        preExit() { }
+    virtual     void        setMasterMono_l(bool mono __unused) { }
+    virtual     bool        requireMonoBlend() { return false; }
 
     friend class AudioFlinger;      // for mEffectChains
 
@@ -457,6 +459,7 @@
                 static const size_t     kLogSize = 4 * 1024;
                 sp<NBLog::Writer>       mNBLogWriter;
                 bool                    mSystemReady;
+                bool                    mNotifiedBatteryStart;
 };
 
 // --- PlaybackThread ---
@@ -838,19 +841,6 @@
                 bool        mHwSupportsPause;
                 bool        mHwPaused;
                 bool        mFlushPending;
-private:
-    // timestamp latch:
-    //  D input is written by threadLoop_write while mutex is unlocked, and read while locked
-    //  Q output is written while locked, and read while locked
-    struct {
-        AudioTimestamp  mTimestamp;
-        uint32_t        mUnpresentedFrames;
-        KeyedVector<Track *, uint32_t> mFramesReleased;
-    } mLatchD, mLatchQ;
-    bool mLatchDValid;  // true means mLatchD is valid
-                        //     (except for mFramesReleased which is filled in later),
-                        //     and clock it into latch at next opportunity
-    bool mLatchQValid;  // true means mLatchQ is valid
 };
 
 class MixerThread : public PlaybackThread {
@@ -908,6 +898,7 @@
                 //          mFastMixer->sq()    // for mutating and pushing state
                 int32_t     mFastMixerFutex;    // for cold idle
 
+                std::atomic_bool mMasterMono;
 public:
     virtual     bool        hasFastMixer() const { return mFastMixer != 0; }
     virtual     FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex) const {
@@ -915,6 +906,17 @@
                               return mFastMixerDumpState.mTracks[fastIndex].mUnderruns;
                             }
 
+protected:
+    virtual     void       setMasterMono_l(bool mono) {
+                               mMasterMono.store(mono);
+                               if (mFastMixer != nullptr) { /* hasFastMixer() */
+                                   mFastMixer->setMasterMono(mMasterMono);
+                               }
+                           }
+                // the FastMixer performs mono blend if it exists.
+                // Blending with limiter is not idempotent,
+                // and blending without limiter is idempotent but inefficient to do twice.
+    virtual     bool       requireMonoBlend() { return mMasterMono.load() && !hasFastMixer(); }
 };
 
 class DirectOutputThread : public PlaybackThread {
@@ -1096,7 +1098,7 @@
         virtual void sync(size_t *framesAvailable = NULL, bool *hasOverrun = NULL);
 
         // AudioBufferProvider interface
-        virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts);
+        virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer);
         virtual void        releaseBuffer(AudioBufferProvider::Buffer* buffer);
     private:
         RecordTrack * const mRecordTrack;
@@ -1309,6 +1311,8 @@
             // rolling index that is never cleared
             int32_t                             mRsmpInRear;    // last filled frame + 1
 
+            ExtendedTimestamp                   mTimestamp;
+
             // For dumpsys
             const sp<NBAIO_Sink>                mTeeSink;
 
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 98bf96e..26067e3 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -50,7 +50,6 @@
 
     enum track_type {
         TYPE_DEFAULT,
-        TYPE_TIMED,
         TYPE_OUTPUT,
         TYPE_PATCH,
     };
@@ -83,7 +82,6 @@
             sp<IMemory> getBuffers() const { return mBufferMemory; }
             void*       buffer() const { return mBuffer; }
             bool        isFastTrack() const { return (mFlags & IAudioFlinger::TRACK_FAST) != 0; }
-            bool        isTimedTrack() const { return (mType == TYPE_TIMED); }
             bool        isOutputTrack() const { return (mType == TYPE_OUTPUT); }
             bool        isPatchTrack() const { return (mType == TYPE_PATCH); }
             bool        isExternalTrack() const { return !isOutputTrack() && !isPatchTrack(); }
@@ -93,7 +91,7 @@
                         TrackBase& operator = (const TrackBase&);
 
     // AudioBufferProvider interface
-    virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts) = 0;
+    virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
     virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
 
     // ExtendedAudioBufferProvider interface is only needed for Track,
@@ -132,7 +130,7 @@
     }
 
     bool isOut() const { return mIsOut; }
-                                    // true for Track and TimedTrack, false for RecordTrack,
+                                    // true for Track, false for RecordTrack,
                                     // this could be a track type if needed later
 
     const wp<ThreadBase> mThread;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 0e24b52..1a48e07 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -27,9 +27,6 @@
 
 #include <private/media/AudioTrackShared.h>
 
-#include <common_time/cc_helper.h>
-#include <common_time/local_clock.h>
-
 #include "AudioMixer.h"
 #include "AudioFlinger.h"
 #include "ServiceUtilities.h"
@@ -53,6 +50,10 @@
 #define ALOGVV(a...) do { } while(0)
 #endif
 
+// TODO move to a common header  (Also shared with AudioTrack.cpp)
+#define NANOS_PER_SECOND    1000000000
+#define TIME_TO_NANOS(time) ((uint64_t)time.tv_sec * NANOS_PER_SECOND + time.tv_nsec)
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -88,7 +89,7 @@
         mChannelCount(isOut ?
                 audio_channel_count_from_out_mask(channelMask) :
                 audio_channel_count_from_in_mask(channelMask)),
-        mFrameSize(audio_is_linear_pcm(format) ?
+        mFrameSize(audio_has_proportional_frames(format) ?
                 mChannelCount * audio_bytes_per_sample(format) : sizeof(int8_t)),
         mFrameCount(frameCount),
         mSessionId(sessionId),
@@ -100,13 +101,11 @@
         mType(type),
         mThreadIoHandle(thread->id())
 {
-    // if the caller is us, trust the specified uid
-    if (IPCThreadState::self()->getCallingPid() != getpid_cached || clientUid == -1) {
-        int newclientUid = IPCThreadState::self()->getCallingUid();
-        if (clientUid != -1 && clientUid != newclientUid) {
-            ALOGW("uid %d tried to pass itself off as %d", newclientUid, clientUid);
-        }
-        clientUid = newclientUid;
+    const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+    if (!isTrustedCallingUid(callingUid) || clientUid == -1) {
+        ALOGW_IF(clientUid != -1 && clientUid != (int)callingUid,
+                "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, clientUid);
+        clientUid = (int)callingUid;
     }
     // clientUid contains the uid of the app that is responsible for this track, so we can blame
     // battery usage on it.
@@ -244,7 +243,7 @@
 
 // AudioBufferProvider interface
 // getNextBuffer() = 0;
-// This implementation of releaseBuffer() is used by Track and RecordTrack, but not TimedTrack
+// This implementation of releaseBuffer() is used by Track and RecordTrack
 void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
 {
 #ifdef TEE_SINK
@@ -310,43 +309,6 @@
     return mTrack->attachAuxEffect(EffectId);
 }
 
-status_t AudioFlinger::TrackHandle::allocateTimedBuffer(size_t size,
-                                                         sp<IMemory>* buffer) {
-    if (!mTrack->isTimedTrack())
-        return INVALID_OPERATION;
-
-    PlaybackThread::TimedTrack* tt =
-            reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get());
-    return tt->allocateTimedBuffer(size, buffer);
-}
-
-status_t AudioFlinger::TrackHandle::queueTimedBuffer(const sp<IMemory>& buffer,
-                                                     int64_t pts) {
-    if (!mTrack->isTimedTrack())
-        return INVALID_OPERATION;
-
-    if (buffer == 0 || buffer->pointer() == NULL) {
-        ALOGE("queueTimedBuffer() buffer is 0 or has NULL pointer()");
-        return BAD_VALUE;
-    }
-
-    PlaybackThread::TimedTrack* tt =
-            reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get());
-    return tt->queueTimedBuffer(buffer, pts);
-}
-
-status_t AudioFlinger::TrackHandle::setMediaTimeTransform(
-    const LinearTransform& xform, int target) {
-
-    if (!mTrack->isTimedTrack())
-        return INVALID_OPERATION;
-
-    PlaybackThread::TimedTrack* tt =
-            reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get());
-    return tt->setMediaTimeTransform(
-        xform, static_cast<TimedAudioTrack::TargetTimeline>(target));
-}
-
 status_t AudioFlinger::TrackHandle::setParameters(const String8& keyValuePairs) {
     return mTrack->setParameters(keyValuePairs);
 }
@@ -399,6 +361,9 @@
     mAuxBuffer(NULL),
     mAuxEffectId(0), mHasVolumeController(false),
     mPresentationCompleteFrames(0),
+    mFrameMap(16 /* sink-frame-to-track-frame map memory */),
+    mSinkTimestampValid(false),
+    // mSinkTimestamp
     mFastIndex(-1),
     mCachedVolume(1.0),
     mIsInvalid(false),
@@ -592,7 +557,7 @@
 
 // AudioBufferProvider interface
 status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(
-        AudioBufferProvider::Buffer* buffer, int64_t pts __unused)
+        AudioBufferProvider::Buffer* buffer)
 {
     ServerProxy::Buffer buf;
     size_t desiredFrames = buffer->frameCount;
@@ -602,7 +567,10 @@
     buffer->raw = buf.mRaw;
     if (buf.mFrameCount == 0) {
         mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
+    } else {
+        mAudioTrackServerProxy->tallyUnderrunFrames(0);
     }
+
     return status;
 }
 
@@ -628,6 +596,11 @@
     return mAudioTrackServerProxy->framesReleased();
 }
 
+void AudioFlinger::PlaybackThread::Track::onTimestamp(const AudioTimestamp &timestamp)
+{
+    mAudioTrackServerProxy->setTimestamp(timestamp);
+}
+
 // Don't call for fast tracks; the framesReady() could result in priority inversion
 bool AudioFlinger::PlaybackThread::Track::isReady() const {
     if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing()) {
@@ -691,6 +664,11 @@
             ALOGV("? => ACTIVE (%d) on thread %p", mName, this);
         }
 
+        // states to reset position info for non-offloaded/direct tracks
+        if (!isOffloaded() && !isDirect()
+                && (state == IDLE || state == STOPPED || state == FLUSHED)) {
+            mFrameMap.reset();
+        }
         PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
         if (isFastTrack()) {
             // refresh fast track underruns on start because that field is never cleared
@@ -885,7 +863,7 @@
 
 status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& timestamp)
 {
-    // Client should implement this using SSQ; the unpresented frame count in latch is irrelevant
+    // FastTrack timestamps are read through SSQ
     if (isFastTrack()) {
         return INVALID_OPERATION;
     }
@@ -897,36 +875,31 @@
     Mutex::Autolock _l(thread->mLock);
     PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
 
-    status_t result = INVALID_OPERATION;
-    if (!isOffloaded() && !isDirect()) {
-        if (!playbackThread->mLatchQValid) {
-            return INVALID_OPERATION;
-        }
-        // FIXME Not accurate under dynamic changes of sample rate and speed.
-        // Do not use track's mSampleRate as it is not current for mixer tracks.
-        uint32_t sampleRate = mAudioTrackServerProxy->getSampleRate();
-        AudioPlaybackRate playbackRate = mAudioTrackServerProxy->getPlaybackRate();
-        uint32_t unpresentedFrames = ((double) playbackThread->mLatchQ.mUnpresentedFrames *
-                sampleRate * playbackRate.mSpeed)/ playbackThread->mSampleRate;
-        // FIXME Since we're using a raw pointer as the key, it is theoretically possible
-        //       for a brand new track to share the same address as a recently destroyed
-        //       track, and thus for us to get the frames released of the wrong track.
-        //       It is unlikely that we would be able to call getTimestamp() so quickly
-        //       right after creating a new track.  Nevertheless, the index here should
-        //       be changed to something that is unique.  Or use a completely different strategy.
-        ssize_t i = playbackThread->mLatchQ.mFramesReleased.indexOfKey(this);
-        uint32_t framesWritten = i >= 0 ?
-                playbackThread->mLatchQ.mFramesReleased[i] :
-                mAudioTrackServerProxy->framesReleased();
-        if (framesWritten >= unpresentedFrames) {
-            timestamp.mPosition = framesWritten - unpresentedFrames;
-            timestamp.mTime = playbackThread->mLatchQ.mTimestamp.mTime;
-            result = NO_ERROR;
-        }
-    } else { // offloaded or direct
-        result = playbackThread->getTimestamp_l(timestamp);
+    if (isOffloaded() || isDirect()) {
+        return playbackThread->getTimestamp_l(timestamp);
     }
 
+    if (!mFrameMap.hasData()) {
+        // WOULD_BLOCK is consistent with AudioTrack::getTimestamp() in the
+        // FLUSHED and STOPPED state.  We should only return INVALID_OPERATION
+        // when this method is not permitted due to configuration or device.
+        return WOULD_BLOCK;
+    }
+    status_t result = OK;
+    if (!mSinkTimestampValid) { // if no sink position, try to fetch again
+        result = playbackThread->getTimestamp_l(mSinkTimestamp);
+    }
+
+    if (result == OK) {
+        // Lookup the track frame corresponding to the sink frame position.
+        timestamp.mPosition = mFrameMap.findX(mSinkTimestamp.mPosition);
+        timestamp.mTime = mSinkTimestamp.mTime;
+        // ALOGD("track (server-side) timestamp: mPosition(%u)  mTime(%llu)",
+        //        timestamp.mPosition, TIME_TO_NANOS(timestamp.mTime));
+    }
+    // (Possible) FIXME: mSinkTimestamp is updated only when the track is on
+    // the Thread active list. If the track is no longer on the thread active
+    // list should we use current time?
     return result;
 }
 
@@ -1116,526 +1089,19 @@
         mResumeToStopping = false;
     }
 }
-// ----------------------------------------------------------------------------
 
-sp<AudioFlinger::PlaybackThread::TimedTrack>
-AudioFlinger::PlaybackThread::TimedTrack::create(
-            PlaybackThread *thread,
-            const sp<Client>& client,
-            audio_stream_type_t streamType,
-            uint32_t sampleRate,
-            audio_format_t format,
-            audio_channel_mask_t channelMask,
-            size_t frameCount,
-            const sp<IMemory>& sharedBuffer,
-            int sessionId,
-            int uid)
-{
-    if (!client->reserveTimedTrack())
-        return 0;
-
-    return new TimedTrack(
-        thread, client, streamType, sampleRate, format, channelMask, frameCount,
-        sharedBuffer, sessionId, uid);
-}
-
-AudioFlinger::PlaybackThread::TimedTrack::TimedTrack(
-            PlaybackThread *thread,
-            const sp<Client>& client,
-            audio_stream_type_t streamType,
-            uint32_t sampleRate,
-            audio_format_t format,
-            audio_channel_mask_t channelMask,
-            size_t frameCount,
-            const sp<IMemory>& sharedBuffer,
-            int sessionId,
-            int uid)
-    : Track(thread, client, streamType, sampleRate, format, channelMask,
-            frameCount, (sharedBuffer != 0) ? sharedBuffer->pointer() : NULL, sharedBuffer,
-                    sessionId, uid, IAudioFlinger::TRACK_TIMED, TYPE_TIMED),
-      mQueueHeadInFlight(false),
-      mTrimQueueHeadOnRelease(false),
-      mFramesPendingInQueue(0),
-      mTimedSilenceBuffer(NULL),
-      mTimedSilenceBufferSize(0),
-      mTimedAudioOutputOnTime(false),
-      mMediaTimeTransformValid(false)
-{
-    LocalClock lc;
-    mLocalTimeFreq = lc.getLocalFreq();
-
-    mLocalTimeToSampleTransform.a_zero = 0;
-    mLocalTimeToSampleTransform.b_zero = 0;
-    mLocalTimeToSampleTransform.a_to_b_numer = sampleRate;
-    mLocalTimeToSampleTransform.a_to_b_denom = mLocalTimeFreq;
-    LinearTransform::reduce(&mLocalTimeToSampleTransform.a_to_b_numer,
-                            &mLocalTimeToSampleTransform.a_to_b_denom);
-
-    mMediaTimeToSampleTransform.a_zero = 0;
-    mMediaTimeToSampleTransform.b_zero = 0;
-    mMediaTimeToSampleTransform.a_to_b_numer = sampleRate;
-    mMediaTimeToSampleTransform.a_to_b_denom = 1000000;
-    LinearTransform::reduce(&mMediaTimeToSampleTransform.a_to_b_numer,
-                            &mMediaTimeToSampleTransform.a_to_b_denom);
-}
-
-AudioFlinger::PlaybackThread::TimedTrack::~TimedTrack() {
-    mClient->releaseTimedTrack();
-    delete [] mTimedSilenceBuffer;
-}
-
-status_t AudioFlinger::PlaybackThread::TimedTrack::allocateTimedBuffer(
-    size_t size, sp<IMemory>* buffer) {
-
-    Mutex::Autolock _l(mTimedBufferQueueLock);
-
-    trimTimedBufferQueue_l();
-
-    // lazily initialize the shared memory heap for timed buffers
-    if (mTimedMemoryDealer == NULL) {
-        const int kTimedBufferHeapSize = 512 << 10;
-
-        mTimedMemoryDealer = new MemoryDealer(kTimedBufferHeapSize,
-                                              "AudioFlingerTimed");
-        if (mTimedMemoryDealer == NULL) {
-            return NO_MEMORY;
-        }
-    }
-
-    sp<IMemory> newBuffer = mTimedMemoryDealer->allocate(size);
-    if (newBuffer == 0 || newBuffer->pointer() == NULL) {
-        return NO_MEMORY;
-    }
-
-    *buffer = newBuffer;
-    return NO_ERROR;
-}
-
-// caller must hold mTimedBufferQueueLock
-void AudioFlinger::PlaybackThread::TimedTrack::trimTimedBufferQueue_l() {
-    int64_t mediaTimeNow;
-    {
-        Mutex::Autolock mttLock(mMediaTimeTransformLock);
-        if (!mMediaTimeTransformValid)
-            return;
-
-        int64_t targetTimeNow;
-        status_t res = (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME)
-            ? mCCHelper.getCommonTime(&targetTimeNow)
-            : mCCHelper.getLocalTime(&targetTimeNow);
-
-        if (OK != res)
-            return;
-
-        if (!mMediaTimeTransform.doReverseTransform(targetTimeNow,
-                                                    &mediaTimeNow)) {
-            return;
-        }
-    }
-
-    size_t trimEnd;
-    for (trimEnd = 0; trimEnd < mTimedBufferQueue.size(); trimEnd++) {
-        int64_t bufEnd;
-
-        if ((trimEnd + 1) < mTimedBufferQueue.size()) {
-            // We have a next buffer.  Just use its PTS as the PTS of the frame
-            // following the last frame in this buffer.  If the stream is sparse
-            // (ie, there are deliberate gaps left in the stream which should be
-            // filled with silence by the TimedAudioTrack), then this can result
-            // in one extra buffer being left un-trimmed when it could have
-            // been.  In general, this is not typical, and we would rather
-            // optimized away the TS calculation below for the more common case
-            // where PTSes are contiguous.
-            bufEnd = mTimedBufferQueue[trimEnd + 1].pts();
-        } else {
-            // We have no next buffer.  Compute the PTS of the frame following
-            // the last frame in this buffer by computing the duration of of
-            // this frame in media time units and adding it to the PTS of the
-            // buffer.
-            int64_t frameCount = mTimedBufferQueue[trimEnd].buffer()->size()
-                               / mFrameSize;
-
-            if (!mMediaTimeToSampleTransform.doReverseTransform(frameCount,
-                                                                &bufEnd)) {
-                ALOGE("Failed to convert frame count of %lld to media time"
-                      " duration" " (scale factor %d/%u) in %s",
-                      frameCount,
-                      mMediaTimeToSampleTransform.a_to_b_numer,
-                      mMediaTimeToSampleTransform.a_to_b_denom,
-                      __PRETTY_FUNCTION__);
-                break;
-            }
-            bufEnd += mTimedBufferQueue[trimEnd].pts();
-        }
-
-        if (bufEnd > mediaTimeNow)
-            break;
-
-        // Is the buffer we want to use in the middle of a mix operation right
-        // now?  If so, don't actually trim it.  Just wait for the releaseBuffer
-        // from the mixer which should be coming back shortly.
-        if (!trimEnd && mQueueHeadInFlight) {
-            mTrimQueueHeadOnRelease = true;
-        }
-    }
-
-    size_t trimStart = mTrimQueueHeadOnRelease ? 1 : 0;
-    if (trimStart < trimEnd) {
-        // Update the bookkeeping for framesReady()
-        for (size_t i = trimStart; i < trimEnd; ++i) {
-            updateFramesPendingAfterTrim_l(mTimedBufferQueue[i], "trim");
-        }
-
-        // Now actually remove the buffers from the queue.
-        mTimedBufferQueue.removeItemsAt(trimStart, trimEnd);
-    }
-}
-
-void AudioFlinger::PlaybackThread::TimedTrack::trimTimedBufferQueueHead_l(
-        const char* logTag) {
-    ALOG_ASSERT(mTimedBufferQueue.size() > 0,
-                "%s called (reason \"%s\"), but timed buffer queue has no"
-                " elements to trim.", __FUNCTION__, logTag);
-
-    updateFramesPendingAfterTrim_l(mTimedBufferQueue[0], logTag);
-    mTimedBufferQueue.removeAt(0);
-}
-
-void AudioFlinger::PlaybackThread::TimedTrack::updateFramesPendingAfterTrim_l(
-        const TimedBuffer& buf,
-        const char* logTag __unused) {
-    uint32_t bufBytes        = buf.buffer()->size();
-    uint32_t consumedAlready = buf.position();
-
-    ALOG_ASSERT(consumedAlready <= bufBytes,
-                "Bad bookkeeping while updating frames pending.  Timed buffer is"
-                " only %u bytes long, but claims to have consumed %u"
-                " bytes.  (update reason: \"%s\")",
-                bufBytes, consumedAlready, logTag);
-
-    uint32_t bufFrames = (bufBytes - consumedAlready) / mFrameSize;
-    ALOG_ASSERT(mFramesPendingInQueue >= bufFrames,
-                "Bad bookkeeping while updating frames pending.  Should have at"
-                " least %u queued frames, but we think we have only %u.  (update"
-                " reason: \"%s\")",
-                bufFrames, mFramesPendingInQueue, logTag);
-
-    mFramesPendingInQueue -= bufFrames;
-}
-
-status_t AudioFlinger::PlaybackThread::TimedTrack::queueTimedBuffer(
-    const sp<IMemory>& buffer, int64_t pts) {
-
-    {
-        Mutex::Autolock mttLock(mMediaTimeTransformLock);
-        if (!mMediaTimeTransformValid)
-            return INVALID_OPERATION;
-    }
-
-    Mutex::Autolock _l(mTimedBufferQueueLock);
-
-    uint32_t bufFrames = buffer->size() / mFrameSize;
-    mFramesPendingInQueue += bufFrames;
-    mTimedBufferQueue.add(TimedBuffer(buffer, pts));
-
-    return NO_ERROR;
-}
-
-status_t AudioFlinger::PlaybackThread::TimedTrack::setMediaTimeTransform(
-    const LinearTransform& xform, TimedAudioTrack::TargetTimeline target) {
-
-    ALOGVV("setMediaTimeTransform az=%lld bz=%lld n=%d d=%u tgt=%d",
-           xform.a_zero, xform.b_zero, xform.a_to_b_numer, xform.a_to_b_denom,
-           target);
-
-    if (!(target == TimedAudioTrack::LOCAL_TIME ||
-          target == TimedAudioTrack::COMMON_TIME)) {
-        return BAD_VALUE;
-    }
-
-    Mutex::Autolock lock(mMediaTimeTransformLock);
-    mMediaTimeTransform = xform;
-    mMediaTimeTransformTarget = target;
-    mMediaTimeTransformValid = true;
-
-    return NO_ERROR;
-}
-
-#define min(a, b) ((a) < (b) ? (a) : (b))
-
-// implementation of getNextBuffer for tracks whose buffers have timestamps
-status_t AudioFlinger::PlaybackThread::TimedTrack::getNextBuffer(
-    AudioBufferProvider::Buffer* buffer, int64_t pts)
-{
-    if (pts == AudioBufferProvider::kInvalidPTS) {
-        buffer->raw = NULL;
-        buffer->frameCount = 0;
-        mTimedAudioOutputOnTime = false;
-        return INVALID_OPERATION;
-    }
-
-    Mutex::Autolock _l(mTimedBufferQueueLock);
-
-    ALOG_ASSERT(!mQueueHeadInFlight,
-                "getNextBuffer called without releaseBuffer!");
-
-    while (true) {
-
-        // if we have no timed buffers, then fail
-        if (mTimedBufferQueue.isEmpty()) {
-            buffer->raw = NULL;
-            buffer->frameCount = 0;
-            return NOT_ENOUGH_DATA;
-        }
-
-        TimedBuffer& head = mTimedBufferQueue.editItemAt(0);
-
-        // calculate the PTS of the head of the timed buffer queue expressed in
-        // local time
-        int64_t headLocalPTS;
-        {
-            Mutex::Autolock mttLock(mMediaTimeTransformLock);
-
-            ALOG_ASSERT(mMediaTimeTransformValid, "media time transform invalid");
-
-            if (mMediaTimeTransform.a_to_b_denom == 0) {
-                // the transform represents a pause, so yield silence
-                timedYieldSilence_l(buffer->frameCount, buffer);
-                return NO_ERROR;
-            }
-
-            int64_t transformedPTS;
-            if (!mMediaTimeTransform.doForwardTransform(head.pts(),
-                                                        &transformedPTS)) {
-                // the transform failed.  this shouldn't happen, but if it does
-                // then just drop this buffer
-                ALOGW("timedGetNextBuffer transform failed");
-                buffer->raw = NULL;
-                buffer->frameCount = 0;
-                trimTimedBufferQueueHead_l("getNextBuffer; no transform");
-                return NO_ERROR;
-            }
-
-            if (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME) {
-                if (OK != mCCHelper.commonTimeToLocalTime(transformedPTS,
-                                                          &headLocalPTS)) {
-                    buffer->raw = NULL;
-                    buffer->frameCount = 0;
-                    return INVALID_OPERATION;
-                }
-            } else {
-                headLocalPTS = transformedPTS;
-            }
-        }
-
-        uint32_t sr = sampleRate();
-
-        // adjust the head buffer's PTS to reflect the portion of the head buffer
-        // that has already been consumed
-        int64_t effectivePTS = headLocalPTS +
-                ((head.position() / mFrameSize) * mLocalTimeFreq / sr);
-
-        // Calculate the delta in samples between the head of the input buffer
-        // queue and the start of the next output buffer that will be written.
-        // If the transformation fails because of over or underflow, it means
-        // that the sample's position in the output stream is so far out of
-        // whack that it should just be dropped.
-        int64_t sampleDelta;
-        if (llabs(effectivePTS - pts) >= (static_cast<int64_t>(1) << 31)) {
-            ALOGV("*** head buffer is too far from PTS: dropped buffer");
-            trimTimedBufferQueueHead_l("getNextBuffer, buf pts too far from"
-                                       " mix");
-            continue;
-        }
-        if (!mLocalTimeToSampleTransform.doForwardTransform(
-                (effectivePTS - pts) << 32, &sampleDelta)) {
-            ALOGV("*** too late during sample rate transform: dropped buffer");
-            trimTimedBufferQueueHead_l("getNextBuffer, bad local to sample");
-            continue;
-        }
-
-        ALOGVV("*** getNextBuffer head.pts=%lld head.pos=%d pts=%lld"
-               " sampleDelta=[%d.%08x]",
-               head.pts(), head.position(), pts,
-               static_cast<int32_t>((sampleDelta >= 0 ? 0 : 1)
-                   + (sampleDelta >> 32)),
-               static_cast<uint32_t>(sampleDelta & 0xFFFFFFFF));
-
-        // if the delta between the ideal placement for the next input sample and
-        // the current output position is within this threshold, then we will
-        // concatenate the next input samples to the previous output
-        const int64_t kSampleContinuityThreshold =
-                (static_cast<int64_t>(sr) << 32) / 250;
-
-        // if this is the first buffer of audio that we're emitting from this track
-        // then it should be almost exactly on time.
-        const int64_t kSampleStartupThreshold = 1LL << 32;
-
-        if ((mTimedAudioOutputOnTime && llabs(sampleDelta) <= kSampleContinuityThreshold) ||
-           (!mTimedAudioOutputOnTime && llabs(sampleDelta) <= kSampleStartupThreshold)) {
-            // the next input is close enough to being on time, so concatenate it
-            // with the last output
-            timedYieldSamples_l(buffer);
-
-            ALOGVV("*** on time: head.pos=%d frameCount=%u",
-                    head.position(), buffer->frameCount);
-            return NO_ERROR;
-        }
-
-        // Looks like our output is not on time.  Reset our on timed status.
-        // Next time we mix samples from our input queue, then should be within
-        // the StartupThreshold.
-        mTimedAudioOutputOnTime = false;
-        if (sampleDelta > 0) {
-            // the gap between the current output position and the proper start of
-            // the next input sample is too big, so fill it with silence
-            uint32_t framesUntilNextInput = (sampleDelta + 0x80000000) >> 32;
-
-            timedYieldSilence_l(framesUntilNextInput, buffer);
-            ALOGV("*** silence: frameCount=%u", buffer->frameCount);
-            return NO_ERROR;
-        } else {
-            // the next input sample is late
-            uint32_t lateFrames = static_cast<uint32_t>(-((sampleDelta + 0x80000000) >> 32));
-            size_t onTimeSamplePosition =
-                    head.position() + lateFrames * mFrameSize;
-
-            if (onTimeSamplePosition > head.buffer()->size()) {
-                // all the remaining samples in the head are too late, so
-                // drop it and move on
-                ALOGV("*** too late: dropped buffer");
-                trimTimedBufferQueueHead_l("getNextBuffer, dropped late buffer");
-                continue;
-            } else {
-                // skip over the late samples
-                head.setPosition(onTimeSamplePosition);
-
-                // yield the available samples
-                timedYieldSamples_l(buffer);
-
-                ALOGV("*** late: head.pos=%d frameCount=%u", head.position(), buffer->frameCount);
-                return NO_ERROR;
-            }
-        }
-    }
-}
-
-// Yield samples from the timed buffer queue head up to the given output
-// buffer's capacity.
-//
-// Caller must hold mTimedBufferQueueLock
-void AudioFlinger::PlaybackThread::TimedTrack::timedYieldSamples_l(
-    AudioBufferProvider::Buffer* buffer) {
-
-    const TimedBuffer& head = mTimedBufferQueue[0];
-
-    buffer->raw = (static_cast<uint8_t*>(head.buffer()->pointer()) +
-                   head.position());
-
-    uint32_t framesLeftInHead = ((head.buffer()->size() - head.position()) /
-                                 mFrameSize);
-    size_t framesRequested = buffer->frameCount;
-    buffer->frameCount = min(framesLeftInHead, framesRequested);
-
-    mQueueHeadInFlight = true;
-    mTimedAudioOutputOnTime = true;
-}
-
-// Yield samples of silence up to the given output buffer's capacity
-//
-// Caller must hold mTimedBufferQueueLock
-void AudioFlinger::PlaybackThread::TimedTrack::timedYieldSilence_l(
-    uint32_t numFrames, AudioBufferProvider::Buffer* buffer) {
-
-    // lazily allocate a buffer filled with silence
-    if (mTimedSilenceBufferSize < numFrames * mFrameSize) {
-        delete [] mTimedSilenceBuffer;
-        mTimedSilenceBufferSize = numFrames * mFrameSize;
-        mTimedSilenceBuffer = new uint8_t[mTimedSilenceBufferSize];
-        memset(mTimedSilenceBuffer, 0, mTimedSilenceBufferSize);
-    }
-
-    buffer->raw = mTimedSilenceBuffer;
-    size_t framesRequested = buffer->frameCount;
-    buffer->frameCount = min(numFrames, framesRequested);
-
-    mTimedAudioOutputOnTime = false;
-}
-
-// AudioBufferProvider interface
-void AudioFlinger::PlaybackThread::TimedTrack::releaseBuffer(
-    AudioBufferProvider::Buffer* buffer) {
-
-    Mutex::Autolock _l(mTimedBufferQueueLock);
-
-    // If the buffer which was just released is part of the buffer at the head
-    // of the queue, be sure to update the amt of the buffer which has been
-    // consumed.  If the buffer being returned is not part of the head of the
-    // queue, its either because the buffer is part of the silence buffer, or
-    // because the head of the timed queue was trimmed after the mixer called
-    // getNextBuffer but before the mixer called releaseBuffer.
-    if (buffer->raw == mTimedSilenceBuffer) {
-        ALOG_ASSERT(!mQueueHeadInFlight,
-                    "Queue head in flight during release of silence buffer!");
-        goto done;
-    }
-
-    ALOG_ASSERT(mQueueHeadInFlight,
-                "TimedTrack::releaseBuffer of non-silence buffer, but no queue"
-                " head in flight.");
-
-    if (mTimedBufferQueue.size()) {
-        TimedBuffer& head = mTimedBufferQueue.editItemAt(0);
-
-        void* start = head.buffer()->pointer();
-        void* end   = reinterpret_cast<void*>(
-                        reinterpret_cast<uint8_t*>(head.buffer()->pointer())
-                        + head.buffer()->size());
-
-        ALOG_ASSERT((buffer->raw >= start) && (buffer->raw < end),
-                    "released buffer not within the head of the timed buffer"
-                    " queue; qHead = [%p, %p], released buffer = %p",
-                    start, end, buffer->raw);
-
-        head.setPosition(head.position() +
-                (buffer->frameCount * mFrameSize));
-        mQueueHeadInFlight = false;
-
-        ALOG_ASSERT(mFramesPendingInQueue >= buffer->frameCount,
-                    "Bad bookkeeping during releaseBuffer!  Should have at"
-                    " least %u queued frames, but we think we have only %u",
-                    buffer->frameCount, mFramesPendingInQueue);
-
-        mFramesPendingInQueue -= buffer->frameCount;
-
-        if ((static_cast<size_t>(head.position()) >= head.buffer()->size())
-            || mTrimQueueHeadOnRelease) {
-            trimTimedBufferQueueHead_l("releaseBuffer");
-            mTrimQueueHeadOnRelease = false;
-        }
+//To be called with thread lock held
+void AudioFlinger::PlaybackThread::Track::updateTrackFrameInfo(
+        uint32_t trackFramesReleased, uint32_t sinkFramesWritten, AudioTimestamp *timeStamp) {
+    mFrameMap.push(trackFramesReleased, sinkFramesWritten);
+    if (timeStamp == NULL) {
+        mSinkTimestampValid = false;
     } else {
-        LOG_ALWAYS_FATAL("TimedTrack::releaseBuffer of non-silence buffer with no"
-                  " buffers in the timed buffer queue");
+        mSinkTimestampValid = true;
+        mSinkTimestamp = *timeStamp;
     }
-
-done:
-    buffer->raw = 0;
-    buffer->frameCount = 0;
 }
 
-size_t AudioFlinger::PlaybackThread::TimedTrack::framesReady() const {
-    Mutex::Autolock _l(mTimedBufferQueueLock);
-    return mFramesPendingInQueue;
-}
-
-AudioFlinger::PlaybackThread::TimedTrack::TimedBuffer::TimedBuffer()
-        : mPTS(0), mPosition(0) {}
-
-AudioFlinger::PlaybackThread::TimedTrack::TimedBuffer::TimedBuffer(
-    const sp<IMemory>& buffer, int64_t pts)
-        : mBuffer(buffer), mPTS(pts), mPosition(0) {}
-
-
 // ----------------------------------------------------------------------------
 
 AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(
@@ -1854,7 +1320,7 @@
 
 // AudioBufferProvider interface
 status_t AudioFlinger::PlaybackThread::PatchTrack::getNextBuffer(
-        AudioBufferProvider::Buffer* buffer, int64_t pts)
+        AudioBufferProvider::Buffer* buffer)
 {
     ALOG_ASSERT(mPeerProxy != 0, "PatchTrack::getNextBuffer() called without peer proxy");
     Proxy::Buffer buf;
@@ -1865,7 +1331,7 @@
     if (buf.mFrameCount == 0) {
         return WOULD_BLOCK;
     }
-    status = Track::getNextBuffer(buffer, pts);
+    status = Track::getNextBuffer(buffer);
     return status;
 }
 
@@ -1977,8 +1443,10 @@
         return;
     }
 
-    mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount,
-                                              mFrameSize, !isExternalTrack());
+    mAudioRecordServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount,
+            mFrameSize, !isExternalTrack());
+    mServerProxy = mAudioRecordServerProxy;
+
     mResamplerBufferProvider = new ResamplerBufferProvider(this);
 
     if (flags & IAudioFlinger::TRACK_FAST) {
@@ -2004,8 +1472,7 @@
 }
 
 // AudioBufferProvider interface
-status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer,
-        int64_t pts __unused)
+status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
 {
     ServerProxy::Buffer buf;
     buf.mFrameCount = buffer->frameCount;
@@ -2116,6 +1583,24 @@
     mFramesToDrop = 0;
 }
 
+void AudioFlinger::RecordThread::RecordTrack::updateTrackFrameInfo(
+        int64_t trackFramesReleased, int64_t sourceFramesRead,
+        uint32_t halSampleRate, const ExtendedTimestamp &timestamp)
+{
+    ExtendedTimestamp local = timestamp;
+
+    // Convert HAL frames to server-side track frames at track sample rate.
+    // We use trackFramesReleased and sourceFramesRead as an anchor point.
+    for (int i = ExtendedTimestamp::LOCATION_SERVER; i < ExtendedTimestamp::LOCATION_MAX; ++i) {
+        if (local.mTimeNs[i] != 0) {
+            const int64_t relativeServerFrames = local.mPosition[i] - sourceFramesRead;
+            const int64_t relativeTrackFrames = relativeServerFrames
+                    * mSampleRate / halSampleRate; // TODO: potential computation overflow
+            local.mPosition[i] = relativeTrackFrames + trackFramesReleased;
+        }
+    }
+    mAudioRecordServerProxy->setExtendedTimestamp(local);
+}
 
 AudioFlinger::RecordThread::PatchRecord::PatchRecord(RecordThread *recordThread,
                                                      uint32_t sampleRate,
@@ -2145,7 +1630,7 @@
 
 // AudioBufferProvider interface
 status_t AudioFlinger::RecordThread::PatchRecord::getNextBuffer(
-                                                  AudioBufferProvider::Buffer* buffer, int64_t pts)
+                                                  AudioBufferProvider::Buffer* buffer)
 {
     ALOG_ASSERT(mPeerProxy != 0, "PatchRecord::getNextBuffer() called without peer proxy");
     Proxy::Buffer buf;
@@ -2157,7 +1642,7 @@
     if (buf.mFrameCount == 0) {
         return WOULD_BLOCK;
     }
-    status = RecordTrack::getNextBuffer(buffer, pts);
+    status = RecordTrack::getNextBuffer(buffer);
     return status;
 }
 
diff --git a/services/audioflinger/test-resample.cpp b/services/audioflinger/test-resample.cpp
index 7893778..bae3c5b 100644
--- a/services/audioflinger/test-resample.cpp
+++ b/services/audioflinger/test-resample.cpp
@@ -272,9 +272,7 @@
             mFrameSize(frameSize),
             mNextFrame(0), mUnrel(0), mPvalues(Pvalues), mNextPidx(0) {
         }
-        virtual status_t getNextBuffer(Buffer* buffer,
-                int64_t pts = kInvalidPTS) {
-            (void)pts; // suppress warning
+        virtual status_t getNextBuffer(Buffer* buffer) {
             size_t requestedFrames = buffer->frameCount;
             if (requestedFrames > mNumFrames - mNextFrame) {
                 buffer->frameCount = mNumFrames - mNextFrame;
diff --git a/services/audioflinger/tests/Android.mk b/services/audioflinger/tests/Android.mk
index e152468..6182de0 100644
--- a/services/audioflinger/tests/Android.mk
+++ b/services/audioflinger/tests/Android.mk
@@ -47,7 +47,6 @@
 LOCAL_SHARED_LIBRARIES := \
 	libeffects \
 	libnbaio \
-	libcommon_time_client \
 	libaudioresampler \
 	libaudioutils \
 	libdl \
diff --git a/services/audioflinger/tests/test-mixer.cpp b/services/audioflinger/tests/test-mixer.cpp
index 8da6245..65e22da 100644
--- a/services/audioflinger/tests/test-mixer.cpp
+++ b/services/audioflinger/tests/test-mixer.cpp
@@ -307,7 +307,7 @@
                         (char *) auxAddr + i * auxFrameSize);
             }
         }
-        mixer->process(AudioBufferProvider::kInvalidPTS);
+        mixer->process();
     }
     outputFrames = i; // reset output frames to the data actually produced.
 
diff --git a/services/audioflinger/tests/test_utils.h b/services/audioflinger/tests/test_utils.h
index 3d51cdc..283c768 100644
--- a/services/audioflinger/tests/test_utils.h
+++ b/services/audioflinger/tests/test_utils.h
@@ -112,7 +112,7 @@
         mNextIdx = 0;
     }
 
-    virtual android::status_t getNextBuffer(Buffer* buffer, int64_t pts __unused = kInvalidPTS)
+    virtual android::status_t getNextBuffer(Buffer* buffer)
     {
         size_t requestedFrames = buffer->frameCount;
         if (requestedFrames > mNumFrames - mNextFrame) {
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index 5b38e1c..8218edd 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -24,6 +24,7 @@
     $(call include-path-for, audio-utils) \
     $(TOPDIR)frameworks/av/services/audiopolicy/common/include \
     $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface \
+    $(TOPDIR)frameworks/av/services/audiopolicy/utilities
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
@@ -55,8 +56,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= \
-    managerdefault/AudioPolicyManager.cpp \
+LOCAL_SRC_FILES:= managerdefault/AudioPolicyManager.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
@@ -66,12 +66,15 @@
 
 ifeq ($(USE_CONFIGURABLE_AUDIO_POLICY), 1)
 
+ifneq ($(USE_XML_AUDIO_POLICY_CONF), 1)
+$(error Configurable policy does not support legacy conf file)
+endif #ifneq ($(USE_XML_AUDIO_POLICY_CONF), 1)
+
 LOCAL_REQUIRED_MODULES := \
     parameter-framework.policy \
     audio_policy_criteria.conf \
 
-LOCAL_C_INCLUDES += \
-    $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/include \
+LOCAL_C_INCLUDES += $(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/include
 
 LOCAL_SHARED_LIBRARIES += libaudiopolicyengineconfigurable
 
@@ -79,16 +82,25 @@
 
 LOCAL_SHARED_LIBRARIES += libaudiopolicyenginedefault
 
-endif
+endif # ifeq ($(USE_CONFIGURABLE_AUDIO_POLICY), 1)
 
 LOCAL_C_INCLUDES += \
     $(TOPDIR)frameworks/av/services/audiopolicy/common/include \
     $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface \
+    $(TOPDIR)frameworks/av/services/audiopolicy/utilities
 
 LOCAL_STATIC_LIBRARIES := \
     libmedia_helper \
     libaudiopolicycomponents
 
+ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
+LOCAL_STATIC_LIBRARIES += libxml2
+
+LOCAL_SHARED_LIBRARIES += libicuuc
+
+LOCAL_CFLAGS += -DUSE_XML_AUDIO_POLICY_CONF
+endif #ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
+
 LOCAL_MODULE:= libaudiopolicymanagerdefault
 
 include $(BUILD_SHARED_LIBRARY)
@@ -108,7 +120,7 @@
 
 LOCAL_C_INCLUDES += \
     $(TOPDIR)frameworks/av/services/audiopolicy/common/include \
-    $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface \
+    $(TOPDIR)frameworks/av/services/audiopolicy/engine/interface
 
 LOCAL_MODULE:= libaudiopolicymanager
 
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index c1e7bc0..4dcc6b2 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -67,6 +67,16 @@
         API_INPUT_TELEPHONY_RX, // used for capture from telephony RX path
     } input_type_t;
 
+   enum {
+        API_INPUT_CONCURRENCY_NONE = 0,
+        API_INPUT_CONCURRENCY_CALL = (1 << 0),      // Concurrency with a call
+        API_INPUT_CONCURRENCY_CAPTURE = (1 << 1),   // Concurrency with another capture
+
+        API_INPUT_CONCURRENCY_ALL = (API_INPUT_CONCURRENCY_CALL | API_INPUT_CONCURRENCY_CAPTURE),
+   };
+
+   typedef uint32_t concurrency_type__mask_t;
+
 public:
     virtual ~AudioPolicyInterface() {}
     //
@@ -140,7 +150,8 @@
                                      input_type_t *inputType) = 0;
     // indicates to the audio policy manager that the input starts being used.
     virtual status_t startInput(audio_io_handle_t input,
-                                audio_session_t session) = 0;
+                                audio_session_t session,
+                                concurrency_type__mask_t *concurrency) = 0;
     // indicates to the audio policy manager that the input stops being used.
     virtual status_t stopInput(audio_io_handle_t input,
                                audio_session_t session) = 0;
@@ -225,8 +236,12 @@
 
     virtual status_t startAudioSource(const struct audio_port_config *source,
                                       const audio_attributes_t *attributes,
-                                      audio_io_handle_t *handle) = 0;
+                                      audio_io_handle_t *handle,
+                                      uid_t uid) = 0;
     virtual status_t stopAudioSource(audio_io_handle_t handle) = 0;
+
+    virtual status_t setMasterMono(bool mono) = 0;
+    virtual status_t getMasterMono(bool *mono) = 0;
 };
 
 
@@ -331,6 +346,9 @@
     virtual audio_unique_id_t newAudioUniqueId() = 0;
 
     virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0;
+
+    virtual void onRecordingConfigurationUpdate(int event, audio_session_t session,
+                    audio_source_t source) = 0;
 };
 
 extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface);
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index 712f7a7..d091179 100755
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -30,6 +30,17 @@
     float mDBAttenuation;
 };
 
+/**
+ * device categories used for volume curve management.
+ */
+enum device_category {
+    DEVICE_CATEGORY_HEADSET,
+    DEVICE_CATEGORY_SPEAKER,
+    DEVICE_CATEGORY_EARPIECE,
+    DEVICE_CATEGORY_EXT_MEDIA,
+    DEVICE_CATEGORY_CNT
+};
+
 class Volume
 {
 public:
@@ -50,17 +61,6 @@
     };
 
     /**
-     * device categories used for volume curve management.
-     */
-    enum device_category {
-        DEVICE_CATEGORY_HEADSET,
-        DEVICE_CATEGORY_SPEAKER,
-        DEVICE_CATEGORY_EARPIECE,
-        DEVICE_CATEGORY_EXT_MEDIA,
-        DEVICE_CATEGORY_CNT
-    };
-
-    /**
      * extract one device relevant for volume control from multiple device selection
      *
      * @param[in] device for which the volume category is associated
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 4b73e3c..e3ee4e5 100755
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -18,6 +18,8 @@
 
 #include <system/audio.h>
 
+static const audio_format_t gDynamicFormat = AUDIO_FORMAT_DEFAULT;
+
 // For mixed output and inputs, the policy will use max mixer sampling rates.
 // Do not limit sampling rate otherwise
 #define MAX_MIXER_SAMPLING_RATE 192000
@@ -28,9 +30,9 @@
 
 /**
  * A device mask for all audio input devices that are considered "virtual" when evaluating
- * active inputs in getActiveInput()
+ * active inputs in getActiveInputs()
  */
-#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL  (AUDIO_DEVICE_IN_REMOTE_SUBMIX|AUDIO_DEVICE_IN_FM_TUNER)
+#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL  (AUDIO_DEVICE_IN_REMOTE_SUBMIX)
 
 
 /**
@@ -86,3 +88,41 @@
            (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
             ((device & APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL) != 0));
 }
+
+/**
+ * Returns the priority of a given audio source for capture. The priority is used when more than one
+ * capture session is active on a given input stream to determine which session drives routing and
+ * effect configuration.
+ *
+ * @param[in] inputSource to consider. Valid sources are:
+ * - AUDIO_SOURCE_VOICE_COMMUNICATION
+ * - AUDIO_SOURCE_CAMCORDER
+ * - AUDIO_SOURCE_MIC
+ * - AUDIO_SOURCE_FM_TUNER
+ * - AUDIO_SOURCE_VOICE_RECOGNITION
+ * - AUDIO_SOURCE_HOTWORD
+ *
+ * @return the corresponding input source priority or 0 if priority is irrelevant for this source.
+ *      This happens when the specified source cannot share a given input stream (e.g remote submix)
+ *      The higher the value, the higher the priority.
+ */
+static inline int32_t source_priority(audio_source_t inputSource)
+{
+    switch (inputSource) {
+    case AUDIO_SOURCE_VOICE_COMMUNICATION:
+        return 6;
+    case AUDIO_SOURCE_CAMCORDER:
+        return 5;
+    case AUDIO_SOURCE_MIC:
+        return 4;
+    case AUDIO_SOURCE_FM_TUNER:
+        return 3;
+    case AUDIO_SOURCE_VOICE_RECOGNITION:
+        return 2;
+    case AUDIO_SOURCE_HOTWORD:
+        return 1;
+    default:
+        break;
+    }
+    return 0;
+}
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index 8728ff3..5c81410 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -5,28 +5,55 @@
 LOCAL_SRC_FILES:= \
     src/DeviceDescriptor.cpp \
     src/AudioGain.cpp \
-    src/StreamDescriptor.cpp \
     src/HwModule.cpp \
     src/IOProfile.cpp \
     src/AudioPort.cpp \
+    src/AudioProfile.cpp \
+    src/AudioRoute.cpp \
     src/AudioPolicyMix.cpp \
     src/AudioPatch.cpp \
     src/AudioInputDescriptor.cpp \
     src/AudioOutputDescriptor.cpp \
+    src/AudioCollections.cpp \
     src/EffectDescriptor.cpp \
-    src/ConfigParsingUtils.cpp \
     src/SoundTriggerSession.cpp \
     src/SessionRoute.cpp \
+    src/AudioSourceDescriptor.cpp \
+    src/VolumeCurve.cpp \
+    src/TypeConverter.cpp \
+    src/AudioSession.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
     libutils \
     liblog \
 
-LOCAL_C_INCLUDES += \
+LOCAL_C_INCLUDES := \
     $(LOCAL_PATH)/include \
     $(TOPDIR)frameworks/av/services/audiopolicy/common/include \
-    $(TOPDIR)frameworks/av/services/audiopolicy
+    $(TOPDIR)frameworks/av/services/audiopolicy \
+    $(TOPDIR)frameworks/av/services/audiopolicy/utilities \
+
+ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
+
+LOCAL_SRC_FILES += src/Serializer.cpp
+
+LOCAL_STATIC_LIBRARIES += libxml2
+
+LOCAL_SHARED_LIBRARIES += libicuuc
+
+LOCAL_C_INCLUDES += \
+    $(TOPDIR)external/libxml2/include \
+    $(TOPDIR)external/icu/icu4c/source/common
+
+else
+
+LOCAL_SRC_FILES += \
+    src/ConfigParsingUtils.cpp \
+    src/StreamDescriptor.cpp \
+    src/Gains.cpp
+
+endif #ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
 
 LOCAL_EXPORT_C_INCLUDE_DIRS := \
     $(LOCAL_PATH)/include
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
new file mode 100644
index 0000000..8f00d22
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#pragma once
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
+namespace android {
+
+class AudioPort;
+class AudioRoute;
+
+class AudioPortVector : public Vector<sp<AudioPort> >
+{
+public:
+    sp<AudioPort> findByTagName(const String8 &tagName) const;
+};
+
+
+class AudioRouteVector : public Vector<sp<AudioRoute> >
+{
+public:
+    status_t dump(int fd, int spaces) const;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
index 21fbf9b..cea5c0b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
@@ -28,10 +28,39 @@
     AudioGain(int index, bool useInChannelMask);
     virtual ~AudioGain() {}
 
+    void setMode(audio_gain_mode_t mode) { mGain.mode = mode; }
+    const audio_gain_mode_t &getMode() const { return mGain.mode; }
+
+    void setChannelMask(audio_channel_mask_t mask) { mGain.channel_mask = mask; }
+    const audio_channel_mask_t &getChannelMask() const { return mGain.channel_mask; }
+
+    void setMinValueInMb(int minValue) { mGain.min_value = minValue; }
+    int getMinValueInMb() const { return mGain.min_value; }
+
+    void setMaxValueInMb(int maxValue) { mGain.max_value = maxValue; }
+    int getMaxValueInMb() const { return mGain.max_value; }
+
+    void setDefaultValueInMb(int defaultValue) { mGain.default_value = defaultValue; }
+    int getDefaultValueInMb() const { return mGain.default_value; }
+
+    void setStepValueInMb(uint32_t stepValue) { mGain.step_value = stepValue; }
+    int getStepValueInMb() const { return mGain.step_value; }
+
+    void setMinRampInMs(uint32_t minRamp) { mGain.min_ramp_ms = minRamp; }
+    int getMinRampInMs() const { return mGain.min_ramp_ms; }
+
+    void setMaxRampInMs(uint32_t maxRamp) { mGain.max_ramp_ms = maxRamp; }
+    int getMaxRampInMs() const { return mGain.max_ramp_ms; }
+
+    // TODO: remove dump from here (split serialization)
     void dump(int fd, int spaces, int index) const;
 
     void getDefaultConfig(struct audio_gain_config *config);
     status_t checkConfig(const struct audio_gain_config *config);
+
+    const struct audio_gain &getGain() const { return mGain; }
+
+private:
     int               mIndex;
     struct audio_gain mGain;
     bool              mUseInChannelMask;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 48d09ed..282bece 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include "AudioPort.h"
+#include "AudioSession.h"
 #include <utils/Errors.h>
 #include <system/audio.h>
 #include <utils/SortedVector.h>
@@ -36,6 +37,7 @@
     void setIoHandle(audio_io_handle_t ioHandle);
     audio_port_handle_t getId() const;
     audio_module_handle_t getModuleHandle() const;
+    uint32_t getOpenRefCount() const;
 
     status_t    dump(int fd);
 
@@ -43,14 +45,7 @@
     audio_devices_t               mDevice;         // current device this input is routed to
     AudioMix                      *mPolicyMix;     // non NULL when used by a dynamic policy
     audio_patch_handle_t          mPatchHandle;
-    uint32_t                      mRefCount;       // number of AudioRecord clients using
-    // this input
-    uint32_t                      mOpenRefCount;
-    audio_source_t                mInputSource;    // input source selected by application
-    //(mediarecorder.h)
     const sp<IOProfile>           mProfile;        // I/O profile this output derives from
-    SortedVector<audio_session_t> mSessions;       // audio sessions attached to this input
-    bool                          mIsSoundTrigger; // used by a soundtrigger capture
 
     virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
             const struct audio_port_config *srcConfig = NULL) const;
@@ -60,17 +55,29 @@
     SortedVector<audio_session_t> getPreemptedSessions() const;
     bool hasPreemptedSession(audio_session_t session) const;
     void clearPreemptedSessions();
+    bool isActive() const;
+    bool isSourceActive(audio_source_t source) const;
+    audio_source_t inputSource() const;
+    bool isSoundTrigger() const;
+    status_t addAudioSession(audio_session_t session,
+                             const sp<AudioSession>& audioSession);
+    status_t removeAudioSession(audio_session_t session);
+    sp<AudioSession> getAudioSession(audio_session_t session) const;
+    AudioSessionCollection getAudioSessions(bool activeOnly) const;
+    size_t getAudioSessionCount(bool activeOnly) const;
+    audio_source_t getHighestPrioritySource(bool activeOnly) const;
 
 private:
     audio_port_handle_t           mId;
-    // Because a preemtible capture session can preempt another one, we end up in an endless loop
+    // audio sessions attached to this input
+    AudioSessionCollection        mSessions;
+    // Because a preemptible capture session can preempt another one, we end up in an endless loop
     // situation were each session is allowed to restart after being preempted,
     // thus preempting the other one which restarts and so on.
     // To avoid this situation, we store which audio session was preempted when
     // a particular input started and prevent preemption of this active input by this session.
     // We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc...
     SortedVector<audio_session_t> mPreemptedSessions;
-
 };
 
 class AudioInputCollection :
@@ -88,7 +95,7 @@
      * Only considers inputs from physical devices (e.g. main mic, headset mic) when
      * ignoreVirtualInputs is true.
      */
-    audio_io_handle_t getActiveInput(bool ignoreVirtualInputs = true);
+    Vector<sp <AudioInputDescriptor> > getActiveInputs(bool ignoreVirtualInputs = true);
 
     audio_devices_t getSupportedDevices(audio_io_handle_t handle) const;
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 50f622d..f8439be 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -22,12 +22,14 @@
 #include <utils/Timers.h>
 #include <utils/KeyedVector.h>
 #include <system/audio.h>
+#include "AudioSourceDescriptor.h"
 
 namespace android {
 
 class IOProfile;
 class AudioMix;
 class AudioPolicyClientInterface;
+class DeviceDescriptor;
 
 // descriptor for audio outputs. Used to maintain current configuration of each opened audio output
 // and keep track of the usage of this output by each audio stream type.
@@ -126,6 +128,31 @@
     uint32_t mGlobalRefCount;  // non-stream-specific ref count
 };
 
+// Audio output driven by an input device directly.
+class HwAudioOutputDescriptor: public AudioOutputDescriptor
+{
+public:
+    HwAudioOutputDescriptor(const sp<AudioSourceDescriptor>& source,
+                            AudioPolicyClientInterface *clientInterface);
+    virtual ~HwAudioOutputDescriptor() {}
+
+    status_t    dump(int fd);
+
+    virtual audio_devices_t supportedDevices();
+    virtual bool setVolume(float volume,
+                           audio_stream_type_t stream,
+                           audio_devices_t device,
+                           uint32_t delayMs,
+                           bool force);
+
+    virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
+                           const struct audio_port_config *srcConfig = NULL) const;
+    virtual void toAudioPort(struct audio_port *port) const;
+
+    const sp<AudioSourceDescriptor> mSource;
+
+};
+
 class SwAudioOutputCollection :
         public DefaultKeyedVector< audio_io_handle_t, sp<SwAudioOutputDescriptor> >
 {
@@ -160,4 +187,19 @@
     status_t dump(int fd) const;
 };
 
+class HwAudioOutputCollection :
+        public DefaultKeyedVector< audio_io_handle_t, sp<HwAudioOutputDescriptor> >
+{
+public:
+    bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
+
+    /**
+     * return true if any output is playing anything besides the stream to ignore
+     */
+    bool isAnyOutputActive(audio_stream_type_t streamToIgnore) const;
+
+    status_t dump(int fd) const;
+};
+
+
 }; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
new file mode 100644
index 0000000..f2756b5
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#pragma once
+
+#include <AudioGain.h>
+#include <VolumeCurve.h>
+#include <AudioPort.h>
+#include <AudioPatch.h>
+#include <DeviceDescriptor.h>
+#include <IOProfile.h>
+#include <HwModule.h>
+#include <AudioInputDescriptor.h>
+#include <AudioOutputDescriptor.h>
+#include <AudioPolicyMix.h>
+#include <EffectDescriptor.h>
+#include <SoundTriggerSession.h>
+#include <SessionRoute.h>
+
+namespace android {
+
+class AudioPolicyConfig
+{
+public:
+    AudioPolicyConfig(HwModuleCollection &hwModules,
+                      DeviceVector &availableOutputDevices,
+                      DeviceVector &availableInputDevices,
+                      sp<DeviceDescriptor> &defaultOutputDevices,
+                      bool &isSpeakerDrcEnabled,
+                      VolumeCurvesCollection *volumes = nullptr)
+        : mHwModules(hwModules),
+          mAvailableOutputDevices(availableOutputDevices),
+          mAvailableInputDevices(availableInputDevices),
+          mDefaultOutputDevices(defaultOutputDevices),
+          mVolumeCurves(volumes),
+          mIsSpeakerDrcEnabled(isSpeakerDrcEnabled)
+    {}
+
+    void setVolumes(const VolumeCurvesCollection &volumes)
+    {
+        if (mVolumeCurves != nullptr) {
+            *mVolumeCurves = volumes;
+        }
+    }
+
+    void setHwModules(const HwModuleCollection &hwModules)
+    {
+        mHwModules = hwModules;
+    }
+
+    void addAvailableDevice(const sp<DeviceDescriptor> &availableDevice)
+    {
+        if (audio_is_output_device(availableDevice->type())) {
+            mAvailableOutputDevices.add(availableDevice);
+        } else if (audio_is_input_device(availableDevice->type())) {
+            mAvailableInputDevices.add(availableDevice);
+        }
+    }
+
+    void addAvailableInputDevices(const DeviceVector &availableInputDevices)
+    {
+        mAvailableInputDevices.add(availableInputDevices);
+    }
+
+    void addAvailableOutputDevices(const DeviceVector &availableOutputDevices)
+    {
+        mAvailableOutputDevices.add(availableOutputDevices);
+    }
+
+    void setSpeakerDrcEnabled(bool isSpeakerDrcEnabled)
+    {
+        mIsSpeakerDrcEnabled = isSpeakerDrcEnabled;
+    }
+
+    const HwModuleCollection getHwModules() const { return mHwModules; }
+
+    const DeviceVector &getAvailableInputDevices() const
+    {
+        return mAvailableInputDevices;
+    }
+
+    const DeviceVector &getAvailableOutputDevices() const
+    {
+        return mAvailableOutputDevices;
+    }
+
+    void setDefaultOutputDevice(const sp<DeviceDescriptor> &defaultDevice)
+    {
+        mDefaultOutputDevices = defaultDevice;
+    }
+
+    const sp<DeviceDescriptor> &getDefaultOutputDevice() const { return mDefaultOutputDevices; }
+
+    void setDefault(void)
+    {
+        mDefaultOutputDevices = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
+        sp<HwModule> module;
+        sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
+        mAvailableOutputDevices.add(mDefaultOutputDevices);
+        mAvailableInputDevices.add(defaultInputDevice);
+
+        module = new HwModule("primary");
+
+        sp<OutputProfile> outProfile;
+        outProfile = new OutputProfile(String8("primary"));
+        outProfile->attach(module);
+        outProfile->addAudioProfile(
+                new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
+        outProfile->addSupportedDevice(mDefaultOutputDevices);
+        outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
+        module->mOutputProfiles.add(outProfile);
+
+        sp<InputProfile> inProfile;
+        inProfile = new InputProfile(String8("primary"));
+        inProfile->attach(module);
+        inProfile->addAudioProfile(
+                new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000));
+        inProfile->addSupportedDevice(defaultInputDevice);
+        module->mInputProfiles.add(inProfile);
+
+        mHwModules.add(module);
+    }
+
+private:
+    HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
+    DeviceVector &mAvailableOutputDevices;
+    DeviceVector &mAvailableInputDevices;
+    sp<DeviceDescriptor> &mDefaultOutputDevices;
+    VolumeCurvesCollection *mVolumeCurves;
+    bool &mIsSpeakerDrcEnabled;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index d51f4e1..c952831 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -69,7 +69,8 @@
      * @return NO_ERROR if an output was found for the given attribute (in this case, the
      *                  descriptor output param is initialized), error code otherwise.
      */
-    status_t getOutputForAttr(audio_attributes_t attributes, sp<SwAudioOutputDescriptor> &desc);
+    status_t getOutputForAttr(audio_attributes_t attributes, uid_t uid,
+            sp<SwAudioOutputDescriptor> &desc);
 
     audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource,
                                                   audio_devices_t availableDeviceTypes,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 4fdf5b4..0da3aea 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include "AudioCollections.h"
+#include "AudioProfile.h"
 #include <utils/String8.h>
 #include <utils/Vector.h>
 #include <utils/RefBase.h>
@@ -27,14 +29,40 @@
 
 class HwModule;
 class AudioGain;
+class AudioRoute;
+typedef Vector<sp<AudioGain> > AudioGainCollection;
 
 class AudioPort : public virtual RefBase
 {
 public:
-    AudioPort(const String8& name, audio_port_type_t type,
-              audio_port_role_t role);
+    AudioPort(const String8& name, audio_port_type_t type,  audio_port_role_t role) :
+        mName(name), mType(type), mRole(role), mFlags(AUDIO_OUTPUT_FLAG_NONE) {}
+
     virtual ~AudioPort() {}
 
+    void setName(const String8 &name) { mName = name; }
+    const String8 &getName() const { return mName; }
+
+    audio_port_type_t getType() const { return mType; }
+    audio_port_role_t getRole() const { return mRole; }
+
+    virtual const String8 getTagName() const = 0;
+
+    void setGains(const AudioGainCollection &gains) { mGains = gains; }
+    const AudioGainCollection &getGains() const { return mGains; }
+
+    void setFlags(uint32_t flags)
+    {
+        //force direct flag if offload flag is set: offloading implies a direct output stream
+        // and all common behaviors are driven by checking only the direct flag
+        // this should normally be set appropriately in the policy configuration file
+        if (mRole == AUDIO_PORT_ROLE_SOURCE && (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+            flags |= AUDIO_OUTPUT_FLAG_DIRECT;
+        }
+        mFlags = flags;
+    }
+    uint32_t getFlags() const { return mFlags; }
+
     virtual void attach(const sp<HwModule>& module);
     bool isAttached() { return mModule != 0; }
 
@@ -43,66 +71,80 @@
     virtual void toAudioPort(struct audio_port *port) const;
 
     virtual void importAudioPort(const sp<AudioPort> port);
-    void clearCapabilities();
 
-    void loadSamplingRates(char *name);
-    void loadFormats(char *name);
-    void loadOutChannels(char *name);
-    void loadInChannels(char *name);
+    void addAudioProfile(const sp<AudioProfile> &profile) { mProfiles.add(profile); }
 
-    audio_gain_mode_t loadGainMode(char *name);
-    void loadGain(cnode *root, int index);
-    virtual void loadGains(cnode *root);
+    void setAudioProfiles(const AudioProfileVector &profiles) { mProfiles = profiles; }
+    AudioProfileVector &getAudioProfiles() { return mProfiles; }
+
+    bool hasValidAudioProfile() const { return mProfiles.hasValidProfile(); }
+
+    bool hasDynamicAudioProfile() const { return mProfiles.hasDynamicProfile(); }
 
     // searches for an exact match
-    status_t checkExactSamplingRate(uint32_t samplingRate) const;
-    // searches for a compatible match, and returns the best match via updatedSamplingRate
-    status_t checkCompatibleSamplingRate(uint32_t samplingRate,
-            uint32_t *updatedSamplingRate) const;
-    // searches for an exact match
-    status_t checkExactChannelMask(audio_channel_mask_t channelMask) const;
-    // searches for a compatible match, currently implemented for input channel masks only
-    status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
-            audio_channel_mask_t *updatedChannelMask) const;
+    status_t checkExactAudioProfile(uint32_t samplingRate,
+                                    audio_channel_mask_t channelMask,
+                                    audio_format_t format) const
+    {
+        return mProfiles.checkExactProfile(samplingRate, channelMask, format);
+    }
 
-    status_t checkExactFormat(audio_format_t format) const;
-    // searches for a compatible match, currently implemented for input formats only
-    status_t checkCompatibleFormat(audio_format_t format, audio_format_t *updatedFormat) const;
+    // searches for a compatible match, currently implemented for input
+    // parameters are input|output, returned value is the best match.
+    status_t checkCompatibleAudioProfile(uint32_t &samplingRate,
+                                         audio_channel_mask_t &channelMask,
+                                         audio_format_t &format) const
+    {
+        return mProfiles.checkCompatibleProfile(samplingRate, channelMask, format, mType, mRole);
+    }
+
+    void clearAudioProfiles() { return mProfiles.clearProfiles(); }
+
     status_t checkGain(const struct audio_gain_config *gainConfig, int index) const;
 
-    uint32_t pickSamplingRate() const;
-    audio_channel_mask_t pickChannelMask() const;
-    audio_format_t pickFormat() const;
+    void pickAudioProfile(uint32_t &samplingRate,
+                          audio_channel_mask_t &channelMask,
+                          audio_format_t &format) const;
 
     static const audio_format_t sPcmFormatCompareTable[];
-    static int compareFormats(const audio_format_t *format1, const audio_format_t *format2) {
-        return compareFormats(*format1, *format2);
-    }
+
     static int compareFormats(audio_format_t format1, audio_format_t format2);
 
     audio_module_handle_t getModuleHandle() const;
     uint32_t getModuleVersion() const;
     const char *getModuleName() const;
 
-    void dump(int fd, int spaces) const;
+    bool useInputChannelMask() const
+    {
+        return ((mType == AUDIO_PORT_TYPE_DEVICE) && (mRole == AUDIO_PORT_ROLE_SOURCE)) ||
+                ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SINK));
+    }
+
+    inline bool isDirectOutput() const
+    {
+        return (mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
+                (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
+    }
+
+    void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
+    const AudioRouteVector &getRoutes() const { return mRoutes; }
+
+    void dump(int fd, int spaces, bool verbose = true) const;
     void log(const char* indent) const;
 
-    String8           mName;
-    audio_port_type_t mType;
-    audio_port_role_t mRole;
-    bool              mUseInChannelMask;
-    // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
-    // indicates the supported parameters should be read from the output stream
-    // after it is opened for the first time
-    Vector <uint32_t> mSamplingRates; // supported sampling rates
-    Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks
-    Vector <audio_format_t> mFormats; // supported audio formats
-    Vector < sp<AudioGain> > mGains; // gain controllers
+    AudioGainCollection mGains; // gain controllers
     sp<HwModule> mModule;                 // audio HW module exposing this I/O stream
-    uint32_t mFlags; // attribute flags (e.g primary output,
-                     // direct output...).
 
 private:
+    void pickChannelMask(audio_channel_mask_t &channelMask, const ChannelsVector &channelMasks) const;
+    void pickSamplingRate(uint32_t &rate,const SampleRateVector &samplingRates) const;
+
+    String8  mName;
+    audio_port_type_t mType;
+    audio_port_role_t mRole;
+    uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
+    AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
+    AudioRouteVector mRoutes; // Routes involving this port
     static volatile int32_t mNextUniqueId;
 };
 
@@ -113,10 +155,14 @@
     virtual ~AudioPortConfig() {}
 
     status_t applyAudioPortConfig(const struct audio_port_config *config,
-            struct audio_port_config *backupConfig = NULL);
+                                  struct audio_port_config *backupConfig = NULL);
     virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
-            const struct audio_port_config *srcConfig = NULL) const = 0;
+                                   const struct audio_port_config *srcConfig = NULL) const = 0;
     virtual sp<AudioPort> getAudioPort() const = 0;
+    virtual bool hasSameHwModuleAs(const sp<AudioPortConfig>& other) const {
+        return (other != 0) &&
+                (other->getAudioPort()->getModuleHandle() == getAudioPort()->getModuleHandle());
+    }
     uint32_t mSamplingRate;
     audio_format_t mFormat;
     audio_channel_mask_t mChannelMask;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
new file mode 100644
index 0000000..404e27d
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#pragma once
+
+#include "policy.h"
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
+namespace android {
+
+typedef SortedVector<uint32_t> SampleRateVector;
+typedef SortedVector<audio_channel_mask_t> ChannelsVector;
+typedef Vector<audio_format_t> FormatVector;
+
+template <typename T>
+bool operator == (const SortedVector<T> &left, const SortedVector<T> &right);
+
+class AudioProfile : public virtual RefBase
+{
+public:
+    AudioProfile(audio_format_t format,
+                 audio_channel_mask_t channelMasks,
+                 uint32_t samplingRate) :
+        mName(String8("")),
+        mFormat(format)
+    {
+        mChannelMasks.add(channelMasks);
+        mSamplingRates.add(samplingRate);
+    }
+
+    AudioProfile(audio_format_t format,
+                 const ChannelsVector &channelMasks,
+                 const SampleRateVector &samplingRateCollection) :
+        mName(String8("")),
+        mFormat(format),
+        mChannelMasks(channelMasks),
+        mSamplingRates(samplingRateCollection)
+    {}
+
+    audio_format_t getFormat() const { return mFormat; }
+
+    void setChannels(const ChannelsVector &channelMasks)
+    {
+        if (mIsDynamicChannels) {
+            mChannelMasks = channelMasks;
+        }
+    }
+    const ChannelsVector &getChannels() const { return mChannelMasks; }
+
+    void setSampleRates(const SampleRateVector &sampleRates)
+    {
+        if (mIsDynamicRate) {
+            mSamplingRates = sampleRates;
+        }
+    }
+    const SampleRateVector &getSampleRates() const { return mSamplingRates; }
+
+    bool isValid() const { return hasValidFormat() && hasValidRates() && hasValidChannels(); }
+
+    void clear()
+    {
+        if (mIsDynamicChannels) {
+            mChannelMasks.clear();
+        }
+        if (mIsDynamicRate) {
+            mSamplingRates.clear();
+        }
+    }
+
+    inline bool supportsChannels(audio_channel_mask_t channels) const
+    {
+        return mChannelMasks.indexOf(channels) >= 0;
+    }
+    inline bool supportsRate(uint32_t rate) const
+    {
+        return mSamplingRates.indexOf(rate) >= 0;
+    }
+
+    status_t checkExact(uint32_t rate, audio_channel_mask_t channels, audio_format_t format) const;
+
+    status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
+                                        audio_channel_mask_t &updatedChannelMask,
+                                        audio_port_type_t portType,
+                                        audio_port_role_t portRole) const;
+
+    status_t checkCompatibleSamplingRate(uint32_t samplingRate,
+                                         uint32_t &updatedSamplingRate) const;
+
+    bool hasValidFormat() const { return mFormat != AUDIO_FORMAT_DEFAULT; }
+    bool hasValidRates() const { return !mSamplingRates.isEmpty(); }
+    bool hasValidChannels() const { return !mChannelMasks.isEmpty(); }
+
+    void setDynamicChannels(bool dynamic) { mIsDynamicChannels = dynamic; }
+    bool isDynamicChannels() const { return mIsDynamicChannels; }
+
+    void setDynamicRate(bool dynamic) { mIsDynamicRate = dynamic; }
+    bool isDynamicRate() const { return mIsDynamicRate; }
+
+    void setDynamicFormat(bool dynamic) { mIsDynamicFormat = dynamic; }
+    bool isDynamicFormat() const { return mIsDynamicFormat; }
+
+    bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }
+
+    void dump(int fd, int spaces) const;
+
+private:
+    String8  mName;
+    audio_format_t mFormat;
+    ChannelsVector mChannelMasks;
+    SampleRateVector mSamplingRates;
+
+    bool mIsDynamicFormat = false;
+    bool mIsDynamicChannels = false;
+    bool mIsDynamicRate = false;
+};
+
+
+class AudioProfileVector : public Vector<sp<AudioProfile> >
+{
+public:
+    ssize_t add(const sp<AudioProfile> &profile)
+    {
+        ssize_t index = Vector::add(profile);
+        // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
+        // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
+        // [](const audio_format_t *format1, const audio_format_t *format2) {
+        //     return compareFormats(*format1, *format2);
+        // }
+        sort(compareFormats);
+        return index;
+    }
+
+    // This API is intended to be used by the policy manager once retrieving capabilities
+    // for a profile with dynamic format, rate and channels attributes
+    ssize_t addProfileFromHal(const sp<AudioProfile> &profileToAdd)
+    {
+        // Check valid profile to add:
+        if (!profileToAdd->hasValidFormat()) {
+            return -1;
+        }
+        if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+            FormatVector formats;
+            formats.add(profileToAdd->getFormat());
+            setFormats(FormatVector(formats));
+            return 0;
+        }
+        if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
+            setSampleRatesFor(profileToAdd->getSampleRates(), profileToAdd->getFormat());
+            return 0;
+        }
+        if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+            setChannelsFor(profileToAdd->getChannels(), profileToAdd->getFormat());
+            return 0;
+        }
+        // Go through the list of profile to avoid duplicates
+        for (size_t profileIndex = 0; profileIndex < size(); profileIndex++) {
+            const sp<AudioProfile> &profile = itemAt(profileIndex);
+            if (profile->isValid() && profile == profileToAdd) {
+                // Nothing to do
+                return profileIndex;
+            }
+        }
+        profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
+        return add(profileToAdd);
+    }
+
+    sp<AudioProfile> getFirstValidProfile() const
+    {
+        for (size_t i = 0; i < size(); i++) {
+            if (itemAt(i)->isValid()) {
+                return itemAt(i);
+            }
+        }
+        return 0;
+    }
+
+    bool hasValidProfile() const { return getFirstValidProfile() != 0; }
+
+    status_t checkExactProfile(uint32_t samplingRate, audio_channel_mask_t channelMask,
+                               audio_format_t format) const;
+
+    status_t checkCompatibleProfile(uint32_t &samplingRate, audio_channel_mask_t &channelMask,
+                                    audio_format_t &format,
+                                    audio_port_type_t portType,
+                                    audio_port_role_t portRole) const;
+
+    FormatVector getSupportedFormats() const
+    {
+        FormatVector supportedFormats;
+        for (size_t i = 0; i < size(); i++) {
+            if (itemAt(i)->hasValidFormat()) {
+                supportedFormats.add(itemAt(i)->getFormat());
+            }
+        }
+        return supportedFormats;
+    }
+
+    bool hasDynamicProfile() const
+    {
+        for (size_t i = 0; i < size(); i++) {
+            if (itemAt(i)->isDynamic()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    bool hasDynamicFormat() const
+    {
+        return getProfileFor(gDynamicFormat) != 0;
+    }
+
+    bool hasDynamicChannelsFor(audio_format_t format) const
+    {
+       for (size_t i = 0; i < size(); i++) {
+           sp<AudioProfile> profile = itemAt(i);
+           if (profile->getFormat() == format && profile->isDynamicChannels()) {
+               return true;
+           }
+       }
+       return false;
+    }
+
+    bool hasDynamicRateFor(audio_format_t format) const
+    {
+        for (size_t i = 0; i < size(); i++) {
+            sp<AudioProfile> profile = itemAt(i);
+            if (profile->getFormat() == format && profile->isDynamicRate()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // One audio profile will be added for each format supported by Audio HAL
+    void setFormats(const FormatVector &formats)
+    {
+        // Only allow to change the format of dynamic profile
+        sp<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat);
+        if (dynamicFormatProfile == 0) {
+            return;
+        }
+        for (size_t i = 0; i < formats.size(); i++) {
+            sp<AudioProfile> profile = new AudioProfile(formats[i],
+                                                        dynamicFormatProfile->getChannels(),
+                                                        dynamicFormatProfile->getSampleRates());
+            profile->setDynamicFormat(true);
+            profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
+            profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
+            add(profile);
+        }
+    }
+
+    void clearProfiles()
+    {
+        for (size_t i = size(); i != 0; ) {
+            sp<AudioProfile> profile = itemAt(--i);
+            if (profile->isDynamicFormat() && profile->hasValidFormat()) {
+                removeAt(i);
+                continue;
+            }
+            profile->clear();
+        }
+    }
+
+    void dump(int fd, int spaces) const
+    {
+        const size_t SIZE = 256;
+        char buffer[SIZE];
+
+        snprintf(buffer, SIZE, "%*s- Profiles:\n", spaces, "");
+        write(fd, buffer, strlen(buffer));
+        for (size_t i = 0; i < size(); i++) {
+            snprintf(buffer, SIZE, "%*sProfile %zu:", spaces + 4, "", i);
+            write(fd, buffer, strlen(buffer));
+            itemAt(i)->dump(fd, spaces + 8);
+        }
+    }
+
+private:
+    void setSampleRatesFor(const SampleRateVector &sampleRates, audio_format_t format)
+    {
+        for (size_t i = 0; i < size(); i++) {
+            sp<AudioProfile> profile = itemAt(i);
+            if (profile->getFormat() == format && profile->isDynamicRate()) {
+                if (profile->hasValidRates()) {
+                    // Need to create a new profile with same format
+                    sp<AudioProfile> profileToAdd = new AudioProfile(format, profile->getChannels(),
+                                                                     sampleRates);
+                    profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+                    add(profileToAdd);
+                } else {
+                    profile->setSampleRates(sampleRates);
+                }
+                return;
+            }
+        }
+    }
+
+    void setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format)
+    {
+        for (size_t i = 0; i < size(); i++) {
+            sp<AudioProfile> profile = itemAt(i);
+            if (profile->getFormat() == format && profile->isDynamicChannels()) {
+                if (profile->hasValidChannels()) {
+                    // Need to create a new profile with same format
+                    sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMasks,
+                                                                     profile->getSampleRates());
+                    profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+                    add(profileToAdd);
+                } else {
+                    profile->setChannels(channelMasks);
+                }
+                return;
+            }
+        }
+    }
+
+    sp<AudioProfile> getProfileFor(audio_format_t format) const
+    {
+        for (size_t i = 0; i < size(); i++) {
+            if (itemAt(i)->getFormat() == format) {
+                return itemAt(i);
+            }
+        }
+        return 0;
+    }
+
+    static int compareFormats(const sp<AudioProfile> *profile1, const sp<AudioProfile> *profile2);
+};
+
+bool operator == (const AudioProfile &left, const AudioProfile &right);
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
new file mode 100644
index 0000000..67e197f
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#pragma once
+
+#include "AudioCollections.h"
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+
+namespace android
+{
+
+class AudioPort;
+class DeviceDescriptor;
+
+typedef enum {
+    AUDIO_ROUTE_MUX = 0,
+    AUDIO_ROUTE_MIX = 1
+} audio_route_type_t;
+
+class AudioRoute  : public virtual RefBase
+{
+public:
+    AudioRoute(audio_route_type_t type) : mType(type) {}
+
+    void setSources(const AudioPortVector &sources) { mSources = sources; }
+    const AudioPortVector &getSources() const { return mSources; }
+
+    void setSink(const sp<AudioPort> &sink) { mSink = sink; }
+    const sp<AudioPort> &getSink() const { return mSink; }
+
+    audio_route_type_t getType() const { return mType; }
+
+    void dump(int fd, int spaces) const;
+
+private:
+    AudioPortVector mSources;
+    sp<AudioPort> mSink;
+    audio_route_type_t mType;
+
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
new file mode 100644
index 0000000..648cc00
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#pragma once
+
+#include <system/audio.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <media/AudioPolicy.h>
+
+namespace android {
+
+class AudioPolicyClientInterface;
+
+class AudioSession : public RefBase
+{
+public:
+    AudioSession(audio_session_t session,
+                 audio_source_t inputSource,
+                 audio_format_t format,
+                 uint32_t sampleRate,
+                 audio_channel_mask_t channelMask,
+                 audio_input_flags_t flags,
+                 uid_t uid,
+                 bool isSoundTrigger,
+                 AudioMix* policyMix,
+                 AudioPolicyClientInterface *clientInterface);
+
+    status_t dump(int fd, int spaces, int index) const;
+
+    audio_session_t session() const { return mSession; }
+    audio_source_t inputSource()const { return mInputSource; }
+    audio_format_t format() const { return mFormat; }
+    uint32_t sampleRate() const { return mSampleRate; }
+    audio_channel_mask_t channelMask() const { return mChannelMask; }
+    audio_input_flags_t flags() const { return mFlags; }
+    uid_t uid() const { return mUid; }
+    bool matches(const sp<AudioSession> &other) const;
+    bool isSoundTrigger() const { return mIsSoundTrigger; }
+    uint32_t openCount() const { return mOpenCount; } ;
+    uint32_t activeCount() const { return mActiveCount; } ;
+
+    uint32_t changeOpenCount(int delta);
+    uint32_t changeActiveCount(int delta);
+
+private:
+    const audio_session_t mSession;
+    const audio_source_t mInputSource;
+    const audio_format_t mFormat;
+    const uint32_t mSampleRate;
+    const audio_channel_mask_t mChannelMask;
+    const audio_input_flags_t mFlags;
+    const uid_t mUid;
+    bool  mIsSoundTrigger;
+    uint32_t  mOpenCount;
+    uint32_t  mActiveCount;
+    AudioMix* mPolicyMix; // non NULL when used by a dynamic policy
+    AudioPolicyClientInterface* mClientInterface;
+};
+
+class AudioSessionCollection :
+    public DefaultKeyedVector<audio_session_t, sp<AudioSession> >
+{
+public:
+    status_t addSession(audio_session_t session,
+                             const sp<AudioSession>& audioSession);
+
+    status_t removeSession(audio_session_t session);
+
+    uint32_t getOpenCount() const;
+
+    AudioSessionCollection getActiveSessions() const;
+    size_t getActiveSessionCount() const;
+    bool hasActiveSession() const;
+    bool isSourceActive(audio_source_t source) const;
+    audio_source_t getHighestPrioritySource(bool activeOnly) const;
+
+    status_t dump(int fd, int spaces) const;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
new file mode 100644
index 0000000..7e1e24d
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#pragma once
+
+#include <system/audio.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <RoutingStrategy.h>
+#include <AudioPatch.h>
+
+namespace android {
+
+class SwAudioOutputDescriptor;
+class HwAudioOutputDescriptor;
+class DeviceDescriptor;
+
+class AudioSourceDescriptor: public RefBase
+{
+public:
+    AudioSourceDescriptor(const sp<DeviceDescriptor> device, const audio_attributes_t *attributes,
+                          uid_t uid) :
+        mDevice(device), mAttributes(*attributes), mUid(uid) {}
+    virtual ~AudioSourceDescriptor() {}
+
+    audio_patch_handle_t getHandle() const { return mPatchDesc->mHandle; }
+
+    status_t    dump(int fd);
+
+    const sp<DeviceDescriptor> mDevice;
+    const audio_attributes_t mAttributes;
+    uid_t mUid;
+    sp<AudioPatch> mPatchDesc;
+    wp<SwAudioOutputDescriptor> mSwOutput;
+    wp<HwAudioOutputDescriptor> mHwOutput;
+};
+
+class AudioSourceCollection :
+        public DefaultKeyedVector< audio_patch_handle_t, sp<AudioSourceDescriptor> >
+{
+public:
+    status_t dump(int fd) const;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
index 78d2cdf..ee95ceb 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include "AudioPolicyConfig.h"
 #include "DeviceDescriptor.h"
 #include "HwModule.h"
 #include "audio_policy_conf.h"
@@ -33,243 +34,26 @@
 // Definitions for audio_policy.conf file parsing
 // ----------------------------------------------------------------------------
 
-struct StringToEnum {
-    const char *name;
-    uint32_t value;
-};
-
-// TODO: move to a separate file. Should be in sync with audio.h.
-#define STRING_TO_ENUM(string) { #string, (uint32_t)string } // uint32_t cast removes warning
-#define NAME_TO_ENUM(name, value) { name, value }
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-#endif
-
-const StringToEnum sDeviceTypeToEnumTable[] = {
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_EARPIECE),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER_SAFE),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADSET),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_SCO),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_A2DP),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_DIGITAL),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_HDMI),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_ACCESSORY),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_DEVICE),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_USB),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_TELEPHONY_TX),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_LINE),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_HDMI_ARC),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPDIF),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_FM),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_LINE),
-    STRING_TO_ENUM(AUDIO_DEVICE_OUT_IP),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_AMBIENT),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_ALL_SCO),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_HDMI),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_TELEPHONY_RX),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_VOICE_CALL),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_DEVICE),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_FM_TUNER),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_TV_TUNER),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_LINE),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_SPDIF),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_LOOPBACK),
-    STRING_TO_ENUM(AUDIO_DEVICE_IN_IP),
-};
-
-const StringToEnum sDeviceNameToEnumTable[] = {
-    NAME_TO_ENUM("Earpiece", AUDIO_DEVICE_OUT_EARPIECE),
-    NAME_TO_ENUM("Speaker", AUDIO_DEVICE_OUT_SPEAKER),
-    NAME_TO_ENUM("Speaker Protected", AUDIO_DEVICE_OUT_SPEAKER_SAFE),
-    NAME_TO_ENUM("Wired Headset", AUDIO_DEVICE_OUT_WIRED_HEADSET),
-    NAME_TO_ENUM("Wired Headphones", AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
-    NAME_TO_ENUM("BT SCO", AUDIO_DEVICE_OUT_BLUETOOTH_SCO),
-    NAME_TO_ENUM("BT SCO Headset", AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET),
-    NAME_TO_ENUM("BT SCO Car Kit", AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
-    NAME_TO_ENUM("", AUDIO_DEVICE_OUT_ALL_SCO),
-    NAME_TO_ENUM("BT A2DP Out", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP),
-    NAME_TO_ENUM("BT A2DP Headphones", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES),
-    NAME_TO_ENUM("BT A2DP Speaker", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
-    NAME_TO_ENUM("", AUDIO_DEVICE_OUT_ALL_A2DP),
-    NAME_TO_ENUM("HDMI Out", AUDIO_DEVICE_OUT_AUX_DIGITAL),
-    NAME_TO_ENUM("HDMI Out", AUDIO_DEVICE_OUT_HDMI),
-    NAME_TO_ENUM("Analog Dock Out", AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
-    NAME_TO_ENUM("Digital Dock Out", AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
-    NAME_TO_ENUM("USB Host Out", AUDIO_DEVICE_OUT_USB_ACCESSORY),
-    NAME_TO_ENUM("USB Device Out", AUDIO_DEVICE_OUT_USB_DEVICE),
-    NAME_TO_ENUM("", AUDIO_DEVICE_OUT_ALL_USB),
-    NAME_TO_ENUM("Reroute Submix Out", AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
-    NAME_TO_ENUM("Telephony Tx", AUDIO_DEVICE_OUT_TELEPHONY_TX),
-    NAME_TO_ENUM("Line Out", AUDIO_DEVICE_OUT_LINE),
-    NAME_TO_ENUM("HDMI ARC Out", AUDIO_DEVICE_OUT_HDMI_ARC),
-    NAME_TO_ENUM("S/PDIF Out", AUDIO_DEVICE_OUT_SPDIF),
-    NAME_TO_ENUM("FM transceiver Out", AUDIO_DEVICE_OUT_FM),
-    NAME_TO_ENUM("Aux Line Out", AUDIO_DEVICE_OUT_AUX_LINE),
-    NAME_TO_ENUM("IP Out", AUDIO_DEVICE_OUT_IP),
-    NAME_TO_ENUM("Ambient Mic", AUDIO_DEVICE_IN_AMBIENT),
-    NAME_TO_ENUM("Built-In Mic", AUDIO_DEVICE_IN_BUILTIN_MIC),
-    NAME_TO_ENUM("BT SCO Headset Mic", AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
-    NAME_TO_ENUM("", AUDIO_DEVICE_IN_ALL_SCO),
-    NAME_TO_ENUM("Wired Headset Mic", AUDIO_DEVICE_IN_WIRED_HEADSET),
-    NAME_TO_ENUM("HDMI In", AUDIO_DEVICE_IN_AUX_DIGITAL),
-    NAME_TO_ENUM("HDMI In", AUDIO_DEVICE_IN_HDMI),
-    NAME_TO_ENUM("Telephony Rx", AUDIO_DEVICE_IN_TELEPHONY_RX),
-    NAME_TO_ENUM("Telephony Rx", AUDIO_DEVICE_IN_VOICE_CALL),
-    NAME_TO_ENUM("Built-In Back Mic", AUDIO_DEVICE_IN_BACK_MIC),
-    NAME_TO_ENUM("Reroute Submix In", AUDIO_DEVICE_IN_REMOTE_SUBMIX),
-    NAME_TO_ENUM("Analog Dock In", AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
-    NAME_TO_ENUM("Digital Dock In", AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
-    NAME_TO_ENUM("USB Host In", AUDIO_DEVICE_IN_USB_ACCESSORY),
-    NAME_TO_ENUM("USB Device In", AUDIO_DEVICE_IN_USB_DEVICE),
-    NAME_TO_ENUM("FM Tuner In", AUDIO_DEVICE_IN_FM_TUNER),
-    NAME_TO_ENUM("TV Tuner In", AUDIO_DEVICE_IN_TV_TUNER),
-    NAME_TO_ENUM("Line In", AUDIO_DEVICE_IN_LINE),
-    NAME_TO_ENUM("S/PDIF In", AUDIO_DEVICE_IN_SPDIF),
-    NAME_TO_ENUM("BT A2DP In", AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
-    NAME_TO_ENUM("Loopback In", AUDIO_DEVICE_IN_LOOPBACK),
-    NAME_TO_ENUM("IP In", AUDIO_DEVICE_IN_IP),
-};
-
-const StringToEnum sOutputFlagNameToEnumTable[] = {
-    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
-    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
-    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST),
-    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
-    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
-    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
-    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_HW_AV_SYNC),
-    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_TTS),
-    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_RAW),
-    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_SYNC),
-};
-
-const StringToEnum sInputFlagNameToEnumTable[] = {
-    STRING_TO_ENUM(AUDIO_INPUT_FLAG_FAST),
-    STRING_TO_ENUM(AUDIO_INPUT_FLAG_HW_HOTWORD),
-    STRING_TO_ENUM(AUDIO_INPUT_FLAG_RAW),
-    STRING_TO_ENUM(AUDIO_INPUT_FLAG_SYNC),
-};
-
-const StringToEnum sFormatNameToEnumTable[] = {
-    STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
-    STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
-    STRING_TO_ENUM(AUDIO_FORMAT_PCM_32_BIT),
-    STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
-    STRING_TO_ENUM(AUDIO_FORMAT_PCM_FLOAT),
-    STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
-    STRING_TO_ENUM(AUDIO_FORMAT_MP3),
-    STRING_TO_ENUM(AUDIO_FORMAT_AAC),
-    STRING_TO_ENUM(AUDIO_FORMAT_AAC_MAIN),
-    STRING_TO_ENUM(AUDIO_FORMAT_AAC_LC),
-    STRING_TO_ENUM(AUDIO_FORMAT_AAC_SSR),
-    STRING_TO_ENUM(AUDIO_FORMAT_AAC_LTP),
-    STRING_TO_ENUM(AUDIO_FORMAT_AAC_HE_V1),
-    STRING_TO_ENUM(AUDIO_FORMAT_AAC_SCALABLE),
-    STRING_TO_ENUM(AUDIO_FORMAT_AAC_ERLC),
-    STRING_TO_ENUM(AUDIO_FORMAT_AAC_LD),
-    STRING_TO_ENUM(AUDIO_FORMAT_AAC_HE_V2),
-    STRING_TO_ENUM(AUDIO_FORMAT_AAC_ELD),
-    STRING_TO_ENUM(AUDIO_FORMAT_VORBIS),
-    STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V1),
-    STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V2),
-    STRING_TO_ENUM(AUDIO_FORMAT_OPUS),
-    STRING_TO_ENUM(AUDIO_FORMAT_AC3),
-    STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
-    STRING_TO_ENUM(AUDIO_FORMAT_DTS),
-    STRING_TO_ENUM(AUDIO_FORMAT_DTS_HD),
-};
-
-const StringToEnum sOutChannelsNameToEnumTable[] = {
-    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_MONO),
-    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
-    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_QUAD),
-    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
-    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
-};
-
-const StringToEnum sInChannelsNameToEnumTable[] = {
-    STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
-    STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
-    STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
-};
-
-const StringToEnum sIndexChannelsNameToEnumTable[] = {
-    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_1),
-    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_2),
-    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_3),
-    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_4),
-    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_5),
-    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_6),
-    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_7),
-    STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_8),
-};
-
-const StringToEnum sGainModeNameToEnumTable[] = {
-    STRING_TO_ENUM(AUDIO_GAIN_MODE_JOINT),
-    STRING_TO_ENUM(AUDIO_GAIN_MODE_CHANNELS),
-    STRING_TO_ENUM(AUDIO_GAIN_MODE_RAMP),
-};
-
 class ConfigParsingUtils
 {
 public:
-    static uint32_t stringToEnum(const struct StringToEnum *table,
-            size_t size,
-            const char *name);
-    static const char *enumToString(const struct StringToEnum *table,
-            size_t size,
-            uint32_t value);
-    static bool stringToBool(const char *value);
-    static uint32_t parseOutputFlagNames(char *name);
-    static uint32_t parseInputFlagNames(char *name);
-    static audio_devices_t parseDeviceNames(char *name);
-
-    static void loadHwModules(cnode *root, HwModuleCollection &hwModules,
-                              DeviceVector &availableInputDevices,
-                              DeviceVector &availableOutputDevices,
-                              sp<DeviceDescriptor> &defaultOutputDevices,
-                              bool &isSpeakerDrcEnabled);
-
-    static void loadGlobalConfig(cnode *root, const sp<HwModule>& module,
-                                 DeviceVector &availableInputDevices,
-                                 DeviceVector &availableOutputDevices,
-                                 sp<DeviceDescriptor> &defaultOutputDevices,
-                                 bool &isSpeakerDrcEnabled);
-
-    static status_t loadAudioPolicyConfig(const char *path,
-                                          HwModuleCollection &hwModules,
-                                          DeviceVector &availableInputDevices,
-                                          DeviceVector &availableOutputDevices,
-                                          sp<DeviceDescriptor> &defaultOutputDevices,
-                                          bool &isSpeakerDrcEnabled);
+    static status_t loadConfig(const char *path, AudioPolicyConfig &config);
 
 private:
-    static void loadHwModule(cnode *root, HwModuleCollection &hwModules,
-                             DeviceVector &availableInputDevices,
-                             DeviceVector &availableOutputDevices,
-                             sp<DeviceDescriptor> &defaultOutputDevices,
-                             bool &isSpeakerDrcEnabled);
+    static void loadAudioPortGain(cnode *root, AudioPort &audioPort, int index);
+    static void loadAudioPortGains(cnode *root, AudioPort &audioPort);
+    static void loadDeviceDescriptorGains(cnode *root, sp<DeviceDescriptor> &deviceDesc);
+    static status_t loadHwModuleDevice(cnode *root, DeviceVector &devices);
+    static status_t loadHwModuleProfile(cnode *root, sp<HwModule> &module, audio_port_role_t role);
+    static void loadDevicesFromTag(const char *tag, DeviceVector &devices,
+                            const DeviceVector &declaredDevices);
+    static void loadHwModules(cnode *root, HwModuleCollection &hwModules,
+                              AudioPolicyConfig &config);
+    static void loadGlobalConfig(cnode *root, AudioPolicyConfig &config,
+                                 const sp<HwModule> &primaryModule);
+    static void loadModuleGlobalConfig(cnode *root, const sp<HwModule> &module,
+                                       AudioPolicyConfig &config);
+    static status_t loadHwModule(cnode *root, sp<HwModule> &module, AudioPolicyConfig &config);
 };
 
 }; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index c42ece6..54fcd0b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -29,10 +29,15 @@
 class DeviceDescriptor : public AudioPort, public AudioPortConfig
 {
 public:
-    DeviceDescriptor(audio_devices_t type);
+     // Note that empty name refers by convention to a generic device.
+    DeviceDescriptor(audio_devices_t type, const String8 &tagName = String8(""));
 
     virtual ~DeviceDescriptor() {}
 
+    virtual const String8 getTagName() const { return mTagName; }
+
+    audio_devices_t type() const { return mDeviceType; }
+
     bool equals(const sp<DeviceDescriptor>& other) const;
 
     // AudioPortConfig
@@ -42,50 +47,46 @@
 
     // AudioPort
     virtual void attach(const sp<HwModule>& module);
-    virtual void loadGains(cnode *root);
     virtual void toAudioPort(struct audio_port *port) const;
     virtual void importAudioPort(const sp<AudioPort> port);
 
     audio_port_handle_t getId() const;
-    audio_devices_t type() const { return mDeviceType; }
-    status_t dump(int fd, int spaces, int index) const;
+    status_t dump(int fd, int spaces, int index, bool verbose = true) const;
     void log() const;
 
-    String8 mTag;
     String8 mAddress;
 
 private:
+    String8 mTagName; // Unique human readable identifier for a device port found in conf file.
     audio_devices_t     mDeviceType;
     audio_port_handle_t mId;
 
 friend class DeviceVector;
 };
 
-class DeviceVector : public SortedVector< sp<DeviceDescriptor> >
+class DeviceVector : public SortedVector<sp<DeviceDescriptor> >
 {
 public:
     DeviceVector() : SortedVector(), mDeviceTypes(AUDIO_DEVICE_NONE) {}
 
     ssize_t add(const sp<DeviceDescriptor>& item);
+    void add(const DeviceVector &devices);
     ssize_t remove(const sp<DeviceDescriptor>& item);
     ssize_t indexOf(const sp<DeviceDescriptor>& item) const;
 
     audio_devices_t types() const { return mDeviceTypes; }
 
-    void loadDevicesFromType(audio_devices_t types);
-    void loadDevicesFromTag(char *tag, const DeviceVector& declaredDevices);
-
     sp<DeviceDescriptor> getDevice(audio_devices_t type, String8 address) const;
     DeviceVector getDevicesFromType(audio_devices_t types) const;
     sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
-    sp<DeviceDescriptor> getDeviceFromTag(const String8& tag) const;
+    sp<DeviceDescriptor> getDeviceFromTagName(const String8 &tagName) const;
     DeviceVector getDevicesFromTypeAddr(audio_devices_t type, String8 address) const;
 
     audio_devices_t getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
 
     audio_policy_dev_state_t getDeviceConnectionState(const sp<DeviceDescriptor> &devDesc) const;
 
-    status_t dump(int fd, const String8 &direction) const;
+    status_t dump(int fd, const String8 &tag, int spaces = 0, bool verbose = true) const;
 
 private:
     void refreshTypes();
diff --git a/services/audiopolicy/enginedefault/src/Gains.h b/services/audiopolicy/common/managerdefinitions/include/Gains.h
similarity index 87%
rename from services/audiopolicy/enginedefault/src/Gains.h
rename to services/audiopolicy/common/managerdefinitions/include/Gains.h
index 7620b7d..34afc8c 100644
--- a/services/audiopolicy/enginedefault/src/Gains.h
+++ b/services/audiopolicy/common/managerdefinitions/include/Gains.h
@@ -29,12 +29,7 @@
 class Gains
 {
 public :
-    static float volIndexToAmpl(Volume::device_category deviceCategory,
-                                const StreamDescriptor& streamDesc,
-                                int indexInUi);
-
-    static float volIndexToDb(Volume::device_category deviceCategory,
-                              const StreamDescriptor& streamDesc,
+    static float volIndexToDb(const VolumeCurvePoint *point, int indexMin, int indexMax,
                               int indexInUi);
 
     // default volume curve
@@ -58,7 +53,7 @@
     static const VolumeCurvePoint sSilentVolumeCurve[Volume::VOLCNT];
     static const VolumeCurvePoint sFullScaleVolumeCurve[Volume::VOLCNT];
     // default volume curves per stream and device category. See initializeVolumeCurves()
-    static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][Volume::DEVICE_CATEGORY_CNT];
+    static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][DEVICE_CATEGORY_CNT];
 };
 
 }; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index 92c3ea2..93d03e6 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -17,26 +17,54 @@
 #pragma once
 
 #include "DeviceDescriptor.h"
+#include "AudioRoute.h"
+#include <hardware/audio.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
 #include <utils/Errors.h>
 #include <utils/Vector.h>
 #include <system/audio.h>
 #include <cutils/config_utils.h>
+#include <string>
 
 namespace android {
 
 class IOProfile;
+class InputProfile;
+class OutputProfile;
+
+typedef Vector<sp<IOProfile> > InputProfileCollection;
+typedef Vector<sp<IOProfile> > OutputProfileCollection;
+typedef Vector<sp<IOProfile> > IOProfileCollection;
 
 class HwModule : public RefBase
 {
 public:
-    HwModule(const char *name);
+    HwModule(const char *name, uint32_t halVersion = AUDIO_DEVICE_API_VERSION_MIN);
     ~HwModule();
 
-    status_t loadOutput(cnode *root);
-    status_t loadInput(cnode *root);
-    status_t loadDevice(cnode *root);
+    const char *getName() const { return mName.string(); }
+
+
+    const DeviceVector &getDeclaredDevices() const { return mDeclaredDevices; }
+    void setDeclaredDevices(const DeviceVector &devices);
+
+    const InputProfileCollection &getInputProfiles() const { return mInputProfiles; }
+
+    const OutputProfileCollection &getOutputProfiles() const { return mOutputProfiles; }
+
+    void setProfiles(const IOProfileCollection &profiles);
+
+    void setHalVersion(uint32_t halVersion) { mHalVersion = halVersion; }
+    uint32_t getHalVersion() const { return mHalVersion; }
+
+    sp<DeviceDescriptor> getRouteSinkDevice(const sp<AudioRoute> &route) const;
+    DeviceVector getRouteSourceDevices(const sp<AudioRoute> &route) const;
+    void setRoutes(const AudioRouteVector &routes);
+
+    status_t addOutputProfile(const sp<IOProfile> &profile);
+    status_t addInputProfile(const sp<IOProfile> &profile);
+    status_t addProfile(const sp<IOProfile> &profile);
 
     status_t addOutputProfile(String8 name, const audio_config_t *config,
             audio_devices_t device, String8 address);
@@ -47,26 +75,38 @@
 
     audio_module_handle_t getHandle() const { return mHandle; }
 
+    sp<AudioPort> findPortByTagName(const String8 &tagName) const
+    {
+        return mPorts.findByTagName(tagName);
+    }
+
+    // TODO remove from here (split serialization)
     void dump(int fd);
 
-    const char *const        mName; // base name of the audio HW module (primary, a2dp ...)
-    uint32_t                 mHalVersion; // audio HAL API version
-    audio_module_handle_t    mHandle;
-    Vector < sp<IOProfile> > mOutputProfiles; // output profiles exposed by this module
-    Vector < sp<IOProfile> > mInputProfiles;  // input profiles exposed by this module
-    DeviceVector             mDeclaredDevices; // devices declared in audio_policy.conf
+    const String8 mName; // base name of the audio HW module (primary, a2dp ...)
+    audio_module_handle_t mHandle;
+    OutputProfileCollection mOutputProfiles; // output profiles exposed by this module
+    InputProfileCollection mInputProfiles;  // input profiles exposed by this module
+
+private:
+    void refreshSupportedDevices();
+
+    uint32_t mHalVersion; // audio HAL API version
+    DeviceVector mDeclaredDevices; // devices declared in audio_policy configuration file.
+    AudioRouteVector mRoutes;
+    AudioPortVector mPorts;
 };
 
-class HwModuleCollection : public Vector< sp<HwModule> >
+class HwModuleCollection : public Vector<sp<HwModule> >
 {
 public:
     sp<HwModule> getModuleFromName(const char *name) const;
 
-    sp <HwModule> getModuleForDevice(audio_devices_t device) const;
+    sp<HwModule> getModuleForDevice(audio_devices_t device) const;
 
-    sp<DeviceDescriptor>  getDeviceDescriptor(const audio_devices_t device,
-                                              const char *device_address,
-                                              const char *device_name) const;
+    sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t device,
+                                             const char *device_address,
+                                             const char *device_name) const;
 
     status_t dump(int fd) const;
 };
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index ab6fcc1..eae9586 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -33,8 +33,11 @@
 class IOProfile : public AudioPort
 {
 public:
-    IOProfile(const String8& name, audio_port_role_t role);
-    virtual ~IOProfile();
+    IOProfile(const String8 &name, audio_port_role_t role)
+        : AudioPort(name, AUDIO_PORT_TYPE_MIX, role) {}
+
+    // For a Profile aka MixPort, tag name and name are equivalent.
+    virtual const String8 getTagName() const { return getName(); }
 
     // This method is used for both output and input.
     // If parameter updatedSamplingRate is non-NULL, it is assigned the actual sample rate.
@@ -53,8 +56,67 @@
     void dump(int fd);
     void log();
 
-    DeviceVector  mSupportedDevices; // supported devices
-                                     // (devices this output can be routed to)
+    bool hasSupportedDevices() const { return !mSupportedDevices.isEmpty(); }
+
+    bool supportDevice(audio_devices_t device) const
+    {
+        if (audio_is_output_devices(device)) {
+            return mSupportedDevices.types() & device;
+        }
+        return mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN);
+    }
+
+    bool supportDeviceAddress(const String8 &address) const
+    {
+        return mSupportedDevices[0]->mAddress == address;
+    }
+
+    // chose first device present in mSupportedDevices also part of deviceType
+    audio_devices_t getSupportedDeviceForType(audio_devices_t deviceType) const
+    {
+        for (size_t k = 0; k  < mSupportedDevices.size(); k++) {
+            audio_devices_t profileType = mSupportedDevices[k]->type();
+            if (profileType & deviceType) {
+                return profileType;
+            }
+        }
+        return AUDIO_DEVICE_NONE;
+    }
+
+    audio_devices_t getSupportedDevicesType() const { return mSupportedDevices.types(); }
+
+    void clearSupportedDevices() { mSupportedDevices.clear(); }
+    void addSupportedDevice(const sp<DeviceDescriptor> &device)
+    {
+        mSupportedDevices.add(device);
+    }
+
+    void setSupportedDevices(const DeviceVector &devices)
+    {
+        mSupportedDevices = devices;
+    }
+
+    sp<DeviceDescriptor> getSupportedDeviceByAddress(audio_devices_t type, String8 address) const
+    {
+        return mSupportedDevices.getDevice(type, address);
+    }
+
+    const DeviceVector &getSupportedDevices() const { return mSupportedDevices; }
+
+private:
+    DeviceVector mSupportedDevices; // supported devices: this input/output can be routed from/to
+};
+
+class InputProfile : public IOProfile
+{
+public:
+    InputProfile(const String8 &name) : IOProfile(name, AUDIO_PORT_ROLE_SINK) {}
+};
+
+class OutputProfile : public IOProfile
+{
+public:
+    OutputProfile(const String8 &name) : IOProfile(name, AUDIO_PORT_ROLE_SOURCE) {}
 };
 
 }; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h
new file mode 100644
index 0000000..8dc3eda
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#pragma once
+
+#include <system/audio.h>
+#include <Volume.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class IVolumeCurvesCollection
+{
+public:
+    virtual void clearCurrentVolumeIndex(audio_stream_type_t stream) = 0;
+    virtual void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device,
+                                       int index) = 0;
+    virtual bool canBeMuted(audio_stream_type_t stream) = 0;
+    virtual int getVolumeIndexMin(audio_stream_type_t stream) const = 0;
+    virtual int getVolumeIndex(audio_stream_type_t stream, audio_devices_t device) = 0;
+    virtual int getVolumeIndexMax(audio_stream_type_t stream) const = 0;
+    virtual float volIndexToDb(audio_stream_type_t stream, device_category device,
+                               int indexInUi) const = 0;
+    virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax) = 0;
+
+    virtual void initializeVolumeCurves(bool /*isSpeakerDrcEnabled*/) {}
+    virtual void switchVolumeCurve(audio_stream_type_t src, audio_stream_type_t dst) = 0;
+    virtual void restoreOriginVolumeCurve(audio_stream_type_t stream)
+    {
+        switchVolumeCurve(stream, stream);
+    }
+
+    virtual status_t dump(int fd) const = 0;
+
+protected:
+    virtual ~IVolumeCurvesCollection() {}
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/Serializer.h b/services/audiopolicy/common/managerdefinitions/include/Serializer.h
new file mode 100644
index 0000000..078b582
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/Serializer.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#pragma once
+
+#include "AudioPolicyConfig.h"
+#include <utils/StrongPointer.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <string>
+#include <sstream>
+#include <fstream>
+
+struct _xmlNode;
+struct _xmlDoc;
+
+namespace android {
+
+struct AudioGainTraits
+{
+    static const char *const tag;
+    static const char *const collectionTag;
+
+    struct Attributes
+    {
+        static const char mode[]; /**< gain modes supported, e.g. AUDIO_GAIN_MODE_CHANNELS. */
+        /** controlled channels, needed if mode AUDIO_GAIN_MODE_CHANNELS. */
+        static const char channelMask[];
+        static const char minValueMB[]; /**< min value in millibel. */
+        static const char maxValueMB[]; /**< max value in millibel. */
+        static const char defaultValueMB[]; /**< default value in millibel. */
+        static const char stepValueMB[]; /**< step value in millibel. */
+        static const char minRampMs[]; /**< needed if mode AUDIO_GAIN_MODE_RAMP. */
+        static const char maxRampMs[]; /**< .needed if mode AUDIO_GAIN_MODE_RAMP */
+    };
+
+    typedef AudioGain Element;
+    typedef sp<Element> PtrElement;
+    typedef AudioGainCollection Collection;
+    typedef void *PtrSerializingCtx;
+
+    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+                                PtrSerializingCtx serializingContext);
+
+    // Gain has no child
+};
+
+// A profile section contains a name,  one audio format and the list of supported sampling rates
+// and channel masks for this format
+struct AudioProfileTraits
+{
+    static const char *const tag;
+    static const char *const collectionTag;
+
+    struct Attributes
+    {
+        static const char name[];
+        static const char samplingRates[];
+        static const char format[];
+        static const char channelMasks[];
+    };
+
+    typedef AudioProfile Element;
+    typedef sp<AudioProfile> PtrElement;
+    typedef AudioProfileVector Collection;
+    typedef void *PtrSerializingCtx;
+
+    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+                                PtrSerializingCtx serializingContext);
+};
+
+struct MixPortTraits
+{
+    static const char *const tag;
+    static const char *const collectionTag;
+
+    struct Attributes
+    {
+        static const char name[];
+        static const char role[];
+        static const char flags[];
+    };
+
+    typedef IOProfile Element;
+    typedef sp<Element> PtrElement;
+    typedef IOProfileCollection Collection;
+    typedef void *PtrSerializingCtx;
+
+    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+                                PtrSerializingCtx serializingContext);
+
+    // Children are: GainTraits
+};
+
+struct DevicePortTraits
+{
+    static const char *const tag;
+    static const char *const collectionTag;
+
+    struct Attributes
+    {
+        static const char tagName[]; /**<  <device tag name>: any string without space. */
+        static const char type[]; /**< <device type>. */
+        static const char role[]; /**< <device role: sink or source>. */
+        static const char roleSource[]; /**< <attribute role source value>. */
+        static const char address[]; /**< optional: device address, char string less than 64. */
+    };
+    typedef DeviceDescriptor Element;
+    typedef sp<DeviceDescriptor> PtrElement;
+    typedef DeviceVector Collection;
+    typedef void *PtrSerializingCtx;
+
+    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+                                PtrSerializingCtx serializingContext);
+    // Children are: GainTraits (optionnal)
+};
+
+struct RouteTraits
+{
+    static const char *const tag;
+    static const char *const collectionTag;
+
+    struct Attributes
+    {
+        static const char type[]; /**< <route type>: mix or mux. */
+        static const char typeMix[]; /**< type attribute mix value. */
+        static const char sink[]; /**< <sink: involved in this route>. */
+        static const char sources[]; /**< sources: all source that can be involved in this route. */
+    };
+    typedef AudioRoute Element;
+    typedef sp<AudioRoute> PtrElement;
+    typedef AudioRouteVector Collection;
+    typedef HwModule *PtrSerializingCtx;
+
+    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+                                PtrSerializingCtx ctx);
+};
+
+struct ModuleTraits
+{
+    static const char *const tag;
+    static const char *const collectionTag;
+
+    static const char *const childAttachedDevicesTag;
+    static const char *const childAttachedDeviceTag;
+    static const char *const childDefaultOutputDeviceTag;
+
+    struct Attributes
+    {
+        static const char name[];
+        static const char version[];
+    };
+
+    typedef HwModule Element;
+    typedef sp<Element> PtrElement;
+    typedef HwModuleCollection Collection;
+    typedef AudioPolicyConfig *PtrSerializingCtx;
+
+    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+                                PtrSerializingCtx serializingContext);
+
+    // Children are: mixPortTraits, devicePortTraits and routeTraits
+    // Need to call deserialize on each child
+};
+
+struct GlobalConfigTraits
+{
+    static const char *const tag;
+
+    struct Attributes
+    {
+        static const char speakerDrcEnabled[];
+    };
+
+    static status_t deserialize(const _xmlNode *root, AudioPolicyConfig &config);
+};
+
+struct VolumeTraits
+{
+    static const char *const tag;
+    static const char *const collectionTag;
+    static const char *const volumePointTag;
+
+    struct Attributes
+    {
+        static const char stream[];
+        static const char deviceCategory[];
+        static const char reference[];
+    };
+
+    typedef VolumeCurve Element;
+    typedef sp<VolumeCurve> PtrElement;
+    typedef VolumeCurvesCollection Collection;
+    typedef void *PtrSerializingCtx;
+
+    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+                                PtrSerializingCtx serializingContext);
+
+    // No Child
+};
+
+class PolicySerializer
+{
+private:
+    static const char *const rootName;
+
+    static const char *const versionAttribute;
+    static const uint32_t gMajor; /**< the major number of the policy xml format version. */
+    static const uint32_t gMinor; /**< the minor number of the policy xml format version. */
+
+public:
+    PolicySerializer();
+    status_t deserialize(const char *str, AudioPolicyConfig &config);
+
+private:
+    typedef AudioPolicyConfig Element;
+
+    std::string mRootElementName;
+    std::string mVersion;
+
+    // Children are: ModulesTraits, VolumeTraits
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
index 84db5ab..af178f9 100644
--- a/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
@@ -16,7 +16,7 @@
 
 #pragma once
 
-#include <Volume.h>
+#include "IVolumeCurvesCollection.h"
 #include <utils/KeyedVector.h>
 #include <utils/StrongPointer.h>
 #include <utils/SortedVector.h>
@@ -41,14 +41,14 @@
 
     void dump(int fd) const;
 
-    void setVolumeCurvePoint(Volume::device_category deviceCategory, const VolumeCurvePoint *point);
-    const VolumeCurvePoint *getVolumeCurvePoint(Volume::device_category deviceCategory) const
+    void setVolumeCurvePoint(device_category deviceCategory, const VolumeCurvePoint *point);
+    const VolumeCurvePoint *getVolumeCurvePoint(device_category deviceCategory) const
     {
         return mVolumeCurve[deviceCategory];
     }
 
 private:
-    const VolumeCurvePoint *mVolumeCurve[Volume::DEVICE_CATEGORY_CNT];
+    const VolumeCurvePoint *mVolumeCurve[DEVICE_CATEGORY_CNT];
     KeyedVector<audio_devices_t, int> mIndexCur; /**< current volume index per device. */
     int mIndexMin; /**< min volume index. */
     int mIndexMax; /**< max volume index. */
@@ -58,28 +58,43 @@
 /**
  * stream descriptors collection for volume control
  */
-class StreamDescriptorCollection : public DefaultKeyedVector<audio_stream_type_t, StreamDescriptor>
+class StreamDescriptorCollection : public DefaultKeyedVector<audio_stream_type_t, StreamDescriptor>,
+                                   public IVolumeCurvesCollection
 {
 public:
     StreamDescriptorCollection();
 
-    void clearCurrentVolumeIndex(audio_stream_type_t stream);
-    void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device, int index);
+    virtual void clearCurrentVolumeIndex(audio_stream_type_t stream);
+    virtual void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device,
+                                       int index);
+    virtual bool canBeMuted(audio_stream_type_t stream);
+    virtual int getVolumeIndexMin(audio_stream_type_t stream) const
+    {
+        return valueFor(stream).getVolumeIndexMin();
+    }
+    virtual int getVolumeIndex(audio_stream_type_t stream, audio_devices_t device)
+    {
+        return valueFor(stream).getVolumeIndex(device);
+    }
+    virtual int getVolumeIndexMax(audio_stream_type_t stream) const
+    {
+        return valueFor(stream).getVolumeIndexMax();
+    }
+    virtual float volIndexToDb(audio_stream_type_t stream, device_category device,
+                               int indexInUi) const;
+    virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax);
+    virtual void initializeVolumeCurves(bool isSpeakerDrcEnabled);
+    virtual void switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst);
 
-    bool canBeMuted(audio_stream_type_t stream);
+    virtual status_t dump(int fd) const;
 
-    status_t dump(int fd) const;
-
-    void setVolumeCurvePoint(audio_stream_type_t stream,
-                             Volume::device_category deviceCategory,
+private:
+    void setVolumeCurvePoint(audio_stream_type_t stream, device_category deviceCategory,
                              const VolumeCurvePoint *point);
-
     const VolumeCurvePoint *getVolumeCurvePoint(audio_stream_type_t stream,
-                                                Volume::device_category deviceCategory) const;
-
+                                                device_category deviceCategory) const;
     void setVolumeIndexMin(audio_stream_type_t stream,int volIndexMin);
     void setVolumeIndexMax(audio_stream_type_t stream,int volIndexMax);
-
 };
 
 }; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
new file mode 100644
index 0000000..b828f81
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#pragma once
+
+#include "policy.h"
+#include <Volume.h>
+#include <system/audio.h>
+#include <convert/convert.h>
+#include <utils/Log.h>
+#include <string>
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+
+namespace android {
+
+struct SampleRateTraits
+{
+    typedef uint32_t Type;
+    typedef SortedVector<Type> Collection;
+};
+struct DeviceTraits
+{
+    typedef audio_devices_t Type;
+    typedef Vector<Type> Collection;
+};
+struct OutputFlagTraits
+{
+    typedef audio_output_flags_t Type;
+    typedef Vector<Type> Collection;
+};
+struct InputFlagTraits
+{
+    typedef audio_input_flags_t Type;
+    typedef Vector<Type> Collection;
+};
+struct FormatTraits
+{
+    typedef audio_format_t Type;
+    typedef Vector<Type> Collection;
+};
+struct ChannelTraits
+{
+    typedef audio_channel_mask_t Type;
+    typedef SortedVector<Type> Collection;
+};
+struct OutputChannelTraits : public ChannelTraits {};
+struct InputChannelTraits : public ChannelTraits {};
+struct ChannelIndexTraits : public ChannelTraits {};
+struct GainModeTraits
+{
+    typedef audio_gain_mode_t Type;
+    typedef Vector<Type> Collection;
+};
+struct StreamTraits
+{
+  typedef audio_stream_type_t Type;
+  typedef Vector<Type> Collection;
+};
+struct DeviceCategoryTraits
+{
+  typedef device_category Type;
+  typedef Vector<Type> Collection;
+};
+template <typename T>
+struct DefaultTraits
+{
+  typedef T Type;
+  typedef Vector<Type> Collection;
+};
+
+template <class Traits>
+static void collectionFromString(const std::string &str, typename Traits::Collection &collection,
+                                 const char *del = "|")
+{
+    char *literal = strdup(str.c_str());
+    for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+        typename Traits::Type value;
+        if (utilities::convertTo<std::string, typename Traits::Type >(cstr, value)) {
+            collection.add(value);
+        }
+    }
+    free(literal);
+}
+
+template <class Traits>
+class TypeConverter
+{
+public:
+    static bool toString(const typename Traits::Type &value, std::string &str);
+
+    static bool fromString(const std::string &str, typename Traits::Type &result);
+
+    static void collectionFromString(const std::string &str,
+                                     typename Traits::Collection &collection,
+                                     const char *del = "|");
+
+    static uint32_t maskFromString(const std::string &str, const char *del = "|");
+
+protected:
+    struct Table {
+        const char *literal;
+        typename Traits::Type value;
+    };
+
+    static const Table mTable[];
+    static const size_t mSize;
+};
+
+typedef TypeConverter<DeviceTraits> DeviceConverter;
+typedef TypeConverter<OutputFlagTraits> OutputFlagConverter;
+typedef TypeConverter<InputFlagTraits> InputFlagConverter;
+typedef TypeConverter<FormatTraits> FormatConverter;
+typedef TypeConverter<OutputChannelTraits> OutputChannelConverter;
+typedef TypeConverter<InputChannelTraits> InputChannelConverter;
+typedef TypeConverter<ChannelIndexTraits> ChannelIndexConverter;
+typedef TypeConverter<GainModeTraits> GainModeConverter;
+typedef TypeConverter<StreamTraits> StreamTypeConverter;
+typedef TypeConverter<DeviceCategoryTraits> DeviceCategoryConverter;
+
+static SampleRateTraits::Collection samplingRatesFromString(const std::string &samplingRates,
+                                                            const char *del = "|")
+{
+    SampleRateTraits::Collection samplingRateCollection;
+    collectionFromString<SampleRateTraits>(samplingRates, samplingRateCollection, del);
+    return samplingRateCollection;
+}
+
+static FormatTraits::Collection formatsFromString(const std::string &formats, const char *del = "|")
+{
+    FormatTraits::Collection formatCollection;
+    FormatConverter::collectionFromString(formats, formatCollection, del);
+    return formatCollection;
+}
+
+static audio_format_t formatFromString(const std::string &literalFormat)
+{
+    audio_format_t format;
+    if (literalFormat.empty()) {
+        return gDynamicFormat;
+    }
+    FormatConverter::fromString(literalFormat, format);
+    return format;
+}
+
+static audio_channel_mask_t channelMaskFromString(const std::string &literalChannels)
+{
+    audio_channel_mask_t channels;
+    if (!OutputChannelConverter::fromString(literalChannels, channels) ||
+            !InputChannelConverter::fromString(literalChannels, channels)) {
+        return AUDIO_CHANNEL_INVALID;
+    }
+    return channels;
+}
+
+static ChannelTraits::Collection channelMasksFromString(const std::string &channels,
+                                                        const char *del = "|")
+{
+    ChannelTraits::Collection channelMaskCollection;
+    OutputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
+    InputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
+    ChannelIndexConverter::collectionFromString(channels, channelMaskCollection, del);
+    return channelMaskCollection;
+}
+
+static InputChannelTraits::Collection inputChannelMasksFromString(const std::string &inChannels,
+                                                                  const char *del = "|")
+{
+    InputChannelTraits::Collection inputChannelMaskCollection;
+    InputChannelConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
+    ChannelIndexConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
+    return inputChannelMaskCollection;
+}
+
+static OutputChannelTraits::Collection outputChannelMasksFromString(const std::string &outChannels,
+                                                                    const char *del = "|")
+{
+    OutputChannelTraits::Collection outputChannelMaskCollection;
+    OutputChannelConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
+    ChannelIndexConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
+    return outputChannelMaskCollection;
+}
+
+}; // namespace android
+
diff --git a/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h b/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
new file mode 100644
index 0000000..009a26f
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#pragma once
+
+#include "IVolumeCurvesCollection.h"
+#include <policy.h>
+#include <hardware/audio.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+#include <string>
+#include <utility>
+
+namespace android {
+
+struct CurvePoint
+{
+    CurvePoint() {}
+    CurvePoint(int index, int attenuationInMb) :
+        mIndex(index), mAttenuationInMb(attenuationInMb) {}
+    uint32_t mIndex;
+    int mAttenuationInMb;
+};
+
+inline bool operator< (const CurvePoint &lhs, const CurvePoint &rhs)
+{
+    return lhs.mIndex < rhs.mIndex;
+}
+
+// A volume curve for a given use case and device cateory
+// It contains of list of points of this cuive expressing the atteunation in Millibels for
+// a given volume index from 0 to 100
+class VolumeCurve : public RefBase
+{
+public:
+    VolumeCurve(device_category device, audio_stream_type_t stream) :
+        mDeviceCategory(device), mStreamType(stream) {}
+
+    device_category getDeviceCategory() const { return mDeviceCategory; }
+    audio_stream_type_t getStreamType() const { return mStreamType; }
+
+    void add(const CurvePoint &point) { mCurvePoints.add(point); }
+
+    float volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const;
+
+    void dump(int fd) const;
+
+private:
+    SortedVector<CurvePoint> mCurvePoints;
+    device_category mDeviceCategory;
+    audio_stream_type_t mStreamType;
+};
+
+// Volume Curves for a given use case indexed by device category
+class VolumeCurvesForStream : public KeyedVector<device_category, sp<VolumeCurve> >
+{
+public:
+    VolumeCurvesForStream() : mIndexMin(0), mIndexMax(1), mCanBeMuted(true)
+    {
+        mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0);
+    }
+
+    sp<VolumeCurve> getCurvesFor(device_category device) const
+    {
+        if (indexOfKey(device) < 0) {
+            return 0;
+        }
+        return valueFor(device);
+    }
+
+    int getVolumeIndex(audio_devices_t device) const
+    {
+        device = Volume::getDeviceForVolume(device);
+        // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT
+        if (mIndexCur.indexOfKey(device) < 0) {
+            device = AUDIO_DEVICE_OUT_DEFAULT;
+        }
+        return mIndexCur.valueFor(device);
+    }
+
+    bool canBeMuted() const { return mCanBeMuted; }
+    void clearCurrentVolumeIndex() { mIndexCur.clear(); }
+    void addCurrentVolumeIndex(audio_devices_t device, int index) { mIndexCur.add(device, index); }
+
+    void setVolumeIndexMin(int volIndexMin) { mIndexMin = volIndexMin; }
+    int getVolumeIndexMin() const { return mIndexMin; }
+
+    void setVolumeIndexMax(int volIndexMax) { mIndexMax = volIndexMax; }
+    int getVolumeIndexMax() const { return mIndexMax; }
+
+    const sp<VolumeCurve> getOriginVolumeCurve(device_category deviceCategory) const
+    {
+        ALOG_ASSERT(mOriginVolumeCurves.indexOfKey(deviceCategory) >= 0, "Invalid device category");
+        return mOriginVolumeCurves.valueFor(deviceCategory);
+    }
+    void setVolumeCurve(device_category deviceCategory, const sp<VolumeCurve> &volumeCurve)
+    {
+        ALOG_ASSERT(indexOfKey(deviceCategory) >= 0, "Invalid device category for Volume Curve");
+        replaceValueFor(deviceCategory, volumeCurve);
+    }
+
+    ssize_t add(const sp<VolumeCurve> &volumeCurve)
+    {
+        device_category deviceCategory = volumeCurve->getDeviceCategory();
+        ssize_t index = indexOfKey(deviceCategory);
+        if (index < 0) {
+            // Keep track of original Volume Curves per device category in order to switch curves.
+            mOriginVolumeCurves.add(deviceCategory, volumeCurve);
+            return KeyedVector::add(deviceCategory, volumeCurve);
+        }
+        return index;
+    }
+
+    float volIndexToDb(device_category deviceCat, int indexInUi) const
+    {
+        return getCurvesFor(deviceCat)->volIndexToDb(indexInUi, mIndexMin, mIndexMax);
+    }
+
+    void dump(int fd, int spaces, bool curvePoints = false) const;
+
+private:
+    KeyedVector<device_category, sp<VolumeCurve> > mOriginVolumeCurves;
+    KeyedVector<audio_devices_t, int> mIndexCur; /**< current volume index per device. */
+    int mIndexMin; /**< min volume index. */
+    int mIndexMax; /**< max volume index. */
+    bool mCanBeMuted; /**< true is the stream can be muted. */
+};
+
+// Collection of Volume Curves indexed by use case
+class VolumeCurvesCollection : public KeyedVector<audio_stream_type_t, VolumeCurvesForStream>,
+                               public IVolumeCurvesCollection
+{
+public:
+    VolumeCurvesCollection()
+    {
+        // Create an empty collection of curves
+        for (ssize_t i = 0 ; i < AUDIO_STREAM_CNT; i++) {
+            audio_stream_type_t stream = static_cast<audio_stream_type_t>(i);
+            KeyedVector::add(stream, VolumeCurvesForStream());
+        }
+    }
+
+    // Once XML has been parsed, must be call first to sanity check table and initialize indexes
+    virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax)
+    {
+        editValueAt(stream).setVolumeIndexMin(indexMin);
+        editValueAt(stream).setVolumeIndexMax(indexMax);
+        return NO_ERROR;
+    }
+    virtual void clearCurrentVolumeIndex(audio_stream_type_t stream)
+    {
+        editCurvesFor(stream).clearCurrentVolumeIndex();
+    }
+    virtual void addCurrentVolumeIndex(audio_stream_type_t stream, audio_devices_t device, int index)
+    {
+        editCurvesFor(stream).addCurrentVolumeIndex(device, index);
+    }
+    virtual bool canBeMuted(audio_stream_type_t stream) { return getCurvesFor(stream).canBeMuted(); }
+
+    virtual int getVolumeIndexMin(audio_stream_type_t stream) const
+    {
+        return getCurvesFor(stream).getVolumeIndexMin();
+    }
+    virtual int getVolumeIndexMax(audio_stream_type_t stream) const
+    {
+        return getCurvesFor(stream).getVolumeIndexMax();
+    }
+    virtual int getVolumeIndex(audio_stream_type_t stream, audio_devices_t device)
+    {
+        return getCurvesFor(stream).getVolumeIndex(device);
+    }
+    virtual void switchVolumeCurve(audio_stream_type_t streamSrc, audio_stream_type_t streamDst)
+    {
+        const VolumeCurvesForStream &sourceCurves = getCurvesFor(streamSrc);
+        VolumeCurvesForStream &dstCurves = editCurvesFor(streamDst);
+        ALOG_ASSERT(sourceCurves.size() == dstCurves.size(), "device category not aligned");
+        for (size_t index = 0; index < sourceCurves.size(); index++) {
+            device_category cat = sourceCurves.keyAt(index);
+            dstCurves.setVolumeCurve(cat, sourceCurves.getOriginVolumeCurve(cat));
+        }
+    }
+    virtual float volIndexToDb(audio_stream_type_t stream, device_category cat, int indexInUi) const
+    {
+        return getCurvesFor(stream).volIndexToDb(cat, indexInUi);
+    }
+
+    virtual status_t dump(int fd) const;
+
+    ssize_t add(const sp<VolumeCurve> &volumeCurve)
+    {
+        audio_stream_type_t streamType = volumeCurve->getStreamType();
+        return editCurvesFor(streamType).add(volumeCurve);
+    }
+    VolumeCurvesForStream &editCurvesFor(audio_stream_type_t stream)
+    {
+        ALOG_ASSERT(indexOfKey(stream) >= 0, "Invalid stream type for Volume Curve");
+        return editValueAt(stream);
+    }
+    const VolumeCurvesForStream &getCurvesFor(audio_stream_type_t stream) const
+    {
+        ALOG_ASSERT(indexOfKey(stream) >= 0, "Invalid stream type for Volume Curve");
+        return valueFor(stream);
+    }
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h b/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
index a393e3b..0a27947 100644
--- a/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
+++ b/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
@@ -47,10 +47,6 @@
 #define DEVICES_TAG "devices"
 #define FLAGS_TAG "flags"
 
-#define DYNAMIC_VALUE_TAG "dynamic" // special value for "channel_masks", "sampling_rates" and
-                                    // "formats" in outputs descriptors indicating that supported
-                                    // values should be queried after opening the output.
-
 #define APM_DEVICES_TAG "devices"
 #define APM_DEVICE_TYPE "type"
 #define APM_DEVICE_ADDRESS "address"
@@ -69,3 +65,7 @@
 #define GAIN_STEP_VALUE "step_value_mB"
 #define GAIN_MIN_RAMP_MS "min_ramp_ms"
 #define GAIN_MAX_RAMP_MS "max_ramp_ms"
+
+#define DYNAMIC_VALUE_TAG "dynamic" // special value for "channel_masks", "sampling_rates" and
+                                    // "formats" in outputs descriptors indicating that supported
+                                    // values should be queried after opening the output.
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
new file mode 100644
index 0000000..635fe4d
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 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 "APM::AudioCollections"
+//#define LOG_NDEBUG 0
+
+#include "AudioCollections.h"
+#include "AudioPort.h"
+#include "AudioRoute.h"
+#include "HwModule.h"
+#include "AudioGain.h"
+
+namespace android {
+
+sp<AudioPort> AudioPortVector::findByTagName(const String8 &tagName) const
+{
+    sp<AudioPort> port = 0;
+    for (size_t i = 0; i < size(); i++) {
+        if (itemAt(i)->getTagName() == tagName) {
+            port = itemAt(i);
+            break;
+        }
+    }
+    return port;
+}
+
+status_t AudioRouteVector::dump(int fd, int spaces) const
+{
+    if (isEmpty()) {
+        return NO_ERROR;
+    }
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+
+    snprintf(buffer, SIZE, "\n%*sAudio Routes (%zu):\n", spaces, "", size());
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < size(); i++) {
+        snprintf(buffer, SIZE, "%*s- Route %zu:\n", spaces, "", i + 1);
+        write(fd, buffer, strlen(buffer));
+        itemAt(i)->dump(fd, 4);
+    }
+    return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
index fc7b0cc..e454941 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
@@ -25,7 +25,6 @@
 #endif
 
 #include "AudioGain.h"
-#include "StreamDescriptor.h"
 #include <utils/Log.h>
 #include <utils/String8.h>
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 626fdae..38d7ad5 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -28,13 +28,11 @@
 
 AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile)
     : mIoHandle(0),
-      mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0), mRefCount(0),
-      mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile), mIsSoundTrigger(false), mId(0)
+      mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0),
+      mProfile(profile), mId(0)
 {
     if (profile != NULL) {
-        mSamplingRate = profile->pickSamplingRate();
-        mFormat = profile->pickFormat();
-        mChannelMask = profile->pickChannelMask();
+        profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
         if (profile->mGains.size() > 0) {
             profile->mGains[0]->getDefaultConfig(&mGain);
         }
@@ -55,11 +53,23 @@
     return mProfile->getModuleHandle();
 }
 
+uint32_t AudioInputDescriptor::getOpenRefCount() const
+{
+    return mSessions.getOpenCount();
+}
+
 audio_port_handle_t AudioInputDescriptor::getId() const
 {
     return mId;
 }
 
+audio_source_t AudioInputDescriptor::inputSource() const
+{
+    // TODO: return highest priority input source
+    return mSessions.size() > 0 ? mSessions.valueAt(0)->inputSource() :
+                       AUDIO_SOURCE_DEFAULT;
+}
+
 void AudioInputDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
                                              const struct audio_port_config *srcConfig) const
 {
@@ -78,7 +88,7 @@
     dstConfig->type = AUDIO_PORT_TYPE_MIX;
     dstConfig->ext.mix.hw_module = getModuleHandle();
     dstConfig->ext.mix.handle = mIoHandle;
-    dstConfig->ext.mix.usecase.source = mInputSource;
+    dstConfig->ext.mix.usecase.source = inputSource();
 }
 
 void AudioInputDescriptor::toAudioPort(struct audio_port *port) const
@@ -113,6 +123,59 @@
     mPreemptedSessions.clear();
 }
 
+bool AudioInputDescriptor::isActive() const {
+    return mSessions.hasActiveSession();
+}
+
+bool AudioInputDescriptor::isSourceActive(audio_source_t source) const
+{
+    return mSessions.isSourceActive(source);
+}
+
+audio_source_t AudioInputDescriptor::getHighestPrioritySource(bool activeOnly) const
+{
+
+    return mSessions.getHighestPrioritySource(activeOnly);
+}
+
+bool AudioInputDescriptor::isSoundTrigger() const {
+    // sound trigger and non sound trigger sessions are not mixed
+    // on a given input
+    return mSessions.valueAt(0)->isSoundTrigger();
+}
+
+sp<AudioSession> AudioInputDescriptor::getAudioSession(
+                                              audio_session_t session) const {
+    return mSessions.valueFor(session);
+}
+
+AudioSessionCollection AudioInputDescriptor::getAudioSessions(bool activeOnly) const
+{
+    if (activeOnly) {
+        return mSessions.getActiveSessions();
+    } else {
+        return mSessions;
+    }
+}
+
+size_t AudioInputDescriptor::getAudioSessionCount(bool activeOnly) const
+{
+    if (activeOnly) {
+        return mSessions.getActiveSessionCount();
+    } else {
+        return mSessions.size();
+    }
+}
+
+status_t AudioInputDescriptor::addAudioSession(audio_session_t session,
+                         const sp<AudioSession>& audioSession) {
+    return mSessions.addSession(session, audioSession);
+}
+
+status_t AudioInputDescriptor::removeAudioSession(audio_session_t session) {
+    return mSessions.removeSession(session);
+}
+
 status_t AudioInputDescriptor::dump(int fd)
 {
     const size_t SIZE = 256;
@@ -129,13 +192,11 @@
     result.append(buffer);
     snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
     result.append(buffer);
-    snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount);
-    result.append(buffer);
-    snprintf(buffer, SIZE, " Open Ref Count %d\n", mOpenRefCount);
-    result.append(buffer);
 
     write(fd, result.string(), result.size());
 
+    mSessions.dump(fd, 1);
+
     return NO_ERROR;
 }
 
@@ -143,10 +204,7 @@
 {
     for (size_t i = 0; i < size(); i++) {
         const sp<AudioInputDescriptor>  inputDescriptor = valueAt(i);
-        if (inputDescriptor->mRefCount == 0) {
-            continue;
-        }
-        if (inputDescriptor->mInputSource == (int)source) {
+        if (inputDescriptor->isSourceActive(source)) {
             return true;
         }
     }
@@ -169,30 +227,33 @@
 {
     uint32_t count = 0;
     for (size_t i = 0; i < size(); i++) {
-        const sp<AudioInputDescriptor>  desc = valueAt(i);
-        if (desc->mRefCount > 0) {
+        const sp<AudioInputDescriptor>  inputDescriptor = valueAt(i);
+        if (inputDescriptor->isActive()) {
             count++;
         }
     }
     return count;
 }
 
-audio_io_handle_t AudioInputCollection::getActiveInput(bool ignoreVirtualInputs)
+Vector<sp <AudioInputDescriptor> > AudioInputCollection::getActiveInputs(bool ignoreVirtualInputs)
 {
+    Vector<sp <AudioInputDescriptor> > activeInputs;
+
     for (size_t i = 0; i < size(); i++) {
-        const sp<AudioInputDescriptor>  input_descriptor = valueAt(i);
-        if ((input_descriptor->mRefCount > 0)
-                && (!ignoreVirtualInputs || !is_virtual_input_device(input_descriptor->mDevice))) {
-            return keyAt(i);
+        const sp<AudioInputDescriptor>  inputDescriptor = valueAt(i);
+        if ((inputDescriptor->isActive())
+                && (!ignoreVirtualInputs ||
+                    !is_virtual_input_device(inputDescriptor->mDevice))) {
+            activeInputs.add(inputDescriptor);
         }
     }
-    return 0;
+    return activeInputs;
 }
 
 audio_devices_t AudioInputCollection::getSupportedDevices(audio_io_handle_t handle) const
 {
     sp<AudioInputDescriptor> inputDesc = valueFor(handle);
-    audio_devices_t devices = inputDesc->mProfile->mSupportedDevices.types();
+    audio_devices_t devices = inputDesc->mProfile->getSupportedDevicesType();
     return devices;
 }
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index a278375..f5927ab 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -47,9 +47,7 @@
         mStrategyMutedByDevice[i] = false;
     }
     if (port != NULL) {
-        mSamplingRate = port->pickSamplingRate();
-        mFormat = port->pickFormat();
-        mChannelMask = port->pickChannelMask();
+        port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
         if (port->mGains.size() > 0) {
             port->mGains[0]->getDefaultConfig(&mGain);
         }
@@ -83,7 +81,7 @@
         return sharesHwModuleWith(outputDesc->subOutput1()) ||
                     sharesHwModuleWith(outputDesc->subOutput2());
     } else {
-        return (getModuleHandle() == outputDesc->getModuleHandle());
+        return hasSameHwModuleAs(outputDesc);
     }
 }
 
@@ -220,15 +218,15 @@
 }
 
 // SwAudioOutputDescriptor implementation
-SwAudioOutputDescriptor::SwAudioOutputDescriptor(
-        const sp<IOProfile>& profile, AudioPolicyClientInterface *clientInterface)
+SwAudioOutputDescriptor::SwAudioOutputDescriptor(const sp<IOProfile>& profile,
+                                                 AudioPolicyClientInterface *clientInterface)
     : 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)
 {
     if (profile != NULL) {
-        mFlags = (audio_output_flags_t)profile->mFlags;
+        mFlags = (audio_output_flags_t)profile->getFlags();
     }
 }
 
@@ -283,7 +281,7 @@
     if (isDuplicated()) {
         return (audio_devices_t)(mOutput1->supportedDevices() | mOutput2->supportedDevices());
     } else {
-        return mProfile->mSupportedDevices.types() ;
+        return mProfile->getSupportedDevicesType();
     }
 }
 
@@ -388,8 +386,64 @@
     return changed;
 }
 
-// SwAudioOutputCollection implementation
+// HwAudioOutputDescriptor implementation
+HwAudioOutputDescriptor::HwAudioOutputDescriptor(const sp<AudioSourceDescriptor>& source,
+                                                 AudioPolicyClientInterface *clientInterface)
+    : AudioOutputDescriptor(source->mDevice, clientInterface),
+      mSource(source)
+{
+}
 
+status_t HwAudioOutputDescriptor::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    AudioOutputDescriptor::dump(fd);
+
+    snprintf(buffer, SIZE, "Source:\n");
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+    mSource->dump(fd);
+
+    return NO_ERROR;
+}
+
+audio_devices_t HwAudioOutputDescriptor::supportedDevices()
+{
+    return mDevice;
+}
+
+void HwAudioOutputDescriptor::toAudioPortConfig(
+                                                 struct audio_port_config *dstConfig,
+                                                 const struct audio_port_config *srcConfig) const
+{
+    mSource->mDevice->toAudioPortConfig(dstConfig, srcConfig);
+}
+
+void HwAudioOutputDescriptor::toAudioPort(
+                                                    struct audio_port *port) const
+{
+    mSource->mDevice->toAudioPort(port);
+}
+
+
+bool HwAudioOutputDescriptor::setVolume(float volume,
+                                        audio_stream_type_t stream,
+                                        audio_devices_t device,
+                                        uint32_t delayMs,
+                                        bool force)
+{
+    bool changed = AudioOutputDescriptor::setVolume(volume, stream, device, delayMs, force);
+
+    if (changed) {
+      // TODO: use gain controller on source device if any to adjust volume
+    }
+    return changed;
+}
+
+// SwAudioOutputCollection implementation
 bool SwAudioOutputCollection::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
 {
     nsecs_t sysTime = systemTime();
@@ -473,7 +527,7 @@
 audio_devices_t SwAudioOutputCollection::getSupportedDevices(audio_io_handle_t handle) const
 {
     sp<SwAudioOutputDescriptor> outputDesc = valueFor(handle);
-    audio_devices_t devices = outputDesc->mProfile->mSupportedDevices.types();
+    audio_devices_t devices = outputDesc->mProfile->getSupportedDevicesType();
     return devices;
 }
 
@@ -494,4 +548,49 @@
     return NO_ERROR;
 }
 
+// HwAudioOutputCollection implementation
+bool HwAudioOutputCollection::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
+{
+    nsecs_t sysTime = systemTime();
+    for (size_t i = 0; i < this->size(); i++) {
+        const sp<HwAudioOutputDescriptor> outputDesc = this->valueAt(i);
+        if (outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool HwAudioOutputCollection::isAnyOutputActive(audio_stream_type_t streamToIgnore) const
+{
+    for (size_t s = 0 ; s < AUDIO_STREAM_CNT ; s++) {
+        if (s == (size_t) streamToIgnore) {
+            continue;
+        }
+        for (size_t i = 0; i < size(); i++) {
+            const sp<HwAudioOutputDescriptor> outputDesc = valueAt(i);
+            if (outputDesc->mRefCount[s] != 0) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+status_t HwAudioOutputCollection::dump(int fd) const
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+
+    snprintf(buffer, SIZE, "\nOutputs dump:\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < size(); i++) {
+        snprintf(buffer, SIZE, "- Output %d dump:\n", keyAt(i));
+        write(fd, buffer, strlen(buffer));
+        valueAt(i)->dump(fd);
+    }
+
+    return NO_ERROR;
+}
+
 }; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
index a06d867..9c28e8f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
@@ -19,7 +19,7 @@
 
 #include "AudioPatch.h"
 #include "AudioGain.h"
-#include "ConfigParsingUtils.h"
+#include "TypeConverter.h"
 #include <cutils/log.h>
 #include <utils/String8.h>
 
@@ -53,10 +53,11 @@
     result.append(buffer);
     for (size_t i = 0; i < mPatch.num_sources; i++) {
         if (mPatch.sources[i].type == AUDIO_PORT_TYPE_DEVICE) {
+            std::string device;
+            DeviceConverter::toString(mPatch.sources[i].ext.device.type, device);
             snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
-                     mPatch.sources[i].id, ConfigParsingUtils::enumToString(sDeviceTypeToEnumTable,
-                                                        ARRAY_SIZE(sDeviceTypeToEnumTable),
-                                                        mPatch.sources[i].ext.device.type));
+                     mPatch.sources[i].id,
+                     device.c_str());
         } else {
             snprintf(buffer, SIZE, "%*s- Mix ID %d I/O handle %d\n", spaces + 2, "",
                      mPatch.sources[i].id, mPatch.sources[i].ext.mix.handle);
@@ -67,10 +68,11 @@
     result.append(buffer);
     for (size_t i = 0; i < mPatch.num_sinks; i++) {
         if (mPatch.sinks[i].type == AUDIO_PORT_TYPE_DEVICE) {
+            std::string device;
+            DeviceConverter::toString(mPatch.sinks[i].ext.device.type, device);
             snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
-                     mPatch.sinks[i].id, ConfigParsingUtils::enumToString(sDeviceTypeToEnumTable,
-                                                        ARRAY_SIZE(sDeviceTypeToEnumTable),
-                                                        mPatch.sinks[i].ext.device.type));
+                     mPatch.sinks[i].id,
+                     device.c_str());
         } else {
             snprintf(buffer, SIZE, "%*s- Mix ID %d I/O handle %d\n", spaces + 2, "",
                      mPatch.sinks[i].id, mPatch.sinks[i].ext.mix.handle);
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 6f1998c..3735c05 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -98,30 +98,111 @@
     }
 }
 
-status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attributes,
+status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attributes, uid_t uid,
                                                     sp<SwAudioOutputDescriptor> &desc)
 {
+    desc = 0;
     for (size_t i = 0; i < size(); i++) {
         sp<AudioPolicyMix> policyMix = valueAt(i);
         AudioMix *mix = policyMix->getMix();
 
         if (mix->mMixType == MIX_TYPE_PLAYERS) {
+            // TODO if adding more player rules (currently only 2), make rule handling "generic"
+            //      as there is no difference in the treatment of usage- or uid-based rules
+            bool hasUsageMatchRules = false;
+            bool hasUsageExcludeRules = false;
+            bool usageMatchFound = false;
+            bool usageExclusionFound = false;
+
+            bool hasUidMatchRules = false;
+            bool hasUidExcludeRules = false;
+            bool uidMatchFound = false;
+            bool uidExclusionFound = false;
+
+            bool hasAddrMatch = false;
+
+            // iterate over all mix criteria to list what rules this mix contains
             for (size_t j = 0; j < mix->mCriteria.size(); j++) {
-                if ((RULE_MATCH_ATTRIBUTE_USAGE == mix->mCriteria[j].mRule &&
-                     mix->mCriteria[j].mAttr.mUsage == attributes.usage) ||
-                        (RULE_EXCLUDE_ATTRIBUTE_USAGE == mix->mCriteria[j].mRule &&
-                         mix->mCriteria[j].mAttr.mUsage != attributes.usage)) {
-                    desc = policyMix->getOutput();
-                    break;
-                }
+                ALOGV("getOutputForAttr: inspecting mix %zu of %zu", i, mix->mCriteria.size());
+
+                // if there is an address match, prioritize that match
                 if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
                         strncmp(attributes.tags + strlen("addr="),
                                 mix->mRegistrationId.string(),
                                 AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
-                    desc = policyMix->getOutput();
+                    hasAddrMatch = true;
                     break;
                 }
+
+                switch (mix->mCriteria[j].mRule) {
+                case RULE_MATCH_ATTRIBUTE_USAGE:
+                    ALOGV("\tmix has RULE_MATCH_ATTRIBUTE_USAGE for usage %d",
+                                                mix->mCriteria[j].mValue.mUsage);
+                    hasUsageMatchRules = true;
+                    if (mix->mCriteria[j].mValue.mUsage == attributes.usage) {
+                        // found one match against all allowed usages
+                        usageMatchFound = true;
+                    }
+                    break;
+                case RULE_EXCLUDE_ATTRIBUTE_USAGE:
+                    ALOGV("\tmix has RULE_EXCLUDE_ATTRIBUTE_USAGE for usage %d",
+                            mix->mCriteria[j].mValue.mUsage);
+                    hasUsageExcludeRules = true;
+                    if (mix->mCriteria[j].mValue.mUsage == attributes.usage) {
+                        // found this usage is to be excluded
+                        usageExclusionFound = true;
+                    }
+                    break;
+                case RULE_MATCH_UID:
+                    ALOGV("\tmix has RULE_MATCH_UID for uid %d", mix->mCriteria[j].mValue.mUid);
+                    hasUidMatchRules = true;
+                    if (mix->mCriteria[j].mValue.mUid == uid) {
+                        // found one UID match against all allowed UIDs
+                        uidMatchFound = true;
+                    }
+                    break;
+                case RULE_EXCLUDE_UID:
+                    ALOGV("\tmix has RULE_EXCLUDE_UID for uid %d", mix->mCriteria[j].mValue.mUid);
+                    hasUidExcludeRules = true;
+                    if (mix->mCriteria[j].mValue.mUid == uid) {
+                        // found this UID is to be excluded
+                        uidExclusionFound = true;
+                    }
+                    break;
+                default:
+                    break;
+                }
+
+                // consistency checks: for each "dimension" of rules (usage, uid...), we can
+                // only have MATCH rules, or EXCLUDE rules in each dimension, not a combination
+                if (hasUsageMatchRules && hasUsageExcludeRules) {
+                    ALOGE("getOutputForAttr: invalid combination of RULE_MATCH_ATTRIBUTE_USAGE"
+                            " and RULE_EXCLUDE_ATTRIBUTE_USAGE in mix %zu", i);
+                    return BAD_VALUE;
+                }
+                if (hasUidMatchRules && hasUidExcludeRules) {
+                    ALOGE("getOutputForAttr: invalid combination of RULE_MATCH_UID"
+                            " and RULE_EXCLUDE_UID in mix %zu", i);
+                    return BAD_VALUE;
+                }
+
+                if ((hasUsageExcludeRules && usageExclusionFound)
+                        || (hasUidExcludeRules && uidExclusionFound)) {
+                    break; // stop iterating on criteria because an exclusion was found (will fail)
+                }
+
+            }//iterate on mix criteria
+
+            // determine if exiting on success (or implicit failure as desc is 0)
+            if (hasAddrMatch ||
+                    !((hasUsageExcludeRules && usageExclusionFound) ||
+                      (hasUsageMatchRules && !usageMatchFound)  ||
+                      (hasUidExcludeRules && uidExclusionFound) ||
+                      (hasUidMatchRules && !uidMatchFound))) {
+                ALOGV("\tgetOutputForAttr will use mix %zu", i);
+                desc = policyMix->getOutput();
             }
+
         } else if (mix->mMixType == MIX_TYPE_RECORDERS) {
             if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE &&
                     strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
@@ -151,9 +232,9 @@
         }
         for (size_t j = 0; j < mix->mCriteria.size(); j++) {
             if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule &&
-                    mix->mCriteria[j].mAttr.mSource == inputSource) ||
+                    mix->mCriteria[j].mValue.mSource == inputSource) ||
                (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mix->mCriteria[j].mRule &&
-                    mix->mCriteria[j].mAttr.mSource != inputSource)) {
+                    mix->mCriteria[j].mValue.mSource != inputSource)) {
                 if (availDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
                     if (policyMix != NULL) {
                         *policyMix = mix;
@@ -174,6 +255,15 @@
     }
     String8 address(attr.tags + strlen("addr="));
 
+#ifdef LOG_NDEBUG
+    ALOGV("getInputMixForAttr looking for address %s\n  mixes available:", address.string());
+    for (size_t i = 0; i < size(); i++) {
+            sp<AudioPolicyMix> policyMix = valueAt(i);
+            AudioMix *mix = policyMix->getMix();
+            ALOGV("\tmix %zu address=%s", i, mix->mRegistrationId.string());
+    }
+#endif
+
     ssize_t index = indexOfKey(address);
     if (index < 0) {
         ALOGW("getInputMixForAttr() no policy for address %s", address.string());
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 4e24f19..191439e 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -16,28 +16,21 @@
 
 #define LOG_TAG "APM::AudioPort"
 //#define LOG_NDEBUG 0
-#include <media/AudioResamplerPublic.h>
+#include "TypeConverter.h"
 #include "AudioPort.h"
 #include "HwModule.h"
 #include "AudioGain.h"
-#include "ConfigParsingUtils.h"
-#include "audio_policy_conf.h"
 #include <policy.h>
 
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
 namespace android {
 
 int32_t volatile AudioPort::mNextUniqueId = 1;
 
 // --- AudioPort class implementation
-
-AudioPort::AudioPort(const String8& name, audio_port_type_t type,
-                     audio_port_role_t role) :
-    mName(name), mType(type), mRole(role), mFlags(0)
-{
-    mUseInChannelMask = ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
-                    ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
-}
-
 void AudioPort::attach(const sp<HwModule>& module)
 {
     mModule = module;
@@ -61,605 +54,178 @@
     if (mModule == 0) {
         return 0;
     }
-    return mModule->mHalVersion;
+    return mModule->getHalVersion();
 }
 
 const char *AudioPort::getModuleName() const
 {
     if (mModule == 0) {
-        return "";
+        return "invalid module";
     }
-    return mModule->mName;
+    return mModule->getName();
 }
 
 void AudioPort::toAudioPort(struct audio_port *port) const
 {
+    // TODO: update this function once audio_port structure reflects the new profile definition.
+    // For compatibility reason: flatening the AudioProfile into audio_port structure.
+    SortedVector<audio_format_t> flatenedFormats;
+    SampleRateVector flatenedRates;
+    ChannelsVector flatenedChannels;
+    for (size_t profileIndex = 0; profileIndex < mProfiles.size(); profileIndex++) {
+        if (mProfiles[profileIndex]->isValid()) {
+            audio_format_t formatToExport = mProfiles[profileIndex]->getFormat();
+            const SampleRateVector &ratesToExport = mProfiles[profileIndex]->getSampleRates();
+            const ChannelsVector &channelsToExport = mProfiles[profileIndex]->getChannels();
+
+            if (flatenedFormats.indexOf(formatToExport) < 0) {
+                flatenedFormats.add(formatToExport);
+            }
+            for (size_t rateIndex = 0; rateIndex < ratesToExport.size(); rateIndex++) {
+                uint32_t rate = ratesToExport[rateIndex];
+                if (flatenedRates.indexOf(rate) < 0) {
+                    flatenedRates.add(rate);
+                }
+            }
+            for (size_t chanIndex = 0; chanIndex < channelsToExport.size(); chanIndex++) {
+                audio_channel_mask_t channels = channelsToExport[chanIndex];
+                if (flatenedChannels.indexOf(channels) < 0) {
+                    flatenedChannels.add(channels);
+                }
+            }
+            if (flatenedRates.size() > AUDIO_PORT_MAX_SAMPLING_RATES ||
+                    flatenedChannels.size() > AUDIO_PORT_MAX_CHANNEL_MASKS ||
+                    flatenedFormats.size() > AUDIO_PORT_MAX_FORMATS) {
+                ALOGE("%s: bailing out: cannot export profiles to port config", __FUNCTION__);
+                return;
+            }
+        }
+    }
     port->role = mRole;
     port->type = mType;
     strlcpy(port->name, mName, AUDIO_PORT_MAX_NAME_LEN);
-    unsigned int i;
-    for (i = 0; i < mSamplingRates.size() && i < AUDIO_PORT_MAX_SAMPLING_RATES; i++) {
-        if (mSamplingRates[i] != 0) {
-            port->sample_rates[i] = mSamplingRates[i];
-        }
+    port->num_sample_rates = flatenedRates.size();
+    port->num_channel_masks = flatenedChannels.size();
+    port->num_formats = flatenedFormats.size();
+    for (size_t i = 0; i < flatenedRates.size(); i++) {
+        port->sample_rates[i] = flatenedRates[i];
     }
-    port->num_sample_rates = i;
-    for (i = 0; i < mChannelMasks.size() && i < AUDIO_PORT_MAX_CHANNEL_MASKS; i++) {
-        if (mChannelMasks[i] != 0) {
-            port->channel_masks[i] = mChannelMasks[i];
-        }
+    for (size_t i = 0; i < flatenedChannels.size(); i++) {
+        port->channel_masks[i] = flatenedChannels[i];
     }
-    port->num_channel_masks = i;
-    for (i = 0; i < mFormats.size() && i < AUDIO_PORT_MAX_FORMATS; i++) {
-        if (mFormats[i] != 0) {
-            port->formats[i] = mFormats[i];
-        }
+    for (size_t i = 0; i < flatenedFormats.size(); i++) {
+        port->formats[i] = flatenedFormats[i];
     }
-    port->num_formats = i;
 
     ALOGV("AudioPort::toAudioPort() num gains %zu", mGains.size());
 
+    uint32_t i;
     for (i = 0; i < mGains.size() && i < AUDIO_PORT_MAX_GAINS; i++) {
-        port->gains[i] = mGains[i]->mGain;
+        port->gains[i] = mGains[i]->getGain();
     }
     port->num_gains = i;
 }
 
-void AudioPort::importAudioPort(const sp<AudioPort> port) {
-    for (size_t k = 0 ; k < port->mSamplingRates.size() ; k++) {
-        const uint32_t rate = port->mSamplingRates.itemAt(k);
-        if (rate != 0) { // skip "dynamic" rates
-            bool hasRate = false;
-            for (size_t l = 0 ; l < mSamplingRates.size() ; l++) {
-                if (rate == mSamplingRates.itemAt(l)) {
-                    hasRate = true;
+void AudioPort::importAudioPort(const sp<AudioPort> port)
+{
+    size_t indexToImport;
+    for (indexToImport = 0; indexToImport < port->mProfiles.size(); indexToImport++) {
+        const sp<AudioProfile> &profileToImport = port->mProfiles[indexToImport];
+        if (profileToImport->isValid()) {
+            // Import only valid port, i.e. valid format, non empty rates and channels masks
+            bool hasSameProfile = false;
+            for (size_t profileIndex = 0; profileIndex < mProfiles.size(); profileIndex++) {
+                if (*mProfiles[profileIndex] == *profileToImport) {
+                    // never import a profile twice
+                    hasSameProfile = true;
                     break;
                 }
             }
-            if (!hasRate) { // never import a sampling rate twice
-                mSamplingRates.add(rate);
+            if (hasSameProfile) { // never import a same profile twice
+                continue;
             }
-        }
-    }
-    for (size_t k = 0 ; k < port->mChannelMasks.size() ; k++) {
-        const audio_channel_mask_t mask = port->mChannelMasks.itemAt(k);
-        if (mask != 0) { // skip "dynamic" masks
-            bool hasMask = false;
-            for (size_t l = 0 ; l < mChannelMasks.size() ; l++) {
-                if (mask == mChannelMasks.itemAt(l)) {
-                    hasMask = true;
-                    break;
-                }
-            }
-            if (!hasMask) { // never import a channel mask twice
-                mChannelMasks.add(mask);
-            }
-        }
-    }
-    for (size_t k = 0 ; k < port->mFormats.size() ; k++) {
-        const audio_format_t format = port->mFormats.itemAt(k);
-        if (format != 0) { // skip "dynamic" formats
-            bool hasFormat = false;
-            for (size_t l = 0 ; l < mFormats.size() ; l++) {
-                if (format == mFormats.itemAt(l)) {
-                    hasFormat = true;
-                    break;
-                }
-            }
-            if (!hasFormat) { // never import a format twice
-                mFormats.add(format);
-            }
+            addAudioProfile(profileToImport);
         }
     }
 }
 
-void AudioPort::clearCapabilities() {
-    mChannelMasks.clear();
-    mFormats.clear();
-    mSamplingRates.clear();
-}
-
-void AudioPort::loadSamplingRates(char *name)
+void AudioPort::pickSamplingRate(uint32_t &pickedRate,const SampleRateVector &samplingRates) const
 {
-    char *str = strtok(name, "|");
-
-    // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
-    // rates should be read from the output stream after it is opened for the first time
-    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
-        mSamplingRates.add(0);
-        return;
-    }
-
-    while (str != NULL) {
-        uint32_t rate = atoi(str);
-        if (rate != 0) {
-            ALOGV("loadSamplingRates() adding rate %d", rate);
-            mSamplingRates.add(rate);
-        }
-        str = strtok(NULL, "|");
-    }
-}
-
-void AudioPort::loadFormats(char *name)
-{
-    char *str = strtok(name, "|");
-
-    // by convention, "0' in the first entry in mFormats indicates the supported formats
-    // should be read from the output stream after it is opened for the first time
-    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
-        mFormats.add(AUDIO_FORMAT_DEFAULT);
-        return;
-    }
-
-    while (str != NULL) {
-        audio_format_t format = (audio_format_t)ConfigParsingUtils::stringToEnum(sFormatNameToEnumTable,
-                                                             ARRAY_SIZE(sFormatNameToEnumTable),
-                                                             str);
-        if (format != AUDIO_FORMAT_DEFAULT) {
-            mFormats.add(format);
-        }
-        str = strtok(NULL, "|");
-    }
-    // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
-    // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
-    // [](const audio_format_t *format1, const audio_format_t *format2) {
-    //     return compareFormats(*format1, *format2);
-    // }
-    mFormats.sort(compareFormats);
-}
-
-void AudioPort::loadInChannels(char *name)
-{
-    const char *str = strtok(name, "|");
-
-    ALOGV("loadInChannels() %s", name);
-
-    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
-        mChannelMasks.add(0);
-        return;
-    }
-
-    while (str != NULL) {
-        audio_channel_mask_t channelMask =
-                (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sInChannelsNameToEnumTable,
-                                                   ARRAY_SIZE(sInChannelsNameToEnumTable),
-                                                   str);
-        if (channelMask == 0) { // if not found, check the channel index table
-            channelMask = (audio_channel_mask_t)
-                      ConfigParsingUtils::stringToEnum(sIndexChannelsNameToEnumTable,
-                              ARRAY_SIZE(sIndexChannelsNameToEnumTable),
-                              str);
-        }
-        if (channelMask != 0) {
-            ALOGV("loadInChannels() adding channelMask %#x", channelMask);
-            mChannelMasks.add(channelMask);
-        }
-        str = strtok(NULL, "|");
-    }
-}
-
-void AudioPort::loadOutChannels(char *name)
-{
-    const char *str = strtok(name, "|");
-
-    ALOGV("loadOutChannels() %s", name);
-
-    // by convention, "0' in the first entry in mChannelMasks indicates the supported channel
-    // masks should be read from the output stream after it is opened for the first time
-    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
-        mChannelMasks.add(0);
-        return;
-    }
-
-    while (str != NULL) {
-        audio_channel_mask_t channelMask =
-                (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sOutChannelsNameToEnumTable,
-                                                   ARRAY_SIZE(sOutChannelsNameToEnumTable),
-                                                   str);
-        if (channelMask == 0) { // if not found, check the channel index table
-            channelMask = (audio_channel_mask_t)
-                      ConfigParsingUtils::stringToEnum(sIndexChannelsNameToEnumTable,
-                              ARRAY_SIZE(sIndexChannelsNameToEnumTable),
-                              str);
-        }
-        if (channelMask != 0) {
-            mChannelMasks.add(channelMask);
-        }
-        str = strtok(NULL, "|");
-    }
-    return;
-}
-
-audio_gain_mode_t AudioPort::loadGainMode(char *name)
-{
-    const char *str = strtok(name, "|");
-
-    ALOGV("loadGainMode() %s", name);
-    audio_gain_mode_t mode = 0;
-    while (str != NULL) {
-        mode |= (audio_gain_mode_t)ConfigParsingUtils::stringToEnum(sGainModeNameToEnumTable,
-                                                ARRAY_SIZE(sGainModeNameToEnumTable),
-                                                str);
-        str = strtok(NULL, "|");
-    }
-    return mode;
-}
-
-void AudioPort::loadGain(cnode *root, int index)
-{
-    cnode *node = root->first_child;
-
-    sp<AudioGain> gain = new AudioGain(index, mUseInChannelMask);
-
-    while (node) {
-        if (strcmp(node->name, GAIN_MODE) == 0) {
-            gain->mGain.mode = loadGainMode((char *)node->value);
-        } else if (strcmp(node->name, GAIN_CHANNELS) == 0) {
-            if (mUseInChannelMask) {
-                gain->mGain.channel_mask =
-                        (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sInChannelsNameToEnumTable,
-                                                           ARRAY_SIZE(sInChannelsNameToEnumTable),
-                                                           (char *)node->value);
-            } else {
-                gain->mGain.channel_mask =
-                        (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sOutChannelsNameToEnumTable,
-                                                           ARRAY_SIZE(sOutChannelsNameToEnumTable),
-                                                           (char *)node->value);
-            }
-        } else if (strcmp(node->name, GAIN_MIN_VALUE) == 0) {
-            gain->mGain.min_value = atoi((char *)node->value);
-        } else if (strcmp(node->name, GAIN_MAX_VALUE) == 0) {
-            gain->mGain.max_value = atoi((char *)node->value);
-        } else if (strcmp(node->name, GAIN_DEFAULT_VALUE) == 0) {
-            gain->mGain.default_value = atoi((char *)node->value);
-        } else if (strcmp(node->name, GAIN_STEP_VALUE) == 0) {
-            gain->mGain.step_value = atoi((char *)node->value);
-        } else if (strcmp(node->name, GAIN_MIN_RAMP_MS) == 0) {
-            gain->mGain.min_ramp_ms = atoi((char *)node->value);
-        } else if (strcmp(node->name, GAIN_MAX_RAMP_MS) == 0) {
-            gain->mGain.max_ramp_ms = atoi((char *)node->value);
-        }
-        node = node->next;
-    }
-
-    ALOGV("loadGain() adding new gain mode %08x channel mask %08x min mB %d max mB %d",
-          gain->mGain.mode, gain->mGain.channel_mask, gain->mGain.min_value, gain->mGain.max_value);
-
-    if (gain->mGain.mode == 0) {
-        return;
-    }
-    mGains.add(gain);
-}
-
-void AudioPort::loadGains(cnode *root)
-{
-    cnode *node = root->first_child;
-    int index = 0;
-    while (node) {
-        ALOGV("loadGains() loading gain %s", node->name);
-        loadGain(node, index++);
-        node = node->next;
-    }
-}
-
-status_t AudioPort::checkExactSamplingRate(uint32_t samplingRate) const
-{
-    if (mSamplingRates.isEmpty()) {
-        return NO_ERROR;
-    }
-
-    for (size_t i = 0; i < mSamplingRates.size(); i ++) {
-        if (mSamplingRates[i] == samplingRate) {
-            return NO_ERROR;
-        }
-    }
-    return BAD_VALUE;
-}
-
-status_t AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate,
-        uint32_t *updatedSamplingRate) const
-{
-    if (mSamplingRates.isEmpty()) {
-        if (updatedSamplingRate != NULL) {
-            *updatedSamplingRate = samplingRate;
-        }
-        return NO_ERROR;
-    }
-
-    // Search for the closest supported sampling rate that is above (preferred)
-    // or below (acceptable) the desired sampling rate, within a permitted ratio.
-    // The sampling rates do not need to be sorted in ascending order.
-    ssize_t maxBelow = -1;
-    ssize_t minAbove = -1;
-    uint32_t candidate;
-    for (size_t i = 0; i < mSamplingRates.size(); i++) {
-        candidate = mSamplingRates[i];
-        if (candidate == samplingRate) {
-            if (updatedSamplingRate != NULL) {
-                *updatedSamplingRate = candidate;
-            }
-            return NO_ERROR;
-        }
-        // candidate < desired
-        if (candidate < samplingRate) {
-            if (maxBelow < 0 || candidate > mSamplingRates[maxBelow]) {
-                maxBelow = i;
-            }
-        // candidate > desired
-        } else {
-            if (minAbove < 0 || candidate < mSamplingRates[minAbove]) {
-                minAbove = i;
-            }
-        }
-    }
-
-    // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
-    if (minAbove >= 0) {
-        candidate = mSamplingRates[minAbove];
-        if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
-            if (updatedSamplingRate != NULL) {
-                *updatedSamplingRate = candidate;
-            }
-            return NO_ERROR;
-        }
-    }
-    // But if we have to up-sample from a lower sampling rate, that's OK.
-    if (maxBelow >= 0) {
-        candidate = mSamplingRates[maxBelow];
-        if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
-            if (updatedSamplingRate != NULL) {
-                *updatedSamplingRate = candidate;
-            }
-            return NO_ERROR;
-        }
-    }
-    // leave updatedSamplingRate unmodified
-    return BAD_VALUE;
-}
-
-status_t AudioPort::checkExactChannelMask(audio_channel_mask_t channelMask) const
-{
-    if (mChannelMasks.isEmpty()) {
-        return NO_ERROR;
-    }
-
-    for (size_t i = 0; i < mChannelMasks.size(); i++) {
-        if (mChannelMasks[i] == channelMask) {
-            return NO_ERROR;
-        }
-    }
-    return BAD_VALUE;
-}
-
-status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
-        audio_channel_mask_t *updatedChannelMask) const
-{
-    if (mChannelMasks.isEmpty()) {
-        if (updatedChannelMask != NULL) {
-            *updatedChannelMask = channelMask;
-        }
-        return NO_ERROR;
-    }
-
-    const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
-    const bool isIndex = audio_channel_mask_get_representation(channelMask)
-            == AUDIO_CHANNEL_REPRESENTATION_INDEX;
-    int bestMatch = 0;
-    for (size_t i = 0; i < mChannelMasks.size(); i ++) {
-        audio_channel_mask_t supported = mChannelMasks[i];
-        if (supported == channelMask) {
-            // Exact matches always taken.
-            if (updatedChannelMask != NULL) {
-                *updatedChannelMask = channelMask;
-            }
-            return NO_ERROR;
-        }
-
-        // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
-        if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
-            // Approximate (best) match:
-            // The match score measures how well the supported channel mask matches the
-            // desired mask, where increasing-is-better.
-            //
-            // TODO: Some tweaks may be needed.
-            // Should be a static function of the data processing library.
-            //
-            // In priority:
-            // match score = 1000 if legacy channel conversion equivalent (always prefer this)
-            // OR
-            // match score += 100 if the channel mask representations match
-            // match score += number of channels matched.
-            //
-            // If there are no matched channels, the mask may still be accepted
-            // but the playback or record will be silent.
-            const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
-                    == AUDIO_CHANNEL_REPRESENTATION_INDEX);
-            int match;
-            if (isIndex && isSupportedIndex) {
-                // index equivalence
-                match = 100 + __builtin_popcount(
-                        audio_channel_mask_get_bits(channelMask)
-                            & audio_channel_mask_get_bits(supported));
-            } else if (isIndex && !isSupportedIndex) {
-                const uint32_t equivalentBits =
-                        (1 << audio_channel_count_from_in_mask(supported)) - 1 ;
-                match = __builtin_popcount(
-                        audio_channel_mask_get_bits(channelMask) & equivalentBits);
-            } else if (!isIndex && isSupportedIndex) {
-                const uint32_t equivalentBits =
-                        (1 << audio_channel_count_from_in_mask(channelMask)) - 1;
-                match = __builtin_popcount(
-                        equivalentBits & audio_channel_mask_get_bits(supported));
-            } else {
-                // positional equivalence
-                match = 100 + __builtin_popcount(
-                        audio_channel_mask_get_bits(channelMask)
-                            & audio_channel_mask_get_bits(supported));
-                switch (supported) {
-                case AUDIO_CHANNEL_IN_FRONT_BACK:
-                case AUDIO_CHANNEL_IN_STEREO:
-                    if (channelMask == AUDIO_CHANNEL_IN_MONO) {
-                        match = 1000;
-                    }
-                    break;
-                case AUDIO_CHANNEL_IN_MONO:
-                    if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
-                            || channelMask == AUDIO_CHANNEL_IN_STEREO) {
-                        match = 1000;
-                    }
-                    break;
-                default:
-                    break;
-                }
-            }
-            if (match > bestMatch) {
-                bestMatch = match;
-                if (updatedChannelMask != NULL) {
-                    *updatedChannelMask = supported;
-                } else {
-                    return NO_ERROR; // any match will do in this case.
-                }
-            }
-        }
-    }
-    return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
-}
-
-status_t AudioPort::checkExactFormat(audio_format_t format) const
-{
-    if (mFormats.isEmpty()) {
-        return NO_ERROR;
-    }
-
-    for (size_t i = 0; i < mFormats.size(); i ++) {
-        if (mFormats[i] == format) {
-            return NO_ERROR;
-        }
-    }
-    return BAD_VALUE;
-}
-
-status_t AudioPort::checkCompatibleFormat(audio_format_t format, audio_format_t *updatedFormat)
-        const
-{
-    if (mFormats.isEmpty()) {
-        if (updatedFormat != NULL) {
-            *updatedFormat = format;
-        }
-        return NO_ERROR;
-    }
-
-    const bool checkInexact = // when port is input and format is linear pcm
-            mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK
-            && audio_is_linear_pcm(format);
-
-    // iterate from best format to worst format (reverse order)
-    for (ssize_t i = mFormats.size() - 1; i >= 0 ; --i) {
-        if (mFormats[i] == format ||
-                (checkInexact
-                        && mFormats[i] != AUDIO_FORMAT_DEFAULT
-                        && audio_is_linear_pcm(mFormats[i]))) {
-            // for inexact checks we take the first linear pcm format due to sorting.
-            if (updatedFormat != NULL) {
-                *updatedFormat = mFormats[i];
-            }
-            return NO_ERROR;
-        }
-    }
-    return BAD_VALUE;
-}
-
-uint32_t AudioPort::pickSamplingRate() const
-{
-    // special case for uninitialized dynamic profile
-    if (mSamplingRates.size() == 1 && mSamplingRates[0] == 0) {
-        return 0;
-    }
-
+    pickedRate = 0;
     // For direct outputs, pick minimum sampling rate: this helps ensuring that the
     // channel count / sampling rate combination chosen will be supported by the connected
     // sink
-    if ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
-            (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))) {
+    if (isDirectOutput()) {
         uint32_t samplingRate = UINT_MAX;
-        for (size_t i = 0; i < mSamplingRates.size(); i ++) {
-            if ((mSamplingRates[i] < samplingRate) && (mSamplingRates[i] > 0)) {
-                samplingRate = mSamplingRates[i];
+        for (size_t i = 0; i < samplingRates.size(); i ++) {
+            if ((samplingRates[i] < samplingRate) && (samplingRates[i] > 0)) {
+                samplingRate = samplingRates[i];
             }
         }
-        return (samplingRate == UINT_MAX) ? 0 : samplingRate;
-    }
+        pickedRate = (samplingRate == UINT_MAX) ? 0 : samplingRate;
+    } else {
+        uint32_t maxRate = MAX_MIXER_SAMPLING_RATE;
 
-    uint32_t samplingRate = 0;
-    uint32_t maxRate = MAX_MIXER_SAMPLING_RATE;
-
-    // For mixed output and inputs, use max mixer sampling rates. Do not
-    // limit sampling rate otherwise
-    // For inputs, also see checkCompatibleSamplingRate().
-    if (mType != AUDIO_PORT_TYPE_MIX) {
-        maxRate = UINT_MAX;
-    }
-    // TODO: should mSamplingRates[] be ordered in terms of our preference
-    // and we return the first (and hence most preferred) match?  This is of concern if
-    // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
-    for (size_t i = 0; i < mSamplingRates.size(); i ++) {
-        if ((mSamplingRates[i] > samplingRate) && (mSamplingRates[i] <= maxRate)) {
-            samplingRate = mSamplingRates[i];
+        // For mixed output and inputs, use max mixer sampling rates. Do not
+        // limit sampling rate otherwise
+        // For inputs, also see checkCompatibleSamplingRate().
+        if (mType != AUDIO_PORT_TYPE_MIX) {
+            maxRate = UINT_MAX;
+        }
+        // TODO: should mSamplingRates[] be ordered in terms of our preference
+        // and we return the first (and hence most preferred) match?  This is of concern if
+        // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
+        for (size_t i = 0; i < samplingRates.size(); i ++) {
+            if ((samplingRates[i] > pickedRate) && (samplingRates[i] <= maxRate)) {
+                pickedRate = samplingRates[i];
+            }
         }
     }
-    return samplingRate;
 }
 
-audio_channel_mask_t AudioPort::pickChannelMask() const
+void AudioPort::pickChannelMask(audio_channel_mask_t &pickedChannelMask,
+                                const ChannelsVector &channelMasks) const
 {
-    // special case for uninitialized dynamic profile
-    if (mChannelMasks.size() == 1 && mChannelMasks[0] == 0) {
-        return AUDIO_CHANNEL_NONE;
-    }
-    audio_channel_mask_t channelMask = AUDIO_CHANNEL_NONE;
-
+    pickedChannelMask = AUDIO_CHANNEL_NONE;
     // For direct outputs, pick minimum channel count: this helps ensuring that the
     // channel count / sampling rate combination chosen will be supported by the connected
     // sink
-    if ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
-            (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))) {
+    if (isDirectOutput()) {
         uint32_t channelCount = UINT_MAX;
-        for (size_t i = 0; i < mChannelMasks.size(); i ++) {
+        for (size_t i = 0; i < channelMasks.size(); i ++) {
             uint32_t cnlCount;
-            if (mUseInChannelMask) {
-                cnlCount = audio_channel_count_from_in_mask(mChannelMasks[i]);
+            if (useInputChannelMask()) {
+                cnlCount = audio_channel_count_from_in_mask(channelMasks[i]);
             } else {
-                cnlCount = audio_channel_count_from_out_mask(mChannelMasks[i]);
+                cnlCount = audio_channel_count_from_out_mask(channelMasks[i]);
             }
             if ((cnlCount < channelCount) && (cnlCount > 0)) {
-                channelMask = mChannelMasks[i];
+                pickedChannelMask = channelMasks[i];
                 channelCount = cnlCount;
             }
         }
-        return channelMask;
-    }
+    } else {
+        uint32_t channelCount = 0;
+        uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
 
-    uint32_t channelCount = 0;
-    uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
-
-    // For mixed output and inputs, use max mixer channel count. Do not
-    // limit channel count otherwise
-    if (mType != AUDIO_PORT_TYPE_MIX) {
-        maxCount = UINT_MAX;
-    }
-    for (size_t i = 0; i < mChannelMasks.size(); i ++) {
-        uint32_t cnlCount;
-        if (mUseInChannelMask) {
-            cnlCount = audio_channel_count_from_in_mask(mChannelMasks[i]);
-        } else {
-            cnlCount = audio_channel_count_from_out_mask(mChannelMasks[i]);
+        // For mixed output and inputs, use max mixer channel count. Do not
+        // limit channel count otherwise
+        if (mType != AUDIO_PORT_TYPE_MIX) {
+            maxCount = UINT_MAX;
         }
-        if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
-            channelMask = mChannelMasks[i];
-            channelCount = cnlCount;
+        for (size_t i = 0; i < channelMasks.size(); i ++) {
+            uint32_t cnlCount;
+            if (useInputChannelMask()) {
+                cnlCount = audio_channel_count_from_in_mask(channelMasks[i]);
+            } else {
+                cnlCount = audio_channel_count_from_out_mask(channelMasks[i]);
+            }
+            if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
+                pickedChannelMask = channelMasks[i];
+                channelCount = cnlCount;
+            }
         }
     }
-    return channelMask;
 }
 
 /* format in order of increasing preference */
@@ -672,8 +238,7 @@
         AUDIO_FORMAT_PCM_FLOAT,
 };
 
-int AudioPort::compareFormats(audio_format_t format1,
-                                                  audio_format_t format2)
+int AudioPort::compareFormats(audio_format_t format1, audio_format_t format2)
 {
     // NOTE: AUDIO_FORMAT_INVALID is also considered not PCM and will be compared equal to any
     // compressed format and better than any PCM format. This is by design of pickFormat()
@@ -703,36 +268,51 @@
     return index1 - index2;
 }
 
-audio_format_t AudioPort::pickFormat() const
+void AudioPort::pickAudioProfile(uint32_t &samplingRate,
+                                 audio_channel_mask_t &channelMask,
+                                 audio_format_t &format) const
 {
-    // special case for uninitialized dynamic profile
-    if (mFormats.size() == 1 && mFormats[0] == 0) {
-        return AUDIO_FORMAT_DEFAULT;
-    }
+    format = AUDIO_FORMAT_DEFAULT;
+    samplingRate = 0;
+    channelMask = AUDIO_CHANNEL_NONE;
 
-    audio_format_t format = AUDIO_FORMAT_DEFAULT;
-    audio_format_t bestFormat =
-            AudioPort::sPcmFormatCompareTable[
-                ARRAY_SIZE(AudioPort::sPcmFormatCompareTable) - 1];
-    // For mixed output and inputs, use best mixer output format. Do not
-    // limit format otherwise
-    if ((mType != AUDIO_PORT_TYPE_MIX) ||
-            ((mRole == AUDIO_PORT_ROLE_SOURCE) &&
-             (((mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) != 0)))) {
+    // special case for uninitialized dynamic profile
+    if (!mProfiles.hasValidProfile()) {
+        return;
+    }
+    audio_format_t bestFormat = sPcmFormatCompareTable[ARRAY_SIZE(sPcmFormatCompareTable) - 1];
+    // For mixed output and inputs, use best mixer output format.
+    // Do not limit format otherwise
+    if ((mType != AUDIO_PORT_TYPE_MIX) || isDirectOutput()) {
         bestFormat = AUDIO_FORMAT_INVALID;
     }
 
-    for (size_t i = 0; i < mFormats.size(); i ++) {
-        if ((compareFormats(mFormats[i], format) > 0) &&
-                (compareFormats(mFormats[i], bestFormat) <= 0)) {
-            format = mFormats[i];
+    for (size_t i = 0; i < mProfiles.size(); i ++) {
+        if (!mProfiles[i]->isValid()) {
+            continue;
+        }
+        audio_format_t formatToCompare = mProfiles[i]->getFormat();
+        if ((compareFormats(formatToCompare, format) > 0) &&
+                (compareFormats(formatToCompare, bestFormat) <= 0)) {
+            uint32_t pickedSamplingRate = 0;
+            audio_channel_mask_t pickedChannelMask = AUDIO_CHANNEL_NONE;
+            pickChannelMask(pickedChannelMask, mProfiles[i]->getChannels());
+            pickSamplingRate(pickedSamplingRate, mProfiles[i]->getSampleRates());
+
+            if (formatToCompare != AUDIO_FORMAT_DEFAULT && pickedChannelMask != AUDIO_CHANNEL_NONE
+                    && pickedSamplingRate != 0) {
+                format = formatToCompare;
+                channelMask = pickedChannelMask;
+                samplingRate = pickedSamplingRate;
+                // TODO: shall we return on the first one or still trying to pick a better Profile?
+            }
         }
     }
-    return format;
+    ALOGV("%s Port[nm:%s] profile rate=%d, format=%d, channels=%d", __FUNCTION__, mName.string(),
+          samplingRate, channelMask, format);
 }
 
-status_t AudioPort::checkGain(const struct audio_gain_config *gainConfig,
-                                                  int index) const
+status_t AudioPort::checkGain(const struct audio_gain_config *gainConfig, int index) const
 {
     if (index < 0 || (size_t)index >= mGains.size()) {
         return BAD_VALUE;
@@ -740,77 +320,27 @@
     return mGains[index]->checkConfig(gainConfig);
 }
 
-void AudioPort::dump(int fd, int spaces) const
+void AudioPort::dump(int fd, int spaces, bool verbose) const
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
 
-    if (mName.length() != 0) {
+    if (!mName.isEmpty()) {
         snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
         result.append(buffer);
+        write(fd, result.string(), result.size());
     }
+    if (verbose) {
+        mProfiles.dump(fd, spaces);
 
-    if (mSamplingRates.size() != 0) {
-        snprintf(buffer, SIZE, "%*s- sampling rates: ", spaces, "");
-        result.append(buffer);
-        for (size_t i = 0; i < mSamplingRates.size(); i++) {
-            if (i == 0 && mSamplingRates[i] == 0) {
-                snprintf(buffer, SIZE, "Dynamic");
-            } else {
-                snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
+        if (mGains.size() != 0) {
+            snprintf(buffer, SIZE, "%*s- gains:\n", spaces, "");
+            result = buffer;
+            write(fd, result.string(), result.size());
+            for (size_t i = 0; i < mGains.size(); i++) {
+                mGains[i]->dump(fd, spaces + 2, i);
             }
-            result.append(buffer);
-            result.append(i == (mSamplingRates.size() - 1) ? "" : ", ");
-        }
-        result.append("\n");
-    }
-
-    if (mChannelMasks.size() != 0) {
-        snprintf(buffer, SIZE, "%*s- channel masks: ", spaces, "");
-        result.append(buffer);
-        for (size_t i = 0; i < mChannelMasks.size(); i++) {
-            ALOGV("AudioPort::dump mChannelMasks %zu %08x", i, mChannelMasks[i]);
-
-            if (i == 0 && mChannelMasks[i] == 0) {
-                snprintf(buffer, SIZE, "Dynamic");
-            } else {
-                snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
-            }
-            result.append(buffer);
-            result.append(i == (mChannelMasks.size() - 1) ? "" : ", ");
-        }
-        result.append("\n");
-    }
-
-    if (mFormats.size() != 0) {
-        snprintf(buffer, SIZE, "%*s- formats: ", spaces, "");
-        result.append(buffer);
-        for (size_t i = 0; i < mFormats.size(); i++) {
-            const char *formatStr = ConfigParsingUtils::enumToString(sFormatNameToEnumTable,
-                                                 ARRAY_SIZE(sFormatNameToEnumTable),
-                                                 mFormats[i]);
-            const bool isEmptyStr = formatStr[0] == 0;
-            if (i == 0 && isEmptyStr) {
-                snprintf(buffer, SIZE, "Dynamic");
-            } else {
-                if (isEmptyStr) {
-                    snprintf(buffer, SIZE, "%#x", mFormats[i]);
-                } else {
-                    snprintf(buffer, SIZE, "%s", formatStr);
-                }
-            }
-            result.append(buffer);
-            result.append(i == (mFormats.size() - 1) ? "" : ", ");
-        }
-        result.append("\n");
-    }
-    write(fd, result.string(), result.size());
-    if (mGains.size() != 0) {
-        snprintf(buffer, SIZE, "%*s- gains:\n", spaces, "");
-        write(fd, buffer, strlen(buffer) + 1);
-        for (size_t i = 0; i < mGains.size(); i++) {
-            mGains[i]->dump(fd, spaces + 2, i);
         }
     }
 }
@@ -830,9 +360,8 @@
     mGain.index = -1;
 }
 
-status_t AudioPortConfig::applyAudioPortConfig(
-                                                        const struct audio_port_config *config,
-                                                        struct audio_port_config *backupConfig)
+status_t AudioPortConfig::applyAudioPortConfig(const struct audio_port_config *config,
+                                               struct audio_port_config *backupConfig)
 {
     struct audio_port_config localBackupConfig;
     status_t status = NO_ERROR;
@@ -845,25 +374,19 @@
         status = NO_INIT;
         goto exit;
     }
+    status = audioport->checkExactAudioProfile(config->sample_rate,
+                                               config->channel_mask,
+                                               config->format);
+    if (status != NO_ERROR) {
+        goto exit;
+    }
     if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
-        status = audioport->checkExactSamplingRate(config->sample_rate);
-        if (status != NO_ERROR) {
-            goto exit;
-        }
         mSamplingRate = config->sample_rate;
     }
     if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
-        status = audioport->checkExactChannelMask(config->channel_mask);
-        if (status != NO_ERROR) {
-            goto exit;
-        }
         mChannelMask = config->channel_mask;
     }
     if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
-        status = audioport->checkExactFormat(config->format);
-        if (status != NO_ERROR) {
-            goto exit;
-        }
         mFormat = config->format;
     }
     if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
@@ -911,9 +434,11 @@
     } else {
         dstConfig->format = AUDIO_FORMAT_INVALID;
     }
-    if (dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) {
+    sp<AudioPort> audioport = getAudioPort();
+    if ((dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) && audioport != NULL) {
         dstConfig->gain = mGain;
-        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)) {
+        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)
+                && audioport->checkGain(&srcConfig->gain, srcConfig->gain.index) == OK) {
             dstConfig->gain = srcConfig->gain;
         }
     } else {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
new file mode 100644
index 0000000..c599665
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 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 "APM::AudioProfile"
+//#define LOG_NDEBUG 0
+
+#include "AudioProfile.h"
+#include "AudioPort.h"
+#include "HwModule.h"
+#include "AudioGain.h"
+#include <utils/SortedVector.h>
+#include "TypeConverter.h"
+#include <media/AudioResamplerPublic.h>
+#include <algorithm>
+
+namespace android {
+
+status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
+                                  audio_format_t format) const
+{
+    if (format == mFormat &&
+            (mChannelMasks.isEmpty() || supportsChannels(channelMask)) &&
+            (mSamplingRates.isEmpty() || supportsRate(samplingRate))) {
+        return NO_ERROR;
+    }
+    return BAD_VALUE;
+}
+
+template <typename T>
+bool operator == (const SortedVector<T> &left, const SortedVector<T> &right)
+{
+    if (left.size() != right.size()) {
+        return false;
+    }
+    for(size_t index = 0; index < right.size(); index++) {
+        if (left[index] != right[index]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
+{
+    return (left.getFormat() == compareTo.getFormat()) &&
+            (left.getChannels() == compareTo.getChannels()) &&
+            (left.getSampleRates() == compareTo.getSampleRates());
+}
+
+status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
+                                                   uint32_t &updatedSamplingRate) const
+{
+    if (mSamplingRates.isEmpty()) {
+        updatedSamplingRate = samplingRate;
+        return NO_ERROR;
+    }
+    // Search for the closest supported sampling rate that is above (preferred)
+    // or below (acceptable) the desired sampling rate, within a permitted ratio.
+    // The sampling rates are sorted in ascending order.
+    size_t orderOfDesiredRate = mSamplingRates.orderOf(samplingRate);
+
+    // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
+    if (orderOfDesiredRate < mSamplingRates.size()) {
+        uint32_t candidate = mSamplingRates[orderOfDesiredRate];
+        if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
+            updatedSamplingRate = candidate;
+            return NO_ERROR;
+        }
+    }
+    // But if we have to up-sample from a lower sampling rate, that's OK.
+    if (orderOfDesiredRate != 0) {
+        uint32_t candidate = mSamplingRates[orderOfDesiredRate - 1];
+        if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
+            updatedSamplingRate = candidate;
+            return NO_ERROR;
+        }
+    }
+    // leave updatedSamplingRate unmodified
+    return BAD_VALUE;
+}
+
+status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
+                                                  audio_channel_mask_t &updatedChannelMask,
+                                                  audio_port_type_t portType,
+                                                  audio_port_role_t portRole) const
+{
+    if (mChannelMasks.isEmpty()) {
+        updatedChannelMask = channelMask;
+        return NO_ERROR;
+    }
+    const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK;
+    const bool isIndex = audio_channel_mask_get_representation(channelMask)
+            == AUDIO_CHANNEL_REPRESENTATION_INDEX;
+    int bestMatch = 0;
+    for (size_t i = 0; i < mChannelMasks.size(); i ++) {
+        audio_channel_mask_t supported = mChannelMasks[i];
+        if (supported == channelMask) {
+            // Exact matches always taken.
+            updatedChannelMask = channelMask;
+            return NO_ERROR;
+        }
+
+        // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
+        if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
+            // Approximate (best) match:
+            // The match score measures how well the supported channel mask matches the
+            // desired mask, where increasing-is-better.
+            //
+            // TODO: Some tweaks may be needed.
+            // Should be a static function of the data processing library.
+            //
+            // In priority:
+            // match score = 1000 if legacy channel conversion equivalent (always prefer this)
+            // OR
+            // match score += 100 if the channel mask representations match
+            // match score += number of channels matched.
+            //
+            // If there are no matched channels, the mask may still be accepted
+            // but the playback or record will be silent.
+            const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
+                    == AUDIO_CHANNEL_REPRESENTATION_INDEX);
+            int match;
+            if (isIndex && isSupportedIndex) {
+                // index equivalence
+                match = 100 + __builtin_popcount(
+                        audio_channel_mask_get_bits(channelMask)
+                            & audio_channel_mask_get_bits(supported));
+            } else if (isIndex && !isSupportedIndex) {
+                const uint32_t equivalentBits =
+                        (1 << audio_channel_count_from_in_mask(supported)) - 1 ;
+                match = __builtin_popcount(
+                        audio_channel_mask_get_bits(channelMask) & equivalentBits);
+            } else if (!isIndex && isSupportedIndex) {
+                const uint32_t equivalentBits =
+                        (1 << audio_channel_count_from_in_mask(channelMask)) - 1;
+                match = __builtin_popcount(
+                        equivalentBits & audio_channel_mask_get_bits(supported));
+            } else {
+                // positional equivalence
+                match = 100 + __builtin_popcount(
+                        audio_channel_mask_get_bits(channelMask)
+                            & audio_channel_mask_get_bits(supported));
+                switch (supported) {
+                case AUDIO_CHANNEL_IN_FRONT_BACK:
+                case AUDIO_CHANNEL_IN_STEREO:
+                    if (channelMask == AUDIO_CHANNEL_IN_MONO) {
+                        match = 1000;
+                    }
+                    break;
+                case AUDIO_CHANNEL_IN_MONO:
+                    if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
+                            || channelMask == AUDIO_CHANNEL_IN_STEREO) {
+                        match = 1000;
+                    }
+                    break;
+                default:
+                    break;
+                }
+            }
+            if (match > bestMatch) {
+                bestMatch = match;
+                updatedChannelMask = supported;
+            }
+        }
+    }
+    return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
+}
+
+void AudioProfile::dump(int fd, int spaces) const
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
+             mIsDynamicChannels ? "[dynamic channels]" : "",
+             mIsDynamicRate ? "[dynamic rates]" : "");
+    result.append(buffer);
+    if (mName.length() != 0) {
+        snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
+        result.append(buffer);
+    }
+    std::string formatLiteral;
+    if (FormatConverter::toString(mFormat, formatLiteral)) {
+        snprintf(buffer, SIZE, "%*s- format: %s\n", spaces, "", formatLiteral.c_str());
+        result.append(buffer);
+    }
+    if (!mSamplingRates.isEmpty()) {
+        snprintf(buffer, SIZE, "%*s- sampling rates:", spaces, "");
+        result.append(buffer);
+        for (size_t i = 0; i < mSamplingRates.size(); i++) {
+            snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
+            result.append(buffer);
+            result.append(i == (mSamplingRates.size() - 1) ? "" : ", ");
+        }
+        result.append("\n");
+    }
+
+    if (!mChannelMasks.isEmpty()) {
+        snprintf(buffer, SIZE, "%*s- channel masks:", spaces, "");
+        result.append(buffer);
+        for (size_t i = 0; i < mChannelMasks.size(); i++) {
+            snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
+            result.append(buffer);
+            result.append(i == (mChannelMasks.size() - 1) ? "" : ", ");
+        }
+        result.append("\n");
+    }
+    write(fd, result.string(), result.size());
+}
+
+status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
+                                               audio_channel_mask_t channelMask,
+                                               audio_format_t format) const
+{
+    if (isEmpty()) {
+        return NO_ERROR;
+    }
+
+    for (size_t i = 0; i < size(); i++) {
+        const sp<AudioProfile> profile = itemAt(i);
+        if (profile->checkExact(samplingRate, channelMask, format) == NO_ERROR) {
+            return NO_ERROR;
+        }
+    }
+    return BAD_VALUE;
+}
+
+status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate,
+                                                    audio_channel_mask_t &channelMask,
+                                                    audio_format_t &format,
+                                                    audio_port_type_t portType,
+                                                    audio_port_role_t portRole) const
+{
+    if (isEmpty()) {
+        return NO_ERROR;
+    }
+
+    const bool checkInexact = // when port is input and format is linear pcm
+            portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK
+            && audio_is_linear_pcm(format);
+
+    // iterate from best format to worst format (reverse order)
+    for (ssize_t i = size() - 1; i >= 0 ; --i) {
+        const sp<AudioProfile> profile = itemAt(i);
+        audio_format_t formatToCompare = profile->getFormat();
+        if (formatToCompare == format ||
+                (checkInexact
+                        && formatToCompare != AUDIO_FORMAT_DEFAULT
+                        && audio_is_linear_pcm(formatToCompare))) {
+            // Compatible profile has been found, checks if this profile has compatible
+            // rate and channels as well
+            audio_channel_mask_t updatedChannels;
+            uint32_t updatedRate;
+            if (profile->checkCompatibleChannelMask(channelMask, updatedChannels,
+                                                    portType, portRole) == NO_ERROR &&
+                    profile->checkCompatibleSamplingRate(samplingRate, updatedRate) == NO_ERROR) {
+                // for inexact checks we take the first linear pcm format due to sorting.
+                format = formatToCompare;
+                channelMask = updatedChannels;
+                samplingRate = updatedRate;
+                return NO_ERROR;
+            }
+        }
+    }
+    return BAD_VALUE;
+}
+
+int AudioProfileVector::compareFormats(const sp<AudioProfile> *profile1,
+                                       const sp<AudioProfile> *profile2)
+{
+    return AudioPort::compareFormats((*profile1)->getFormat(), (*profile2)->getFormat());
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
new file mode 100644
index 0000000..79ad1f7
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 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 "APM::AudioRoute"
+//#define LOG_NDEBUG 0
+
+#include "AudioRoute.h"
+#include "HwModule.h"
+#include "AudioGain.h"
+
+namespace android
+{
+
+void AudioRoute::dump(int fd, int spaces) const
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "%*s- Type: %s\n", spaces, "", mType == AUDIO_ROUTE_MUX ? "Mux" : "Mix");
+    result.append(buffer);
+
+    snprintf(buffer, SIZE, "%*s- Sink: %s\n", spaces, "", mSink->getTagName().string());
+    result.append(buffer);
+
+    if (mSources.size() != 0) {
+        snprintf(buffer, SIZE, "%*s- Sources: \n", spaces, "");
+        result.append(buffer);
+        for (size_t i = 0; i < mSources.size(); i++) {
+            snprintf(buffer, SIZE, "%*s%s \n", spaces + 4, "", mSources[i]->getTagName().string());
+            result.append(buffer);
+        }
+    }
+    result.append("\n");
+
+    write(fd, result.string(), result.size());
+}
+
+}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
new file mode 100644
index 0000000..306ed28
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 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 "APM::AudioSession"
+//#define LOG_NDEBUG 0
+
+#include <AudioPolicyInterface.h>
+#include "policy.h"
+#include "AudioSession.h"
+#include "AudioGain.h"
+#include "TypeConverter.h"
+#include <cutils/log.h>
+#include <utils/String8.h>
+
+namespace android {
+
+AudioSession::AudioSession(audio_session_t session,
+                           audio_source_t inputSource,
+                           audio_format_t format,
+                           uint32_t sampleRate,
+                           audio_channel_mask_t channelMask,
+                           audio_input_flags_t flags,
+                           uid_t uid,
+                           bool isSoundTrigger,
+                           AudioMix* policyMix,
+                           AudioPolicyClientInterface *clientInterface) :
+    mSession(session), mInputSource(inputSource),
+    mFormat(format), mSampleRate(sampleRate), mChannelMask(channelMask),
+    mFlags(flags), mUid(uid), mIsSoundTrigger(isSoundTrigger),
+    mOpenCount(1), mActiveCount(0), mPolicyMix(policyMix), mClientInterface(clientInterface)
+{
+}
+
+uint32_t AudioSession::changeOpenCount(int delta)
+{
+    if ((delta + (int)mOpenCount) < 0) {
+        ALOGW("%s invalid delta %d, open count %d",
+              __FUNCTION__, delta, mOpenCount);
+        mOpenCount = (uint32_t)(-delta);
+    }
+    mOpenCount += delta;
+    ALOGV("%s open count %d", __FUNCTION__, mOpenCount);
+    return mOpenCount;
+}
+
+uint32_t AudioSession::changeActiveCount(int delta)
+{
+    const uint32_t oldActiveCount = mActiveCount;
+    if ((delta + (int)mActiveCount) < 0) {
+        ALOGW("%s invalid delta %d, active count %d",
+              __FUNCTION__, delta, mActiveCount);
+        mActiveCount = (uint32_t)(-delta);
+    }
+    mActiveCount += delta;
+    ALOGV("%s active count %d", __FUNCTION__, mActiveCount);
+
+    if ((oldActiveCount == 0) && (mActiveCount > 0)) {
+        // if input maps to a dynamic policy with an activity listener, notify of state change
+        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+        {
+            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId,
+                    MIX_STATE_MIXING);
+        }
+        mClientInterface->onRecordingConfigurationUpdate(RECORD_CONFIG_EVENT_START,
+                mSession, mInputSource);
+    } else if ((oldActiveCount > 0) && (mActiveCount == 0)) {
+        // if input maps to a dynamic policy with an activity listener, notify of state change
+        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+        {
+            mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId,
+                    MIX_STATE_IDLE);
+        }
+        mClientInterface->onRecordingConfigurationUpdate(RECORD_CONFIG_EVENT_STOP,
+                mSession, mInputSource);
+    }
+
+    return mActiveCount;
+}
+
+bool AudioSession::matches(const sp<AudioSession> &other) const
+{
+    if (other->session() == mSession &&
+        other->inputSource() == mInputSource &&
+        other->format() == mFormat &&
+        other->sampleRate() == mSampleRate &&
+        other->channelMask() == mChannelMask &&
+        other->flags() == mFlags &&
+        other->uid() == mUid) {
+        return true;
+    }
+    return false;
+}
+
+
+status_t AudioSession::dump(int fd, int spaces, int index) const
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "%*sAudio session %d:\n", spaces, "", index+1);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "%*s- session: %2d\n", spaces, "", mSession);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "%*s- owner uid: %2d\n", spaces, "", mUid);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "%*s- input source: %d\n", spaces, "", mInputSource);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "%*s- format: %08x\n", spaces, "", mFormat);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "%*s- sample: %d\n", spaces, "", mSampleRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "%*s- channel mask: %08x\n",
+             spaces, "", mChannelMask);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "%*s- is soundtrigger: %s\n",
+             spaces, "", mIsSoundTrigger ? "true" : "false");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "%*s- open count: %d\n", spaces, "", mOpenCount);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "%*s- active count: %d\n", spaces, "", mActiveCount);
+    result.append(buffer);
+
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+status_t AudioSessionCollection::addSession(audio_session_t session,
+                                         const sp<AudioSession>& audioSession)
+{
+    ssize_t index = indexOfKey(session);
+
+    if (index >= 0) {
+        ALOGW("addSession() session %d already in", session);
+        return ALREADY_EXISTS;
+    }
+    add(session, audioSession);
+    ALOGV("addSession() session %d  client %d source %d",
+            session, audioSession->uid(), audioSession->inputSource());
+    return NO_ERROR;
+}
+
+status_t AudioSessionCollection::removeSession(audio_session_t session)
+{
+    ssize_t index = indexOfKey(session);
+
+    if (index < 0) {
+        ALOGW("removeSession() session %d not in", session);
+        return ALREADY_EXISTS;
+    }
+    ALOGV("removeSession() session %d", session);
+    removeItemsAt(index);
+    return NO_ERROR;
+}
+
+uint32_t AudioSessionCollection::getOpenCount() const
+{
+    uint32_t openCount = 0;
+    for (size_t i = 0; i < size(); i++) {
+        openCount += valueAt(i)->openCount();
+    }
+    return openCount;
+}
+
+AudioSessionCollection AudioSessionCollection::getActiveSessions() const
+{
+    AudioSessionCollection activeSessions;
+    for (size_t i = 0; i < size(); i++) {
+        if (valueAt(i)->activeCount() != 0) {
+            activeSessions.add(valueAt(i)->session(), valueAt(i));
+        }
+    }
+    return activeSessions;
+}
+
+size_t AudioSessionCollection::getActiveSessionCount() const
+{
+    size_t activeCount = 0;
+    for (size_t i = 0; i < size(); i++) {
+        if (valueAt(i)->activeCount() != 0) {
+            activeCount++;
+        }
+    }
+    return activeCount;
+}
+
+bool AudioSessionCollection::hasActiveSession() const
+{
+    return getActiveSessionCount() != 0;
+}
+
+bool AudioSessionCollection::isSourceActive(audio_source_t source) const
+{
+    for (size_t i = 0; i < size(); i++) {
+        const sp<AudioSession>  audioSession = valueAt(i);
+        // AUDIO_SOURCE_HOTWORD is equivalent to AUDIO_SOURCE_VOICE_RECOGNITION only if it
+        // corresponds to an active capture triggered by a hardware hotword recognition
+        if (audioSession->activeCount() > 0 &&
+                ((audioSession->inputSource() == source) ||
+                ((source == AUDIO_SOURCE_VOICE_RECOGNITION) &&
+                 (audioSession->inputSource() == AUDIO_SOURCE_HOTWORD) &&
+                 audioSession->isSoundTrigger()))) {
+            return true;
+        }
+    }
+    return false;
+}
+
+audio_source_t AudioSessionCollection::getHighestPrioritySource(bool activeOnly) const
+{
+    audio_source_t source = AUDIO_SOURCE_DEFAULT;
+    int32_t priority = -1;
+
+    for (size_t i = 0; i < size(); i++) {
+        const sp<AudioSession>  audioSession = valueAt(i);
+        if (activeOnly && audioSession->activeCount() == 0) {
+            continue;
+        }
+        int32_t curPriority = source_priority(audioSession->inputSource());
+        if (curPriority > priority) {
+            priority = curPriority;
+            source = audioSession->inputSource();
+        }
+    }
+    return source;
+}
+
+status_t AudioSessionCollection::dump(int fd, int spaces) const
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    snprintf(buffer, SIZE, "%*sAudio Sessions:\n", spaces, "");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < size(); i++) {
+        valueAt(i)->dump(fd, spaces + 2, i);
+    }
+    return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp
new file mode 100644
index 0000000..ba33e57
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 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 "APM::AudioSourceDescriptor"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <media/AudioPolicyHelper.h>
+#include <HwModule.h>
+#include <AudioGain.h>
+#include <AudioSourceDescriptor.h>
+#include <DeviceDescriptor.h>
+#include <IOProfile.h>
+#include <AudioOutputDescriptor.h>
+
+namespace android {
+
+status_t AudioSourceDescriptor::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "mStream: %d\n", audio_attributes_to_stream_type(&mAttributes));
+    result.append(buffer);
+    snprintf(buffer, SIZE, "mDevice:\n");
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+    mDevice->dump(fd, 2 , 0);
+    return NO_ERROR;
+}
+
+
+status_t AudioSourceCollection::dump(int fd) const
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+
+    snprintf(buffer, SIZE, "\nAudio sources dump:\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < size(); i++) {
+        snprintf(buffer, SIZE, "- Source %d dump:\n", keyAt(i));
+        write(fd, buffer, strlen(buffer));
+        valueAt(i)->dump(fd);
+    }
+
+    return NO_ERROR;
+}
+
+}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
index 89ef045..a3536e5 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
@@ -18,139 +18,230 @@
 //#define LOG_NDEBUG 0
 
 #include "ConfigParsingUtils.h"
+#include <convert/convert.h>
 #include "AudioGain.h"
+#include "IOProfile.h"
+#include "TypeConverter.h"
 #include <hardware/audio.h>
 #include <utils/Log.h>
 #include <cutils/misc.h>
 
 namespace android {
 
-//static
-uint32_t ConfigParsingUtils::stringToEnum(const struct StringToEnum *table,
-                                              size_t size,
-                                              const char *name)
-{
-    for (size_t i = 0; i < size; i++) {
-        if (strcmp(table[i].name, name) == 0) {
-            ALOGV("stringToEnum() found %s", table[i].name);
-            return table[i].value;
-        }
-    }
-    return 0;
-}
-
-//static
-const char *ConfigParsingUtils::enumToString(const struct StringToEnum *table,
-                                              size_t size,
-                                              uint32_t value)
-{
-    for (size_t i = 0; i < size; i++) {
-        if (table[i].value == value) {
-            return table[i].name;
-        }
-    }
-    return "";
-}
-
-//static
-bool ConfigParsingUtils::stringToBool(const char *value)
-{
-    return ((strcasecmp("true", value) == 0) || (strcmp("1", value) == 0));
-}
-
-
 // --- audio_policy.conf file parsing
-//static
-uint32_t ConfigParsingUtils::parseOutputFlagNames(char *name)
-{
-    uint32_t flag = 0;
 
-    // it is OK to cast name to non const here as we are not going to use it after
-    // strtok() modifies it
-    char *flagName = strtok(name, "|");
-    while (flagName != NULL) {
-        if (strlen(flagName) != 0) {
-            flag |= ConfigParsingUtils::stringToEnum(sOutputFlagNameToEnumTable,
-                               ARRAY_SIZE(sOutputFlagNameToEnumTable),
-                               flagName);
+//static
+void ConfigParsingUtils::loadAudioPortGain(cnode *root, AudioPort &audioPort, int index)
+{
+    cnode *node = root->first_child;
+
+    sp<AudioGain> gain = new AudioGain(index, audioPort.useInputChannelMask());
+
+    while (node) {
+        if (strcmp(node->name, GAIN_MODE) == 0) {
+            gain->setMode(GainModeConverter::maskFromString(node->value));
+        } else if (strcmp(node->name, GAIN_CHANNELS) == 0) {
+            audio_channel_mask_t mask;
+            if (audioPort.useInputChannelMask()) {
+                if (InputChannelConverter::fromString(node->value, mask)) {
+                    gain->setChannelMask(mask);
+                }
+            } else {
+                if (OutputChannelConverter::fromString(node->value, mask)) {
+                    gain->setChannelMask(mask);
+                }
+            }
+        } else if (strcmp(node->name, GAIN_MIN_VALUE) == 0) {
+            gain->setMinValueInMb(atoi(node->value));
+        } else if (strcmp(node->name, GAIN_MAX_VALUE) == 0) {
+            gain->setMaxValueInMb(atoi(node->value));
+        } else if (strcmp(node->name, GAIN_DEFAULT_VALUE) == 0) {
+            gain->setDefaultValueInMb(atoi(node->value));
+        } else if (strcmp(node->name, GAIN_STEP_VALUE) == 0) {
+            gain->setStepValueInMb(atoi(node->value));
+        } else if (strcmp(node->name, GAIN_MIN_RAMP_MS) == 0) {
+            gain->setMinRampInMs(atoi(node->value));
+        } else if (strcmp(node->name, GAIN_MAX_RAMP_MS) == 0) {
+            gain->setMaxRampInMs(atoi(node->value));
         }
-        flagName = strtok(NULL, "|");
-    }
-    //force direct flag if offload flag is set: offloading implies a direct output stream
-    // and all common behaviors are driven by checking only the direct flag
-    // this should normally be set appropriately in the policy configuration file
-    if ((flag & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
-        flag |= AUDIO_OUTPUT_FLAG_DIRECT;
+        node = node->next;
     }
 
-    return flag;
+    ALOGV("loadGain() adding new gain mode %08x channel mask %08x min mB %d max mB %d",
+          gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
+          gain->getMaxValueInMb());
+
+    if (gain->getMode() == 0) {
+        return;
+    }
+    audioPort.mGains.add(gain);
+}
+
+void ConfigParsingUtils::loadAudioPortGains(cnode *root, AudioPort &audioPort)
+{
+    cnode *node = root->first_child;
+    int index = 0;
+    while (node) {
+        ALOGV("loadGains() loading gain %s", node->name);
+        loadAudioPortGain(node, audioPort, index++);
+        node = node->next;
+    }
 }
 
 //static
-uint32_t ConfigParsingUtils::parseInputFlagNames(char *name)
+void ConfigParsingUtils::loadDeviceDescriptorGains(cnode *root, sp<DeviceDescriptor> &deviceDesc)
 {
-    uint32_t flag = 0;
+    loadAudioPortGains(root, *deviceDesc);
+    if (deviceDesc->mGains.size() > 0) {
+        deviceDesc->mGains[0]->getDefaultConfig(&deviceDesc->mGain);
+    }
+}
 
-    // it is OK to cast name to non const here as we are not going to use it after
-    // strtok() modifies it
-    char *flagName = strtok(name, "|");
-    while (flagName != NULL) {
-        if (strlen(flagName) != 0) {
-            flag |= stringToEnum(sInputFlagNameToEnumTable,
-                               ARRAY_SIZE(sInputFlagNameToEnumTable),
-                               flagName);
+//static
+status_t ConfigParsingUtils::loadHwModuleDevice(cnode *root, DeviceVector &devices)
+{
+    cnode *node = root->first_child;
+
+    audio_devices_t type = AUDIO_DEVICE_NONE;
+    while (node) {
+        if (strcmp(node->name, APM_DEVICE_TYPE) == 0) {
+            DeviceConverter::fromString(node->value, type);
+            break;
         }
-        flagName = strtok(NULL, "|");
+        node = node->next;
     }
-    return flag;
+    if (type == AUDIO_DEVICE_NONE ||
+            (!audio_is_input_device(type) && !audio_is_output_device(type))) {
+        ALOGW("loadDevice() bad type %08x", type);
+        return BAD_VALUE;
+    }
+    sp<DeviceDescriptor> deviceDesc = new DeviceDescriptor(type, String8(root->name));
+
+    node = root->first_child;
+    while (node) {
+        if (strcmp(node->name, APM_DEVICE_ADDRESS) == 0) {
+            deviceDesc->mAddress = String8((char *)node->value);
+        } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
+            if (audio_is_input_device(type)) {
+                deviceDesc->addAudioProfile(
+                        new AudioProfile(gDynamicFormat,
+                                         inputChannelMasksFromString(node->value),
+                                         SampleRateVector()));
+            } else {
+                deviceDesc->addAudioProfile(
+                        new AudioProfile(gDynamicFormat,
+                                         outputChannelMasksFromString(node->value),
+                                         SampleRateVector()));
+            }
+        } else if (strcmp(node->name, GAINS_TAG) == 0) {
+            loadDeviceDescriptorGains(node, deviceDesc);
+        }
+        node = node->next;
+    }
+
+    ALOGV("loadDevice() adding device tag (literal type) %s type %08x address %s",
+          deviceDesc->getTagName().string(), type, deviceDesc->mAddress.string());
+
+    devices.add(deviceDesc);
+    return NO_ERROR;
 }
 
 //static
-audio_devices_t ConfigParsingUtils::parseDeviceNames(char *name)
+status_t ConfigParsingUtils::loadHwModuleProfile(cnode *root, sp<HwModule> &module,
+                                                 audio_port_role_t role)
 {
-    uint32_t device = 0;
+    cnode *node = root->first_child;
 
-    char *devName = strtok(name, "|");
-    while (devName != NULL) {
-        if (strlen(devName) != 0) {
-            device |= stringToEnum(sDeviceTypeToEnumTable,
-                                 ARRAY_SIZE(sDeviceTypeToEnumTable),
-                                 devName);
-         }
-        devName = strtok(NULL, "|");
-     }
-    return device;
+    sp<IOProfile> profile = new IOProfile(String8(root->name), role);
+
+    AudioProfileVector audioProfiles;
+    SampleRateVector sampleRates;
+    ChannelsVector channels;
+    FormatVector formats;
+
+    while (node) {
+        if (strcmp(node->name, FORMATS_TAG) == 0 &&
+                strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
+            formats = formatsFromString(node->value);
+        } else if (strcmp(node->name, SAMPLING_RATES_TAG) == 0 &&
+                  strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
+            collectionFromString<SampleRateTraits>(node->value, sampleRates);
+        } else if (strcmp(node->name, CHANNELS_TAG) == 0 &&
+                   strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
+            if (role == AUDIO_PORT_ROLE_SINK) {
+                channels = inputChannelMasksFromString(node->value);
+            } else {
+                channels = outputChannelMasksFromString(node->value);
+            }
+        } else if (strcmp(node->name, DEVICES_TAG) == 0) {
+            DeviceVector devices;
+            loadDevicesFromTag(node->value, devices, module->getDeclaredDevices());
+            profile->setSupportedDevices(devices);
+        } else if (strcmp(node->name, FLAGS_TAG) == 0) {
+            if (role == AUDIO_PORT_ROLE_SINK) {
+                profile->setFlags(InputFlagConverter::maskFromString(node->value));
+            } else {
+                profile->setFlags(OutputFlagConverter::maskFromString(node->value));
+            }
+        } else if (strcmp(node->name, GAINS_TAG) == 0) {
+            loadAudioPortGains(node, *profile);
+        }
+        node = node->next;
+    }
+    if (formats.isEmpty()) {
+        sp<AudioProfile> profileToAdd = new AudioProfile(gDynamicFormat, channels, sampleRates);
+        profileToAdd->setDynamicFormat(true);
+        profileToAdd->setDynamicChannels(channels.isEmpty());
+        profileToAdd->setDynamicRate(sampleRates.isEmpty());
+        audioProfiles.add(profileToAdd);
+    } else {
+        for (size_t i = 0; i < formats.size(); i++) {
+            // For compatibility reason, for each format, creates a profile with the same
+            // collection of rate and channels.
+            sp<AudioProfile> profileToAdd = new AudioProfile(formats[i], channels, sampleRates);
+            profileToAdd->setDynamicFormat(formats[i] == gDynamicFormat);
+            profileToAdd->setDynamicChannels(channels.isEmpty());
+            profileToAdd->setDynamicRate(sampleRates.isEmpty());
+            audioProfiles.add(profileToAdd);
+        }
+    }
+    profile->setAudioProfiles(audioProfiles);
+    ALOGW_IF(!profile->hasSupportedDevices(), "load%s() invalid supported devices",
+             role == AUDIO_PORT_ROLE_SINK ? "Input" : "Output");
+    if (profile->hasSupportedDevices()) {
+        ALOGV("load%s() adding Supported Devices %04x, mFlags %04x",
+              role == AUDIO_PORT_ROLE_SINK ? "Input" : "Output",
+              profile->getSupportedDevicesType(), profile->getFlags());
+        return module->addProfile(profile);
+    }
+    return BAD_VALUE;
 }
 
 //static
-void ConfigParsingUtils::loadHwModule(cnode *root, HwModuleCollection &hwModules,
-                                      DeviceVector &availableInputDevices,
-                                      DeviceVector &availableOutputDevices,
-                                      sp<DeviceDescriptor> &defaultOutputDevices,
-                                      bool &isSpeakerDrcEnable)
+status_t ConfigParsingUtils::loadHwModule(cnode *root, sp<HwModule> &module,
+                                          AudioPolicyConfig &config)
 {
     status_t status = NAME_NOT_FOUND;
-    cnode *node;
-    sp<HwModule> module = new HwModule(root->name);
-
-    node = config_find(root, DEVICES_TAG);
+    cnode *node = config_find(root, DEVICES_TAG);
     if (node != NULL) {
         node = node->first_child;
+        DeviceVector devices;
         while (node) {
             ALOGV("loadHwModule() loading device %s", node->name);
-            status_t tmpStatus = module->loadDevice(node);
+            status_t tmpStatus = loadHwModuleDevice(node, devices);
             if (status == NAME_NOT_FOUND || status == NO_ERROR) {
                 status = tmpStatus;
             }
             node = node->next;
         }
+        module->setDeclaredDevices(devices);
     }
     node = config_find(root, OUTPUTS_TAG);
     if (node != NULL) {
         node = node->first_child;
         while (node) {
             ALOGV("loadHwModule() loading output %s", node->name);
-            status_t tmpStatus = module->loadOutput(node);
+            status_t tmpStatus = loadHwModuleProfile(node, module, AUDIO_PORT_ROLE_SOURCE);
             if (status == NAME_NOT_FOUND || status == NO_ERROR) {
                 status = tmpStatus;
             }
@@ -162,27 +253,20 @@
         node = node->first_child;
         while (node) {
             ALOGV("loadHwModule() loading input %s", node->name);
-            status_t tmpStatus = module->loadInput(node);
+            status_t tmpStatus = loadHwModuleProfile(node, module, AUDIO_PORT_ROLE_SINK);
             if (status == NAME_NOT_FOUND || status == NO_ERROR) {
                 status = tmpStatus;
             }
             node = node->next;
         }
     }
-    loadGlobalConfig(root, module, availableInputDevices, availableOutputDevices,
-                     defaultOutputDevices, isSpeakerDrcEnable);
-
-    if (status == NO_ERROR) {
-        hwModules.add(module);
-    }
+    loadModuleGlobalConfig(root, module, config);
+    return status;
 }
 
 //static
 void ConfigParsingUtils::loadHwModules(cnode *root, HwModuleCollection &hwModules,
-                                       DeviceVector &availableInputDevices,
-                                       DeviceVector &availableOutputDevices,
-                                       sp<DeviceDescriptor> &defaultOutputDevices,
-                                       bool &isSpeakerDrcEnabled)
+                                       AudioPolicyConfig &config)
 {
     cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);
     if (node == NULL) {
@@ -192,18 +276,49 @@
     node = node->first_child;
     while (node) {
         ALOGV("loadHwModules() loading module %s", node->name);
-        loadHwModule(node, hwModules, availableInputDevices, availableOutputDevices,
-                     defaultOutputDevices, isSpeakerDrcEnabled);
+        sp<HwModule> module = new HwModule(node->name);
+        if (loadHwModule(node, module, config) == NO_ERROR) {
+            hwModules.add(module);
+        }
         node = node->next;
     }
 }
 
 //static
-void ConfigParsingUtils::loadGlobalConfig(cnode *root, const sp<HwModule>& module,
-                                          DeviceVector &availableInputDevices,
-                                          DeviceVector &availableOutputDevices,
-                                          sp<DeviceDescriptor> &defaultOutputDevice,
-                                          bool &speakerDrcEnabled)
+void ConfigParsingUtils::loadDevicesFromTag(const char *tag, DeviceVector &devices,
+                                            const DeviceVector &declaredDevices)
+{
+    char *tagLiteral = strndup(tag, strlen(tag));
+    char *devTag = strtok(tagLiteral, "|");
+    while (devTag != NULL) {
+        if (strlen(devTag) != 0) {
+            audio_devices_t type;
+            if (DeviceConverter::fromString(devTag, type)) {
+                uint32_t inBit = type & AUDIO_DEVICE_BIT_IN;
+                type &= ~AUDIO_DEVICE_BIT_IN;
+                while (type) {
+                  audio_devices_t singleType =
+                        inBit | (1 << (31 - __builtin_clz(type)));
+                    type &= ~singleType;
+                    sp<DeviceDescriptor> dev = new DeviceDescriptor(singleType);
+                    devices.add(dev);
+                }
+            } else {
+                sp<DeviceDescriptor> deviceDesc =
+                        declaredDevices.getDeviceFromTagName(String8(devTag));
+                if (deviceDesc != 0) {
+                    devices.add(deviceDesc);
+                }
+            }
+        }
+        devTag = strtok(NULL, "|");
+    }
+    free(tagLiteral);
+}
+
+//static
+void ConfigParsingUtils::loadModuleGlobalConfig(cnode *root, const sp<HwModule> &module,
+                                                AudioPolicyConfig &config)
 {
     cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
 
@@ -212,52 +327,68 @@
     }
     DeviceVector declaredDevices;
     if (module != NULL) {
-        declaredDevices = module->mDeclaredDevices;
+        declaredDevices = module->getDeclaredDevices();
     }
 
     node = node->first_child;
     while (node) {
         if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
-            availableOutputDevices.loadDevicesFromTag((char *)node->value,
-                                                        declaredDevices);
+            DeviceVector availableOutputDevices;
+            loadDevicesFromTag(node->value, availableOutputDevices, declaredDevices);
             ALOGV("loadGlobalConfig() Attached Output Devices %08x",
                   availableOutputDevices.types());
+            config.addAvailableOutputDevices(availableOutputDevices);
         } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) {
-            audio_devices_t device = (audio_devices_t)stringToEnum(
-                    sDeviceTypeToEnumTable,
-                    ARRAY_SIZE(sDeviceTypeToEnumTable),
-                    (char *)node->value);
+            audio_devices_t device = AUDIO_DEVICE_NONE;
+            DeviceConverter::fromString(node->value, device);
             if (device != AUDIO_DEVICE_NONE) {
-                defaultOutputDevice = new DeviceDescriptor(device);
+                sp<DeviceDescriptor> defaultOutputDevice = new DeviceDescriptor(device);
+                config.setDefaultOutputDevice(defaultOutputDevice);
+                ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", defaultOutputDevice->type());
             } else {
                 ALOGW("loadGlobalConfig() default device not specified");
             }
-            ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", defaultOutputDevice->type());
         } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
-            availableInputDevices.loadDevicesFromTag((char *)node->value,
-                                                       declaredDevices);
+            DeviceVector availableInputDevices;
+            loadDevicesFromTag(node->value, availableInputDevices, declaredDevices);
             ALOGV("loadGlobalConfig() Available InputDevices %08x", availableInputDevices.types());
-        } else if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
-            speakerDrcEnabled = stringToBool((char *)node->value);
-            ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", speakerDrcEnabled);
+            config.addAvailableInputDevices(availableInputDevices);
         } else if (strcmp(AUDIO_HAL_VERSION_TAG, node->name) == 0) {
             uint32_t major, minor;
             sscanf((char *)node->value, "%u.%u", &major, &minor);
-            module->mHalVersion = HARDWARE_DEVICE_API_VERSION(major, minor);
+            module->setHalVersion(HARDWARE_DEVICE_API_VERSION(major, minor));
             ALOGV("loadGlobalConfig() mHalVersion = %04x major %u minor %u",
-                  module->mHalVersion, major, minor);
+                  module->getHalVersion(), major, minor);
         }
         node = node->next;
     }
 }
 
 //static
-status_t ConfigParsingUtils::loadAudioPolicyConfig(const char *path,
-                                                   HwModuleCollection &hwModules,
-                                                   DeviceVector &availableInputDevices,
-                                                   DeviceVector &availableOutputDevices,
-                                                   sp<DeviceDescriptor> &defaultOutputDevices,
-                                                   bool &isSpeakerDrcEnabled)
+void ConfigParsingUtils::loadGlobalConfig(cnode *root, AudioPolicyConfig &config,
+                                          const sp<HwModule>& primaryModule)
+{
+    cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
+
+    if (node == NULL) {
+        return;
+    }
+    node = node->first_child;
+    while (node) {
+        if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
+            bool speakerDrcEnabled;
+            if (utilities::convertTo<std::string, bool>(node->value, speakerDrcEnabled)) {
+                ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", speakerDrcEnabled);
+                config.setSpeakerDrcEnabled(speakerDrcEnabled);
+            }
+        }
+        node = node->next;
+    }
+    loadModuleGlobalConfig(root, primaryModule, config);
+}
+
+//static
+status_t ConfigParsingUtils::loadConfig(const char *path, AudioPolicyConfig &config)
 {
     cnode *root;
     char *data;
@@ -269,13 +400,14 @@
     root = config_node("", "");
     config_load(root, data);
 
-    loadHwModules(root, hwModules,
-                  availableInputDevices, availableOutputDevices,
-                  defaultOutputDevices, isSpeakerDrcEnabled);
-    // legacy audio_policy.conf files have one global_configuration section
-    loadGlobalConfig(root, hwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY),
-                     availableInputDevices, availableOutputDevices,
-                     defaultOutputDevices, isSpeakerDrcEnabled);
+    HwModuleCollection hwModules;
+    loadHwModules(root, hwModules, config);
+
+    // legacy audio_policy.conf files have one global_configuration section, attached to primary.
+    loadGlobalConfig(root, config, hwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY));
+
+    config.setHwModules(hwModules);
+
     config_free(root);
     free(root);
     free(data);
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 1f1fca3..787f53f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -18,19 +18,21 @@
 //#define LOG_NDEBUG 0
 
 #include "DeviceDescriptor.h"
+#include "TypeConverter.h"
 #include "AudioGain.h"
 #include "HwModule.h"
-#include "ConfigParsingUtils.h"
 
 namespace android {
 
-DeviceDescriptor::DeviceDescriptor(audio_devices_t type) :
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const String8 &tagName) :
     AudioPort(String8(""), AUDIO_PORT_TYPE_DEVICE,
               audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
                                              AUDIO_PORT_ROLE_SOURCE),
-    mTag(""), mAddress(""), mDeviceType(type), mId(0)
+    mAddress(""), mTagName(tagName), mDeviceType(type), mId(0)
 {
-
+    if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX || type == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ) {
+        mAddress = String8("0");
+    }
 }
 
 audio_port_handle_t DeviceDescriptor::getId() const
@@ -59,14 +61,6 @@
                 mChannelMask == other->mChannelMask);
 }
 
-void DeviceDescriptor::loadGains(cnode *root)
-{
-    AudioPort::loadGains(root);
-    if (mGains.size() > 0) {
-        mGains[0]->getDefaultConfig(&mGain);
-    }
-}
-
 void DeviceVector::refreshTypes()
 {
     mDeviceTypes = AUDIO_DEVICE_NONE;
@@ -86,6 +80,16 @@
     return -1;
 }
 
+void DeviceVector::add(const DeviceVector &devices)
+{
+    for (size_t i = 0; i < devices.size(); i++) {
+        sp<DeviceDescriptor> device = devices.itemAt(i);
+        if (indexOf(device) < 0 && SortedVector::add(device) >= 0) {
+            refreshTypes();
+        }
+    }
+}
+
 ssize_t DeviceVector::add(const sp<DeviceDescriptor>& item)
 {
     ssize_t ret = indexOf(item);
@@ -129,49 +133,6 @@
     return devices;
 }
 
-void DeviceVector::loadDevicesFromType(audio_devices_t types)
-{
-    DeviceVector deviceList;
-
-    uint32_t role_bit = AUDIO_DEVICE_BIT_IN & types;
-    types &= ~role_bit;
-
-    while (types) {
-        uint32_t i = 31 - __builtin_clz(types);
-        uint32_t type = 1 << i;
-        types &= ~type;
-        add(new DeviceDescriptor(type | role_bit));
-    }
-}
-
-void DeviceVector::loadDevicesFromTag(char *tag,
-                                       const DeviceVector& declaredDevices)
-{
-    char *devTag = strtok(tag, "|");
-    while (devTag != NULL) {
-        if (strlen(devTag) != 0) {
-            audio_devices_t type = ConfigParsingUtils::stringToEnum(sDeviceTypeToEnumTable,
-                                 ARRAY_SIZE(sDeviceTypeToEnumTable),
-                                 devTag);
-            if (type != AUDIO_DEVICE_NONE) {
-                sp<DeviceDescriptor> dev = new DeviceDescriptor(type);
-                if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX ||
-                        type == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ) {
-                    dev->mAddress = String8("0");
-                }
-                add(dev);
-            } else {
-                sp<DeviceDescriptor> deviceDesc =
-                        declaredDevices.getDeviceFromTag(String8(devTag));
-                if (deviceDesc != 0) {
-                    add(deviceDesc);
-                }
-            }
-         }
-         devTag = strtok(NULL, "|");
-     }
-}
-
 sp<DeviceDescriptor> DeviceVector::getDevice(audio_devices_t type, String8 address) const
 {
     sp<DeviceDescriptor> device;
@@ -234,11 +195,11 @@
     return devices;
 }
 
-sp<DeviceDescriptor> DeviceVector::getDeviceFromTag(const String8& tag) const
+sp<DeviceDescriptor> DeviceVector::getDeviceFromTagName(const String8 &tagName) const
 {
     sp<DeviceDescriptor> device;
     for (size_t i = 0; i < size(); i++) {
-        if (itemAt(i)->mTag == tag) {
+        if (itemAt(i)->getTagName() == tagName) {
             device = itemAt(i);
             break;
         }
@@ -246,16 +207,18 @@
     return device;
 }
 
-
-status_t DeviceVector::dump(int fd, const String8 &direction) const
+status_t DeviceVector::dump(int fd, const String8 &tag, int spaces, bool verbose) const
 {
+    if (isEmpty()) {
+        return NO_ERROR;
+    }
     const size_t SIZE = 256;
     char buffer[SIZE];
 
-    snprintf(buffer, SIZE, "\n Available %s devices:\n", direction.string());
+    snprintf(buffer, SIZE, "%*s- %s devices:\n", spaces, "", tag.string());
     write(fd, buffer, strlen(buffer));
     for (size_t i = 0; i < size(); i++) {
-        itemAt(i)->dump(fd, 2, i);
+        itemAt(i)->dump(fd, spaces + 2, i, verbose);
     }
     return NO_ERROR;
 }
@@ -303,12 +266,10 @@
 
 void DeviceDescriptor::importAudioPort(const sp<AudioPort> port) {
     AudioPort::importAudioPort(port);
-    mSamplingRate = port->pickSamplingRate();
-    mFormat = port->pickFormat();
-    mChannelMask = port->pickChannelMask();
+    port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
 }
 
-status_t DeviceDescriptor::dump(int fd, int spaces, int index) const
+status_t DeviceDescriptor::dump(int fd, int spaces, int index, bool verbose) const
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -320,28 +281,30 @@
         snprintf(buffer, SIZE, "%*s- id: %2d\n", spaces, "", mId);
         result.append(buffer);
     }
-    snprintf(buffer, SIZE, "%*s- type: %-48s\n", spaces, "",
-            ConfigParsingUtils::enumToString(sDeviceTypeToEnumTable,
-                    ARRAY_SIZE(sDeviceTypeToEnumTable),
-                    mDeviceType));
-    result.append(buffer);
+    if (!mTagName.isEmpty()) {
+        snprintf(buffer, SIZE, "%*s- tag name: %s\n", spaces, "", mTagName.string());
+        result.append(buffer);
+    }
+    std::string deviceLiteral;
+    if (DeviceConverter::toString(mDeviceType, deviceLiteral)) {
+        snprintf(buffer, SIZE, "%*s- type: %-48s\n", spaces, "", deviceLiteral.c_str());
+        result.append(buffer);
+    }
     if (mAddress.size() != 0) {
         snprintf(buffer, SIZE, "%*s- address: %-32s\n", spaces, "", mAddress.string());
         result.append(buffer);
     }
     write(fd, result.string(), result.size());
-    AudioPort::dump(fd, spaces);
+    AudioPort::dump(fd, spaces, verbose);
 
     return NO_ERROR;
 }
 
 void DeviceDescriptor::log() const
 {
-    ALOGI("Device id:%d type:0x%X:%s, addr:%s",
-          mId,
-          mDeviceType,
-          ConfigParsingUtils::enumToString(
-             sDeviceNameToEnumTable, ARRAY_SIZE(sDeviceNameToEnumTable), mDeviceType),
+    std::string device;
+    DeviceConverter::toString(mDeviceType, device);
+    ALOGI("Device id:%d type:0x%X:%s, addr:%s", mId,  mDeviceType, device.c_str(),
           mAddress.string());
 
     AudioPort::log("  ");
diff --git a/services/audiopolicy/enginedefault/src/Gains.cpp b/services/audiopolicy/common/managerdefinitions/src/Gains.cpp
similarity index 90%
rename from services/audiopolicy/enginedefault/src/Gains.cpp
rename to services/audiopolicy/common/managerdefinitions/src/Gains.cpp
index d06365c..e3fc9a8 100644
--- a/services/audiopolicy/enginedefault/src/Gains.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Gains.cpp
@@ -114,7 +114,7 @@
 };
 
 const VolumeCurvePoint *Gains::sVolumeProfiles[AUDIO_STREAM_CNT]
-                                                  [Volume::DEVICE_CATEGORY_CNT] = {
+                                                  [DEVICE_CATEGORY_CNT] = {
     { // AUDIO_STREAM_VOICE_CALL
         Gains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
         Gains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
@@ -197,17 +197,11 @@
 };
 
 //static
-float Gains::volIndexToDb(Volume::device_category deviceCategory,
-                          const StreamDescriptor& streamDesc,
-                          int indexInUi)
+float Gains::volIndexToDb(const VolumeCurvePoint *curve, int indexMin, int indexMax, int indexInUi)
 {
-    const VolumeCurvePoint *curve = streamDesc.getVolumeCurvePoint(deviceCategory);
-
     // the volume index in the UI is relative to the min and max volume indices for this stream type
-    int nbSteps = 1 + curve[Volume::VOLMAX].mIndex -
-            curve[Volume::VOLMIN].mIndex;
-    int volIdx = (nbSteps * (indexInUi - streamDesc.getVolumeIndexMin())) /
-            (streamDesc.getVolumeIndexMax() - streamDesc.getVolumeIndexMin());
+    int nbSteps = 1 + curve[Volume::VOLMAX].mIndex - curve[Volume::VOLMIN].mIndex;
+    int volIdx = (nbSteps * (indexInUi - indexMin)) / (indexMax - indexMin);
 
     // find what part of the curve this index volume belongs to, or if it's out of bounds
     int segment = 0;
@@ -241,15 +235,4 @@
     return decibels;
 }
 
-
-//static
-float Gains::volIndexToAmpl(Volume::device_category deviceCategory,
-                            const StreamDescriptor& streamDesc,
-                            int indexInUi)
-{
-    return Volume::DbToAmpl(volIndexToDb(deviceCategory, streamDesc, indexInUi));
-}
-
-
-
 }; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 7e2050b..dd2a60a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -20,190 +20,83 @@
 #include "HwModule.h"
 #include "IOProfile.h"
 #include "AudioGain.h"
-#include "ConfigParsingUtils.h"
-#include "audio_policy_conf.h"
 #include <hardware/audio.h>
 #include <policy.h>
 
 namespace android {
 
-HwModule::HwModule(const char *name)
-    : mName(strndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN)),
-      mHalVersion(AUDIO_DEVICE_API_VERSION_MIN), mHandle(0)
+HwModule::HwModule(const char *name, uint32_t halVersion)
+    : mName(String8(name)),
+      mHandle(0),
+      mHalVersion(halVersion)
 {
 }
 
 HwModule::~HwModule()
 {
     for (size_t i = 0; i < mOutputProfiles.size(); i++) {
-        mOutputProfiles[i]->mSupportedDevices.clear();
+        mOutputProfiles[i]->clearSupportedDevices();
     }
     for (size_t i = 0; i < mInputProfiles.size(); i++) {
-        mInputProfiles[i]->mSupportedDevices.clear();
+        mInputProfiles[i]->clearSupportedDevices();
     }
-    free((void *)mName);
-}
-
-status_t HwModule::loadInput(cnode *root)
-{
-    cnode *node = root->first_child;
-
-    sp<IOProfile> profile = new IOProfile(String8(root->name), AUDIO_PORT_ROLE_SINK);
-
-    while (node) {
-        if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
-            profile->loadSamplingRates((char *)node->value);
-        } else if (strcmp(node->name, FORMATS_TAG) == 0) {
-            profile->loadFormats((char *)node->value);
-        } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
-            profile->loadInChannels((char *)node->value);
-        } else if (strcmp(node->name, DEVICES_TAG) == 0) {
-            profile->mSupportedDevices.loadDevicesFromTag((char *)node->value,
-                                                           mDeclaredDevices);
-        } else if (strcmp(node->name, FLAGS_TAG) == 0) {
-            profile->mFlags = ConfigParsingUtils::parseInputFlagNames((char *)node->value);
-        } else if (strcmp(node->name, GAINS_TAG) == 0) {
-            profile->loadGains(node);
-        }
-        node = node->next;
-    }
-    ALOGW_IF(profile->mSupportedDevices.isEmpty(),
-            "loadInput() invalid supported devices");
-    ALOGW_IF(profile->mChannelMasks.size() == 0,
-            "loadInput() invalid supported channel masks");
-    ALOGW_IF(profile->mSamplingRates.size() == 0,
-            "loadInput() invalid supported sampling rates");
-    ALOGW_IF(profile->mFormats.size() == 0,
-            "loadInput() invalid supported formats");
-    if (!profile->mSupportedDevices.isEmpty() &&
-            (profile->mChannelMasks.size() != 0) &&
-            (profile->mSamplingRates.size() != 0) &&
-            (profile->mFormats.size() != 0)) {
-
-        ALOGV("loadInput() adding input Supported Devices %04x",
-              profile->mSupportedDevices.types());
-
-        profile->attach(this);
-        mInputProfiles.add(profile);
-        return NO_ERROR;
-    } else {
-        return BAD_VALUE;
-    }
-}
-
-status_t HwModule::loadOutput(cnode *root)
-{
-    cnode *node = root->first_child;
-
-    sp<IOProfile> profile = new IOProfile(String8(root->name), AUDIO_PORT_ROLE_SOURCE);
-
-    while (node) {
-        if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
-            profile->loadSamplingRates((char *)node->value);
-        } else if (strcmp(node->name, FORMATS_TAG) == 0) {
-            profile->loadFormats((char *)node->value);
-        } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
-            profile->loadOutChannels((char *)node->value);
-        } else if (strcmp(node->name, DEVICES_TAG) == 0) {
-            profile->mSupportedDevices.loadDevicesFromTag((char *)node->value,
-                                                           mDeclaredDevices);
-        } else if (strcmp(node->name, FLAGS_TAG) == 0) {
-            profile->mFlags = ConfigParsingUtils::parseOutputFlagNames((char *)node->value);
-        } else if (strcmp(node->name, GAINS_TAG) == 0) {
-            profile->loadGains(node);
-        }
-        node = node->next;
-    }
-    ALOGW_IF(profile->mSupportedDevices.isEmpty(),
-            "loadOutput() invalid supported devices");
-    ALOGW_IF(profile->mChannelMasks.size() == 0,
-            "loadOutput() invalid supported channel masks");
-    ALOGW_IF(profile->mSamplingRates.size() == 0,
-            "loadOutput() invalid supported sampling rates");
-    ALOGW_IF(profile->mFormats.size() == 0,
-            "loadOutput() invalid supported formats");
-    if (!profile->mSupportedDevices.isEmpty() &&
-            (profile->mChannelMasks.size() != 0) &&
-            (profile->mSamplingRates.size() != 0) &&
-            (profile->mFormats.size() != 0)) {
-
-        ALOGV("loadOutput() adding output Supported Devices %04x, mFlags %04x",
-              profile->mSupportedDevices.types(), profile->mFlags);
-        profile->attach(this);
-        mOutputProfiles.add(profile);
-        return NO_ERROR;
-    } else {
-        return BAD_VALUE;
-    }
-}
-
-status_t HwModule::loadDevice(cnode *root)
-{
-    cnode *node = root->first_child;
-
-    audio_devices_t type = AUDIO_DEVICE_NONE;
-    while (node) {
-        if (strcmp(node->name, APM_DEVICE_TYPE) == 0) {
-            type = ConfigParsingUtils::parseDeviceNames((char *)node->value);
-            break;
-        }
-        node = node->next;
-    }
-    if (type == AUDIO_DEVICE_NONE ||
-            (!audio_is_input_device(type) && !audio_is_output_device(type))) {
-        ALOGW("loadDevice() bad type %08x", type);
-        return BAD_VALUE;
-    }
-    sp<DeviceDescriptor> deviceDesc = new DeviceDescriptor(type);
-    deviceDesc->mTag = String8(root->name);
-
-    node = root->first_child;
-    while (node) {
-        if (strcmp(node->name, APM_DEVICE_ADDRESS) == 0) {
-            deviceDesc->mAddress = String8((char *)node->value);
-        } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
-            if (audio_is_input_device(type)) {
-                deviceDesc->loadInChannels((char *)node->value);
-            } else {
-                deviceDesc->loadOutChannels((char *)node->value);
-            }
-        } else if (strcmp(node->name, GAINS_TAG) == 0) {
-            deviceDesc->loadGains(node);
-        }
-        node = node->next;
-    }
-
-    ALOGV("loadDevice() adding device tag %s type %08x address %s",
-          deviceDesc->mTag.string(), type, deviceDesc->mAddress.string());
-
-    mDeclaredDevices.add(deviceDesc);
-
-    return NO_ERROR;
 }
 
 status_t HwModule::addOutputProfile(String8 name, const audio_config_t *config,
-                                                  audio_devices_t device, String8 address)
+                                    audio_devices_t device, String8 address)
 {
-    sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SOURCE);
+    sp<IOProfile> profile = new OutputProfile(name);
 
-    profile->mSamplingRates.add(config->sample_rate);
-    profile->mChannelMasks.add(config->channel_mask);
-    profile->mFormats.add(config->format);
+    profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
+                                              config->sample_rate));
 
     sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
     devDesc->mAddress = address;
-    profile->mSupportedDevices.add(devDesc);
+    profile->addSupportedDevice(devDesc);
 
+    return addOutputProfile(profile);
+}
+
+status_t HwModule::addOutputProfile(const sp<IOProfile> &profile)
+{
     profile->attach(this);
     mOutputProfiles.add(profile);
-
+    mPorts.add(profile);
     return NO_ERROR;
 }
 
+status_t HwModule::addInputProfile(const sp<IOProfile> &profile)
+{
+    profile->attach(this);
+    mInputProfiles.add(profile);
+    mPorts.add(profile);
+    return NO_ERROR;
+}
+
+status_t HwModule::addProfile(const sp<IOProfile> &profile)
+{
+    switch (profile->getRole()) {
+    case AUDIO_PORT_ROLE_SOURCE:
+        return addOutputProfile(profile);
+    case AUDIO_PORT_ROLE_SINK:
+        return addInputProfile(profile);
+    case AUDIO_PORT_ROLE_NONE:
+        return BAD_VALUE;
+    }
+    return BAD_VALUE;
+}
+
+void HwModule::setProfiles(const IOProfileCollection &profiles)
+{
+    for (size_t i = 0; i < profiles.size(); i++) {
+        addProfile(profiles[i]);
+    }
+}
+
 status_t HwModule::removeOutputProfile(String8 name)
 {
     for (size_t i = 0; i < mOutputProfiles.size(); i++) {
-        if (mOutputProfiles[i]->mName == name) {
+        if (mOutputProfiles[i]->getName() == name) {
             mOutputProfiles.removeAt(i);
             break;
         }
@@ -213,30 +106,26 @@
 }
 
 status_t HwModule::addInputProfile(String8 name, const audio_config_t *config,
-                                                  audio_devices_t device, String8 address)
+                                   audio_devices_t device, String8 address)
 {
-    sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SINK);
-
-    profile->mSamplingRates.add(config->sample_rate);
-    profile->mChannelMasks.add(config->channel_mask);
-    profile->mFormats.add(config->format);
+    sp<IOProfile> profile = new InputProfile(name);
+    profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
+                                              config->sample_rate));
 
     sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
     devDesc->mAddress = address;
-    profile->mSupportedDevices.add(devDesc);
+    profile->addSupportedDevice(devDesc);
 
-    ALOGV("addInputProfile() name %s rate %d mask 0x08", name.string(), config->sample_rate, config->channel_mask);
+    ALOGV("addInputProfile() name %s rate %d mask 0x%08x",
+          name.string(), config->sample_rate, config->channel_mask);
 
-    profile->attach(this);
-    mInputProfiles.add(profile);
-
-    return NO_ERROR;
+    return addInputProfile(profile);
 }
 
 status_t HwModule::removeInputProfile(String8 name)
 {
     for (size_t i = 0; i < mInputProfiles.size(); i++) {
-        if (mInputProfiles[i]->mName == name) {
+        if (mInputProfiles[i]->getName() == name) {
             mInputProfiles.removeAt(i);
             break;
         }
@@ -245,6 +134,88 @@
     return NO_ERROR;
 }
 
+void HwModule::setDeclaredDevices(const DeviceVector &devices)
+{
+    mDeclaredDevices = devices;
+    for (size_t i = 0; i < devices.size(); i++) {
+        mPorts.add(devices[i]);
+    }
+}
+
+sp<DeviceDescriptor> HwModule::getRouteSinkDevice(const sp<AudioRoute> &route) const
+{
+    sp<DeviceDescriptor> sinkDevice = 0;
+    if (route->getSink()->getType() == AUDIO_PORT_TYPE_DEVICE) {
+        sinkDevice = mDeclaredDevices.getDeviceFromTagName(route->getSink()->getTagName());
+    }
+    return sinkDevice;
+}
+
+DeviceVector HwModule::getRouteSourceDevices(const sp<AudioRoute> &route) const
+{
+    DeviceVector sourceDevices;
+    Vector <sp<AudioPort> > sources = route->getSources();
+    for (size_t i = 0; i < sources.size(); i++) {
+        if (sources[i]->getType() == AUDIO_PORT_TYPE_DEVICE) {
+            sourceDevices.add(mDeclaredDevices.getDeviceFromTagName(sources[i]->getTagName()));
+        }
+    }
+    return sourceDevices;
+}
+
+void HwModule::setRoutes(const AudioRouteVector &routes)
+{
+    mRoutes = routes;
+    // Now updating the streams (aka IOProfile until now) supported devices
+    refreshSupportedDevices();
+}
+
+void HwModule::refreshSupportedDevices()
+{
+    // Now updating the streams (aka IOProfile until now) supported devices
+    for (size_t i = 0; i < mInputProfiles.size(); i++) {
+        sp<IOProfile> stream = mInputProfiles[i];
+        DeviceVector sourceDevices;
+        const AudioRouteVector &routes = stream->getRoutes();
+        for (size_t j = 0; j < routes.size(); j++) {
+            sp<AudioPort> sink = routes[j]->getSink();
+            if (sink == 0 || stream != sink) {
+                ALOGE("%s: Invalid route attached to input stream", __FUNCTION__);
+                continue;
+            }
+            DeviceVector sourceDevicesForRoute = getRouteSourceDevices(routes[j]);
+            if (sourceDevicesForRoute.isEmpty()) {
+                ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
+                continue;
+            }
+            sourceDevices.add(sourceDevicesForRoute);
+        }
+        if (sourceDevices.isEmpty()) {
+            ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
+            continue;
+        }
+        stream->setSupportedDevices(sourceDevices);
+    }
+    for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+        sp<IOProfile> stream = mOutputProfiles[i];
+        DeviceVector sinkDevices;
+        const AudioRouteVector &routes = stream->getRoutes();
+        for (size_t j = 0; j < routes.size(); j++) {
+            sp<AudioPort> source = routes[j]->getSources().findByTagName(stream->getTagName());
+            if (source == 0 || stream != source) {
+                ALOGE("%s: Invalid route attached to output stream", __FUNCTION__);
+                continue;
+            }
+            sp<DeviceDescriptor> sinkDevice = getRouteSinkDevice(routes[j]);
+            if (sinkDevice == 0) {
+                ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().string());
+                continue;
+            }
+            sinkDevices.add(sinkDevice);
+        }
+        stream->setSupportedDevices(sinkDevices);
+    }
+}
 
 void HwModule::dump(int fd)
 {
@@ -252,7 +223,7 @@
     char buffer[SIZE];
     String8 result;
 
-    snprintf(buffer, SIZE, "  - name: %s\n", mName);
+    snprintf(buffer, SIZE, "  - name: %s\n", getName());
     result.append(buffer);
     snprintf(buffer, SIZE, "  - handle: %d\n", mHandle);
     result.append(buffer);
@@ -275,12 +246,8 @@
             mInputProfiles[i]->dump(fd);
         }
     }
-    if (mDeclaredDevices.size()) {
-        write(fd, "  - devices:\n", strlen("  - devices:\n"));
-        for (size_t i = 0; i < mDeclaredDevices.size(); i++) {
-            mDeclaredDevices[i]->dump(fd, 4, i);
-        }
-    }
+    mDeclaredDevices.dump(fd, String8("Declared"),  2, true);
+    mRoutes.dump(fd, 2);
 }
 
 sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
@@ -289,7 +256,7 @@
 
     for (size_t i = 0; i < size(); i++)
     {
-        if (strcmp(itemAt(i)->mName, name) == 0) {
+        if (strcmp(itemAt(i)->getName(), name) == 0) {
             return itemAt(i);
         }
     }
@@ -302,20 +269,19 @@
     sp <HwModule> module;
 
     for (size_t i = 0; i < size(); i++) {
-        if (itemAt(i)->mHandle == 0) {
+        if (itemAt(i)->getHandle() == 0) {
             continue;
         }
         if (audio_is_output_device(device)) {
             for (size_t j = 0; j < itemAt(i)->mOutputProfiles.size(); j++)
             {
-                if (itemAt(i)->mOutputProfiles[j]->mSupportedDevices.types() & device) {
+                if (itemAt(i)->mOutputProfiles[j]->supportDevice(device)) {
                     return itemAt(i);
                 }
             }
         } else {
             for (size_t j = 0; j < itemAt(i)->mInputProfiles.size(); j++) {
-                if (itemAt(i)->mInputProfiles[j]->mSupportedDevices.types() &
-                        device & ~AUDIO_DEVICE_BIT_IN) {
+                if (itemAt(i)->mInputProfiles[j]->supportDevice(device)) {
                     return itemAt(i);
                 }
             }
@@ -340,19 +306,20 @@
             continue;
         }
         DeviceVector deviceList =
-                hwModule->mDeclaredDevices.getDevicesFromTypeAddr(device, address);
+                hwModule->getDeclaredDevices().getDevicesFromTypeAddr(device, address);
         if (!deviceList.isEmpty()) {
             return deviceList.itemAt(0);
         }
-        deviceList = hwModule->mDeclaredDevices.getDevicesFromType(device);
+        deviceList = hwModule->getDeclaredDevices().getDevicesFromType(device);
         if (!deviceList.isEmpty()) {
+            deviceList.itemAt(0)->setName(String8(device_name));
+            deviceList.itemAt(0)->mAddress = address;
             return deviceList.itemAt(0);
         }
     }
 
-    sp<DeviceDescriptor> devDesc =
-            new DeviceDescriptor(device);
-    devDesc->mName = device_name;
+    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
+    devDesc->setName(String8(device_name));
     devDesc->mAddress = address;
     return devDesc;
 }
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index 7b6d51d..204eb04 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -20,18 +20,10 @@
 #include "IOProfile.h"
 #include "HwModule.h"
 #include "AudioGain.h"
+#include "TypeConverter.h"
 
 namespace android {
 
-IOProfile::IOProfile(const String8& name, audio_port_role_t role)
-    : AudioPort(name, AUDIO_PORT_TYPE_MIX, role)
-{
-}
-
-IOProfile::~IOProfile()
-{
-}
-
 // checks if the IO profile is compatible with specified parameters.
 // Sampling rate, format and channel mask must be specified in order to
 // get a valid a match
@@ -45,8 +37,10 @@
                                     audio_channel_mask_t *updatedChannelMask,
                                     uint32_t flags) const
 {
-    const bool isPlaybackThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SOURCE;
-    const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
+    const bool isPlaybackThread =
+            getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SOURCE;
+    const bool isRecordThread =
+            getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SINK;
     ALOG_ASSERT(isPlaybackThread != isRecordThread);
 
 
@@ -61,47 +55,35 @@
         }
     }
 
-    if (samplingRate == 0) {
-         return false;
-    }
-    uint32_t myUpdatedSamplingRate = samplingRate;
-    if (isPlaybackThread && checkExactSamplingRate(samplingRate) != NO_ERROR) {
-         return false;
-    }
-    if (isRecordThread && checkCompatibleSamplingRate(samplingRate, &myUpdatedSamplingRate) !=
-            NO_ERROR) {
+    if (samplingRate == 0 || !audio_is_valid_format(format) ||
+            (isPlaybackThread && (!audio_is_output_channel(channelMask))) ||
+            (isRecordThread && (!audio_is_input_channel(channelMask)))) {
          return false;
     }
 
-    if (!audio_is_valid_format(format)) {
-        return false;
-    }
-    if (isPlaybackThread && checkExactFormat(format) != NO_ERROR) {
-        return false;
-    }
     audio_format_t myUpdatedFormat = format;
-    if (isRecordThread && checkCompatibleFormat(format, &myUpdatedFormat) != NO_ERROR) {
-        return false;
-    }
-
-    if (isPlaybackThread && (!audio_is_output_channel(channelMask) ||
-            checkExactChannelMask(channelMask) != NO_ERROR)) {
-        return false;
-    }
     audio_channel_mask_t myUpdatedChannelMask = channelMask;
-    if (isRecordThread && (!audio_is_input_channel(channelMask) ||
-            checkCompatibleChannelMask(channelMask, &myUpdatedChannelMask) != NO_ERROR)) {
-        return false;
+    uint32_t myUpdatedSamplingRate = samplingRate;
+    if (isRecordThread)
+    {
+        if (checkCompatibleAudioProfile(
+                myUpdatedSamplingRate, myUpdatedChannelMask, myUpdatedFormat) != NO_ERROR) {
+            return false;
+        }
+    } else {
+        if (checkExactAudioProfile(samplingRate, channelMask, format) != NO_ERROR) {
+            return false;
+        }
     }
 
-    if (isPlaybackThread && (mFlags & flags) != flags) {
+    if (isPlaybackThread && (getFlags() & flags) != flags) {
         return false;
     }
     // The only input flag that is allowed to be different is the fast flag.
     // An existing fast stream is compatible with a normal track request.
     // An existing normal stream is compatible with a fast track request,
     // but the fast request will be denied by AudioFlinger and converted to normal track.
-    if (isRecordThread && ((mFlags ^ flags) &
+    if (isRecordThread && ((getFlags() ^ flags) &
             ~AUDIO_INPUT_FLAG_FAST)) {
         return false;
     }
@@ -126,39 +108,15 @@
 
     AudioPort::dump(fd, 4);
 
-    snprintf(buffer, SIZE, "    - flags: 0x%04x\n", mFlags);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "    - devices:\n");
+    snprintf(buffer, SIZE, "    - flags: 0x%04x\n", getFlags());
     result.append(buffer);
     write(fd, result.string(), result.size());
-    for (size_t i = 0; i < mSupportedDevices.size(); i++) {
-        mSupportedDevices[i]->dump(fd, 6, i);
-    }
+    mSupportedDevices.dump(fd, String8("Supported"), 4, false);
 }
 
 void IOProfile::log()
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    ALOGV("    - sampling rates: ");
-    for (size_t i = 0; i < mSamplingRates.size(); i++) {
-        ALOGV("  %d", mSamplingRates[i]);
-    }
-
-    ALOGV("    - channel masks: ");
-    for (size_t i = 0; i < mChannelMasks.size(); i++) {
-        ALOGV("  0x%04x", mChannelMasks[i]);
-    }
-
-    ALOGV("    - formats: ");
-    for (size_t i = 0; i < mFormats.size(); i++) {
-        ALOGV("  0x%08x", mFormats[i]);
-    }
-
-    ALOGV("    - devices: 0x%04x\n", mSupportedDevices.types());
-    ALOGV("    - flags: 0x%04x\n", mFlags);
+    // @TODO: forward log to AudioPort
 }
 
 }; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
new file mode 100644
index 0000000..3e5bb7d
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -0,0 +1,641 @@
+/*
+ * Copyright (C) 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 "APM::Serializer"
+//#define LOG_NDEBUG 0
+
+#include "Serializer.h"
+#include <convert/convert.h>
+#include "TypeConverter.h"
+#include <libxml/parser.h>
+#include <libxml/xinclude.h>
+#include <string>
+#include <sstream>
+#include <istream>
+
+using std::string;
+
+namespace android {
+
+string getXmlAttribute(const xmlNode *cur, const char *attribute)
+{
+    xmlChar *xmlValue = xmlGetProp(cur, (const xmlChar*)attribute);
+    if (xmlValue == NULL) {
+        return "";
+    }
+    string value((const char*)xmlValue);
+    xmlFree(xmlValue);
+    return value;
+}
+
+using utilities::convertTo;
+
+const char *const PolicySerializer::rootName = "audioPolicyConfiguration";
+const char *const PolicySerializer::versionAttribute = "version";
+const uint32_t PolicySerializer::gMajor = 1;
+const uint32_t PolicySerializer::gMinor = 0;
+static const char *const gReferenceElementName = "reference";
+static const char *const gReferenceAttributeName = "name";
+
+template <class Trait>
+static void getReference(const _xmlNode *root, const _xmlNode *&refNode, const string &refName)
+{
+    const _xmlNode *col = root;
+    while (col != NULL) {
+        if (!xmlStrcmp(col->name, (const xmlChar *)Trait::collectionTag)) {
+            const xmlNode *cur = col->children;
+            while (cur != NULL) {
+                if ((!xmlStrcmp(cur->name, (const xmlChar *)gReferenceElementName))) {
+                    string name = getXmlAttribute(cur, gReferenceAttributeName);
+                    if (refName == name) {
+                        refNode = cur;
+                        return;
+                    }
+                }
+                cur = cur->next;
+            }
+        }
+        col = col->next;
+    }
+    return;
+}
+
+template <class Trait>
+static status_t deserializeCollection(_xmlDoc *doc, const _xmlNode *cur,
+                                      typename Trait::Collection &collection,
+                                      typename Trait::PtrSerializingCtx serializingContext)
+{
+    const xmlNode *root = cur->xmlChildrenNode;
+    while (root != NULL) {
+        if (xmlStrcmp(root->name, (const xmlChar *)Trait::collectionTag) &&
+                xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
+            root = root->next;
+            continue;
+        }
+        const xmlNode *child = root;
+        if (!xmlStrcmp(child->name, (const xmlChar *)Trait::collectionTag)) {
+            child = child->xmlChildrenNode;
+        }
+        while (child != NULL) {
+            if (!xmlStrcmp(child->name, (const xmlChar *)Trait::tag)) {
+                typename Trait::PtrElement element;
+                status_t status = Trait::deserialize(doc, child, element, serializingContext);
+                if (status != NO_ERROR) {
+                    return status;
+                }
+                if (collection.add(element) < 0) {
+                    ALOGE("%s: could not add element to %s collection", __FUNCTION__,
+                          Trait::collectionTag);
+                }
+            }
+            child = child->next;
+        }
+        if (!xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
+            return NO_ERROR;
+        }
+        root = root->next;
+    }
+    return NO_ERROR;
+}
+
+const char *const AudioGainTraits::tag = "gain";
+const char *const AudioGainTraits::collectionTag = "gains";
+
+const char AudioGainTraits::Attributes::mode[] = "mode";
+const char AudioGainTraits::Attributes::channelMask[] = "channel_mask";
+const char AudioGainTraits::Attributes::minValueMB[] = "minValueMB";
+const char AudioGainTraits::Attributes::maxValueMB[] = "maxValueMB";
+const char AudioGainTraits::Attributes::defaultValueMB[] = "defaultValueMB";
+const char AudioGainTraits::Attributes::stepValueMB[] = "stepValueMB";
+const char AudioGainTraits::Attributes::minRampMs[] = "minRampMs";
+const char AudioGainTraits::Attributes::maxRampMs[] = "maxRampMs";
+
+status_t AudioGainTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &gain,
+                                      PtrSerializingCtx /*serializingContext*/)
+{
+    static uint32_t index = 0;
+    gain = new Element(index++, true);
+
+    string mode = getXmlAttribute(root, Attributes::mode);
+    if (!mode.empty()) {
+        gain->setMode(GainModeConverter::maskFromString(mode));
+    }
+
+    string channelsLiteral = getXmlAttribute(root, Attributes::channelMask);
+    if (!channelsLiteral.empty()) {
+        gain->setChannelMask(channelMaskFromString(channelsLiteral));
+    }
+
+    string minValueMBLiteral = getXmlAttribute(root, Attributes::minValueMB);
+    uint32_t minValueMB;
+    if (!minValueMBLiteral.empty() && convertTo(minValueMBLiteral, minValueMB)) {
+        gain->setMinValueInMb(minValueMB);
+    }
+
+    string maxValueMBLiteral = getXmlAttribute(root, Attributes::maxValueMB);
+    uint32_t maxValueMB;
+    if (!maxValueMBLiteral.empty() && convertTo(maxValueMBLiteral, maxValueMB)) {
+        gain->setMaxValueInMb(maxValueMB);
+    }
+
+    string defaultValueMBLiteral = getXmlAttribute(root, Attributes::defaultValueMB);
+    uint32_t defaultValueMB;
+    if (!defaultValueMBLiteral.empty() && convertTo(defaultValueMBLiteral, defaultValueMB)) {
+        gain->setDefaultValueInMb(defaultValueMB);
+    }
+
+    string stepValueMBLiteral = getXmlAttribute(root, Attributes::stepValueMB);
+    uint32_t stepValueMB;
+    if (!stepValueMBLiteral.empty() && convertTo(stepValueMBLiteral, stepValueMB)) {
+        gain->setStepValueInMb(stepValueMB);
+    }
+
+    string minRampMsLiteral = getXmlAttribute(root, Attributes::minRampMs);
+    uint32_t minRampMs;
+    if (!minRampMsLiteral.empty() && convertTo(minRampMsLiteral, minRampMs)) {
+        gain->setMinRampInMs(minRampMs);
+    }
+
+    string maxRampMsLiteral = getXmlAttribute(root, Attributes::maxRampMs);
+    uint32_t maxRampMs;
+    if (!maxRampMsLiteral.empty() && convertTo(maxRampMsLiteral, maxRampMs)) {
+        gain->setMaxRampInMs(maxRampMs);
+    }
+    ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d", __FUNCTION__,
+          gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
+          gain->getMaxValueInMb());
+
+    if (gain->getMode() == 0) {
+        return BAD_VALUE;
+    }
+    return NO_ERROR;
+}
+
+const char *const AudioProfileTraits::collectionTag = "profiles";
+const char *const AudioProfileTraits::tag = "profile";
+
+const char AudioProfileTraits::Attributes::name[] = "name";
+const char AudioProfileTraits::Attributes::samplingRates[] = "samplingRates";
+const char AudioProfileTraits::Attributes::format[] = "format";
+const char AudioProfileTraits::Attributes::channelMasks[] = "channelMasks";
+
+status_t AudioProfileTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &profile,
+                                         PtrSerializingCtx /*serializingContext*/)
+{
+    string samplingRates = getXmlAttribute(root, Attributes::samplingRates);
+    string format = getXmlAttribute(root, Attributes::format);
+    string channels = getXmlAttribute(root, Attributes::channelMasks);
+
+    profile = new Element(formatFromString(format), channelMasksFromString(channels, ","),
+                          samplingRatesFromString(samplingRates, ","));
+
+    profile->setDynamicFormat(profile->getFormat() == gDynamicFormat);
+    profile->setDynamicChannels(profile->getChannels().isEmpty());
+    profile->setDynamicRate(profile->getSampleRates().isEmpty());
+
+    return NO_ERROR;
+}
+
+
+const char *const MixPortTraits::collectionTag = "mixPorts";
+const char *const MixPortTraits::tag = "mixPort";
+
+const char MixPortTraits::Attributes::name[] = "name";
+const char MixPortTraits::Attributes::role[] = "role";
+const char MixPortTraits::Attributes::flags[] = "flags";
+
+status_t MixPortTraits::deserialize(_xmlDoc *doc, const _xmlNode *child, PtrElement &mixPort,
+                                    PtrSerializingCtx /*serializingContext*/)
+{
+    string name = getXmlAttribute(child, Attributes::name);
+    if (name.empty()) {
+        ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
+        return BAD_VALUE;
+    }
+    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
+    string role = getXmlAttribute(child, Attributes::role);
+    if (role.empty()) {
+        ALOGE("%s: No %s found", __FUNCTION__, Attributes::role);
+        return BAD_VALUE;
+    }
+    ALOGV("%s: Role=%s", __FUNCTION__, role.c_str());
+    audio_port_role_t portRole = role == "source" ? AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
+
+    mixPort = new Element(String8(name.c_str()), portRole);
+
+    AudioProfileTraits::Collection profiles;
+    deserializeCollection<AudioProfileTraits>(doc, child, profiles, NULL);
+    if (profiles.isEmpty()) {
+        sp <AudioProfile> dynamicProfile = new AudioProfile(gDynamicFormat,
+                                                            ChannelsVector(), SampleRateVector());
+        dynamicProfile->setDynamicFormat(true);
+        dynamicProfile->setDynamicChannels(true);
+        dynamicProfile->setDynamicRate(true);
+        profiles.add(dynamicProfile);
+    }
+    mixPort->setAudioProfiles(profiles);
+
+    string flags = getXmlAttribute(child, Attributes::flags);
+    if (!flags.empty()) {
+        // Source role
+        if (portRole == AUDIO_PORT_ROLE_SOURCE) {
+            mixPort->setFlags(OutputFlagConverter::maskFromString(flags));
+        } else {
+            // Sink role
+            mixPort->setFlags(InputFlagConverter::maskFromString(flags));
+        }
+    }
+    // Deserialize children
+    AudioGainTraits::Collection gains;
+    deserializeCollection<AudioGainTraits>(doc, child, gains, NULL);
+    mixPort->setGains(gains);
+
+    return NO_ERROR;
+}
+
+const char *const DevicePortTraits::tag = "devicePort";
+const char *const DevicePortTraits::collectionTag = "devicePorts";
+
+const char DevicePortTraits::Attributes::tagName[] = "tagName";
+const char DevicePortTraits::Attributes::type[] = "type";
+const char DevicePortTraits::Attributes::role[] = "role";
+const char DevicePortTraits::Attributes::address[] = "address";
+const char DevicePortTraits::Attributes::roleSource[] = "source";
+
+status_t DevicePortTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &deviceDesc,
+                                       PtrSerializingCtx /*serializingContext*/)
+{
+    string name = getXmlAttribute(root, Attributes::tagName);
+    if (name.empty()) {
+        ALOGE("%s: No %s found", __FUNCTION__, Attributes::tagName);
+        return BAD_VALUE;
+    }
+    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::tagName, name.c_str());
+    string typeName = getXmlAttribute(root, Attributes::type);
+    if (typeName.empty()) {
+        ALOGE("%s: no type for %s", __FUNCTION__, name.c_str());
+        return BAD_VALUE;
+    }
+    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::type, typeName.c_str());
+    string role = getXmlAttribute(root, Attributes::role);
+    if (role.empty()) {
+        ALOGE("%s: No %s found", __FUNCTION__, Attributes::role);
+        return BAD_VALUE;
+    }
+    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::role, role.c_str());
+    audio_port_role_t portRole = (role == Attributes::roleSource) ?
+                AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
+
+    audio_devices_t type = AUDIO_DEVICE_NONE;
+    if (!DeviceConverter::fromString(typeName, type) ||
+            (!audio_is_input_device(type) && portRole == AUDIO_PORT_ROLE_SOURCE) ||
+            (!audio_is_output_devices(type) && portRole == AUDIO_PORT_ROLE_SINK)) {
+        ALOGW("%s: bad type %08x", __FUNCTION__, type);
+        return BAD_VALUE;
+    }
+    deviceDesc = new Element(type, String8(name.c_str()));
+
+    string address = getXmlAttribute(root, Attributes::address);
+    if (!address.empty()) {
+        ALOGV("%s: address=%s for %s", __FUNCTION__, address.c_str(), name.c_str());
+        deviceDesc->mAddress = String8(address.c_str());
+    }
+
+    AudioProfileTraits::Collection profiles;
+    deserializeCollection<AudioProfileTraits>(doc, root, profiles, NULL);
+    if (profiles.isEmpty()) {
+        sp <AudioProfile> dynamicProfile = new AudioProfile(gDynamicFormat,
+                                                            ChannelsVector(), SampleRateVector());
+        dynamicProfile->setDynamicFormat(true);
+        dynamicProfile->setDynamicChannels(true);
+        dynamicProfile->setDynamicRate(true);
+        profiles.add(dynamicProfile);
+    }
+    deviceDesc->setAudioProfiles(profiles);
+
+    // Deserialize AudioGain children
+    deserializeCollection<AudioGainTraits>(doc, root, deviceDesc->mGains, NULL);
+    ALOGV("%s: adding device tag %s type %08x address %s", __FUNCTION__,
+          deviceDesc->getName().string(), type, deviceDesc->mAddress.string());
+    return NO_ERROR;
+}
+
+const char *const RouteTraits::tag = "route";
+const char *const RouteTraits::collectionTag = "routes";
+
+const char RouteTraits::Attributes::type[] = "type";
+const char RouteTraits::Attributes::typeMix[] = "mix";
+const char RouteTraits::Attributes::sink[] = "sink";
+const char RouteTraits::Attributes::sources[] = "sources";
+
+
+status_t RouteTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &element,
+                                  PtrSerializingCtx ctx)
+{
+    string type = getXmlAttribute(root, Attributes::type);
+    if (type.empty()) {
+        ALOGE("%s: No %s found", __FUNCTION__, Attributes::type);
+        return BAD_VALUE;
+    }
+    audio_route_type_t routeType = (type == Attributes::typeMix) ?
+                AUDIO_ROUTE_MIX : AUDIO_ROUTE_MUX;
+
+    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::type, type.c_str());
+    element = new Element(routeType);
+
+    string sinkAttr = getXmlAttribute(root, Attributes::sink);
+    if (sinkAttr.empty()) {
+        ALOGE("%s: No %s found", __FUNCTION__, Attributes::sink);
+        return BAD_VALUE;
+    }
+    // Convert Sink name to port pointer
+    sp<AudioPort> sink = ctx->findPortByTagName(String8(sinkAttr.c_str()));
+    if (sink == NULL) {
+        ALOGE("%s: no sink found with name=%s", __FUNCTION__, sinkAttr.c_str());
+        return BAD_VALUE;
+    }
+    element->setSink(sink);
+
+    string sourcesAttr = getXmlAttribute(root, Attributes::sources);
+    if (sourcesAttr.empty()) {
+        ALOGE("%s: No %s found", __FUNCTION__, Attributes::sources);
+        return BAD_VALUE;
+    }
+    // Tokenize and Convert Sources name to port pointer
+    AudioPortVector sources;
+    char *sourcesLiteral = strndup(sourcesAttr.c_str(), strlen(sourcesAttr.c_str()));
+    char *devTag = strtok(sourcesLiteral, ",");
+    while (devTag != NULL) {
+        if (strlen(devTag) != 0) {
+            sp<AudioPort> source = ctx->findPortByTagName(String8(devTag));
+            if (source == NULL) {
+                ALOGE("%s: no source found with name=%s", __FUNCTION__, devTag);
+                return BAD_VALUE;
+            }
+            sources.add(source);
+        }
+        devTag = strtok(NULL, ",");
+    }
+    free(sourcesLiteral);
+
+    sink->addRoute(element);
+    for (size_t i = 0; i < sources.size(); i++) {
+        sp<AudioPort> source = sources.itemAt(i);
+        source->addRoute(element);
+    }
+    element->setSources(sources);
+    return NO_ERROR;
+}
+
+const char *const ModuleTraits::childAttachedDevicesTag = "attachedDevices";
+const char *const ModuleTraits::childAttachedDeviceTag = "item";
+const char *const ModuleTraits::childDefaultOutputDeviceTag = "defaultOutputDevice";
+
+const char *const ModuleTraits::tag = "module";
+const char *const ModuleTraits::collectionTag = "modules";
+
+const char ModuleTraits::Attributes::name[] = "name";
+const char ModuleTraits::Attributes::version[] = "halVersion";
+
+status_t ModuleTraits::deserialize(xmlDocPtr doc, const xmlNode *root, PtrElement &module,
+                                   PtrSerializingCtx ctx)
+{
+    string name = getXmlAttribute(root, Attributes::name);
+    if (name.empty()) {
+        ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
+        return BAD_VALUE;
+    }
+    uint32_t version = AUDIO_DEVICE_API_VERSION_MIN;
+    string versionLiteral = getXmlAttribute(root, Attributes::version);
+    if (!versionLiteral.empty()) {
+        uint32_t major, minor;
+        sscanf(versionLiteral.c_str(), "%u.%u", &major, &minor);
+        version = HARDWARE_DEVICE_API_VERSION(major, minor);
+        ALOGV("%s: mHalVersion = %04x major %u minor %u",  __FUNCTION__,
+              version, major, minor);
+    }
+
+    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
+
+    module = new Element(name.c_str(), version);
+
+    // Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
+    MixPortTraits::Collection mixPorts;
+    deserializeCollection<MixPortTraits>(doc, root, mixPorts, NULL);
+    module->setProfiles(mixPorts);
+
+    DevicePortTraits::Collection devicePorts;
+    deserializeCollection<DevicePortTraits>(doc, root, devicePorts, NULL);
+    module->setDeclaredDevices(devicePorts);
+
+    RouteTraits::Collection routes;
+    deserializeCollection<RouteTraits>(doc, root, routes, module.get());
+    module->setRoutes(routes);
+
+    const xmlNode *children = root->xmlChildrenNode;
+    while (children != NULL) {
+        if (!xmlStrcmp(children->name, (const xmlChar *)childAttachedDevicesTag)) {
+            ALOGV("%s: %s %s found", __FUNCTION__, tag, childAttachedDevicesTag);
+            const xmlNode *child = children->xmlChildrenNode;
+            while (child != NULL) {
+                if (!xmlStrcmp(child->name, (const xmlChar *)childAttachedDeviceTag)) {
+                    xmlChar *attachedDevice = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
+                    if (attachedDevice != NULL) {
+                        ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childAttachedDeviceTag,
+                              (const char*)attachedDevice);
+                        sp<DeviceDescriptor> device =
+                                module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice));
+                        ctx->addAvailableDevice(device);
+                        xmlFree(attachedDevice);
+                    }
+                }
+                child = child->next;
+            }
+        }
+        if (!xmlStrcmp(children->name, (const xmlChar *)childDefaultOutputDeviceTag)) {
+            xmlChar *defaultOutputDevice = xmlNodeListGetString(doc, children->xmlChildrenNode, 1);;
+            if (defaultOutputDevice != NULL) {
+                ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childDefaultOutputDeviceTag,
+                      (const char*)defaultOutputDevice);
+                sp<DeviceDescriptor> device =
+                        module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)defaultOutputDevice));
+                if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
+                    ctx->setDefaultOutputDevice(device);
+                    ALOGV("%s: default is %08x", __FUNCTION__, ctx->getDefaultOutputDevice()->type());
+                }
+                xmlFree(defaultOutputDevice);
+            }
+        }
+        children = children->next;
+    }
+    return NO_ERROR;
+}
+
+const char *const GlobalConfigTraits::tag = "globalConfiguration";
+
+const char GlobalConfigTraits::Attributes::speakerDrcEnabled[] = "speaker_drc_enabled";
+
+
+status_t GlobalConfigTraits::deserialize(const xmlNode *cur, AudioPolicyConfig &config)
+{
+    const xmlNode *root = cur->xmlChildrenNode;
+    while (root != NULL) {
+        if (!xmlStrcmp(root->name, (const xmlChar *)tag)) {
+            string speakerDrcEnabled =
+                    getXmlAttribute(root, Attributes::speakerDrcEnabled);
+            bool isSpeakerDrcEnabled;
+            if (!speakerDrcEnabled.empty() &&
+                    convertTo<string, bool>(speakerDrcEnabled, isSpeakerDrcEnabled)) {
+                config.setSpeakerDrcEnabled(isSpeakerDrcEnabled);
+            }
+            return NO_ERROR;
+        }
+        root = root->next;
+    }
+    return NO_ERROR;
+}
+
+
+const char *const VolumeTraits::tag = "volume";
+const char *const VolumeTraits::collectionTag = "volumes";
+const char *const VolumeTraits::volumePointTag = "point";
+
+const char VolumeTraits::Attributes::stream[] = "stream";
+const char VolumeTraits::Attributes::deviceCategory[] = "deviceCategory";
+const char VolumeTraits::Attributes::reference[] = "ref";
+
+status_t VolumeTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
+                                   PtrSerializingCtx /*serializingContext*/)
+{
+    string streamTypeLiteral = getXmlAttribute(root, Attributes::stream);
+    if (streamTypeLiteral.empty()) {
+        ALOGE("%s: No %s found", __FUNCTION__, Attributes::stream);
+        return BAD_VALUE;
+    }
+    audio_stream_type_t streamType;
+    if (!StreamTypeConverter::fromString(streamTypeLiteral, streamType)) {
+        ALOGE("%s: Invalid %s", __FUNCTION__, Attributes::stream);
+        return BAD_VALUE;
+    }
+    string deviceCategoryLiteral = getXmlAttribute(root, Attributes::deviceCategory);
+    if (deviceCategoryLiteral.empty()) {
+        ALOGE("%s: No %s found", __FUNCTION__, Attributes::deviceCategory);
+        return BAD_VALUE;
+    }
+    device_category deviceCategory;
+    if (!DeviceCategoryConverter::fromString(deviceCategoryLiteral, deviceCategory)) {
+        ALOGE("%s: Invalid %s=%s", __FUNCTION__, Attributes::deviceCategory,
+              deviceCategoryLiteral.c_str());
+        return BAD_VALUE;
+    }
+
+    string referenceName = getXmlAttribute(root, Attributes::reference);
+    const _xmlNode *ref = NULL;
+    if (!referenceName.empty()) {
+        getReference<VolumeTraits>(root->parent, ref, referenceName);
+        if (ref == NULL) {
+            ALOGE("%s: No reference Ptr found for %s", __FUNCTION__, referenceName.c_str());
+            return BAD_VALUE;
+        }
+    }
+
+    element = new Element(deviceCategory, streamType);
+
+    const xmlNode *child = referenceName.empty() ? root->xmlChildrenNode : ref->xmlChildrenNode;
+    while (child != NULL) {
+        if (!xmlStrcmp(child->name, (const xmlChar *)volumePointTag)) {
+            xmlChar *pointDefinition = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);;
+            if (pointDefinition == NULL) {
+                return BAD_VALUE;
+            }
+            ALOGV("%s: %s=%s", __FUNCTION__, tag, (const char*)pointDefinition);
+            Vector<int32_t> point;
+            collectionFromString<DefaultTraits<int32_t> >((const char*)pointDefinition, point, ",");
+            if (point.size() != 2) {
+                ALOGE("%s: Invalid %s: %s", __FUNCTION__, volumePointTag,
+                      (const char*)pointDefinition);
+                return BAD_VALUE;
+            }
+            element->add(CurvePoint(point[0], point[1]));
+            xmlFree(pointDefinition);
+        }
+        child = child->next;
+    }
+    return NO_ERROR;
+}
+
+PolicySerializer::PolicySerializer() : mRootElementName(rootName)
+{
+    std::ostringstream oss;
+    oss << gMajor << "." << gMinor;
+    mVersion = oss.str();
+    ALOGV("%s: Version=%s Root=%s", __FUNCTION__, mVersion.c_str(), mRootElementName.c_str());
+}
+
+status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig &config)
+{
+    xmlDocPtr doc;
+    doc = xmlParseFile(configFile);
+    if (doc == NULL) {
+        ALOGE("%s: Could not parse %s document.", __FUNCTION__, configFile);
+        return BAD_VALUE;
+    }
+    xmlNodePtr cur = xmlDocGetRootElement(doc);
+    if (cur == NULL) {
+        ALOGE("%s: Could not parse %s document: empty.", __FUNCTION__, configFile);
+        xmlFreeDoc(doc);
+        return BAD_VALUE;
+    }
+    if (xmlXIncludeProcess(doc) < 0) {
+         ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __FUNCTION__, configFile);
+    }
+
+    if (xmlStrcmp(cur->name, (const xmlChar *) mRootElementName.c_str()))  {
+        ALOGE("%s: No %s root element found in xml data %s.", __FUNCTION__, mRootElementName.c_str(),
+              (const char *)cur->name);
+        xmlFreeDoc(doc);
+        return BAD_VALUE;
+    }
+
+    string version = getXmlAttribute(cur, versionAttribute);
+    if (version.empty()) {
+        ALOGE("%s: No version found in root node %s", __FUNCTION__, mRootElementName.c_str());
+        return BAD_VALUE;
+    }
+    if (version != mVersion) {
+        ALOGE("%s: Version does not match; expect %s got %s", __FUNCTION__, mVersion.c_str(),
+              version.c_str());
+        return BAD_VALUE;
+    }
+    // Lets deserialize children
+    // Modules
+    ModuleTraits::Collection modules;
+    deserializeCollection<ModuleTraits>(doc, cur, modules, &config);
+    config.setHwModules(modules);
+
+    // deserialize volume section
+    VolumeTraits::Collection volumes;
+    deserializeCollection<VolumeTraits>(doc, cur, volumes, &config);
+    config.setVolumes(volumes);
+
+    // Global Configuration
+    GlobalConfigTraits::deserialize(cur, config);
+
+    xmlFreeDoc(doc);
+    return android::OK;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
index 4ca27c2..8388a50 100644
--- a/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
@@ -25,6 +25,7 @@
 #endif
 
 #include "StreamDescriptor.h"
+#include "Gains.h"
 #include <utils/Log.h>
 #include <utils/String8.h>
 
@@ -71,7 +72,7 @@
     mIndexMax = volIndexMax;
 }
 
-void StreamDescriptor::setVolumeCurvePoint(Volume::device_category deviceCategory,
+void StreamDescriptor::setVolumeCurvePoint(device_category deviceCategory,
                                            const VolumeCurvePoint *point)
 {
     mVolumeCurve[deviceCategory] = point;
@@ -121,14 +122,14 @@
 }
 
 void StreamDescriptorCollection::setVolumeCurvePoint(audio_stream_type_t stream,
-                                                     Volume::device_category deviceCategory,
+                                                     device_category deviceCategory,
                                                      const VolumeCurvePoint *point)
 {
     editValueAt(stream).setVolumeCurvePoint(deviceCategory, point);
 }
 
 const VolumeCurvePoint *StreamDescriptorCollection::getVolumeCurvePoint(audio_stream_type_t stream,
-                                                                        Volume::device_category deviceCategory) const
+                                                                        device_category deviceCategory) const
 {
     return valueAt(stream).getVolumeCurvePoint(deviceCategory);
 }
@@ -143,6 +144,65 @@
     return editValueAt(stream).setVolumeIndexMax(volIndexMax);
 }
 
+float StreamDescriptorCollection::volIndexToDb(audio_stream_type_t stream, device_category category,
+                                               int indexInUi) const
+{
+    const StreamDescriptor &streamDesc = valueAt(stream);
+    return Gains::volIndexToDb(streamDesc.getVolumeCurvePoint(category),
+                               streamDesc.getVolumeIndexMin(), streamDesc.getVolumeIndexMax(),
+                               indexInUi);
+}
+
+status_t StreamDescriptorCollection::initStreamVolume(audio_stream_type_t stream,
+                                                      int indexMin, int indexMax)
+{
+    ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
+    if (indexMin < 0 || indexMin >= indexMax) {
+        ALOGW("initStreamVolume() invalid index limits for stream %d, min %d, max %d",
+              stream , indexMin, indexMax);
+        return BAD_VALUE;
+    }
+    setVolumeIndexMin(stream, indexMin);
+    setVolumeIndexMax(stream, indexMax);
+    return NO_ERROR;
+}
+
+void StreamDescriptorCollection::initializeVolumeCurves(bool isSpeakerDrcEnabled)
+{
+    for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
+        for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+            setVolumeCurvePoint(static_cast<audio_stream_type_t>(i),
+                                static_cast<device_category>(j),
+                                Gains::sVolumeProfiles[i][j]);
+        }
+    }
+
+    // Check availability of DRC on speaker path: if available, override some of the speaker curves
+    if (isSpeakerDrcEnabled) {
+        setVolumeCurvePoint(AUDIO_STREAM_SYSTEM, DEVICE_CATEGORY_SPEAKER,
+                            Gains::sDefaultSystemVolumeCurveDrc);
+        setVolumeCurvePoint(AUDIO_STREAM_RING, DEVICE_CATEGORY_SPEAKER,
+                            Gains::sSpeakerSonificationVolumeCurveDrc);
+        setVolumeCurvePoint(AUDIO_STREAM_ALARM, DEVICE_CATEGORY_SPEAKER,
+                            Gains::sSpeakerSonificationVolumeCurveDrc);
+        setVolumeCurvePoint(AUDIO_STREAM_NOTIFICATION, DEVICE_CATEGORY_SPEAKER,
+                            Gains::sSpeakerSonificationVolumeCurveDrc);
+        setVolumeCurvePoint(AUDIO_STREAM_MUSIC, DEVICE_CATEGORY_SPEAKER,
+                            Gains::sSpeakerMediaVolumeCurveDrc);
+        setVolumeCurvePoint(AUDIO_STREAM_ACCESSIBILITY, DEVICE_CATEGORY_SPEAKER,
+                            Gains::sSpeakerMediaVolumeCurveDrc);
+    }
+}
+
+void StreamDescriptorCollection::switchVolumeCurve(audio_stream_type_t streamSrc,
+                                                   audio_stream_type_t streamDst)
+{
+    for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+        setVolumeCurvePoint(streamDst, static_cast<device_category>(j),
+                            Gains::sVolumeProfiles[streamSrc][j]);
+    }
+}
+
 status_t StreamDescriptorCollection::dump(int fd) const
 {
     const size_t SIZE = 256;
diff --git a/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
new file mode 100644
index 0000000..f613f94
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 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 "TypeConverter.h"
+
+namespace android {
+
+#define MAKE_STRING_FROM_ENUM(string) { #string, string }
+
+template <>
+const DeviceConverter::Table DeviceConverter::mTable[] = {
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_EARPIECE),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_SPEAKER),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_SPEAKER_SAFE),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADSET),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ALL_SCO),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ALL_A2DP),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_AUX_DIGITAL),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_HDMI),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_USB_ACCESSORY),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_USB_DEVICE),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ALL_USB),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_TELEPHONY_TX),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_LINE),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_HDMI_ARC),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_SPDIF),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_FM),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_AUX_LINE),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_IP),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_AMBIENT),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ALL_SCO),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_HDMI),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_TELEPHONY_RX),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_VOICE_CALL),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_DEVICE),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_FM_TUNER),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_TV_TUNER),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_LINE),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_SPDIF),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_LOOPBACK),
+        MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_IP),
+};
+
+template<>
+const size_t DeviceConverter::mSize = sizeof(DeviceConverter::mTable) /
+        sizeof(DeviceConverter::mTable[0]);
+
+
+template <>
+const OutputFlagConverter::Table OutputFlagConverter::mTable[] = {
+    MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
+    MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
+    MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_FAST),
+    MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
+    MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
+    MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
+    MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_HW_AV_SYNC),
+    MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_TTS),
+    MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_RAW),
+    MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_SYNC),
+};
+template<>
+const size_t OutputFlagConverter::mSize = sizeof(OutputFlagConverter::mTable) /
+        sizeof(OutputFlagConverter::mTable[0]);
+
+
+template <>
+const InputFlagConverter::Table InputFlagConverter::mTable[] = {
+    MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_FAST),
+    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),
+};
+template<>
+const size_t InputFlagConverter::mSize = sizeof(InputFlagConverter::mTable) /
+        sizeof(InputFlagConverter::mTable[0]);
+
+
+template <>
+const FormatConverter::Table FormatConverter::mTable[] = {
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_16_BIT),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_8_BIT),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_32_BIT),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_FLOAT),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_MP3),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_MAIN),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LC),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_SSR),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LTP),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_HE_V1),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_SCALABLE),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ERLC),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LD),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_HE_V2),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ELD),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_VORBIS),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_HE_AAC_V1),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_HE_AAC_V2),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_OPUS),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AC3),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_E_AC3),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_DTS),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_DTS_HD),
+    MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_IEC61937),
+};
+template<>
+const size_t FormatConverter::mSize = sizeof(FormatConverter::mTable) /
+        sizeof(FormatConverter::mTable[0]);
+
+
+template <>
+const OutputChannelConverter::Table OutputChannelConverter::mTable[] = {
+    MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_MONO),
+    MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_STEREO),
+    MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_QUAD),
+    MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
+    MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
+};
+template<>
+const size_t OutputChannelConverter::mSize = sizeof(OutputChannelConverter::mTable) /
+        sizeof(OutputChannelConverter::mTable[0]);
+
+
+template <>
+const InputChannelConverter::Table InputChannelConverter::mTable[] = {
+    MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_MONO),
+    MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_STEREO),
+    MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
+};
+template<>
+const size_t InputChannelConverter::mSize = sizeof(InputChannelConverter::mTable) /
+        sizeof(InputChannelConverter::mTable[0]);
+
+template <>
+const ChannelIndexConverter::Table ChannelIndexConverter::mTable[] = {
+    {"AUDIO_CHANNEL_INDEX_MASK_1", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_1)},
+    {"AUDIO_CHANNEL_INDEX_MASK_2", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_2)},
+    {"AUDIO_CHANNEL_INDEX_MASK_3", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_3)},
+    {"AUDIO_CHANNEL_INDEX_MASK_4", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_4)},
+    {"AUDIO_CHANNEL_INDEX_MASK_5", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_5)},
+    {"AUDIO_CHANNEL_INDEX_MASK_6", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_6)},
+    {"AUDIO_CHANNEL_INDEX_MASK_7", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_7)},
+    {"AUDIO_CHANNEL_INDEX_MASK_8", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_8)},
+};
+template<>
+const size_t ChannelIndexConverter::mSize = sizeof(ChannelIndexConverter::mTable) /
+        sizeof(ChannelIndexConverter::mTable[0]);
+
+
+template <>
+const GainModeConverter::Table GainModeConverter::mTable[] = {
+    MAKE_STRING_FROM_ENUM(AUDIO_GAIN_MODE_JOINT),
+    MAKE_STRING_FROM_ENUM(AUDIO_GAIN_MODE_CHANNELS),
+    MAKE_STRING_FROM_ENUM(AUDIO_GAIN_MODE_RAMP),
+};
+
+template<>
+const size_t GainModeConverter::mSize = sizeof(GainModeConverter::mTable) /
+        sizeof(GainModeConverter::mTable[0]);
+
+template <>
+const DeviceCategoryConverter::Table DeviceCategoryConverter::mTable[] = {
+    MAKE_STRING_FROM_ENUM(DEVICE_CATEGORY_HEADSET),
+    MAKE_STRING_FROM_ENUM(DEVICE_CATEGORY_SPEAKER),
+    MAKE_STRING_FROM_ENUM(DEVICE_CATEGORY_EARPIECE),
+    MAKE_STRING_FROM_ENUM(DEVICE_CATEGORY_EXT_MEDIA)
+};
+
+template<>
+const size_t DeviceCategoryConverter::mSize = sizeof(DeviceCategoryConverter::mTable) /
+        sizeof(DeviceCategoryConverter::mTable[0]);
+
+template <>
+const StreamTypeConverter::Table StreamTypeConverter::mTable[] = {
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_VOICE_CALL),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_SYSTEM),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_RING),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_MUSIC),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ALARM),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_NOTIFICATION),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_BLUETOOTH_SCO ),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ENFORCED_AUDIBLE),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_DTMF),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_TTS),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ACCESSIBILITY),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_REROUTING),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_PATCH),
+};
+
+template<>
+const size_t StreamTypeConverter::mSize = sizeof(StreamTypeConverter::mTable) /
+        sizeof(StreamTypeConverter::mTable[0]);
+
+template <class Traits>
+bool TypeConverter<Traits>::toString(const typename Traits::Type &value, std::string &str)
+{
+    for (size_t i = 0; i < mSize; i++) {
+        if (mTable[i].value == value) {
+            str = mTable[i].literal;
+            return true;
+        }
+    }
+    return false;
+}
+
+template <class Traits>
+bool TypeConverter<Traits>::fromString(const std::string &str, typename Traits::Type &result)
+{
+    for (size_t i = 0; i < mSize; i++) {
+        if (strcmp(mTable[i].literal, str.c_str()) == 0) {
+            ALOGV("stringToEnum() found %s", mTable[i].literal);
+            result = mTable[i].value;
+            return true;
+        }
+    }
+    return false;
+}
+
+template <class Traits>
+void TypeConverter<Traits>::collectionFromString(const std::string &str,
+                                                 typename Traits::Collection &collection,
+                                                 const char *del)
+{
+    char *literal = strdup(str.c_str());
+
+    for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+        typename Traits::Type value;
+        if (fromString(cstr, value)) {
+            collection.add(value);
+        }
+    }
+    free(literal);
+}
+
+template <class Traits>
+uint32_t TypeConverter<Traits>::maskFromString(const std::string &str, const char *del)
+{
+    char *literal = strdup(str.c_str());
+    uint32_t value = 0;
+    for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+        typename Traits::Type type;
+        if (fromString(cstr, type)) {
+            value |= static_cast<uint32_t>(type);
+        }
+    }
+    free(literal);
+    return value;
+}
+
+template class TypeConverter<DeviceTraits>;
+template class TypeConverter<OutputFlagTraits>;
+template class TypeConverter<InputFlagTraits>;
+template class TypeConverter<FormatTraits>;
+template class TypeConverter<OutputChannelTraits>;
+template class TypeConverter<InputChannelTraits>;
+template class TypeConverter<ChannelIndexTraits>;
+template class TypeConverter<GainModeTraits>;
+template class TypeConverter<StreamTraits>;
+template class TypeConverter<DeviceCategoryTraits>;
+
+}; // namespace android
+
diff --git a/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp b/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp
new file mode 100644
index 0000000..ab2b51f
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 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 "APM::VolumeCurve"
+//#define LOG_NDEBUG 0
+
+#include "VolumeCurve.h"
+#include "TypeConverter.h"
+
+namespace android {
+
+float VolumeCurve::volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const
+{
+    ALOG_ASSERT(!mCurvePoints.isEmpty(), "Invalid volume curve");
+
+    size_t nbCurvePoints = mCurvePoints.size();
+    // the volume index in the UI is relative to the min and max volume indices for this stream
+    int nbSteps = 1 + mCurvePoints[nbCurvePoints - 1].mIndex - mCurvePoints[0].mIndex;
+    int volIdx = (nbSteps * (indexInUi - volIndexMin)) / (volIndexMax - volIndexMin);
+
+    // Where would this volume index been inserted in the curve point
+    size_t indexInUiPosition = mCurvePoints.orderOf(CurvePoint(volIdx, 0));
+    if (indexInUiPosition >= nbCurvePoints) {
+        return 0.0f; // out of bounds
+    }
+    if (indexInUiPosition == 0) {
+        if (indexInUiPosition != mCurvePoints[0].mIndex) {
+            return VOLUME_MIN_DB; // out of bounds
+        }
+        return mCurvePoints[0].mAttenuationInMb / 100.0f;
+    }
+    // linear interpolation in the attenuation table in dB
+    float decibels = (mCurvePoints[indexInUiPosition - 1].mAttenuationInMb / 100.0f) +
+            ((float)(volIdx - mCurvePoints[indexInUiPosition - 1].mIndex)) *
+                ( ((mCurvePoints[indexInUiPosition].mAttenuationInMb / 100.0f) -
+                        (mCurvePoints[indexInUiPosition - 1].mAttenuationInMb / 100.0f)) /
+                    ((float)(mCurvePoints[indexInUiPosition].mIndex -
+                            mCurvePoints[indexInUiPosition - 1].mIndex)) );
+
+    ALOGV("VOLUME mDeviceCategory %d, mStreamType %d vol index=[%d %d %d], dB=[%.1f %.1f %.1f]",
+            mDeviceCategory, mStreamType,
+            mCurvePoints[indexInUiPosition - 1].mIndex, volIdx,
+            mCurvePoints[indexInUiPosition].mIndex,
+            ((float)mCurvePoints[indexInUiPosition - 1].mAttenuationInMb / 100.0f), decibels,
+            ((float)mCurvePoints[indexInUiPosition].mAttenuationInMb / 100.0f));
+
+    return decibels;
+}
+
+void VolumeCurve::dump(int fd) const
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, " {");
+    result.append(buffer);
+    for (size_t i = 0; i < mCurvePoints.size(); i++) {
+        snprintf(buffer, SIZE, "(%3d, %5d)",
+                 mCurvePoints[i].mIndex, mCurvePoints[i].mAttenuationInMb);
+        result.append(buffer);
+        result.append(i == (mCurvePoints.size() - 1) ? " }\n" : ", ");
+    }
+    write(fd, result.string(), result.size());
+}
+
+void VolumeCurvesForStream::dump(int fd, int spaces = 0, bool curvePoints) const
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    if (!curvePoints) {
+        snprintf(buffer, SIZE, "%s         %02d         %02d         ",
+                 mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax);
+        result.append(buffer);
+        for (size_t i = 0; i < mIndexCur.size(); i++) {
+            snprintf(buffer, SIZE, "%04x : %02d, ", mIndexCur.keyAt(i), mIndexCur.valueAt(i));
+            result.append(buffer);
+        }
+        result.append("\n");
+        write(fd, result.string(), result.size());
+        return;
+    }
+
+    for (size_t i = 0; i < size(); i++) {
+        std::string deviceCatLiteral;
+        DeviceCategoryConverter::toString(keyAt(i), deviceCatLiteral);
+        snprintf(buffer, SIZE, "%*s %s :",
+                 spaces, "", deviceCatLiteral.c_str());
+        write(fd, buffer, strlen(buffer));
+        valueAt(i)->dump(fd);
+    }
+    result.append("\n");
+    write(fd, result.string(), result.size());
+}
+
+status_t VolumeCurvesCollection::dump(int fd) const
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+
+    snprintf(buffer, SIZE, "\nStreams dump:\n");
+    write(fd, buffer, strlen(buffer));
+    snprintf(buffer, SIZE,
+             " Stream  Can be muted  Index Min  Index Max  Index Cur [device : index]...\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < size(); i++) {
+        snprintf(buffer, SIZE, " %02zu      ", i);
+        write(fd, buffer, strlen(buffer));
+        valueAt(i).dump(fd);
+    }
+    snprintf(buffer, SIZE, "\nVolume Curves for Use Cases (aka Stream types) dump:\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < size(); i++) {
+        std::string streamTypeLiteral;
+        StreamTypeConverter::toString(keyAt(i), streamTypeLiteral);
+        snprintf(buffer, SIZE,
+                 " %s (%02zu): Curve points for device category (index, attenuation in millibel)\n",
+                 streamTypeLiteral.c_str(), i);
+        write(fd, buffer, strlen(buffer));
+        valueAt(i).dump(fd, 2, true);
+    }
+
+    return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/config/a2dp_audio_policy_configuration.xml b/services/audiopolicy/config/a2dp_audio_policy_configuration.xml
new file mode 100644
index 0000000..ced7463
--- /dev/null
+++ b/services/audiopolicy/config/a2dp_audio_policy_configuration.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- A2dp Audio HAL Audio Policy Configuration file -->
+<module name="a2dp" halVersion="2.0">
+    <mixPorts>
+        <mixPort name="a2dp output" role="source">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="44100"
+                     channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+        </mixPort>
+        <mixPort name="a2dp input" role="sink">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="44100,48000"
+                     channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/>
+        </mixPort>
+    </mixPorts>
+    <devicePorts>
+        <devicePort tagName="BT A2DP Out" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP" role="sink">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="44100"
+                     channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+        </devicePort>
+        <devicePort tagName="BT A2DP Headphones" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES" role="sink">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="44100"
+                     channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+        </devicePort>
+        <devicePort tagName="BT A2DP Speaker" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER" role="sink">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="44100"
+                     channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+        </devicePort>
+        <devicePort tagName="BT A2DP In" type="AUDIO_DEVICE_IN_BLUETOOTH_A2DP" role="source">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="44100,48000"
+                     channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/>
+        </devicePort>
+    </devicePorts>
+    <routes>
+        <route type="mix" sink="BT A2DP Out"
+               sources="a2dp output"/>
+        <route type="mix" sink="BT A2DP Headphones"
+               sources="a2dp output"/>
+        <route type="mix" sink="BT A2DP Speaker"
+               sources="a2dp output"/>
+        <route type="mix" sink="a2dp input"
+               sources="BT A2DP In"/>
+    </routes>
+</module>
diff --git a/services/audiopolicy/config/audio_policy_configuration.xml b/services/audiopolicy/config/audio_policy_configuration.xml
new file mode 100644
index 0000000..7af2f81
--- /dev/null
+++ b/services/audiopolicy/config/audio_policy_configuration.xml
@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 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.
+-->
+
+<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <!-- version section contains a “version” tag in the form “major.minor” e.g version=”1.0” -->
+
+    <!-- Global configuration Decalaration -->
+    <globalConfiguration speaker_drc_enabled="true"/>
+
+
+    <!-- Modules section:
+        There is one section per audio HW module present on the platform.
+        Each module section will contains two mandatory tags for audio HAL “halVersion” and “name”.
+        The module names are the same as in current .conf file:
+                “primary”, “A2DP”, “remote_submix”, “USB”
+        Each module will contain the following sections:
+        “devicePorts”: a list of device descriptors for all input and output devices accessible via this
+        module.
+        This contains both permanently attached devices and removable devices.
+        “mixPorts”: listing all output and input streams exposed by the audio HAL
+        “routes”: list of possible connections between input and output devices or between stream and
+        devices.
+            "route": is defined by an attribute:
+                -"type": <mux|mix> means all sources are mutual exclusive (mux) or can be mixed (mix)
+                -"sink": the sink involved in this route
+                -"sources": all the sources than can be connected to the sink via vis route
+        “attachedDevices”: permanently attached devices.
+        The attachedDevices section is a list of devices names. The names correspond to device names
+        defined in <devicePorts> section.
+        “defaultOutputDevice”: device to be used by default when no policy rule applies
+    -->
+    <modules>
+        <!-- Primary Audio HAL -->
+        <module name="primary" halVersion="3.0">
+            <attachedDevices>
+                <item>Speaker</item>
+                <item>Built-In Mic</item>
+                <item>Built-In Back Mic</item>
+            </attachedDevices>
+            <defaultOutputDevice>Speaker</defaultOutputDevice>
+            <mixPorts>
+                <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="deep_buffer" role="source"
+                        flags="AUDIO_OUTPUT_FLAG_DEEP_BUFFER">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="compressed_offload" role="source"
+                         flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING">
+                    <profile name="" format="AUDIO_FORMAT_MP3"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+                             channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
+                    <profile name="" format="AUDIO_FORMAT_AAC"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+                             channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
+                    <profile name="" format="AUDIO_FORMAT_AAC_LC"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+                             channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
+                </mixPort>
+                <mixPort name="voice_tx" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
+                </mixPort>
+                <mixPort name="primary input" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+                             channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
+                </mixPort>
+                <mixPort name="voice_rx" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+                </mixPort>
+            </mixPorts>
+            <devicePorts>
+                <!-- Output devices declaration, i.e. Sink DEVICE PORT -->
+                <devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink">
+                   <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+                </devicePort>
+                <devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER" address="">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                    <gains>
+                        <gain name="gain_1" mode="AUDIO_GAIN_MODE_JOINT"
+                              minValueMB="-8400"
+                              maxValueMB="4000"
+                              defaultValueMB="0"
+                              stepValueMB="100"/>
+                    </gains>
+                </devicePort>
+                <devicePort tagName="Wired Headset" type="AUDIO_DEVICE_OUT_WIRED_HEADSET" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </devicePort>
+                <devicePort tagName="Wired Headphones" type="AUDIO_DEVICE_OUT_WIRED_HEADPHONE" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </devicePort>
+                <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
+                </devicePort>
+                <devicePort tagName="BT SCO Headset" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
+                </devicePort>
+                <devicePort tagName="BT SCO Car Kit" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
+                </devicePort>
+                <devicePort tagName="Telephony Tx" type="AUDIO_DEVICE_OUT_TELEPHONY_TX" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
+                </devicePort>
+
+                <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+                             channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
+                </devicePort>
+                <devicePort tagName="Built-In Back Mic" type="AUDIO_DEVICE_IN_BACK_MIC" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+                             channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
+                </devicePort>
+                <devicePort tagName="Wired Headset Mic" type="AUDIO_DEVICE_IN_WIRED_HEADSET" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
+                             channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
+                </devicePort>
+                <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+                </devicePort>
+                <devicePort tagName="Telephony Rx" type="AUDIO_DEVICE_IN_TELEPHONY_RX" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+                </devicePort>
+            </devicePorts>
+            <!-- route declaration, i.e. list all available sources for a given sink -->
+            <routes>
+                <route type="mix" sink="Earpiece"
+                       sources="primary output,deep_buffer,BT SCO Headset Mic"/>
+                <route type="mix" sink="Speaker"
+                       sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
+                <route type="mix" sink="Wired Headset"
+                       sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
+                <route type="mix" sink="Wired Headphones"
+                       sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
+                <route type="mix" sink="Telephony Tx"
+                       sources="voice_tx"/>
+                <route type="mix" sink="primary input"
+                       sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic"/>
+                <route type="mix" sink="Telephony Tx"
+                       sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic"/>
+                <route type="mix" sink="voice_rx"
+                       sources="Telephony Rx"/>
+            </routes>
+
+        </module>
+
+        <!-- HDMI Audio HAL -->
+        <module description="HDMI Audio HAL" name="hdmi" version="2.0">
+            <mixPorts>
+                <mixPort name="hdmi output" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000"/>
+                </mixPort>
+            </mixPorts>
+            <devicePorts>
+                <devicePort tagName="HDMI Out" type="AUDIO_DEVICE_OUT_AUX_DIGITAL" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </devicePort>
+            </devicePorts>
+            <routes>
+                <route type="mix" sink="HDMI Out"
+                       sources="hdmi output"/>
+            </routes>
+        </module>
+
+        <!-- A2dp Audio HAL -->
+        <xi:include href="a2dp_audio_policy_configuration.xml"/>
+
+        <!-- Usb Audio HAL -->
+        <xi:include href="usb_audio_policy_configuration.xml"/>
+
+        <!-- Remote Submix Audio HAL -->
+        <xi:include href="r_submix_audio_policy_configuration.xml"/>
+
+    </modules>
+    <!-- End of Modules section -->
+
+    <!-- Volume section -->
+
+    <xi:include href="audio_policy_volumes.xml"/>
+    <xi:include href="default_volume_tables.xml"/>
+
+    <!-- End of Volume section -->
+
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/config/audio_policy_volumes.xml b/services/audiopolicy/config/audio_policy_volumes.xml
new file mode 100644
index 0000000..43a47b0
--- /dev/null
+++ b/services/audiopolicy/config/audio_policy_volumes.xml
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 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.
+-->
+<!-- Volume section defines a volume curve for a given use case and device category.
+It contains a list of points of this curve expressing the attenuation in Millibels for a given
+volume index from 0 to 100.
+<volume stream=”AUDIO_STREAM_MUSIC” deviceCategory=””>
+<point>0,-9600</point>
+<point>100,0</point>
+</volume>
+-->
+
+<volumes>
+    <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_HEADSET">
+        <point>0,-4200</point>
+        <point>33,-2800</point>
+        <point>66,-1400</point>
+        <point>100,0</point>
+    </volume>
+    <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+        <point>0,-2400</point>
+        <point>33,-1600</point>
+        <point>66,-800</point>
+        <point>100,0</point>
+    </volume>
+    <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_EARPIECE">
+        <point>0,-2400</point>
+        <point>33,-1600</point>
+        <point>66,-800</point>
+        <point>100,0</point>
+    </volume>
+    <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+                                             ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_SYSTEM" deviceCategory="DEVICE_CATEGORY_HEADSET">
+        <point>1,-3000</point>
+        <point>33,-2600</point>
+        <point>66,-2200</point>
+        <point>100,-1800</point>
+    </volume>
+    <volume stream="AUDIO_STREAM_SYSTEM" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+                                         ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_SYSTEM" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+                                         ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_SYSTEM" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+                                         ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_RING" deviceCategory="DEVICE_CATEGORY_HEADSET"
+                                       ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_RING" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+        <point>1,-2970</point>
+        <point>33,-2010</point>
+        <point>66,-1020</point>
+        <point>100,0</point>
+    </volume>
+    <volume stream="AUDIO_STREAM_RING" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+                                       ref="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_RING" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+                                       ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_HEADSET"
+                                        ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+                                        ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+                                        ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+                                        ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_ALARM" deviceCategory="DEVICE_CATEGORY_HEADSET"
+                                        ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_ALARM" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+        <point>1,-2970</point>
+        <point>33,-2010</point>
+        <point>66,-1020</point>
+        <point>100,0</point>
+    </volume>
+    <volume stream="AUDIO_STREAM_ALARM" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+                                        ref="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_ALARM" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+                                        ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_NOTIFICATION" deviceCategory="DEVICE_CATEGORY_HEADSET"
+                                               ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_NOTIFICATION" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+        <point>1,-2970</point>
+        <point>33,-2010</point>
+        <point>66,-1020</point>
+        <point>100,0</point>
+    </volume>
+    <volume stream="AUDIO_STREAM_NOTIFICATION" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+                                               ref="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_NOTIFICATION" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+                                               ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_BLUETOOTH_SCO" deviceCategory="DEVICE_CATEGORY_HEADSET">
+        <point>0,-4200</point>
+        <point>33,-2800</point>
+        <point>66,-1400</point>
+        <point>100,0</point>
+    </volume>
+    <volume stream="AUDIO_STREAM_BLUETOOTH_SCO" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+        <point>0,-2400</point>
+        <point>33,-1600</point>
+        <point>66,-800</point>
+        <point>100,0</point>
+    </volume>
+    <volume stream="AUDIO_STREAM_BLUETOOTH_SCO" deviceCategory="DEVICE_CATEGORY_EARPIECE">
+        <point>0,-4200</point>
+        <point>33,-2800</point>
+        <point>66,-1400</point>
+        <point>100,0</point>
+    </volume>
+    <volume stream="AUDIO_STREAM_BLUETOOTH_SCO" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+                                                ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_ENFORCED_AUDIBLE" deviceCategory="DEVICE_CATEGORY_HEADSET">
+        <point>1,-3000</point>
+        <point>33,-2600</point>
+        <point>66,-2200</point>
+        <point>100,-1800</point>
+    </volume>
+    <volume stream="AUDIO_STREAM_ENFORCED_AUDIBLE" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+                                                   ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_ENFORCED_AUDIBLE" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+                                                   ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_ENFORCED_AUDIBLE" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+                                                   ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_DTMF" deviceCategory="DEVICE_CATEGORY_HEADSET">
+        <point>1,-3000</point>
+        <point>33,-2600</point>
+        <point>66,-2200</point>
+        <point>100,-1800</point>
+    </volume>
+    <volume stream="AUDIO_STREAM_DTMF" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+                                       ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_DTMF" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+                                       ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_DTMF" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+                                       ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_TTS" deviceCategory="DEVICE_CATEGORY_HEADSET"
+                                      ref="SILENT_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_TTS" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+                                      ref="FULL_SCALE_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_TTS" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+                                      ref="SILENT_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_TTS" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+                                      ref="SILENT_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_ACCESSIBILITY" deviceCategory="DEVICE_CATEGORY_HEADSET"
+                                                ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_ACCESSIBILITY" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+                                                ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_ACCESSIBILITY" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+                                                ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_ACCESSIBILITY" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+                                                ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_REROUTING" deviceCategory="DEVICE_CATEGORY_HEADSET"
+                                            ref="FULL_SCALE_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_REROUTING" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+                                            ref="FULL_SCALE_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_REROUTING" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+                                            ref="FULL_SCALE_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_REROUTING" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+                                            ref="FULL_SCALE_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_PATCH" deviceCategory="DEVICE_CATEGORY_HEADSET"
+                                        ref="FULL_SCALE_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_PATCH" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+                                        ref="FULL_SCALE_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_PATCH" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+                                        ref="FULL_SCALE_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_PATCH" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+                                        ref="FULL_SCALE_VOLUME_CURVE"/>
+</volumes>
+
diff --git a/services/audiopolicy/config/default_volume_tables.xml b/services/audiopolicy/config/default_volume_tables.xml
new file mode 100644
index 0000000..9a22b1d
--- /dev/null
+++ b/services/audiopolicy/config/default_volume_tables.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 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.
+-->
+<!-- Default Volume Tables included by Audio Policy Configuration file -->
+<!-- Full Default Volume table for all device category -->
+<volumes>
+    <reference name="FULL_SCALE_VOLUME_CURVE">
+    <!-- Full Scale reference Volume Curve -->
+        <point>0,0</point>
+        <point>100,0</point>
+    </reference>
+    <reference name="SILENT_VOLUME_CURVE">
+        <point>0,-9600</point>
+        <point>100,-9600</point>
+    </reference>
+    <reference name="DEFAULT_SYSTEM_VOLUME_CURVE">
+    <!-- Default System reference Volume Curve -->
+        <point>1,-2400</point>
+        <point>33,-1800</point>
+        <point>66,-1200</point>
+        <point>100,-600</point>
+    </reference>
+    <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+    <!-- Default Media reference Volume Curve -->
+        <point>1,-5800</point>
+        <point>20,-4000</point>
+        <point>60,-1700</point>
+        <point>100,0</point>
+    </reference>
+    <reference name="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE">
+    <!--Default Volume Curve -->
+        <point>1,-4950</point>
+        <point>33,-3350</point>
+        <point>66,-1700</point>
+        <point>100,0</point>
+    </reference>
+    <reference name="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE">
+    <!-- Default is Speaker Media Volume Curve -->
+        <point>1,-5800</point>
+        <point>20,-4000</point>
+        <point>60,-1700</point>
+        <point>100,0</point>
+    </reference>
+    <reference name="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE">
+    <!--Default Volume Curve -->
+        <point>1,-4950</point>
+        <point>33,-3350</point>
+        <point>66,-1700</point>
+        <point>100,0</point>
+    </reference>
+    <reference name="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE">
+    <!-- Default is Ext Media System Volume Curve -->
+        <point>1,-5800</point>
+        <point>20,-4000</point>
+        <point>60,-2100</point>
+        <point>100,-1000</point>
+    </reference>
+</volumes>
diff --git a/services/audiopolicy/config/r_submix_audio_policy_configuration.xml b/services/audiopolicy/config/r_submix_audio_policy_configuration.xml
new file mode 100644
index 0000000..dc2a5ec
--- /dev/null
+++ b/services/audiopolicy/config/r_submix_audio_policy_configuration.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 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.
+-->
+<!-- Remote Submix Audio Policy Configuration file -->
+<module name="r_submix" halVersion="2.0">
+    <attachedDevices>
+        <item>Remote Submix In</item>
+    </attachedDevices>
+    <mixPorts>
+        <mixPort name="r_submix output" role="source">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+        </mixPort>
+        <mixPort name="r_submix input" role="sink">
+           <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                    samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+        </mixPort>
+   </mixPorts>
+   <devicePorts>
+       <devicePort tagName="Remote Submix Out" type="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"  role="sink">
+           <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                    samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+       </devicePort>
+       <devicePort tagName="Remote Submix In" type="AUDIO_DEVICE_IN_REMOTE_SUBMIX"  role="source">
+           <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                    samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+        </devicePort>
+    </devicePorts>
+    <routes>
+        <route type="mix" sink="Remote Submix Out"
+               sources="r_submix output"/>
+        <route type="mix" sink="r_submix input"
+               sources="Remote Submix In"/>
+    </routes>
+</module>
diff --git a/services/audiopolicy/config/usb_audio_policy_configuration.xml b/services/audiopolicy/config/usb_audio_policy_configuration.xml
new file mode 100644
index 0000000..1630a94
--- /dev/null
+++ b/services/audiopolicy/config/usb_audio_policy_configuration.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 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.
+-->
+<!-- USB Audio HAL Audio Policy Configuration file -->
+
+<module name="usb" halVersion="2.0">
+    <mixPorts>
+        <mixPort name="usb_accessory output" role="source">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+        </mixPort>
+        <mixPort name="usb_device output" role="source"/>
+        <mixPort name="usb_device input" role="sink"/>
+    </mixPorts>
+    <devicePorts>
+        <devicePort tagName="USB Host Out" type="AUDIO_DEVICE_OUT_USB_ACCESSORY" role="sink">
+            <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                     samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+        </devicePort>
+        <devicePort tagName="USB Device Out" type="AUDIO_DEVICE_OUT_USB_DEVICE" role="sink"/>
+        <devicePort tagName="USB Device In" type="AUDIO_DEVICE_IN_USB_DEVICE" role="source"/>
+    </devicePorts>
+    <routes>
+        <route type="mix" sink="USB Host Out"
+               sources="usb_accessory output"/>
+        <route type="mix" sink="USB Device Out"
+               sources="usb_device output"/>
+        <route type="mix" sink="usb_device input"
+               sources="USB Device In"/>
+    </routes>
+</module>
diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
index e73e543..567ff9e 100755
--- a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
+++ b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
@@ -133,37 +133,6 @@
     virtual status_t setDeviceConnectionState(const android::sp<android::DeviceDescriptor> devDesc,
                                               audio_policy_dev_state_t state) = 0;
 
-    /**
-     * Translate a volume index given by the UI to an amplification value in dB for a stream type
-     * and a device category.
-     *
-     * @param[in] deviceCategory for which the conversion is requested.
-     * @param[in] stream type for which the conversion is requested.
-     * @param[in] indexInUi index received from the UI to be translated.
-     *
-     * @return amplification value in dB matching the UI index for this given device and stream.
-     */
-    virtual float volIndexToDb(Volume::device_category deviceCategory, audio_stream_type_t stream,
-                                 int indexInUi) = 0;
-
-    /**
-     * Initialize the min / max index of volume applicable for a given stream type. These indexes
-     * will be used upon conversion of UI index to volume amplification.
-     *
-     * @param[in] stream type for which the indexes need to be set
-     * @param[in] indexMin Minimum index allowed for this stream.
-     * @param[in] indexMax Maximum index allowed for this stream.
-     */
-    virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax) = 0;
-
-    /**
-     * Initialize volume curves for each strategy and device category
-     *
-     * @param[in] isSpeakerDrcEnabled true on devices that use DRC on the DEVICE_CATEGORY_SPEAKER
-                  path to boost soft sounds, used to adjust volume curves accordingly
-     */
-    virtual void initializeVolumeCurves(bool isSpeakerDrcEnabled) = 0;
-
 protected:
     virtual ~AudioPolicyManagerInterface() {}
 };
diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
index 6d43df2..846fa48 100755
--- a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
+++ b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <IVolumeCurvesCollection.h>
 #include <AudioGain.h>
 #include <AudioPort.h>
 #include <AudioPatch.h>
@@ -25,7 +26,6 @@
 #include <AudioOutputDescriptor.h>
 #include <AudioPolicyMix.h>
 #include <SoundTriggerSession.h>
-#include <StreamDescriptor.h>
 
 namespace android {
 
@@ -51,7 +51,7 @@
 
     virtual const DeviceVector &getAvailableInputDevices() const = 0;
 
-    virtual StreamDescriptorCollection &getStreamDescriptors() = 0;
+    virtual IVolumeCurvesCollection &getVolumeCurves() = 0;
 
     virtual const sp<DeviceDescriptor> &getDefaultOutputDevice() const = 0;
 
diff --git a/services/audiopolicy/engineconfigurable/Android.mk b/services/audiopolicy/engineconfigurable/Android.mk
index b18c520..e6b5f85 100755
--- a/services/audiopolicy/engineconfigurable/Android.mk
+++ b/services/audiopolicy/engineconfigurable/Android.mk
@@ -41,7 +41,8 @@
 LOCAL_STATIC_LIBRARIES := \
     libmedia_helper \
     libaudiopolicypfwwrapper \
-    libaudiopolicycomponents
+    libaudiopolicycomponents \
+    libxml2
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
diff --git a/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h b/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
index 74daba5..759d0c9 100755
--- a/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
+++ b/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
@@ -111,13 +111,12 @@
      * Set the strategy to be followed by a stream.
      *
      * @param[in] stream: name of the stream for which the strategy to use has to be set
-     * @param[in] strategy to follow for the given stream.
+     * @param[in] volumeProfile to follow for the given stream.
      *
-     * @return true if the strategy were set correclty for this stream, false otherwise.
+     * @return true if the profile was set correclty for this stream, false otherwise.
      */
     virtual bool setVolumeProfileForStream(const audio_stream_type_t &stream,
-                                           Volume::device_category category,
-                                           const VolumeCurvePoints &points) = 0;
+                                           const audio_stream_type_t &volumeProfile) = 0;
 
     /**
      * Set the strategy to be followed by a usage.
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/example/Android.mk
index e9b1902..e15e418 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Android.mk
@@ -7,6 +7,7 @@
 #
 ################################################################################################
 
+ifeq (1, 0)
 
 LOCAL_PATH := $(call my-dir)
 
@@ -60,14 +61,6 @@
 LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
 
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem-Volume.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := Structure/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
 ######### Policy PFW Settings #########
 include $(CLEAR_VARS)
 LOCAL_MODULE := parameter-framework.policy
@@ -103,3 +96,5 @@
 LOCAL_SRC_FILES := Settings/$(LOCAL_MODULE_STEM)
 include $(BUILD_PREBUILT)
 endif # pfw_rebuild_settings
+
+endif # ifeq (1, 0)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/PolicyConfigurableDomains.xml b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/PolicyConfigurableDomains.xml
index 8cb0723..8c3917a 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/PolicyConfigurableDomains.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/PolicyConfigurableDomains.xml
@@ -52,18 +52,21 @@
       <Configuration Name="BluetoothA2dp">
         <CompoundRule Type="All">
           <SelectionCriterionRule SelectionCriterion="ForceUseForMedia" MatchesWhen="IsNot" Value="ForceNoBtA2dp"/>
+          <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="IsNot" Value="ForceBtSco"/>
           <SelectionCriterionRule SelectionCriterion="AvailableOutputDevices" MatchesWhen="Includes" Value="BluetoothA2dp"/>
         </CompoundRule>
       </Configuration>
       <Configuration Name="BluetoothA2dpHeadphone">
         <CompoundRule Type="All">
           <SelectionCriterionRule SelectionCriterion="ForceUseForMedia" MatchesWhen="IsNot" Value="ForceNoBtA2dp"/>
+          <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="IsNot" Value="ForceBtSco"/>
           <SelectionCriterionRule SelectionCriterion="AvailableOutputDevices" MatchesWhen="Includes" Value="BluetoothA2dpHeadphones"/>
         </CompoundRule>
       </Configuration>
       <Configuration Name="BluetoothA2dpSpeaker">
         <CompoundRule Type="All">
           <SelectionCriterionRule SelectionCriterion="ForceUseForMedia" MatchesWhen="IsNot" Value="ForceNoBtA2dp"/>
+          <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="IsNot" Value="ForceBtSco"/>
           <SelectionCriterionRule SelectionCriterion="AvailableOutputDevices" MatchesWhen="Includes" Value="BluetoothA2dpSpeaker"/>
         </CompoundRule>
       </Configuration>
@@ -119,6 +122,7 @@
         <CompoundRule Type="All">
           <SelectionCriterionRule SelectionCriterion="AvailableOutputDevices" MatchesWhen="Includes" Value="Speaker"/>
           <SelectionCriterionRule SelectionCriterion="ForceUseForHdmiSystemAudio" MatchesWhen="IsNot" Value="ForceHdmiSystemEnforced"/>
+          <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="IsNot" Value="ForceBtSco"/>
         </CompoundRule>
       </Configuration>
       <Configuration Name="Default">
@@ -902,10 +906,7 @@
           <SelectionCriterionRule SelectionCriterion="TelephonyMode" MatchesWhen="IsNot" Value="InCall"/>
           <SelectionCriterionRule SelectionCriterion="TelephonyMode" MatchesWhen="IsNot" Value="InCommunication"/>
           <SelectionCriterionRule SelectionCriterion="ForceUseForMedia" MatchesWhen="IsNot" Value="ForceNoBtA2dp"/>
-          <CompoundRule Type="Any">
-            <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="Is" Value="ForceBtSco"/>
-            <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="Is" Value="ForceNone"/>
-          </CompoundRule>
+          <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="Is" Value="ForceNone"/>
         </CompoundRule>
       </Configuration>
       <Configuration Name="BluetoothA2dpHeadphones">
@@ -914,10 +915,7 @@
           <SelectionCriterionRule SelectionCriterion="TelephonyMode" MatchesWhen="IsNot" Value="InCall"/>
           <SelectionCriterionRule SelectionCriterion="TelephonyMode" MatchesWhen="IsNot" Value="InCommunication"/>
           <SelectionCriterionRule SelectionCriterion="ForceUseForMedia" MatchesWhen="IsNot" Value="ForceNoBtA2dp"/>
-          <CompoundRule Type="Any">
-            <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="Is" Value="ForceBtSco"/>
-            <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="Is" Value="ForceNone"/>
-          </CompoundRule>
+          <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="Is" Value="ForceNone"/>
         </CompoundRule>
       </Configuration>
       <Configuration Name="BluetoothA2dpSpeaker">
@@ -1314,10 +1312,10 @@
           <BitParameter Name="bluetooth_a2dp">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/bluetooth_a2dp_headphones">
-          <BitParameter Name="bluetooth_a2dp_headphones">1</BitParameter>
+          <BitParameter Name="bluetooth_a2dp_headphones">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/bluetooth_a2dp_speaker">
-          <BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
+          <BitParameter Name="bluetooth_a2dp_speaker">1</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
@@ -1924,7 +1922,7 @@
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/speaker">
-          <BitParameter Name="speaker">0</BitParameter>
+          <BitParameter Name="speaker">1</BitParameter>
         </ConfigurableElement>
       </Configuration>
     </Settings>
@@ -8197,6 +8195,22 @@
       <ConfigurableElement Path="/Policy/policy/input_sources/hotword/applicable_input_device/mask/spdif"/>
       <ConfigurableElement Path="/Policy/policy/input_sources/hotword/applicable_input_device/mask/bluetooth_a2dp"/>
       <ConfigurableElement Path="/Policy/policy/input_sources/hotword/applicable_input_device/mask/loopback"/>
+      <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/in"/>
+      <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/communication"/>
+      <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/ambient"/>
+      <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/hdmi"/>
+      <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/telephony_rx"/>
+      <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/back_mic"/>
+      <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/remote_submix"/>
+      <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/anlg_dock_headset"/>
+      <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/dgtl_dock_headset"/>
+      <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/usb_accessory"/>
+      <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/fm_tuner"/>
+      <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/tv_tuner"/>
+      <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/line"/>
+      <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/spdif"/>
+      <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/bluetooth_a2dp"/>
+      <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/loopback"/>
       <ConfigurableElement Path="/Policy/policy/input_sources/fm_tuner/applicable_input_device/mask/in"/>
       <ConfigurableElement Path="/Policy/policy/input_sources/fm_tuner/applicable_input_device/mask/communication"/>
       <ConfigurableElement Path="/Policy/policy/input_sources/fm_tuner/applicable_input_device/mask/ambient"/>
@@ -8733,6 +8747,54 @@
         <ConfigurableElement Path="/Policy/policy/input_sources/hotword/applicable_input_device/mask/loopback">
           <BitParameter Name="loopback">0</BitParameter>
         </ConfigurableElement>
+        <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/in">
+          <BitParameter Name="in">1</BitParameter>
+        </ConfigurableElement>
+        <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/communication">
+          <BitParameter Name="communication">0</BitParameter>
+        </ConfigurableElement>
+        <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/ambient">
+          <BitParameter Name="ambient">0</BitParameter>
+        </ConfigurableElement>
+        <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/hdmi">
+          <BitParameter Name="hdmi">0</BitParameter>
+        </ConfigurableElement>
+        <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/telephony_rx">
+          <BitParameter Name="telephony_rx">0</BitParameter>
+        </ConfigurableElement>
+        <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/back_mic">
+          <BitParameter Name="back_mic">0</BitParameter>
+        </ConfigurableElement>
+        <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/remote_submix">
+          <BitParameter Name="remote_submix">0</BitParameter>
+        </ConfigurableElement>
+        <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
+        </ConfigurableElement>
+        <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/dgtl_dock_headset">
+          <BitParameter Name="dgtl_dock_headset">0</BitParameter>
+        </ConfigurableElement>
+        <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/usb_accessory">
+          <BitParameter Name="usb_accessory">0</BitParameter>
+        </ConfigurableElement>
+        <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/fm_tuner">
+          <BitParameter Name="fm_tuner">0</BitParameter>
+        </ConfigurableElement>
+        <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/tv_tuner">
+          <BitParameter Name="tv_tuner">0</BitParameter>
+        </ConfigurableElement>
+        <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/line">
+          <BitParameter Name="line">0</BitParameter>
+        </ConfigurableElement>
+        <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/spdif">
+          <BitParameter Name="spdif">0</BitParameter>
+        </ConfigurableElement>
+        <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/bluetooth_a2dp">
+          <BitParameter Name="bluetooth_a2dp">0</BitParameter>
+        </ConfigurableElement>
+        <ConfigurableElement Path="/Policy/policy/input_sources/unprocessed/applicable_input_device/mask/loopback">
+          <BitParameter Name="loopback">0</BitParameter>
+        </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/input_sources/fm_tuner/applicable_input_device/mask/in">
           <BitParameter Name="in">1</BitParameter>
         </ConfigurableElement>
@@ -8893,7 +8955,7 @@
           <BitParameter Name="bluetooth_a2dp">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/input_sources/mic/applicable_input_device/mask/wired_headset">
-          <BitParameter Name="wired_headset">1</BitParameter>
+          <BitParameter Name="wired_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/input_sources/mic/applicable_input_device/mask/usb_device">
           <BitParameter Name="usb_device">0</BitParameter>
@@ -9439,7 +9501,7 @@
           <BitParameter Name="usb_device">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/input_sources/voice_communication/applicable_input_device/mask/builtin_mic">
-          <BitParameter Name="builtin_mic">0</BitParameter>
+          <BitParameter Name="builtin_mic">1</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/input_sources/voice_communication/applicable_input_device/mask/back_mic">
           <BitParameter Name="back_mic">0</BitParameter>
@@ -9508,1544 +9570,56 @@
       </Configuration>
     </Configurations>
     <ConfigurableElements>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
+      <ConfigurableElement Path="/Policy/policy/streams/voice_call/applicable_volume_profile/volume_profile"/>
+      <ConfigurableElement Path="/Policy/policy/streams/system/applicable_volume_profile/volume_profile"/>
+      <ConfigurableElement Path="/Policy/policy/streams/ring/applicable_volume_profile/volume_profile"/>
+      <ConfigurableElement Path="/Policy/policy/streams/music/applicable_volume_profile/volume_profile"/>
+      <ConfigurableElement Path="/Policy/policy/streams/alarm/applicable_volume_profile/volume_profile"/>
+      <ConfigurableElement Path="/Policy/policy/streams/notification/applicable_volume_profile/volume_profile"/>
+      <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/applicable_volume_profile/volume_profile"/>
+      <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/applicable_volume_profile/volume_profile"/>
+      <ConfigurableElement Path="/Policy/policy/streams/tts/applicable_volume_profile/volume_profile"/>
+      <ConfigurableElement Path="/Policy/policy/streams/accessibility/applicable_volume_profile/volume_profile"/>
+      <ConfigurableElement Path="/Policy/policy/streams/rerouting/applicable_volume_profile/volume_profile"/>
+      <ConfigurableElement Path="/Policy/policy/streams/patch/applicable_volume_profile/volume_profile"/>
     </ConfigurableElements>
     <Settings>
       <Configuration Name="Calibration">
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
+        <ConfigurableElement Path="/Policy/policy/streams/voice_call/applicable_volume_profile/volume_profile">
+          <EnumParameter Name="volume_profile">voice_call</EnumParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
+        <ConfigurableElement Path="/Policy/policy/streams/system/applicable_volume_profile/volume_profile">
+          <EnumParameter Name="volume_profile">system</EnumParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
+        <ConfigurableElement Path="/Policy/policy/streams/ring/applicable_volume_profile/volume_profile">
+          <EnumParameter Name="volume_profile">ring</EnumParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
+        <ConfigurableElement Path="/Policy/policy/streams/music/applicable_volume_profile/volume_profile">
+          <EnumParameter Name="volume_profile">music</EnumParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
+        <ConfigurableElement Path="/Policy/policy/streams/alarm/applicable_volume_profile/volume_profile">
+          <EnumParameter Name="volume_profile">alarm</EnumParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
+        <ConfigurableElement Path="/Policy/policy/streams/notification/applicable_volume_profile/volume_profile">
+          <EnumParameter Name="volume_profile">notification</EnumParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
+        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/applicable_volume_profile/volume_profile">
+          <EnumParameter Name="volume_profile">bluetooth_sco</EnumParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
+        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/applicable_volume_profile/volume_profile">
+          <EnumParameter Name="volume_profile">enforced_audible</EnumParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
+        <ConfigurableElement Path="/Policy/policy/streams/tts/applicable_volume_profile/volume_profile">
+          <EnumParameter Name="volume_profile">tts</EnumParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
+        <ConfigurableElement Path="/Policy/policy/streams/accessibility/applicable_volume_profile/volume_profile">
+          <EnumParameter Name="volume_profile">accessibility</EnumParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
+        <ConfigurableElement Path="/Policy/policy/streams/rerouting/applicable_volume_profile/volume_profile">
+          <EnumParameter Name="volume_profile">rerouting</EnumParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-16.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-8.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/voice_call/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-30.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-26.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-22.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-21.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/system/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-10.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-49.50000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-33.50000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-35.69921875</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-26.10156250</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-13.19921875</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-49.50000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-33.50000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-27.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/ring/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-10.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-56.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-34.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-11.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/music/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-49.50000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-33.50000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-35.69921875</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-26.10156250</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-13.19921875</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-49.50000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-33.50000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-27.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/alarm/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-10.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-49.50000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-33.50000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-35.69921875</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-26.10156250</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-13.19921875</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-49.50000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-33.50000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-27.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/notification/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-10.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-16.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-8.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/bluetooth_sco/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-30.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-26.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-22.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-27.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/enforced_audible/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-10.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">2</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-68.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-34.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">2</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">2</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/tts/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-96.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-56.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-34.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-11.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/accessibility/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">2</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">2</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">2</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">2</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/rerouting/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">2</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">2</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">2</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">2</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/patch/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
+        <ConfigurableElement Path="/Policy/policy/streams/patch/applicable_volume_profile/volume_profile">
+          <EnumParameter Name="volume_profile">patch</EnumParameter>
         </ConfigurableElement>
       </Configuration>
     </Settings>
@@ -11063,234 +9637,17 @@
       </Configuration>
     </Configurations>
     <ConfigurableElements>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/0/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/1/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/2/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/3/index"/>
-      <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation"/>
+      <ConfigurableElement Path="/Policy/policy/streams/dtmf/applicable_volume_profile/volume_profile"/>
     </ConfigurableElements>
     <Settings>
       <Configuration Name="InCall">
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-30.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-26.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-22.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-27.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-10.00000000</FixedPointParameter>
+        <ConfigurableElement Path="/Policy/policy/streams/dtmf/applicable_volume_profile/volume_profile">
+          <EnumParameter Name="volume_profile">voice_call</EnumParameter>
         </ConfigurableElement>
       </Configuration>
       <Configuration Name="OutOfCall">
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/headset_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-16.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-8.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/speaker_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">0</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-24.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-18.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-12.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/earpiece_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-6.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/0/index">
-          <IntegerParameter Name="index">1</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/0/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-58.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/1/index">
-          <IntegerParameter Name="index">33</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/1/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-40.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/2/index">
-          <IntegerParameter Name="index">66</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/2/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">-17.00000000</FixedPointParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/3/index">
-          <IntegerParameter Name="index">100</IntegerParameter>
-        </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/streams/dtmf/volume_profiles/extmedia_device_category/curve_points/3/db_attenuation">
-          <FixedPointParameter Name="db_attenuation">0.00000000</FixedPointParameter>
+        <ConfigurableElement Path="/Policy/policy/streams/dtmf/applicable_volume_profile/volume_profile">
+          <EnumParameter Name="volume_profile">dtmf</EnumParameter>
         </ConfigurableElement>
       </Configuration>
     </Settings>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_input_source.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_input_source.pfw
index d4bc370..07a3c81 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_input_source.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_input_source.pfw
@@ -186,6 +186,23 @@
 				spdif = 0
 				bluetooth_a2dp = 0
 				loopback = 0
+			component: /Policy/policy/input_sources/unprocessed/applicable_input_device/mask
+				in = 1
+				communication = 0
+				ambient = 0
+				hdmi = 0
+				telephony_rx = 0
+				back_mic = 0
+				remote_submix = 0
+				anlg_dock_headset = 0
+				dgtl_dock_headset = 0
+				usb_accessory = 0
+				fm_tuner = 0
+				tv_tuner = 0
+				line = 0
+				spdif = 0
+				bluetooth_a2dp = 0
+				loopback = 0
 			component: /Policy/policy/input_sources/fm_tuner/applicable_input_device/mask
 				in = 1
 				communication = 0
@@ -239,7 +256,7 @@
 					bluetooth_sco_headset = 1
 				component: mic/applicable_input_device/mask/
 					bluetooth_a2dp = 0
-					wired_headset = 1
+					wired_headset = 0
 					usb_device = 0
 					builtin_mic = 0
 					bluetooth_sco_headset = 1
@@ -484,11 +501,14 @@
 				back_mic = 1
 
 		conf: Default
+			#
+			# Fallback on the default input device which can be builtin mic for example
+			#
 			component: /Policy/policy/input_sources/voice_communication/applicable_input_device/mask
 				bluetooth_sco_headset = 0
 				wired_headset = 0
 				usb_device = 0
-				builtin_mic = 0
+				builtin_mic = 1
 				back_mic = 0
 
 	domain: RemoteSubmix
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_strategy_media.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_strategy_media.pfw
index 38bede5..006ac60 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_strategy_media.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_strategy_media.pfw
@@ -34,6 +34,7 @@
 
 			conf: BluetoothA2dp
 				ForceUseForMedia IsNot ForceNoBtA2dp
+				ForceUseForCommunication IsNot ForceBtSco
 				AvailableOutputDevices Includes BluetoothA2dp
 
 				component: /Policy/policy/strategies/media/selected_output_devices/mask
@@ -53,6 +54,7 @@
 
 			conf: BluetoothA2dpHeadphone
 				ForceUseForMedia IsNot ForceNoBtA2dp
+				ForceUseForCommunication IsNot ForceBtSco
 				AvailableOutputDevices Includes BluetoothA2dpHeadphones
 
 				component: /Policy/policy/strategies/media/selected_output_devices/mask
@@ -72,6 +74,7 @@
 
 			conf: BluetoothA2dpSpeaker
 				ForceUseForMedia IsNot ForceNoBtA2dp
+				ForceUseForCommunication IsNot ForceBtSco
 				AvailableOutputDevices Includes BluetoothA2dpSpeaker
 
 				component: /Policy/policy/strategies/media/selected_output_devices/mask
@@ -263,6 +266,7 @@
 				# If hdmi system audio mode is on, remove speaker out of output list.
 				#
 				ForceUseForHdmiSystemAudio IsNot ForceHdmiSystemEnforced
+				ForceUseForCommunication IsNot ForceBtSco
 
 				component: /Policy/policy/strategies/media/selected_output_devices/mask
 					speaker = 1
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_strategy_phone.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_strategy_phone.pfw
index 7b01491..ae70914 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_strategy_phone.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/device_for_strategy_phone.pfw
@@ -92,9 +92,7 @@
 				TelephonyMode IsNot InCall
 				TelephonyMode IsNot InCommunication
 				ForceUseForMedia IsNot ForceNoBtA2dp
-				ANY
-					ForceUseForCommunication Is ForceBtSco
-					ForceUseForCommunication Is ForceNone
+				ForceUseForCommunication Is ForceNone
 
 				component: /Policy/policy/strategies/phone/selected_output_devices/mask
 					earpiece = 0
@@ -124,9 +122,7 @@
 				TelephonyMode IsNot InCall
 				TelephonyMode IsNot InCommunication
 				ForceUseForMedia IsNot ForceNoBtA2dp
-				ANY
-					ForceUseForCommunication Is ForceBtSco
-					ForceUseForCommunication Is ForceNone
+				ForceUseForCommunication Is ForceNone
 
 				component: /Policy/policy/strategies/phone/selected_output_devices/mask
 					earpiece = 0
@@ -166,8 +162,8 @@
 					bluetooth_sco_headset = 0
 					bluetooth_sco_carkit = 0
 					bluetooth_a2dp = 0
-					bluetooth_a2dp_headphones = 1
-					bluetooth_a2dp_speaker = 0
+					bluetooth_a2dp_headphones = 0
+					bluetooth_a2dp_speaker = 1
 					hdmi = 0
 					angl_dock_headset = 0
 					dgtl_dock_headset = 0
@@ -463,6 +459,9 @@
 					speaker = 1
 
 			conf: Default
+				#
+				# Fallback on default output device which can be speaker for example
+				#
 				component: /Policy/policy/strategies/phone/selected_output_devices/mask
 					earpiece = 0
 					wired_headset = 0
@@ -480,6 +479,6 @@
 					usb_device = 0
 					telephony_tx = 0
 					line = 0
-					speaker = 0
+					speaker = 1
 
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/volumes.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/volumes.pfw
index 1049564..7db4537 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/volumes.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/volumes.pfw
@@ -1,462 +1,18 @@
 supDomain: VolumeProfilesForStream
 	domain: Calibration
 		conf: Calibration
-			component: /Policy/policy/streams
-				component: voice_call/volume_profiles
-					component: headset_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = -24.0
-						1/index = 33
-						1/db_attenuation = -18.0
-						2/index = 66
-						2/db_attenuation = -12.0
-						3/index = 100
-						3/db_attenuation = -6.0
-					component: speaker_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = -24.0
-						1/index = 33
-						1/db_attenuation = -16.0
-						2/index = 66
-						2/db_attenuation = -8.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: earpiece_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = -24.0
-						1/index = 33
-						1/db_attenuation = -18.0
-						2/index = 66
-						2/db_attenuation = -12.0
-						3/index = 100
-						3/db_attenuation = -6.0
-					component: extmedia_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -58.0
-						1/index = 33
-						1/db_attenuation = -40.0
-						2/index = 66
-						2/db_attenuation = -17.0
-						3/index = 100
-						3/db_attenuation = 0.0
-
-				component: system/volume_profiles
-					component: headset_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -30.0
-						1/index = 33
-						1/db_attenuation = -26.0
-						2/index = 66
-						2/db_attenuation = -22.0
-						3/index = 100
-						3/db_attenuation = -18.0
-					component: speaker_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -24.0
-						1/index = 33
-						1/db_attenuation = -18.0
-						2/index = 66
-						2/db_attenuation = -12.0
-						3/index = 100
-						3/db_attenuation = -6.0
-					component: earpiece_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -24.0
-						1/index = 33
-						1/db_attenuation = -18.0
-						2/index = 66
-						2/db_attenuation = -12.0
-						3/index = 100
-						3/db_attenuation = -6.0
-					component: extmedia_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -58.0
-						1/index = 33
-						1/db_attenuation = -40.0
-						2/index = 66
-						2/db_attenuation = -21.0
-						3/index = 100
-						3/db_attenuation = -10.0
-
-				component: ring/volume_profiles
-					component: headset_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -49.5
-						1/index = 33
-						1/db_attenuation = -33.5
-						2/index = 66
-						2/db_attenuation = -17.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: speaker_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -35.7
-						1/index = 33
-						1/db_attenuation = -26.1
-						2/index = 66
-						2/db_attenuation = -13.2
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: earpiece_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -49.5
-						1/index = 33
-						1/db_attenuation = -33.5
-						2/index = 66
-						2/db_attenuation = -17.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: extmedia_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -58.0
-						1/index = 33
-						1/db_attenuation = -40.0
-						2/index = 66
-						2/db_attenuation = -27.0
-						3/index = 100
-						3/db_attenuation = -10.0
-
-				component: music/volume_profiles
-					component: headset_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -58.0
-						1/index = 33
-						1/db_attenuation = -40.0
-						2/index = 66
-						2/db_attenuation = -17.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: speaker_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -56.0
-						1/index = 33
-						1/db_attenuation = -34.0
-						2/index = 66
-						2/db_attenuation = -11.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: earpiece_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -58.0
-						1/index = 33
-						1/db_attenuation = -40.0
-						2/index = 66
-						2/db_attenuation = -17.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: extmedia_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -58.0
-						1/index = 33
-						1/db_attenuation = -40.0
-						2/index = 66
-						2/db_attenuation = -17.0
-						3/index = 100
-						3/db_attenuation = 0.0
-
-				component: alarm/volume_profiles
-					component: headset_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -49.5
-						1/index = 33
-						1/db_attenuation = -33.5
-						2/index = 66
-						2/db_attenuation = -17.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: speaker_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -35.7
-						1/index = 33
-						1/db_attenuation = -26.1
-						2/index = 66
-						2/db_attenuation = -13.2
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: earpiece_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -49.5
-						1/index = 33
-						1/db_attenuation = -33.5
-						2/index = 66
-						2/db_attenuation = -17.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: extmedia_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -58.0
-						1/index = 33
-						1/db_attenuation = -40.0
-						2/index = 66
-						2/db_attenuation = -27.0
-						3/index = 100
-						3/db_attenuation = -10.0
-
-				component: notification/volume_profiles
-					component: headset_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -49.5
-						1/index = 33
-						1/db_attenuation = -33.5
-						2/index = 66
-						2/db_attenuation = -17.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: speaker_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -35.7
-						1/index = 33
-						1/db_attenuation = -26.1
-						2/index = 66
-						2/db_attenuation = -13.2
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: earpiece_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -49.5
-						1/index = 33
-						1/db_attenuation = -33.5
-						2/index = 66
-						2/db_attenuation = -17.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: extmedia_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -58.0
-						1/index = 33
-						1/db_attenuation = -40.0
-						2/index = 66
-						2/db_attenuation = -27.0
-						3/index = 100
-						3/db_attenuation = -10.0
-
-				component: bluetooth_sco/volume_profiles
-					component: headset_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = -24.0
-						1/index = 33
-						1/db_attenuation = -18.0
-						2/index = 66
-						2/db_attenuation = -12.0
-						3/index = 100
-						3/db_attenuation = -6.0
-					component: speaker_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = -24.0
-						1/index = 33
-						1/db_attenuation = -16.0
-						2/index = 66
-						2/db_attenuation = -8.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: earpiece_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = -24.0
-						1/index = 33
-						1/db_attenuation = -18.0
-						2/index = 66
-						2/db_attenuation = -12.0
-						3/index = 100
-						3/db_attenuation = -6.0
-					component: extmedia_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -58.0
-						1/index = 33
-						1/db_attenuation = -40.0
-						2/index = 66
-						2/db_attenuation = -17.0
-						3/index = 100
-						3/db_attenuation = 0.0
-
-				component: enforced_audible/volume_profiles
-					component: headset_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -30.0
-						1/index = 33
-						1/db_attenuation = -26.0
-						2/index = 66
-						2/db_attenuation = -22.0
-						3/index = 100
-						3/db_attenuation = -18.0
-					component: speaker_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -24.0
-						1/index = 33
-						1/db_attenuation = -18.0
-						2/index = 66
-						2/db_attenuation = -12.0
-						3/index = 100
-						3/db_attenuation = -6.0
-					component: earpiece_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -24.0
-						1/index = 33
-						1/db_attenuation = -18.0
-						2/index = 66
-						2/db_attenuation = -12.0
-						3/index = 100
-						3/db_attenuation = -6.0
-					component: extmedia_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -58.0
-						1/index = 33
-						1/db_attenuation = -40.0
-						2/index = 66
-						2/db_attenuation = -27.0
-						3/index = 100
-						3/db_attenuation = -10.0
-
-				component: tts/volume_profiles
-					component: headset_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = -96.0
-						1/index = 1
-						1/db_attenuation = -96.0
-						2/index = 2
-						2/db_attenuation = -96.0
-						3/index = 100
-						3/db_attenuation = -96.0
-					component: speaker_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = -96.0
-						1/index = 33
-						1/db_attenuation = -68.0
-						2/index = 66
-						2/db_attenuation = -34.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: earpiece_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = -96.0
-						1/index = 1
-						1/db_attenuation = -96.0
-						2/index = 2
-						2/db_attenuation = -96.0
-						3/index = 100
-						3/db_attenuation = -96.0
-					component: extmedia_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = -96.0
-						1/index = 1
-						1/db_attenuation = -96.0
-						2/index = 2
-						2/db_attenuation = -96.0
-						3/index = 100
-						3/db_attenuation = -96.0
-
-				component: accessibility/volume_profiles
-					component: headset_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -58.0
-						1/index = 33
-						1/db_attenuation = -40.0
-						2/index = 66
-						2/db_attenuation = -17.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: speaker_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -56.0
-						1/index = 33
-						1/db_attenuation = -34.0
-						2/index = 66
-						2/db_attenuation = -11.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: earpiece_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -58.0
-						1/index = 33
-						1/db_attenuation = -40.0
-						2/index = 66
-						2/db_attenuation = -17.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: extmedia_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -58.0
-						1/index = 33
-						1/db_attenuation = -40.0
-						2/index = 66
-						2/db_attenuation = -17.0
-						3/index = 100
-						3/db_attenuation = 0.0
-
-				component: rerouting/volume_profiles
-					component: headset_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = 0.0
-						1/index = 1
-						1/db_attenuation = 0.0
-						2/index = 2
-						2/db_attenuation = 0.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: speaker_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = 0.0
-						1/index = 1
-						1/db_attenuation = 0.0
-						2/index = 2
-						2/db_attenuation = 0.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: earpiece_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = 0.0
-						1/index = 1
-						1/db_attenuation = 0.0
-						2/index = 2
-						2/db_attenuation = 0.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: extmedia_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = 0.0
-						1/index = 1
-						1/db_attenuation = 0.0
-						2/index = 2
-						2/db_attenuation = 0.0
-						3/index = 100
-						3/db_attenuation = 0.0
-
-				component: patch/volume_profiles
-					component: headset_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = 0.0
-						1/index = 1
-						1/db_attenuation = 0.0
-						2/index = 2
-						2/db_attenuation = 0.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: speaker_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = 0.0
-						1/index = 1
-						1/db_attenuation = 0.0
-						2/index = 2
-						2/db_attenuation = 0.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: earpiece_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = 0.0
-						1/index = 1
-						1/db_attenuation = 0.0
-						2/index = 2
-						2/db_attenuation = 0.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: extmedia_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = 0.0
-						1/index = 1
-						1/db_attenuation = 0.0
-						2/index = 2
-						2/db_attenuation = 0.0
-						3/index = 100
-						3/db_attenuation = 0.0
+			/Policy/policy/streams/voice_call/applicable_volume_profile/volume_profile = voice_call
+			/Policy/policy/streams/system/applicable_volume_profile/volume_profile = system
+			/Policy/policy/streams/ring/applicable_volume_profile/volume_profile = ring
+			/Policy/policy/streams/music/applicable_volume_profile/volume_profile = music
+			/Policy/policy/streams/alarm/applicable_volume_profile/volume_profile = alarm
+			/Policy/policy/streams/notification/applicable_volume_profile/volume_profile = notification
+			/Policy/policy/streams/bluetooth_sco/applicable_volume_profile/volume_profile = bluetooth_sco
+			/Policy/policy/streams/enforced_audible/applicable_volume_profile/volume_profile = enforced_audible
+			/Policy/policy/streams/tts/applicable_volume_profile/volume_profile = tts
+			/Policy/policy/streams/accessibility/applicable_volume_profile/volume_profile = accessibility
+			/Policy/policy/streams/rerouting/applicable_volume_profile/volume_profile = rerouting
+			/Policy/policy/streams/patch/applicable_volume_profile/volume_profile = patch
 
 	domain: Dtmf
 		conf: InCall
@@ -464,82 +20,9 @@
 				TelephonyMode Is InCall
 				TelephonyMode Is InCommunication
 
-			component: /Policy/policy/streams
-				component: dtmf/volume_profiles
-					component: headset_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -30.0
-						1/index = 33
-						1/db_attenuation = -26.0
-						2/index = 66
-						2/db_attenuation = -22.0
-						3/index = 100
-						3/db_attenuation = -18.0
-					component: speaker_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -24.0
-						1/index = 33
-						1/db_attenuation = -18.0
-						2/index = 66
-						2/db_attenuation = -12.0
-						3/index = 100
-						3/db_attenuation = -6.0
-					component: earpiece_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -24.0
-						1/index = 33
-						1/db_attenuation = -18.0
-						2/index = 66
-						2/db_attenuation = -12.0
-						3/index = 100
-						3/db_attenuation = -6.0
-					component: extmedia_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -58.0
-						1/index = 33
-						1/db_attenuation = -40.0
-						2/index = 66
-						2/db_attenuation = -27.0
-						3/index = 100
-						3/db_attenuation = -10.0
+			/Policy/policy/streams/dtmf/applicable_volume_profile/volume_profile = voice_call
 
 		conf: OutOfCall
-			component: /Policy/policy/streams
-				component: dtmf/volume_profiles
-					component: headset_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = -24.0
-						1/index = 33
-						1/db_attenuation = -18.0
-						2/index = 66
-						2/db_attenuation = -12.0
-						3/index = 100
-						3/db_attenuation = -6.0
-					component: speaker_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = -24.0
-						1/index = 33
-						1/db_attenuation = -16.0
-						2/index = 66
-						2/db_attenuation = -8.0
-						3/index = 100
-						3/db_attenuation = 0.0
-					component: earpiece_device_category/curve_points
-						0/index = 0
-						0/db_attenuation = -24.0
-						1/index = 33
-						1/db_attenuation = -18.0
-						2/index = 66
-						2/db_attenuation = -12.0
-						3/index = 100
-						3/db_attenuation = -6.0
-					component: extmedia_device_category/curve_points
-						0/index = 1
-						0/db_attenuation = -58.0
-						1/index = 33
-						1/db_attenuation = -40.0
-						2/index = 66
-						2/db_attenuation = -17.0
-						3/index = 100
-						3/db_attenuation = 0.0
+			/Policy/policy/streams/dtmf/applicable_volume_profile/volume_profile = dtmf
+
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem-CommonTypes.xml b/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem-CommonTypes.xml
index 821d6ad..6d6145a 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem-CommonTypes.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem-CommonTypes.xml
@@ -6,8 +6,6 @@
     profile. It must match with the output device enum parameter.
     -->
      <!--#################### GLOBAL COMPONENTS BEGIN ####################-->
-     <!-- Common Types defintion -->
-     <xi:include href="PolicySubsystem-Volume.xml"/>
 
      <!--#################### GLOBAL COMPONENTS END ####################-->
 
@@ -30,7 +28,7 @@
             <BitParameter Name="usb_accessory" Size="1" Pos="13"/>
             <BitParameter Name="usb_device" Size="1" Pos="14"/>
             <BitParameter Name="remote_submix" Size="1" Pos="15"/>
-            <BitParameter Name="telephony_tx" Size="1" Pos="26"/>
+            <BitParameter Name="telephony_tx" Size="1" Pos="16"/>
             <BitParameter Name="line" Size="1" Pos="17"/>
             <BitParameter Name="hdmi_arc" Size="1" Pos="18"/>
             <BitParameter Name="spdif" Size="1" Pos="19"/>
@@ -111,8 +109,9 @@
             <BitParameter Name="voice_recognition" Size="1" Pos="6"/>
             <BitParameter Name="voice_communication" Size="1" Pos="7"/>
             <BitParameter Name="remote_submix" Size="1" Pos="8"/>
-            <BitParameter Name="fm_tuner" Size="1" Pos="9"/>
-            <BitParameter Name="hotword" Size="1" Pos="10"/>
+            <BitParameter Name="unprocessed" Size="1" Pos="9"/>
+            <BitParameter Name="fm_tuner" Size="1" Pos="10"/>
+            <BitParameter Name="hotword" Size="1" Pos="11"/>
         </BitParameterBlock>
     </ComponentType>
 
@@ -142,10 +141,28 @@
 
     <!--#################### STREAM COMMON TYPES BEGIN ####################-->
 
+    <ComponentType Name="VolumeProfileType">
+        <EnumParameter Name="volume_profile" Size="32">
+            <ValuePair Literal="voice_call" Numerical="0"/>
+            <ValuePair Literal="system" Numerical="1"/>
+            <ValuePair Literal="ring" Numerical="2"/>
+            <ValuePair Literal="music" Numerical="3"/>
+            <ValuePair Literal="alarm" Numerical="4"/>
+            <ValuePair Literal="notification" Numerical="5"/>
+            <ValuePair Literal="bluetooth_sco" Numerical="6"/>
+            <ValuePair Literal="enforced_audible" Numerical="7"/>
+            <ValuePair Literal="dtmf" Numerical="8"/>
+            <ValuePair Literal="tts" Numerical="9"/>
+            <ValuePair Literal="accessibility" Numerical="10"/>
+            <ValuePair Literal="rerouting" Numerical="11"/>
+            <ValuePair Literal="patch" Numerical="12"/>
+        </EnumParameter>
+    </ComponentType>
+
     <ComponentType Name="Stream">
-        <Component Name="applicable_strategy" Type="Strategy" Mapping="Stream:'%1'"/>
-        <Component Name="volume_profiles" Type="VolumeCurvesCategories"
-                   Description="A volume profile is refered by the stream type."/>
+        <Component Name="applicable_strategy" Type="Strategy"/>
+        <Component Name="applicable_volume_profile" Type="VolumeProfileType"
+                   Description="Volume profile followed by a given stream type."/>
     </ComponentType>
 
     <!--#################### STREAM COMMON TYPES END ####################-->
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem-Volume.xml b/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem-Volume.xml
deleted file mode 100755
index cf39cc2..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem-Volume.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ComponentTypeSet xmlns:xi="http://www.w3.org/2001/XInclude"
-                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-                  xsi:noNamespaceSchemaLocation="Schemas/ComponentTypeSet.xsd">
-  <ComponentType Name="VolumeCurvePoints">
-    <ParameterBlock Name="curve_points" ArrayLength="4" Mapping="VolumeProfile:'%1'"
-        Description="4 points to define the volume attenuation curve, each
-                     characterized by the volume index (from 0 to 100) at which
-                     they apply, and the attenuation in dB at that index.
-                     We use 100 steps to avoid rounding errors when computing
-                     the volume">
-        <IntegerParameter Name="index" Size="32"/>
-        <FixedPointParameter Name="db_attenuation" Size="16" Integral="7" Fractional="8"/>
-     </ParameterBlock>
-    </ComponentType>
-
-    <ComponentType Name="VolumeCurvesCategories">
-        <Component Name="headset_device_category" Type="VolumeCurvePoints" Mapping="Category:0"/>
-        <Component Name="speaker_device_category" Type="VolumeCurvePoints" Mapping="Category:1"/>
-        <Component Name="earpiece_device_category" Type="VolumeCurvePoints" Mapping="Category:2"/>
-        <Component Name="extmedia_device_category" Type="VolumeCurvePoints" Mapping="Category:3"/>
-    </ComponentType>
-
-</ComponentTypeSet>
-
-
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem.xml b/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem.xml
index b21f6ae..e35511c 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Structure/PolicySubsystem.xml
@@ -38,29 +38,29 @@
 
         <ComponentType Name="Streams" Description="associated to audio_stream_type_t definition,
                              identifier mapping must match the value of the enum">
-            <Component Name="voice_call" Type="Stream" Mapping="Amend1:VoiceCall,Identifier:0"/>
-            <Component Name="system" Type="Stream" Mapping="Amend1:System,Identifier:1"/>
-            <Component Name="ring" Type="Stream" Mapping="Amend1:Ring,Identifier:2"/>
-            <Component Name="music" Type="Stream" Mapping="Amend1:Music,Identifier:3"/>
-            <Component Name="alarm" Type="Stream" Mapping="Amend1:Alarm,Identifier:4"/>
+            <Component Name="voice_call" Type="Stream" Mapping="Stream:VoiceCall,Identifier:0"/>
+            <Component Name="system" Type="Stream" Mapping="Stream:System,Identifier:1"/>
+            <Component Name="ring" Type="Stream" Mapping="Stream:Ring,Identifier:2"/>
+            <Component Name="music" Type="Stream" Mapping="Stream:Music,Identifier:3"/>
+            <Component Name="alarm" Type="Stream" Mapping="Stream:Alarm,Identifier:4"/>
             <Component Name="notification" Type="Stream"
-                                           Mapping="Amend1:Notification,Identifier:5"/>
+                                           Mapping="Stream:Notification,Identifier:5"/>
             <Component Name="bluetooth_sco" Type="Stream"
-                                            Mapping="Amend1:BluetoothSco,Identifier:6"/>
+                                            Mapping="Stream:BluetoothSco,Identifier:6"/>
             <Component Name="enforced_audible" Type="Stream"
-                                               Mapping="Amend1:EnforceAudible,Identifier:7"
+                                               Mapping="Stream:EnforceAudible,Identifier:7"
                        Description="Sounds that cannot be muted by user and must
                                     be routed to speaker"/>
-            <Component Name="dtmf" Type="Stream" Mapping="Amend1:Dtmf,Identifier:8"/>
-            <Component Name="tts" Type="Stream" Mapping="Amend1:Tts,Identifier:9"
+            <Component Name="dtmf" Type="Stream" Mapping="Stream:Dtmf,Identifier:8"/>
+            <Component Name="tts" Type="Stream" Mapping="Stream:Tts,Identifier:9"
                              Description="Transmitted Through Speaker.
                                           Plays over speaker only, silent on other devices"/>
             <Component Name="accessibility" Type="Stream"
-                                            Mapping="Amend1:Accessibility,Identifier:10"
+                                            Mapping="Stream:Accessibility,Identifier:10"
                              Description="For accessibility talk back prompts"/>
-            <Component Name="rerouting" Type="Stream" Mapping="Amend1:Rerouting,Identifier:11"
+            <Component Name="rerouting" Type="Stream" Mapping="Stream:Rerouting,Identifier:11"
                              Description="For dynamic policy output mixes"/>
-            <Component Name="patch" Type="Stream" Mapping="Amend1:Patch,Identifier:12"
+            <Component Name="patch" Type="Stream" Mapping="Stream:Patch,Identifier:12"
                              Description="For internal audio flinger tracks. Fixed volume"/>
         </ComponentType>
 
@@ -120,6 +120,8 @@
                                                   Mapping="Amend1:VoiceCommunication,Identifier:7"/>
             <Component Name="remote_submix" Type="InputSource"
                                             Mapping="Amend1:RemoteSubmix,Identifier:8"/>
+            <Component Name="unprocessed" Type="InputSource"
+                                            Mapping="Amend1:Unprocessed,Identifier:9"/>
             <Component Name="fm_tuner" Type="InputSource" Mapping="Amend1:FmTuner,Identifier:1998"/>
             <Component Name="hotword" Type="InputSource" Mapping="Amend1:Hotword,Identifier:1999"/>
         </ComponentType>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
index a523656..c65de92 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.mk
@@ -8,7 +8,6 @@
     PolicySubsystem.cpp \
     Strategy.cpp \
     InputSource.cpp \
-    VolumeProfile.cpp \
     Stream.cpp \
     Usage.cpp
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
index 497d555..ccb10ae 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
@@ -30,24 +30,16 @@
                                 context),
       mPolicySubsystem(static_cast<const PolicySubsystem *>(
                            instanceConfigurableElement->getBelongingSubsystem())),
-      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface()),
-      mApplicableInputDevice(mDefaultApplicableInputDevice)
+      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
 {
     mId = static_cast<audio_source_t>(context.getItemAsInteger(MappingKeyIdentifier));
     // Declares the strategy to audio policy engine
     mPolicyPluginInterface->addInputSource(getFormattedMappingValue(), mId);
 }
 
-bool InputSource::receiveFromHW(string & /*error*/)
-{
-    blackboardWrite(&mApplicableInputDevice, sizeof(mApplicableInputDevice));
-    return true;
-}
-
 bool InputSource::sendToHW(string & /*error*/)
 {
     uint32_t applicableInputDevice;
     blackboardRead(&applicableInputDevice, sizeof(applicableInputDevice));
-    mApplicableInputDevice = applicableInputDevice;
-    return mPolicyPluginInterface->setDeviceForInputSource(mId, mApplicableInputDevice);
+    return mPolicyPluginInterface->setDeviceForInputSource(mId, applicableInputDevice);
 }
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.h
index 67c5b50..0db4f70 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.h
@@ -32,7 +32,6 @@
              const CMappingContext &context);
 
 protected:
-    virtual bool receiveFromHW(std::string &error);
     virtual bool sendToHW(std::string &error);
 
 private:
@@ -44,6 +43,4 @@
     android::AudioPolicyPluginInterface *mPolicyPluginInterface;
 
     audio_source_t mId; /**< input source identifier to link with audio.h. */
-    uint32_t mApplicableInputDevice; /**< applicable input device for this strategy. */
-    static const uint32_t mDefaultApplicableInputDevice = 0; /**< default input device. */
 };
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
index bf3906d..6412134 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
@@ -20,7 +20,6 @@
 #include "Strategy.h"
 #include "Stream.h"
 #include "InputSource.h"
-#include "VolumeProfile.h"
 #include "Usage.h"
 #include <AudioPolicyPluginInterface.h>
 #include <AudioPolicyEngineInstance.h>
@@ -40,7 +39,6 @@
 const char *const PolicySubsystem::mStrategyComponentName = "Strategy";
 const char *const PolicySubsystem::mInputSourceComponentName = "InputSource";
 const char *const PolicySubsystem::mUsageComponentName = "Usage";
-const char *const PolicySubsystem::mVolumeProfileComponentName = "VolumeProfile";
 
 PolicySubsystem::PolicySubsystem(const std::string &name)
     : CSubsystem(name),
@@ -67,7 +65,7 @@
     addSubsystemObjectFactory(
         new TSubsystemObjectFactory<Stream>(
             mStreamComponentName,
-            (1 << MappingKeyAmend1) | (1 << MappingKeyIdentifier))
+            (1 << MappingKeyIdentifier))
         );
     addSubsystemObjectFactory(
         new TSubsystemObjectFactory<Strategy>(
@@ -84,11 +82,6 @@
             mInputSourceComponentName,
             (1 << MappingKeyAmend1) | (1 << MappingKeyIdentifier))
         );
-    addSubsystemObjectFactory(
-        new TSubsystemObjectFactory<VolumeProfile>(
-            mVolumeProfileComponentName,
-            (1 << MappingKeyAmend1) | (1 << MappingKeyIdentifier) | (1 << MappingKeyIdentifier))
-        );
 }
 
 // Retrieve Route interface
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.h
index 3c26fe1..e3143a5 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.h
@@ -56,5 +56,4 @@
     static const char *const mStrategyComponentName;
     static const char *const mInputSourceComponentName;
     static const char *const mUsageComponentName;
-    static const char *const mVolumeProfileComponentName;
 };
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp
index 1848813..5c536d5 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp
@@ -31,8 +31,7 @@
                                 context),
       mPolicySubsystem(static_cast<const PolicySubsystem *>(
                            instanceConfigurableElement->getBelongingSubsystem())),
-      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface()),
-      mApplicableOutputDevice(mDefaultApplicableOutputDevice)
+      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
 {
     mId = static_cast<routing_strategy>(context.getItemAsInteger(MappingKeyIdentifier));
 
@@ -40,12 +39,6 @@
     mPolicyPluginInterface->addStrategy(getFormattedMappingValue(), mId);
 }
 
-bool Strategy::receiveFromHW(string & /*error*/)
-{
-    blackboardWrite(&mApplicableOutputDevice, sizeof(mApplicableOutputDevice));
-    return true;
-}
-
 bool Strategy::sendToHW(string & /*error*/)
 {
     uint32_t applicableOutputDevice;
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.h
index 9a9b3e4..cbb72e2 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.h
@@ -32,7 +32,6 @@
              const CMappingContext &context);
 
 protected:
-    virtual bool receiveFromHW(std::string &error);
     virtual bool sendToHW(std::string &error);
 
 private:
@@ -44,6 +43,4 @@
     android::AudioPolicyPluginInterface *mPolicyPluginInterface;
 
     android::routing_strategy mId; /**< strategy identifier to link with audio.h.*/
-    uint32_t mApplicableOutputDevice; /**< applicable output device for this strategy. */
-    static const uint32_t mDefaultApplicableOutputDevice = 0; /**< default output device. */
 };
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.cpp
index 575b0bb..4387634 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.cpp
@@ -24,15 +24,10 @@
 Stream::Stream(const string &mappingValue,
                    CInstanceConfigurableElement *instanceConfigurableElement,
                    const CMappingContext &context)
-    : CFormattedSubsystemObject(instanceConfigurableElement,
-                                mappingValue,
-                                MappingKeyAmend1,
-                                (MappingKeyAmendEnd - MappingKeyAmend1 + 1),
-                                context),
+    : CSubsystemObject(instanceConfigurableElement),
       mPolicySubsystem(static_cast<const PolicySubsystem *>(
                            instanceConfigurableElement->getBelongingSubsystem())),
-      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface()),
-      mApplicableStrategy(mDefaultApplicableStrategy)
+      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
 {
     mId = static_cast<audio_stream_type_t>(context.getItemAsInteger(MappingKeyIdentifier));
 
@@ -40,17 +35,17 @@
     mPolicyPluginInterface->addStream(getFormattedMappingValue(), mId);
 }
 
-bool Stream::receiveFromHW(string & /*error*/)
-{
-    blackboardWrite(&mApplicableStrategy, sizeof(mApplicableStrategy));
-    return true;
-}
-
 bool Stream::sendToHW(string & /*error*/)
 {
-    uint32_t applicableStrategy;
-    blackboardRead(&applicableStrategy, sizeof(applicableStrategy));
-    mApplicableStrategy = applicableStrategy;
-    return mPolicyPluginInterface->setStrategyForStream(mId,
-                                              static_cast<routing_strategy>(mApplicableStrategy));
+    Applicable params;
+    blackboardRead(&params, sizeof(params));
+
+    mPolicyPluginInterface->setStrategyForStream(mId,
+                                                 static_cast<routing_strategy>(params.strategy));
+
+    mPolicyPluginInterface->setVolumeProfileForStream(mId,
+                                                      static_cast<audio_stream_type_t>(params.volumeProfile));
+
+    return true;
+
 }
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.h
index 7d90c36..4b0e081 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Stream.h
@@ -16,7 +16,7 @@
 
 #pragma once
 
-#include "FormattedSubsystemObject.h"
+#include "SubsystemObject.h"
 #include "InstanceConfigurableElement.h"
 #include "MappingContext.h"
 #include <AudioPolicyPluginInterface.h>
@@ -24,15 +24,21 @@
 
 class PolicySubsystem;
 
-class Stream : public CFormattedSubsystemObject
+class Stream : public CSubsystemObject
 {
+private:
+    struct Applicable
+    {
+        uint32_t strategy; /**< applicable strategy for this stream. */
+        uint32_t volumeProfile; /**< applicable strategy for this stream. */
+    } __attribute__((packed));
+
 public:
     Stream(const std::string &mappingValue,
              CInstanceConfigurableElement *instanceConfigurableElement,
              const CMappingContext &context);
 
 protected:
-    virtual bool receiveFromHW(std::string &error);
     virtual bool sendToHW(std::string &error);
 
 private:
@@ -42,8 +48,5 @@
      * Interface to communicate with Audio Policy Engine.
      */
     android::AudioPolicyPluginInterface *mPolicyPluginInterface;
-
     audio_stream_type_t mId; /**< stream type identifier to link with audio.h. */
-    uint32_t mApplicableStrategy; /**< applicable strategy for this stream. */
-    static const uint32_t mDefaultApplicableStrategy = 0; /**< default strategy. */
 };
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp
index 1916b9b..eb7d78f 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp
@@ -31,8 +31,7 @@
                                 context),
       mPolicySubsystem(static_cast<const PolicySubsystem *>(
                            instanceConfigurableElement->getBelongingSubsystem())),
-      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface()),
-      mApplicableStrategy(mDefaultApplicableStrategy)
+      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
 {
     mId = static_cast<audio_usage_t>(context.getItemAsInteger(MappingKeyIdentifier));
 
@@ -40,17 +39,10 @@
     mPolicyPluginInterface->addUsage(getFormattedMappingValue(), mId);
 }
 
-bool Usage::receiveFromHW(string & /*error*/)
-{
-    blackboardWrite(&mApplicableStrategy, sizeof(mApplicableStrategy));
-    return true;
-}
-
 bool Usage::sendToHW(string & /*error*/)
 {
     uint32_t applicableStrategy;
     blackboardRead(&applicableStrategy, sizeof(applicableStrategy));
-    mApplicableStrategy = applicableStrategy;
     return mPolicyPluginInterface->setStrategyForUsage(mId,
-                                              static_cast<routing_strategy>(mApplicableStrategy));
+                                              static_cast<routing_strategy>(applicableStrategy));
 }
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.h
index 8e9b638..3b82f8c 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.h
@@ -32,7 +32,6 @@
              const CMappingContext &context);
 
 protected:
-    virtual bool receiveFromHW(std::string &error);
     virtual bool sendToHW(std::string &error);
 
 private:
@@ -44,6 +43,4 @@
     android::AudioPolicyPluginInterface *mPolicyPluginInterface;
 
     audio_usage_t mId; /**< usage identifier to link with audio.h. */
-    uint32_t mApplicableStrategy; /**< applicable strategy for this usage. */
-    static const uint32_t mDefaultApplicableStrategy = 0; /**< default strategy. */
 };
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.cpp
deleted file mode 100755
index 5c155c8..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 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 "VolumeProfile.h"
-#include "PolicyMappingKeys.h"
-#include "PolicySubsystem.h"
-#include "ParameterBlockType.h"
-#include <Volume.h>
-#include <math.h>
-
-using std::string;
-
-VolumeProfile::VolumeProfile(const string &mappingValue,
-                             CInstanceConfigurableElement *instanceConfigurableElement,
-                             const CMappingContext &context)
-    : CFormattedSubsystemObject(instanceConfigurableElement,
-                                mappingValue,
-                                MappingKeyAmend1,
-                                (MappingKeyAmendEnd - MappingKeyAmend1 + 1),
-                                context),
-      mPolicySubsystem(static_cast<const PolicySubsystem *>(
-                           instanceConfigurableElement->getBelongingSubsystem())),
-      mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
-{
-    uint32_t categoryKey = context.getItemAsInteger(MappingKeyCategory);
-    if (categoryKey >= Volume::DEVICE_CATEGORY_CNT) {
-        mCategory = Volume::DEVICE_CATEGORY_SPEAKER;
-    } else {
-        mCategory = static_cast<Volume::device_category>(categoryKey);
-    }
-    mId = static_cast<audio_stream_type_t>(context.getItemAsInteger(MappingKeyIdentifier));
-
-    // (no exception support, defer the error)
-    if (instanceConfigurableElement->getType() != CInstanceConfigurableElement::EParameterBlock) {
-        return;
-    }
-    // Get actual element type
-    const CParameterBlockType *parameterType = static_cast<const CParameterBlockType *>(
-                instanceConfigurableElement->getTypeElement());
-    mPoints = parameterType->getArrayLength();
-}
-
-bool VolumeProfile::receiveFromHW(string & /*error*/)
-{
-    return true;
-}
-
-bool VolumeProfile::sendToHW(string & /*error*/)
-{
-    Point points[mPoints];
-    blackboardRead(&points, sizeof(Point) * mPoints);
-
-    VolumeCurvePoints pointsVector;
-    for (size_t i = 0; i < mPoints; i++) {
-        VolumeCurvePoint curvePoint;
-        curvePoint.mIndex = points[i].index;
-        curvePoint.mDBAttenuation = static_cast<float>(points[i].dbAttenuation) /
-                (1UL << gFractional);
-        pointsVector.push_back(curvePoint);
-    }
-    return mPolicyPluginInterface->setVolumeProfileForStream(mId, mCategory, pointsVector);
-}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.h
deleted file mode 100755
index a00ae84..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#pragma once
-
-#include "FormattedSubsystemObject.h"
-#include "InstanceConfigurableElement.h"
-#include "MappingContext.h"
-#include <Volume.h>
-#include <AudioPolicyPluginInterface.h>
-#include <string>
-
-class PolicySubsystem;
-
-class VolumeProfile : public CFormattedSubsystemObject
-{
-private:
-    struct Point
-    {
-        int index;
-        /** Volume is using FixedPointParameter until float parameters are available. */
-        int16_t dbAttenuation;
-    } __attribute__((packed));
-
-public:
-    VolumeProfile(const std::string &mappingValue,
-                  CInstanceConfigurableElement *instanceConfigurableElement,
-                  const CMappingContext &context);
-
-protected:
-    virtual bool receiveFromHW(std::string &error);
-    virtual bool sendToHW(std::string &error);
-
-private:
-    const PolicySubsystem *mPolicySubsystem; /**< Route subsytem plugin. */
-
-    /**
-     * Interface to communicate with Audio Policy Engine.
-     */
-    android::AudioPolicyPluginInterface *mPolicyPluginInterface;
-
-    /**
-     * volume profile identifier,  which is in fact a stream type to link with audio.h.
-     */
-    audio_stream_type_t mId;
-
-    size_t mPoints;
-    Volume::device_category mCategory;
-
-    static const uint32_t gFractional = 8; /**< Beware to align with the structure. */
-};
diff --git a/services/audiopolicy/engineconfigurable/src/Collection.h b/services/audiopolicy/engineconfigurable/src/Collection.h
index 8f17b15..b72ded8 100755
--- a/services/audiopolicy/engineconfigurable/src/Collection.h
+++ b/services/audiopolicy/engineconfigurable/src/Collection.h
@@ -47,6 +47,7 @@
 class Collection : public std::map<Key, Element<Key> *>
 {
 private:
+    typedef std::map<Key, Element<Key> *> Base;
     typedef Element<Key> T;
     typedef typename std::map<Key, T *>::iterator CollectionIterator;
     typedef typename std::map<Key, T *>::const_iterator CollectionConstIterator;
@@ -127,7 +128,7 @@
         for (it = (*this).begin(); it != (*this).end(); ++it) {
             delete it->second;
         }
-        (*this).clear();
+        Base::clear();
     }
 
 private:
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index 733cdf6..ed807c6 100755
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -106,27 +106,13 @@
 
 status_t Engine::initCheck()
 {
-    if (mPolicyParameterMgr != NULL && mPolicyParameterMgr->start() != NO_ERROR) {
+    if (mPolicyParameterMgr == NULL || mPolicyParameterMgr->start() != NO_ERROR) {
         ALOGE("%s: could not start Policy PFW", __FUNCTION__);
-        delete mPolicyParameterMgr;
-        mPolicyParameterMgr = NULL;
         return NO_INIT;
     }
     return (mApmObserver != NULL)? NO_ERROR : NO_INIT;
 }
 
-bool Engine::setVolumeProfileForStream(const audio_stream_type_t &streamType,
-                                       Volume::device_category deviceCategory,
-                                       const VolumeCurvePoints &points)
-{
-    Stream *stream = getFromCollection<audio_stream_type_t>(streamType);
-    if (stream == NULL) {
-        ALOGE("%s: stream %d not found", __FUNCTION__, streamType);
-        return false;
-    }
-    return stream->setVolumeProfile(deviceCategory, points) == NO_ERROR;
-}
-
 template <typename Key>
 Element<Key> *Engine::getFromCollection(const Key &key) const
 {
@@ -188,6 +174,18 @@
     return mPolicyEngine->getPropertyForKey<audio_devices_t, routing_strategy>(strategy);
 }
 
+bool Engine::PluginInterfaceImpl::setVolumeProfileForStream(const audio_stream_type_t &stream,
+                                                            const audio_stream_type_t &profile)
+{
+    if (mPolicyEngine->setPropertyForKey<audio_stream_type_t, audio_stream_type_t>(stream,
+                                                                                   profile)) {
+        mPolicyEngine->mApmObserver->getVolumeCurves().switchVolumeCurve(profile, stream);
+        return true;
+    }
+    return false;
+}
+
+
 template <typename Property, typename Key>
 bool Engine::setPropertyForKey(const Property &property, const Key &key)
 {
@@ -199,32 +197,6 @@
     return element->template set<Property>(property) == NO_ERROR;
 }
 
-float Engine::volIndexToDb(Volume::device_category category,
-                             audio_stream_type_t streamType,
-                             int indexInUi)
-{
-    Stream *stream = getFromCollection<audio_stream_type_t>(streamType);
-    if (stream == NULL) {
-        ALOGE("%s: Element indexed by key=%d not found", __FUNCTION__, streamType);
-        return 1.0f;
-    }
-    return stream->volIndexToDb(category, indexInUi);
-}
-
-status_t Engine::initStreamVolume(audio_stream_type_t streamType,
-                                           int indexMin, int indexMax)
-{
-    Stream *stream = getFromCollection<audio_stream_type_t>(streamType);
-    if (stream == NULL) {
-        ALOGE("%s: Stream Type %d not found", __FUNCTION__, streamType);
-        return BAD_TYPE;
-    }
-    mApmObserver->getStreamDescriptors().setVolumeIndexMin(streamType, indexMin);
-    mApmObserver->getStreamDescriptors().setVolumeIndexMax(streamType, indexMax);
-
-    return stream->initVolume(indexMin, indexMax);
-}
-
 status_t Engine::setPhoneState(audio_mode_t mode)
 {
     return mPolicyParameterMgr->setPhoneState(mode);
@@ -246,10 +218,17 @@
     return mPolicyParameterMgr->getForceUse(usage);
 }
 
-status_t Engine::setDeviceConnectionState(audio_devices_t devices, audio_policy_dev_state_t state,
-                                          const char *deviceAddress)
+status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+                                          audio_policy_dev_state_t /*state*/)
 {
-    return mPolicyParameterMgr->setDeviceConnectionState(devices, state, deviceAddress);
+    if (audio_is_output_device(devDesc->type())) {
+        return mPolicyParameterMgr->setAvailableOutputDevices(
+                    mApmObserver->getAvailableOutputDevices().types());
+    } else if (audio_is_input_device(devDesc->type())) {
+        return mPolicyParameterMgr->setAvailableInputDevices(
+                    mApmObserver->getAvailableInputDevices().types());
+    }
+    return BAD_TYPE;
 }
 
 template <>
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.h b/services/audiopolicy/engineconfigurable/src/Engine.h
index 6fa7a13..bc5e035 100755
--- a/services/audiopolicy/engineconfigurable/src/Engine.h
+++ b/services/audiopolicy/engineconfigurable/src/Engine.h
@@ -86,22 +86,7 @@
         virtual android::status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
                                                            audio_policy_dev_state_t state)
         {
-            return mPolicyEngine->setDeviceConnectionState(devDesc->type(), state,
-                                                           devDesc->mAddress);
-        }
-        virtual status_t initStreamVolume(audio_stream_type_t stream,
-                                                   int indexMin, int indexMax)
-        {
-            return mPolicyEngine->initStreamVolume(stream, indexMin, indexMax);
-        }
-
-        virtual void initializeVolumeCurves(bool /*isSpeakerDrcEnabled*/) {}
-
-        virtual float volIndexToDb(Volume::device_category deviceCategory,
-                                     audio_stream_type_t stream,
-                                     int indexInUi)
-        {
-            return mPolicyEngine->volIndexToDb(deviceCategory, stream, indexInUi);
+            return mPolicyEngine->setDeviceConnectionState(devDesc, state);
         }
 
     private:
@@ -142,11 +127,7 @@
                                                                                            stream);
         }
         virtual bool setVolumeProfileForStream(const audio_stream_type_t &stream,
-                                               Volume::device_category deviceCategory,
-                                               const VolumeCurvePoints &points)
-        {
-            return mPolicyEngine->setVolumeProfileForStream(stream, deviceCategory, points);
-        }
+                                               const audio_stream_type_t &volumeProfile);
 
         virtual bool setStrategyForUsage(const audio_usage_t &usage, routing_strategy strategy)
         {
@@ -172,7 +153,7 @@
     void setObserver(AudioPolicyManagerObserver *observer);
 
     bool setVolumeProfileForStream(const audio_stream_type_t &stream,
-                                   Volume::device_category deviceCategory,
+                                   device_category deviceCategory,
                                    const VolumeCurvePoints &points);
 
     status_t initCheck();
@@ -180,14 +161,8 @@
     audio_mode_t getPhoneState() const;
     status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config);
     audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const;
-    status_t setDeviceConnectionState(audio_devices_t devices, audio_policy_dev_state_t state,
-                                      const char *deviceAddress);
-
-    float volIndexToDb(Volume::device_category category,
-                       audio_stream_type_t stream,
-                       int indexInUi);
-    status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax);
-
+    status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+                                      audio_policy_dev_state_t state);
     StrategyCollection mStrategyCollection; /**< Strategies indexed by their enum id. */
     StreamCollection mStreamCollection; /**< Streams indexed by their enum id.  */
     UsageCollection mUsageCollection; /**< Usages indexed by their enum id. */
diff --git a/services/audiopolicy/engineconfigurable/src/Stream.cpp b/services/audiopolicy/engineconfigurable/src/Stream.cpp
index a929435..0ed364f 100755
--- a/services/audiopolicy/engineconfigurable/src/Stream.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Stream.cpp
@@ -62,92 +62,22 @@
     return mApplicableStrategy;
 }
 
-status_t Element<audio_stream_type_t>::setVolumeProfile(Volume::device_category category,
-                                                        const VolumeCurvePoints &points)
+template <>
+status_t Element<audio_stream_type_t>::set<audio_stream_type_t>(audio_stream_type_t volumeProfile)
 {
-    ALOGD("%s: adding volume profile for %s for device category %d, points nb =%d", __FUNCTION__,
-          getName().c_str(), category, points.size());
-    mVolumeProfiles[category] = points;
-
-    for (size_t i = 0; i < points.size(); i++) {
-        ALOGV("%s: %s cat=%d curve index =%d Index=%d dBAttenuation=%f",
-              __FUNCTION__, getName().c_str(), category, i, points[i].mIndex,
-             points[i].mDBAttenuation);
-    }
-    return NO_ERROR;
-}
-
-status_t Element<audio_stream_type_t>::initVolume(int indexMin, int indexMax)
-{
-    ALOGV("initStreamVolume() stream %s, min %d, max %d", getName().c_str(), indexMin, indexMax);
-    if (indexMin < 0 || indexMin >= indexMax) {
-        ALOGW("initStreamVolume() invalid index limits for stream %s, min %d, max %d",
-              getName().c_str(), indexMin, indexMax);
+    if (volumeProfile >= AUDIO_STREAM_CNT) {
         return BAD_VALUE;
     }
-    mIndexMin = indexMin;
-    mIndexMax = indexMax;
-
+    mVolumeProfile = volumeProfile;
+    ALOGD("%s: 0x%X for Stream %s", __FUNCTION__, mVolumeProfile, getName().c_str());
     return NO_ERROR;
 }
 
-float Element<audio_stream_type_t>::volIndexToDb(Volume::device_category deviceCategory,
-                                                   int indexInUi)
+template <>
+audio_stream_type_t Element<audio_stream_type_t>::get<audio_stream_type_t>() const
 {
-    VolumeProfileConstIterator it = mVolumeProfiles.find(deviceCategory);
-    if (it == mVolumeProfiles.end()) {
-        ALOGE("%s: device category %d not found for stream %s", __FUNCTION__, deviceCategory,
-              getName().c_str());
-        return 0.0f;
-    }
-    const VolumeCurvePoints curve = mVolumeProfiles[deviceCategory];
-    if (curve.size() != Volume::VOLCNT) {
-        ALOGE("%s: invalid profile for category %d and for stream %s", __FUNCTION__, deviceCategory,
-              getName().c_str());
-        return 0.0f;
-    }
-
-    // the volume index in the UI is relative to the min and max volume indices for this stream type
-    int nbSteps = 1 + curve[Volume::VOLMAX].mIndex -
-            curve[Volume::VOLMIN].mIndex;
-
-    if (mIndexMax - mIndexMin == 0) {
-        ALOGE("%s: Invalid volume indexes Min=Max=%d", __FUNCTION__, mIndexMin);
-        return 0.0f;
-    }
-    int volIdx = (nbSteps * (indexInUi - mIndexMin)) /
-            (mIndexMax - mIndexMin);
-
-    // find what part of the curve this index volume belongs to, or if it's out of bounds
-    int segment = 0;
-    if (volIdx < curve[Volume::VOLMIN].mIndex) {         // out of bounds
-        return VOLUME_MIN_DB;
-    } else if (volIdx < curve[Volume::VOLKNEE1].mIndex) {
-        segment = 0;
-    } else if (volIdx < curve[Volume::VOLKNEE2].mIndex) {
-        segment = 1;
-    } else if (volIdx <= curve[Volume::VOLMAX].mIndex) {
-        segment = 2;
-    } else {                                                               // out of bounds
-        return 0.0f;
-    }
-
-    // linear interpolation in the attenuation table in dB
-    float decibels = curve[segment].mDBAttenuation +
-            ((float)(volIdx - curve[segment].mIndex)) *
-                ( (curve[segment+1].mDBAttenuation -
-                        curve[segment].mDBAttenuation) /
-                    ((float)(curve[segment+1].mIndex -
-                            curve[segment].mIndex)) );
-
-    ALOGV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f]",
-            curve[segment].mIndex, volIdx,
-            curve[segment+1].mIndex,
-            curve[segment].mDBAttenuation,
-            decibels,
-            curve[segment+1].mDBAttenuation);
-
-    return decibels;
+    ALOGV("%s: 0x%X for Stream %s", __FUNCTION__, mVolumeProfile, getName().c_str());
+    return mVolumeProfile;
 }
 
 } // namespace audio_policy
diff --git a/services/audiopolicy/engineconfigurable/src/Stream.h b/services/audiopolicy/engineconfigurable/src/Stream.h
index 8c39dc6..6902003 100755
--- a/services/audiopolicy/engineconfigurable/src/Stream.h
+++ b/services/audiopolicy/engineconfigurable/src/Stream.h
@@ -18,7 +18,6 @@
 
 #include "Element.h"
 #include "EngineDefinition.h"
-#include <Volume.h>
 #include <RoutingStrategy.h>
 #include <map>
 
@@ -32,17 +31,10 @@
 template <>
 class Element<audio_stream_type_t>
 {
-private:
-    typedef std::map<Volume::device_category, VolumeCurvePoints> VolumeProfiles;
-    typedef VolumeProfiles::iterator VolumeProfileIterator;
-    typedef VolumeProfiles::const_iterator VolumeProfileConstIterator;
-
 public:
     Element(const std::string &name)
         : mName(name),
-          mApplicableStrategy(STRATEGY_MEDIA),
-          mIndexMin(0),
-          mIndexMax(1)
+          mApplicableStrategy(STRATEGY_MEDIA)
     {}
     ~Element() {}
 
@@ -79,12 +71,6 @@
     template <typename Property>
     status_t set(Property property);
 
-    status_t setVolumeProfile(Volume::device_category category, const VolumeCurvePoints &points);
-
-    float volIndexToDb(Volume::device_category deviceCategory, int indexInUi);
-
-    status_t initVolume(int indexMin, int indexMax);
-
 private:
     /* Copy facilities are put private to disable copy. */
     Element(const Element &object);
@@ -95,16 +81,7 @@
 
     routing_strategy mApplicableStrategy; /**< Applicable strategy for this stream. */
 
-    /**
-     * Collection of volume profiles indexed by the stream type.
-     * Volume is the only reason why the stream profile was not removed from policy when introducing
-     * attributes.
-     */
-    VolumeProfiles mVolumeProfiles;
-
-    int mIndexMin;
-
-    int mIndexMax;
+    audio_stream_type_t mVolumeProfile; /**< Volume Profile followed by this stream. */
 };
 
 typedef Element<audio_stream_type_t> Stream;
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
index cfe49d4..cc4d4db 100755
--- a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
@@ -15,6 +15,7 @@
  */
 
 #define LOG_TAG "APM::AudioPolicyEngine/PFWWrapper"
+//#define LOG_NDEBUG 0
 
 #include "ParameterManagerWrapper.h"
 #include "audio_policy_criteria_conf.h"
@@ -88,7 +89,6 @@
               __FUNCTION__, gAudioPolicyCriteriaVendorConfFilePath,
               gAudioPolicyCriteriaConfFilePath);
     }
-    ALOGD("%s: ParameterManagerWrapper instantiated!", __FUNCTION__);
 }
 
 ParameterManagerWrapper::~ParameterManagerWrapper()
@@ -118,7 +118,7 @@
 void ParameterManagerWrapper::addCriterionType(const string &typeName, bool isInclusive)
 {
     ALOG_ASSERT(mPolicyCriterionTypes.find(typeName) == mPolicyCriterionTypes.end(),
-                      "CriterionType " << typeName << " already added");
+                      "CriterionType %s already added", typeName.c_str());
     ALOGD("%s: Adding new criterionType %s", __FUNCTION__, typeName.c_str());
 
     mPolicyCriterionTypes[typeName] = mPfwConnector->createSelectionCriterionType(isInclusive);
@@ -130,7 +130,7 @@
     const string &literalValue)
 {
     ALOG_ASSERT(mPolicyCriterionTypes.find(typeName) != mPolicyCriterionTypes.end(),
-                      "CriterionType " << typeName.c_str() << "not found");
+                      "CriterionType %s not found", typeName.c_str());
     ALOGV("%s: Adding new value pair (%d,%s) for criterionType %s", __FUNCTION__,
           numericValue, literalValue.c_str(), typeName.c_str());
     ISelectionCriterionTypeInterface *criterionType = mPolicyCriterionTypes[typeName];
@@ -224,8 +224,8 @@
 {
     parameterManagerElementSupported<T>();
     typename std::map<string, T *>::iterator it = elementsMap.find(name);
-    ALOG_ASSERT(it != elementsMap.end(), "Element " << name << " not found");
-    return it->second;
+    ALOG_ASSERT(it != elementsMap.end(), "Element %s not found", name.c_str());
+    return it != elementsMap.end() ? it->second : NULL;
 }
 
 template <typename T>
@@ -233,8 +233,8 @@
 {
     parameterManagerElementSupported<T>();
     typename std::map<string, T *>::const_iterator it = elementsMap.find(name);
-    ALOG_ASSERT(it != elementsMap.end(), "Element " << name << " not found");
-    return it->second;
+    ALOG_ASSERT(it != elementsMap.end(), "Element %s not found", name.c_str());
+    return it != elementsMap.end() ? it->second : NULL;
 }
 
 void ParameterManagerWrapper::loadCriteria(cnode *root)
@@ -254,8 +254,8 @@
 void ParameterManagerWrapper::addCriterion(const string &name, const string &typeName,
                               const string &defaultLiteralValue)
 {
-    ALOG_ASSERT(mPolicyCriteria.find(criterionName) == mPolicyCriteria.end(),
-                "Route Criterion " << criterionName << " already added");
+    ALOG_ASSERT(mPolicyCriteria.find(name) == mPolicyCriteria.end(),
+                "Route Criterion %s already added", name.c_str());
 
     ISelectionCriterionTypeInterface *criterionType =
             getElement<ISelectionCriterionTypeInterface>(typeName, mPolicyCriterionTypes);
@@ -278,7 +278,7 @@
     const char *criterionName = root->name;
 
     ALOG_ASSERT(mPolicyCriteria.find(criterionName) == mPolicyCriteria.end(),
-                      "Criterion " << criterionName << " already added");
+                      "Criterion %s already added", criterionName);
 
     string paramKeyName = "";
     string path = "";
@@ -335,7 +335,12 @@
 
 status_t ParameterManagerWrapper::setPhoneState(audio_mode_t mode)
 {
-    ISelectionCriterionInterface *criterion = mPolicyCriteria[gPhoneStateCriterionTag];
+    ISelectionCriterionInterface *criterion =
+            getElement<ISelectionCriterionInterface>(gPhoneStateCriterionTag, mPolicyCriteria);
+    if (criterion == NULL) {
+        ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionTag.c_str());
+        return BAD_VALUE;
+    }
     if (!isValueValidForCriterion(criterion, static_cast<int>(mode))) {
         return BAD_VALUE;
     }
@@ -348,6 +353,10 @@
 {
     const ISelectionCriterionInterface *criterion =
             getElement<ISelectionCriterionInterface>(gPhoneStateCriterionTag, mPolicyCriteria);
+    if (criterion == NULL) {
+        ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionTag.c_str());
+        return AUDIO_MODE_NORMAL;
+    }
     return static_cast<audio_mode_t>(criterion->getCriterionState());
 }
 
@@ -359,7 +368,12 @@
         return BAD_VALUE;
     }
 
-    ISelectionCriterionInterface *criterion = mPolicyCriteria[gForceUseCriterionTag[usage]];
+    ISelectionCriterionInterface *criterion =
+            getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
+    if (criterion == NULL) {
+        ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage].c_str());
+        return BAD_VALUE;
+    }
     if (!isValueValidForCriterion(criterion, static_cast<int>(config))) {
         return BAD_VALUE;
     }
@@ -376,6 +390,10 @@
     }
     const ISelectionCriterionInterface *criterion =
             getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
+    if (criterion == NULL) {
+        ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage].c_str());
+        return AUDIO_POLICY_FORCE_NONE;
+    }
     return static_cast<audio_policy_forced_cfg_t>(criterion->getCriterionState());
 }
 
@@ -387,41 +405,28 @@
     return interface->getLiteralValue(valueToCheck, literalValue);
 }
 
-status_t ParameterManagerWrapper::setDeviceConnectionState(audio_devices_t devices,
-                                                           audio_policy_dev_state_t state,
-                                                           const char */*deviceAddres*/)
+status_t ParameterManagerWrapper::setAvailableInputDevices(audio_devices_t inputDevices)
 {
-    ISelectionCriterionInterface *criterion = NULL;
-
-    if (audio_is_output_devices(devices)) {
-        criterion = mPolicyCriteria[gOutputDeviceCriterionTag];
-    } else if (devices & AUDIO_DEVICE_BIT_IN) {
-        criterion = mPolicyCriteria[gInputDeviceCriterionTag];
-    } else {
-        return BAD_TYPE;
-    }
+    ISelectionCriterionInterface *criterion =
+            getElement<ISelectionCriterionInterface>(gInputDeviceCriterionTag, mPolicyCriteria);
     if (criterion == NULL) {
-        ALOGE("%s: no criterion found for devices", __FUNCTION__);
+        ALOGE("%s: no criterion found for %s", __FUNCTION__, gInputDeviceCriterionTag.c_str());
         return DEAD_OBJECT;
     }
+    criterion->setCriterionState(inputDevices & ~AUDIO_DEVICE_BIT_IN);
+    applyPlatformConfiguration();
+    return NO_ERROR;
+}
 
-    int32_t previousDevices = criterion->getCriterionState();
-    switch (state)
-    {
-    case AUDIO_POLICY_DEVICE_STATE_AVAILABLE:
-        criterion->setCriterionState(previousDevices |= devices);
-        break;
-
-    case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE:
-        if (devices & AUDIO_DEVICE_BIT_IN) {
-            devices &= ~AUDIO_DEVICE_BIT_IN;
-        }
-        criterion->setCriterionState(previousDevices &= ~devices);
-        break;
-
-    default:
-        return BAD_VALUE;
+status_t ParameterManagerWrapper::setAvailableOutputDevices(audio_devices_t outputDevices)
+{
+    ISelectionCriterionInterface *criterion =
+            getElement<ISelectionCriterionInterface>(gOutputDeviceCriterionTag, mPolicyCriteria);
+    if (criterion == NULL) {
+        ALOGE("%s: no criterion found for %s", __FUNCTION__, gOutputDeviceCriterionTag.c_str());
+        return DEAD_OBJECT;
     }
+    criterion->setCriterionState(outputDevices);
     applyPlatformConfiguration();
     return NO_ERROR;
 }
diff --git a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
index 3c5f2c0..4c1acfe 100755
--- a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
+++ b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
@@ -103,18 +103,22 @@
     audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const;
 
     /**
-     * Set the connection state of device(s).
-     * It will set the associated policy parameter framework criterion.
+     * Set the available input devices i.e. set the associated policy parameter framework criterion
      *
-     * @param[in] devices mask of devices for which the state has changed.
-     * @param[in] state of availability of this(these) device(s).
-     * @param[in] deviceAddress: the mask might not be enough, as it may represents a type of
-     *            device, so address of the device will help precise identification.
+     * @param[in] inputDevices mask of available input devices.
      *
      * @return NO_ERROR if devices criterion updated correctly, error code otherwise.
      */
-    status_t setDeviceConnectionState(audio_devices_t devices, audio_policy_dev_state_t state,
-                                      const char *deviceAddress);
+    status_t setAvailableInputDevices(audio_devices_t inputDevices);
+
+    /**
+     * Set the available output devices i.e. set the associated policy parameter framework criterion
+     *
+     * @param[in] outputDevices mask of available output devices.
+     *
+     * @return NO_ERROR if devices criterion updated correctly, error code otherwise.
+     */
+    status_t setAvailableOutputDevices(audio_devices_t outputDevices);
 
 private:
     /**
diff --git a/services/audiopolicy/enginedefault/Android.mk b/services/audiopolicy/enginedefault/Android.mk
index ba9b50a..527d7f6 100755
--- a/services/audiopolicy/enginedefault/Android.mk
+++ b/services/audiopolicy/enginedefault/Android.mk
@@ -8,8 +8,6 @@
 LOCAL_SRC_FILES := \
     src/Engine.cpp \
     src/EngineInstance.cpp \
-    src/Gains.cpp \
-
 
 audio_policy_engine_includes_common := \
     $(LOCAL_PATH)/include \
@@ -34,9 +32,11 @@
 
 LOCAL_MODULE := libaudiopolicyenginedefault
 LOCAL_MODULE_TAGS := optional
+
 LOCAL_STATIC_LIBRARIES := \
     libmedia_helper \
-    libaudiopolicycomponents
+    libaudiopolicycomponents \
+    libxml2
 
 LOCAL_SHARED_LIBRARIES += \
     liblog \
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 0686414..37f79fe 100755
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -25,7 +25,6 @@
 #endif
 
 #include "Engine.h"
-#include "Gains.h"
 #include <AudioPolicyManagerObserver.h>
 #include <AudioPort.h>
 #include <IOProfile.h>
@@ -63,57 +62,6 @@
     return (mApmObserver != NULL) ?  NO_ERROR : NO_INIT;
 }
 
-float Engine::volIndexToDb(Volume::device_category category, audio_stream_type_t streamType,
-                             int indexInUi)
-{
-    const StreamDescriptor &streamDesc = mApmObserver->getStreamDescriptors().valueAt(streamType);
-    return Gains::volIndexToDb(category, streamDesc, indexInUi);
-}
-
-
-status_t Engine::initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax)
-{
-    ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
-    if (indexMin < 0 || indexMin >= indexMax) {
-        ALOGW("initStreamVolume() invalid index limits for stream %d, min %d, max %d",
-              stream , indexMin, indexMax);
-        return BAD_VALUE;
-    }
-    mApmObserver->getStreamDescriptors().setVolumeIndexMin(stream, indexMin);
-    mApmObserver->getStreamDescriptors().setVolumeIndexMax(stream, indexMax);
-    return NO_ERROR;
-}
-
-void Engine::initializeVolumeCurves(bool isSpeakerDrcEnabled)
-{
-    StreamDescriptorCollection &streams = mApmObserver->getStreamDescriptors();
-
-    for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
-        for (int j = 0; j < Volume::DEVICE_CATEGORY_CNT; j++) {
-            streams.setVolumeCurvePoint(static_cast<audio_stream_type_t>(i),
-                                         static_cast<Volume::device_category>(j),
-                                         Gains::sVolumeProfiles[i][j]);
-        }
-    }
-
-    // Check availability of DRC on speaker path: if available, override some of the speaker curves
-    if (isSpeakerDrcEnabled) {
-        streams.setVolumeCurvePoint(AUDIO_STREAM_SYSTEM, Volume::DEVICE_CATEGORY_SPEAKER,
-                Gains::sDefaultSystemVolumeCurveDrc);
-        streams.setVolumeCurvePoint(AUDIO_STREAM_RING, Volume::DEVICE_CATEGORY_SPEAKER,
-                Gains::sSpeakerSonificationVolumeCurveDrc);
-        streams.setVolumeCurvePoint(AUDIO_STREAM_ALARM, Volume::DEVICE_CATEGORY_SPEAKER,
-                Gains::sSpeakerSonificationVolumeCurveDrc);
-        streams.setVolumeCurvePoint(AUDIO_STREAM_NOTIFICATION, Volume::DEVICE_CATEGORY_SPEAKER,
-                Gains::sSpeakerSonificationVolumeCurveDrc);
-        streams.setVolumeCurvePoint(AUDIO_STREAM_MUSIC, Volume::DEVICE_CATEGORY_SPEAKER,
-                Gains::sSpeakerMediaVolumeCurveDrc);
-        streams.setVolumeCurvePoint(AUDIO_STREAM_ACCESSIBILITY, Volume::DEVICE_CATEGORY_SPEAKER,
-                Gains::sSpeakerMediaVolumeCurveDrc);
-    }
-}
-
-
 status_t Engine::setPhoneState(audio_mode_t state)
 {
     ALOGV("setPhoneState() state %d", state);
@@ -131,20 +79,14 @@
     // store previous phone state for management of sonification strategy below
     int oldState = mPhoneState;
     mPhoneState = state;
-    StreamDescriptorCollection &streams = mApmObserver->getStreamDescriptors();
-    // are we entering or starting a call
+
     if (!is_state_in_call(oldState) && is_state_in_call(state)) {
         ALOGV("  Entering call in setPhoneState()");
-        for (int j = 0; j < Volume::DEVICE_CATEGORY_CNT; j++) {
-            streams.setVolumeCurvePoint(AUDIO_STREAM_DTMF, static_cast<Volume::device_category>(j),
-                                         Gains::sVolumeProfiles[AUDIO_STREAM_VOICE_CALL][j]);
-        }
+        mApmObserver->getVolumeCurves().switchVolumeCurve(AUDIO_STREAM_VOICE_CALL,
+                                                          AUDIO_STREAM_DTMF);
     } else if (is_state_in_call(oldState) && !is_state_in_call(state)) {
         ALOGV("  Exiting call in setPhoneState()");
-        for (int j = 0; j < Volume::DEVICE_CATEGORY_CNT; j++) {
-            streams.setVolumeCurvePoint(AUDIO_STREAM_DTMF, static_cast<Volume::device_category>(j),
-                                         Gains::sVolumeProfiles[AUDIO_STREAM_DTMF][j]);
-        }
+        mApmObserver->getVolumeCurves().restoreOriginVolumeCurve(AUDIO_STREAM_DTMF);
     }
     return NO_ERROR;
 }
@@ -663,6 +605,7 @@
         break;
 
     case AUDIO_SOURCE_VOICE_RECOGNITION:
+    case AUDIO_SOURCE_UNPROCESSED:
     case AUDIO_SOURCE_HOTWORD:
         if (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO &&
                 availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 56a4748..8b6eaf6 100755
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -18,7 +18,6 @@
 
 
 #include "AudioPolicyManagerInterface.h"
-#include "Gains.h"
 #include <AudioGain.h>
 #include <policy.h>
 
@@ -93,19 +92,6 @@
         {
             return NO_ERROR;
         }
-        virtual status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax)
-        {
-            return mPolicyEngine->initStreamVolume(stream, indexMin, indexMax);
-        }
-        virtual void initializeVolumeCurves(bool isSpeakerDrcEnabled)
-        {
-            return mPolicyEngine->initializeVolumeCurves(isSpeakerDrcEnabled);
-        }
-        virtual float volIndexToDb(Volume::device_category deviceCategory,
-                                     audio_stream_type_t stream,int indexInUi)
-        {
-            return mPolicyEngine->volIndexToDb(deviceCategory, stream, indexInUi);
-        }
     private:
         Engine *mPolicyEngine;
     } mManagerInterface;
@@ -140,12 +126,6 @@
     routing_strategy getStrategyForUsage(audio_usage_t usage);
     audio_devices_t getDeviceForStrategy(routing_strategy strategy) const;
     audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const;
-
-    float volIndexToDb(Volume::device_category category,
-                         audio_stream_type_t stream, int indexInUi);
-    status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax);
-    void initializeVolumeCurves(bool isSpeakerDrcEnabled);
-
     audio_mode_t mPhoneState;  /**< current phone state. */
 
     /** current forced use configuration. */
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 5ff1c0b..8bb49fa 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -24,6 +24,8 @@
 #define ALOGVV(a...) do { } while(0)
 #endif
 
+#define AUDIO_POLICY_XML_CONFIG_FILE "/system/etc/audio_policy_configuration.xml"
+
 #include <inttypes.h>
 #include <math.h>
 
@@ -37,8 +39,12 @@
 #include <media/AudioPolicyHelper.h>
 #include <soundtrigger/SoundTrigger.h>
 #include "AudioPolicyManager.h"
-#include "audio_policy_conf.h"
+#ifndef USE_XML_AUDIO_POLICY_CONF
 #include <ConfigParsingUtils.h>
+#include <StreamDescriptor.h>
+#endif
+#include <Serializer.h>
+#include "TypeConverter.h"
 #include <policy.h>
 
 namespace android {
@@ -190,6 +196,10 @@
             }
         }
 
+        if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
+            cleanUpForDevice(devDesc);
+        }
+
         mpClientInterface->onAudioPortListUpdate();
         return NO_ERROR;
     }  // end if is output device
@@ -266,6 +276,10 @@
             updateCallRouting(newDevice);
         }
 
+        if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
+            cleanUpForDevice(devDesc);
+        }
+
         mpClientInterface->onAudioPortListUpdate();
         return NO_ERROR;
     } // end if is input device
@@ -406,13 +420,17 @@
         // FIXME: would be better to refine to only inputs whose profile connects to the
         // call TX device but this information is not in the audio patch and logic here must be
         // symmetric to the one in startInput()
-        audio_io_handle_t activeInput = mInputs.getActiveInput();
-        if (activeInput != 0) {
-            sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
-            if (activeDesc->getModuleHandle() == txSourceDeviceDesc->getModuleHandle()) {
-                audio_session_t activeSession = activeDesc->mSessions.itemAt(0);
-                stopInput(activeInput, activeSession);
-                releaseInput(activeInput, activeSession);
+        Vector<sp <AudioInputDescriptor> > activeInputs = mInputs.getActiveInputs();
+        for (size_t i = 0; i < activeInputs.size(); i++) {
+            sp<AudioInputDescriptor> activeDesc = activeInputs[i];
+            if (activeDesc->hasSameHwModuleAs(txSourceDeviceDesc)) {
+                AudioSessionCollection activeSessions =
+                        activeDesc->getAudioSessions(true /*activeOnly*/);
+                for (size_t j = 0; j < activeSessions.size(); j++) {
+                    audio_session_t activeSession = activeSessions.keyAt(j);
+                    stopInput(activeDesc->mIoHandle, activeSession);
+                    releaseInput(activeDesc->mIoHandle, activeSession);
+                }
             }
         }
 
@@ -578,15 +596,16 @@
         }
     }
 
-    audio_io_handle_t activeInput = mInputs.getActiveInput();
-    if (activeInput != 0) {
-        sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
-        audio_devices_t newDevice = getNewInputDevice(activeInput);
+    Vector<sp <AudioInputDescriptor> > activeInputs = mInputs.getActiveInputs();
+    for (size_t i = 0; i < activeInputs.size(); i++) {
+        sp<AudioInputDescriptor> activeDesc = activeInputs[i];
+        audio_devices_t newDevice = getNewInputDevice(activeDesc);
         // Force new input selection if the new device can not be reached via current input
-        if (activeDesc->mProfile->mSupportedDevices.types() & (newDevice & ~AUDIO_DEVICE_BIT_IN)) {
-            setInputDevice(activeInput, newDevice);
+        if (activeDesc->mProfile->getSupportedDevices().types() &
+                (newDevice & ~AUDIO_DEVICE_BIT_IN)) {
+            setInputDevice(activeDesc->mIoHandle, newDevice);
         } else {
-            closeInput(activeInput);
+            closeInput(activeDesc->mIoHandle);
         }
     }
 }
@@ -628,15 +647,15 @@
                 continue;
             }
             // reject profiles not corresponding to a device currently available
-            if ((mAvailableOutputDevices.types() & curProfile->mSupportedDevices.types()) == 0) {
+            if ((mAvailableOutputDevices.types() & curProfile->getSupportedDevicesType()) == 0) {
                 continue;
             }
             // if several profiles are compatible, give priority to one with offload capability
-            if (profile != 0 && ((curProfile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0)) {
+            if (profile != 0 && ((curProfile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0)) {
                 continue;
             }
             profile = curProfile;
-            if ((profile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+            if ((profile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
                 break;
             }
         }
@@ -690,9 +709,9 @@
         stream_type_to_audio_attributes(*stream, &attributes);
     }
     sp<SwAudioOutputDescriptor> desc;
-    if (mPolicyMixes.getOutputForAttr(attributes, desc) == NO_ERROR) {
+    if (mPolicyMixes.getOutputForAttr(attributes, uid, desc) == NO_ERROR) {
         ALOG_ASSERT(desc != 0, "Invalid desc returned by getOutputForAttr");
-        if (!audio_is_linear_pcm(format)) {
+        if (!audio_has_proportional_frames(format)) {
             return BAD_VALUE;
         }
         *stream = streamTypefromAttributesInt(&attributes);
@@ -832,15 +851,15 @@
         goto non_direct_output;
     }
 
-    // Do not allow offloading if one non offloadable effect is enabled. This prevents from
-    // creating an offloaded track and tearing it down immediately after start when audioflinger
-    // detects there is an active non offloadable effect.
+    // Do not allow offloading if one non offloadable effect is enabled or MasterMono is enabled.
+    // This prevents creating an offloaded track and tearing it down immediately after start
+    // when audioflinger detects there is an active non offloadable effect.
     // FIXME: We should check the audio session here but we do not have it in this context.
     // This may prevent offloading in rare situations where effects are left active by apps
     // in the background.
 
     if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
-            !mEffects.isNonOffloadableEffectEnabled()) {
+            !(mEffects.isNonOffloadableEffectEnabled() || mMasterMono)) {
         profile = getProfileForDirectOutput(device,
                                            samplingRate,
                                            format,
@@ -873,7 +892,7 @@
         // if the selected profile is offloaded and no offload info was specified,
         // create a default one
         audio_offload_info_t defaultOffloadInfo = AUDIO_INFO_INITIALIZER;
-        if ((profile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && !offloadInfo) {
+        if ((profile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && !offloadInfo) {
             flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
             defaultOffloadInfo.sample_rate = samplingRate;
             defaultOffloadInfo.channel_mask = channelMask;
@@ -1001,13 +1020,13 @@
                 }
             }
 
-            int commonFlags = popcount(outputDesc->mProfile->mFlags & flags);
+            int commonFlags = popcount(outputDesc->mProfile->getFlags() & flags);
             if (commonFlags > maxCommonFlags) {
                 outputFlags = outputs[i];
                 maxCommonFlags = commonFlags;
                 ALOGV("selectOutput() commonFlags for output %d, %04x", outputs[i], commonFlags);
             }
-            if (outputDesc->mProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+            if (outputDesc->mProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
                 outputPrimary = outputs[i];
             }
         }
@@ -1143,7 +1162,7 @@
 
         // apply volume rules for current stream and device if necessary
         checkAndSetVolume(stream,
-                          mStreams.valueFor(stream).getVolumeIndex(device),
+                          mVolumeCurves->getVolumeIndex(stream, device),
                           outputDesc,
                           device);
 
@@ -1318,10 +1337,10 @@
 
     *input = AUDIO_IO_HANDLE_NONE;
     *inputType = API_INPUT_INVALID;
+
     audio_devices_t device;
     // handle legacy remote submix case where the address was not always specified
     String8 address = String8("");
-    bool isSoundTrigger = false;
     audio_source_t inputSource = attr->source;
     audio_source_t halInputSource;
     AudioMix *policyMix = NULL;
@@ -1376,30 +1395,45 @@
         } else {
             *inputType = API_INPUT_LEGACY;
         }
-        // adapt channel selection to input source
-        switch (inputSource) {
-        case AUDIO_SOURCE_VOICE_UPLINK:
-            channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK;
-            break;
-        case AUDIO_SOURCE_VOICE_DOWNLINK:
-            channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK;
-            break;
-        case AUDIO_SOURCE_VOICE_CALL:
-            channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK;
-            break;
-        default:
-            break;
-        }
-        if (inputSource == AUDIO_SOURCE_HOTWORD) {
-            ssize_t index = mSoundTriggerSessions.indexOfKey(session);
-            if (index >= 0) {
-                *input = mSoundTriggerSessions.valueFor(session);
-                isSoundTrigger = true;
-                flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD);
-                ALOGV("SoundTrigger capture on session %d input %d", session, *input);
-            } else {
-                halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
-            }
+
+    }
+
+    *input = getInputForDevice(device, address, session, uid, inputSource,
+                               samplingRate, format, channelMask, flags,
+                               policyMix);
+    if (*input == AUDIO_IO_HANDLE_NONE) {
+        mInputRoutes.removeRoute(session);
+        return INVALID_OPERATION;
+    }
+    ALOGV("getInputForAttr() returns input type = %d", *inputType);
+    return NO_ERROR;
+}
+
+
+audio_io_handle_t AudioPolicyManager::getInputForDevice(audio_devices_t device,
+                                                        String8 address,
+                                                        audio_session_t session,
+                                                        uid_t uid,
+                                                        audio_source_t inputSource,
+                                                        uint32_t samplingRate,
+                                                        audio_format_t format,
+                                                        audio_channel_mask_t channelMask,
+                                                        audio_input_flags_t flags,
+                                                        AudioMix *policyMix)
+{
+    audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
+    audio_source_t halInputSource = inputSource;
+    bool isSoundTrigger = false;
+
+    if (inputSource == AUDIO_SOURCE_HOTWORD) {
+        ssize_t index = mSoundTriggerSessions.indexOfKey(session);
+        if (index >= 0) {
+            input = mSoundTriggerSessions.valueFor(session);
+            isSoundTrigger = true;
+            flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD);
+            ALOGV("SoundTrigger capture on session %d input %d", session, input);
+        } else {
+            halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
         }
     }
 
@@ -1419,16 +1453,79 @@
         } else if (profileFlags != AUDIO_INPUT_FLAG_NONE) {
             profileFlags = AUDIO_INPUT_FLAG_NONE; // retry
         } else { // fail
-            ALOGW("getInputForAttr() could not find profile for device 0x%X, samplingRate %u,"
-                    "format %#x, channelMask 0x%X, flags %#x",
+            ALOGW("getInputForDevice() could not find profile for device 0x%X,"
+                  "samplingRate %u, format %#x, channelMask 0x%X, flags %#x",
                     device, samplingRate, format, channelMask, flags);
-            return BAD_VALUE;
+            return input;
         }
     }
 
     if (profile->getModuleHandle() == 0) {
         ALOGE("getInputForAttr(): HW module %s not opened", profile->getModuleName());
-        return NO_INIT;
+        return input;
+    }
+
+    sp<AudioSession> audioSession = new AudioSession(session,
+                                                              inputSource,
+                                                              format,
+                                                              samplingRate,
+                                                              channelMask,
+                                                              flags,
+                                                              uid,
+                                                              isSoundTrigger,
+                                                              policyMix, mpClientInterface);
+
+
+    // reuse an open input if possible
+    for (size_t i = 0; i < mInputs.size(); i++) {
+        sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
+        // reuse input if:
+        // - it shares the same profile
+        //      AND
+        // - it is not a reroute submix input
+        //      AND
+        // - it is: not used for sound trigger
+        //                OR
+        //          used for sound trigger and all clients use the same session ID
+        //
+        if ((profile == desc->mProfile) &&
+            (isSoundTrigger == desc->isSoundTrigger()) &&
+            !is_virtual_input_device(device)) {
+
+            sp<AudioSession> as = desc->getAudioSession(session);
+            if (as != 0) {
+                // do not allow unmatching properties on same session
+                if (as->matches(audioSession)) {
+                    as->changeOpenCount(1);
+                } else {
+                    ALOGW("getInputForDevice() record with different attributes"
+                          " exists for session %d", session);
+                    break;
+                }
+            } else if (isSoundTrigger) {
+                break;
+            }
+            // 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 ((desc->mSamplingRate != samplingRate ||
+                    desc->mChannelMask != channelMask ||
+                    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;
+            } else {
+                desc->addAudioSession(session, audioSession);
+                ALOGV("%s: reusing input %d", __FUNCTION__, mInputs.keyAt(i));
+                return mInputs.keyAt(i);
+            }
+        }
     }
 
     audio_config_t config = AUDIO_CONFIG_INITIALIZER;
@@ -1437,7 +1534,7 @@
     config.format = profileFormat;
 
     status_t status = mpClientInterface->openInput(profile->getModuleHandle(),
-                                                   input,
+                                                   &input,
                                                    &config,
                                                    &device,
                                                    address,
@@ -1445,43 +1542,77 @@
                                                    profileFlags);
 
     // only accept input with the exact requested set of parameters
-    if (status != NO_ERROR || *input == AUDIO_IO_HANDLE_NONE ||
+    if (status != NO_ERROR || input == AUDIO_IO_HANDLE_NONE ||
         (profileSamplingRate != config.sample_rate) ||
         (profileFormat != config.format) ||
         (profileChannelMask != config.channel_mask)) {
-        ALOGW("getInputForAttr() failed opening input: samplingRate %d, format %d,"
-                " channelMask %x",
+        ALOGW("getInputForAttr() failed opening input: samplingRate %d"
+              ", format %d, channelMask %x",
                 samplingRate, format, channelMask);
-        if (*input != AUDIO_IO_HANDLE_NONE) {
-            mpClientInterface->closeInput(*input);
+        if (input != AUDIO_IO_HANDLE_NONE) {
+            mpClientInterface->closeInput(input);
         }
-        return BAD_VALUE;
+        return AUDIO_IO_HANDLE_NONE;
     }
 
     sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(profile);
-    inputDesc->mInputSource = inputSource;
-    inputDesc->mRefCount = 0;
-    inputDesc->mOpenRefCount = 1;
     inputDesc->mSamplingRate = profileSamplingRate;
     inputDesc->mFormat = profileFormat;
     inputDesc->mChannelMask = profileChannelMask;
     inputDesc->mDevice = device;
-    inputDesc->mSessions.add(session);
-    inputDesc->mIsSoundTrigger = isSoundTrigger;
     inputDesc->mPolicyMix = policyMix;
+    inputDesc->addAudioSession(session, audioSession);
 
-    ALOGV("getInputForAttr() returns input type = %d", *inputType);
-
-    addInput(*input, inputDesc);
+    addInput(input, inputDesc);
     mpClientInterface->onAudioPortListUpdate();
 
-    return NO_ERROR;
+    return input;
 }
 
+bool AudioPolicyManager::isConcurentCaptureAllowed(const sp<AudioInputDescriptor>& inputDesc,
+        const sp<AudioSession>& audioSession)
+{
+    // Do not allow capture if an active voice call is using a software patch and
+    // the call TX source device is on the same HW module.
+    // FIXME: would be better to refine to only inputs whose profile connects to the
+    // call TX device but this information is not in the audio patch
+    if (mCallTxPatch != 0 &&
+        inputDesc->getModuleHandle() == mCallTxPatch->mPatch.sources[0].ext.device.hw_module) {
+        return false;
+    }
+
+    // starting concurrent capture is enabled if:
+    // 1) capturing for re-routing
+    // 2) capturing for HOTWORD source
+    // 3) capturing for FM TUNER source
+    // 3) All other active captures are either for re-routing or HOTWORD
+
+    if (is_virtual_input_device(inputDesc->mDevice) ||
+            audioSession->inputSource() == AUDIO_SOURCE_HOTWORD ||
+            audioSession->inputSource() == AUDIO_SOURCE_FM_TUNER) {
+        return true;
+    }
+
+    Vector< sp<AudioInputDescriptor> > activeInputs = mInputs.getActiveInputs();
+    for (size_t i = 0; i <  activeInputs.size(); i++) {
+        sp<AudioInputDescriptor> activeInput = activeInputs[i];
+        if ((activeInput->inputSource() != AUDIO_SOURCE_HOTWORD) &&
+                (activeInput->inputSource() != AUDIO_SOURCE_FM_TUNER) &&
+                !is_virtual_input_device(activeInput->mDevice)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+
 status_t AudioPolicyManager::startInput(audio_io_handle_t input,
-                                        audio_session_t session)
+                                        audio_session_t session,
+                                        concurrency_type__mask_t *concurrency)
 {
     ALOGV("startInput() input %d", input);
+    *concurrency = API_INPUT_CONCURRENCY_NONE;
     ssize_t index = mInputs.indexOfKey(input);
     if (index < 0) {
         ALOGW("startInput() unknown input %d", input);
@@ -1489,84 +1620,68 @@
     }
     sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
 
-    index = inputDesc->mSessions.indexOf(session);
-    if (index < 0) {
+    sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
+    if (audioSession == 0) {
         ALOGW("startInput() unknown session %d on input %d", session, input);
         return BAD_VALUE;
     }
 
-    // virtual input devices are compatible with other input devices
-    if (!is_virtual_input_device(inputDesc->mDevice)) {
-
-        // for a non-virtual input device, check if there is another (non-virtual) active input
-        audio_io_handle_t activeInput = mInputs.getActiveInput();
-        if (activeInput != 0 && activeInput != input) {
-
-            // If the already active input uses AUDIO_SOURCE_HOTWORD then it is closed,
-            // otherwise the active input continues and the new input cannot be started.
-            sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
-            if ((activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) &&
-                    !activeDesc->hasPreemptedSession(session)) {
-                ALOGW("startInput(%d) preempting low-priority input %d", input, activeInput);
-                audio_session_t activeSession = activeDesc->mSessions.itemAt(0);
-                SortedVector<audio_session_t> sessions = activeDesc->getPreemptedSessions();
-                sessions.add(activeSession);
-                inputDesc->setPreemptedSessions(sessions);
-                stopInput(activeInput, activeSession);
-                releaseInput(activeInput, activeSession);
-            } else {
-                ALOGE("startInput(%d) failed: other input %d already started", input, activeInput);
-                return INVALID_OPERATION;
-            }
-        }
-
-        // Do not allow capture if an active voice call is using a software patch and
-        // the call TX source device is on the same HW module.
-        // FIXME: would be better to refine to only inputs whose profile connects to the
-        // call TX device but this information is not in the audio patch
-        if (mCallTxPatch != 0 &&
-            inputDesc->getModuleHandle() == mCallTxPatch->mPatch.sources[0].ext.device.hw_module) {
-            return INVALID_OPERATION;
-        }
+    if (!isConcurentCaptureAllowed(inputDesc, audioSession)) {
+        ALOGW("startInput(%d) failed: other input already started", input);
+        return INVALID_OPERATION;
     }
 
+    if (isInCall()) {
+        *concurrency |= API_INPUT_CONCURRENCY_CALL;
+    }
+    if (mInputs.activeInputsCount() != 0) {
+        *concurrency |= API_INPUT_CONCURRENCY_CAPTURE;
+    }
+
+    // increment activity count before calling getNewInputDevice() below as only active sessions
+    // are considered for device selection
+    audioSession->changeActiveCount(1);
+
     // Routing?
     mInputRoutes.incRouteActivity(session);
 
-    if (inputDesc->mRefCount == 0 || mInputRoutes.hasRouteChanged(session)) {
-        // if input maps to a dynamic policy with an activity listener, notify of state change
-        if ((inputDesc->mPolicyMix != NULL)
-                && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
-            mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mRegistrationId,
-                    MIX_STATE_MIXING);
-        }
+    if (audioSession->activeCount() == 1 || mInputRoutes.hasRouteChanged(session)) {
 
-        if (mInputs.activeInputsCount() == 0) {
-            SoundTrigger::setCaptureState(true);
-        }
-        setInputDevice(input, getNewInputDevice(input), true /* force */);
+        setInputDevice(input, getNewInputDevice(inputDesc), true /* force */);
 
-        // automatically enable the remote submix output when input is started if not
-        // used by a policy mix of type MIX_TYPE_RECORDERS
-        // For remote submix (a virtual device), we open only one input per capture request.
-        if (audio_is_remote_submix_device(inputDesc->mDevice)) {
-            String8 address = String8("");
-            if (inputDesc->mPolicyMix == NULL) {
-                address = String8("0");
-            } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
-                address = inputDesc->mPolicyMix->mRegistrationId;
+        if (inputDesc->getAudioSessionCount(true/*activeOnly*/) == 1) {
+            // if input maps to a dynamic policy with an activity listener, notify of state change
+            if ((inputDesc->mPolicyMix != NULL)
+                    && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
+                mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mRegistrationId,
+                        MIX_STATE_MIXING);
             }
-            if (address != "") {
-                setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-                        AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
-                        address, "remote-submix");
+
+            if (mInputs.activeInputsCount() == 0) {
+                SoundTrigger::setCaptureState(true);
+            }
+
+            // automatically enable the remote submix output when input is started if not
+            // used by a policy mix of type MIX_TYPE_RECORDERS
+            // For remote submix (a virtual device), we open only one input per capture request.
+            if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+                String8 address = String8("");
+                if (inputDesc->mPolicyMix == NULL) {
+                    address = String8("0");
+                } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
+                    address = inputDesc->mPolicyMix->mRegistrationId;
+                }
+                if (address != "") {
+                    setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+                            AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+                            address, "remote-submix");
+                }
             }
         }
     }
 
-    ALOGV("AudioPolicyManager::startInput() input source = %d", inputDesc->mInputSource);
+    ALOGV("AudioPolicyManager::startInput() input source = %d", audioSession->inputSource());
 
-    inputDesc->mRefCount++;
     return NO_ERROR;
 }
 
@@ -1581,52 +1696,57 @@
     }
     sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
 
-    index = inputDesc->mSessions.indexOf(session);
+    sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
     if (index < 0) {
         ALOGW("stopInput() unknown session %d on input %d", session, input);
         return BAD_VALUE;
     }
 
-    if (inputDesc->mRefCount == 0) {
+    if (audioSession->activeCount() == 0) {
         ALOGW("stopInput() input %d already stopped", input);
         return INVALID_OPERATION;
     }
 
-    inputDesc->mRefCount--;
+    audioSession->changeActiveCount(-1);
 
     // Routing?
     mInputRoutes.decRouteActivity(session);
 
-    if (inputDesc->mRefCount == 0) {
-        // if input maps to a dynamic policy with an activity listener, notify of state change
-        if ((inputDesc->mPolicyMix != NULL)
-                && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
-            mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mRegistrationId,
-                    MIX_STATE_IDLE);
-        }
+    if (audioSession->activeCount() == 0) {
 
-        // automatically disable the remote submix output when input is stopped if not
-        // used by a policy mix of type MIX_TYPE_RECORDERS
-        if (audio_is_remote_submix_device(inputDesc->mDevice)) {
-            String8 address = String8("");
-            if (inputDesc->mPolicyMix == NULL) {
-                address = String8("0");
-            } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
-                address = inputDesc->mPolicyMix->mRegistrationId;
+        if (inputDesc->isActive()) {
+            setInputDevice(input, getNewInputDevice(inputDesc), false /* force */);
+        } else {
+            // if input maps to a dynamic policy with an activity listener, notify of state change
+            if ((inputDesc->mPolicyMix != NULL)
+                    && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
+                mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mRegistrationId,
+                        MIX_STATE_IDLE);
             }
-            if (address != "") {
-                setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-                                         AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
-                                         address, "remote-submix");
+
+            // automatically disable the remote submix output when input is stopped if not
+            // used by a policy mix of type MIX_TYPE_RECORDERS
+            if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+                String8 address = String8("");
+                if (inputDesc->mPolicyMix == NULL) {
+                    address = String8("0");
+                } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
+                    address = inputDesc->mPolicyMix->mRegistrationId;
+                }
+                if (address != "") {
+                    setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+                                             AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+                                             address, "remote-submix");
+                }
             }
-        }
 
-        resetInputDevice(input);
+            resetInputDevice(input);
 
-        if (mInputs.activeInputsCount() == 0) {
-            SoundTrigger::setCaptureState(false);
+            if (mInputs.activeInputsCount() == 0) {
+                SoundTrigger::setCaptureState(false);
+            }
+            inputDesc->clearPreemptedSessions();
         }
-        inputDesc->clearPreemptedSessions();
     }
     return NO_ERROR;
 }
@@ -1634,6 +1754,7 @@
 void AudioPolicyManager::releaseInput(audio_io_handle_t input,
                                       audio_session_t session)
 {
+
     ALOGV("releaseInput() %d", input);
     ssize_t index = mInputs.indexOfKey(input);
     if (index < 0) {
@@ -1647,18 +1768,23 @@
     sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
     ALOG_ASSERT(inputDesc != 0);
 
-    index = inputDesc->mSessions.indexOf(session);
+    sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
     if (index < 0) {
         ALOGW("releaseInput() unknown session %d on input %d", session, input);
         return;
     }
-    inputDesc->mSessions.remove(session);
-    if (inputDesc->mOpenRefCount == 0) {
-        ALOGW("releaseInput() invalid open ref count %d", inputDesc->mOpenRefCount);
+
+    if (audioSession->openCount() == 0) {
+        ALOGW("releaseInput() invalid open count %d on session %d",
+              audioSession->openCount(), session);
         return;
     }
-    inputDesc->mOpenRefCount--;
-    if (inputDesc->mOpenRefCount > 0) {
+
+    if (audioSession->changeOpenCount(-1) == 0) {
+        inputDesc->removeAudioSession(session);
+    }
+
+    if (inputDesc->getOpenRefCount() > 0) {
         ALOGV("releaseInput() exit > 0");
         return;
     }
@@ -1683,6 +1809,7 @@
         mpClientInterface->closeInput(mInputs.keyAt(input_index));
     }
     mInputs.clear();
+    SoundTrigger::setCaptureState(false);
     nextAudioPortGeneration();
 
     if (patchRemoved) {
@@ -1695,10 +1822,9 @@
                                             int indexMax)
 {
     ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
-    mEngine->initStreamVolume(stream, indexMin, indexMax);
-    //FIXME: AUDIO_STREAM_ACCESSIBILITY volume follows AUDIO_STREAM_MUSIC for now
+    mVolumeCurves->initStreamVolume(stream, indexMin, indexMax);
     if (stream == AUDIO_STREAM_MUSIC) {
-        mEngine->initStreamVolume(AUDIO_STREAM_ACCESSIBILITY, indexMin, indexMax);
+        mVolumeCurves->initStreamVolume(AUDIO_STREAM_ACCESSIBILITY, indexMin, indexMax);
     }
 }
 
@@ -1707,8 +1833,8 @@
                                                   audio_devices_t device)
 {
 
-    if ((index < mStreams.valueFor(stream).getVolumeIndexMin()) ||
-            (index > mStreams.valueFor(stream).getVolumeIndexMax())) {
+    if ((index < mVolumeCurves->getVolumeIndexMin(stream)) ||
+            (index > mVolumeCurves->getVolumeIndexMax(stream))) {
         return BAD_VALUE;
     }
     if (!audio_is_output_device(device)) {
@@ -1716,7 +1842,7 @@
     }
 
     // Force max volume if stream cannot be muted
-    if (!mStreams.canBeMuted(stream)) index = mStreams.valueFor(stream).getVolumeIndexMax();
+    if (!mVolumeCurves->canBeMuted(stream)) index = mVolumeCurves->getVolumeIndexMax(stream);
 
     ALOGV("setStreamVolumeIndex() stream %d, device %04x, index %d",
           stream, device, index);
@@ -1724,30 +1850,30 @@
     // if device is AUDIO_DEVICE_OUT_DEFAULT set default value and
     // clear all device specific values
     if (device == AUDIO_DEVICE_OUT_DEFAULT) {
-        mStreams.clearCurrentVolumeIndex(stream);
+        mVolumeCurves->clearCurrentVolumeIndex(stream);
     }
-    mStreams.addCurrentVolumeIndex(stream, device, index);
+    mVolumeCurves->addCurrentVolumeIndex(stream, device, index);
 
     // update volume on all outputs whose current device is also selected by the same
     // strategy as the device specified by the caller
-    audio_devices_t strategyDevice = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
-
+    audio_devices_t selectedDevices = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
+    // it is possible that the requested device is not selected by the strategy (e.g an explicit
+    // audio patch is active causing getDevicesForStream() to return this device. We must make
+    // sure that the device passed is part of the devices considered when applying volume below.
+    selectedDevices |= device;
 
     //FIXME: AUDIO_STREAM_ACCESSIBILITY volume follows AUDIO_STREAM_MUSIC for now
     audio_devices_t accessibilityDevice = AUDIO_DEVICE_NONE;
     if (stream == AUDIO_STREAM_MUSIC) {
-        mStreams.addCurrentVolumeIndex(AUDIO_STREAM_ACCESSIBILITY, device, index);
+        mVolumeCurves->addCurrentVolumeIndex(AUDIO_STREAM_ACCESSIBILITY, device, index);
         accessibilityDevice = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, true /*fromCache*/);
     }
-    if ((device != AUDIO_DEVICE_OUT_DEFAULT) &&
-            (device & (strategyDevice | accessibilityDevice)) == 0) {
-        return NO_ERROR;
-    }
+
     status_t status = NO_ERROR;
     for (size_t i = 0; i < mOutputs.size(); i++) {
         sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
         audio_devices_t curDevice = Volume::getDeviceForVolume(desc->device());
-        if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & strategyDevice) != 0)) {
+        if ((device == AUDIO_DEVICE_OUT_DEFAULT) || ((curDevice & selectedDevices) != 0)) {
             status_t volStatus = checkAndSetVolume(stream, index, desc, curDevice);
             if (volStatus != NO_ERROR) {
                 status = volStatus;
@@ -1780,7 +1906,7 @@
     }
     device = Volume::getDeviceForVolume(device);
 
-    *index =  mStreams.valueFor(stream).getVolumeIndex(device);
+    *index =  mVolumeCurves->getVolumeIndex(stream, device);
     ALOGV("getStreamVolumeIndex() stream %d device %08x index %d", stream, device, *index);
     return NO_ERROR;
 }
@@ -1872,23 +1998,9 @@
 {
     for (size_t i = 0; i < mInputs.size(); i++) {
         const sp<AudioInputDescriptor>  inputDescriptor = mInputs.valueAt(i);
-        if (inputDescriptor->mRefCount == 0) {
-            continue;
-        }
-        if (inputDescriptor->mInputSource == (int)source) {
+        if (inputDescriptor->isSourceActive(source)) {
             return true;
         }
-        // AUDIO_SOURCE_HOTWORD is equivalent to AUDIO_SOURCE_VOICE_RECOGNITION only if it
-        // corresponds to an active capture triggered by a hardware hotword recognition
-        if ((source == AUDIO_SOURCE_VOICE_RECOGNITION) &&
-                 (inputDescriptor->mInputSource == AUDIO_SOURCE_HOTWORD)) {
-            // FIXME: we should not assume that the first session is the active one and keep
-            // activity count per session. Same in startInput().
-            ssize_t index = mSoundTriggerSessions.indexOfKey(inputDescriptor->mSessions.itemAt(0));
-            if (index >= 0) {
-                return true;
-            }
-        }
     }
     return false;
 }
@@ -1931,7 +2043,7 @@
         return INVALID_OPERATION;
     }
 
-    ALOGV("registerPolicyMixes() num mixes %d", mixes.size());
+    ALOGV("registerPolicyMixes() num mixes %zu", mixes.size());
 
     for (size_t i = 0; i < mixes.size(); i++) {
         String8 address = mixes[i].mRegistrationId;
@@ -1978,7 +2090,7 @@
         return INVALID_OPERATION;
     }
 
-    ALOGV("unregisterPolicyMixes() num mixes %d", mixes.size());
+    ALOGV("unregisterPolicyMixes() num mixes %zu", mixes.size());
 
     for (size_t i = 0; i < mixes.size(); i++) {
         String8 address = mixes[i].mRegistrationId;
@@ -2039,15 +2151,17 @@
     result.append(buffer);
     snprintf(buffer, SIZE, " TTS output %s\n", mTtsOutputAvailable ? "available" : "not available");
     result.append(buffer);
+    snprintf(buffer, SIZE, " Master mono: %s\n", mMasterMono ? "on" : "off");
+    result.append(buffer);
 
     write(fd, result.string(), result.size());
 
-    mAvailableOutputDevices.dump(fd, String8("output"));
-    mAvailableInputDevices.dump(fd, String8("input"));
+    mAvailableOutputDevices.dump(fd, String8("Available output"));
+    mAvailableInputDevices.dump(fd, String8("Available input"));
     mHwModules.dump(fd);
     mOutputs.dump(fd);
     mInputs.dump(fd);
-    mStreams.dump(fd);
+    mVolumeCurves->dump(fd);
     mEffects.dump(fd);
     mAudioPatches.dump(fd);
 
@@ -2066,6 +2180,10 @@
      offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
      offloadInfo.has_video);
 
+    if (mMasterMono) {
+        return false; // no offloading if mono is set.
+    }
+
     // Check if offload has been disabled
     char propValue[PROPERTY_VALUE_MAX];
     if (property_get("audio.offload.disable", propValue, "0")) {
@@ -2223,7 +2341,7 @@
                                                            patch->sources[0].type);
 #if LOG_NDEBUG == 0
     for (size_t i = 0; i < patch->num_sinks; i++) {
-        ALOGV("createAudioPatch sink %d: id %d role %d type %d", i, patch->sinks[i].id,
+        ALOGV("createAudioPatch sink %zu: id %d role %d type %d", i, patch->sinks[i].id,
                                                              patch->sinks[i].role,
                                                              patch->sinks[i].type);
     }
@@ -2391,8 +2509,8 @@
                 // create a software bridge in PatchPanel if:
                 // - source and sink devices are on differnt HW modules OR
                 // - audio HAL version is < 3.0
-                if ((srcDeviceDesc->getModuleHandle() != sinkDeviceDesc->getModuleHandle()) ||
-                        (srcDeviceDesc->mModule->mHalVersion < AUDIO_DEVICE_API_VERSION_3_0)) {
+                if (!srcDeviceDesc->hasSameHwModuleAs(sinkDeviceDesc) ||
+                        (srcDeviceDesc->mModule->getHalVersion() < AUDIO_DEVICE_API_VERSION_3_0)) {
                     // support only one sink device for now to simplify output selection logic
                     if (patch->num_sinks > 1) {
                         return INVALID_OPERATION;
@@ -2491,7 +2609,7 @@
                 return BAD_VALUE;
             }
             setInputDevice(inputDesc->mIoHandle,
-                           getNewInputDevice(inputDesc->mIoHandle),
+                           getNewInputDevice(inputDesc),
                            true,
                            NULL);
         } else if (patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) {
@@ -2588,6 +2706,7 @@
 
 void AudioPolicyManager::releaseResourcesForUid(uid_t uid)
 {
+    clearAudioSources(uid);
     clearAudioPatches(uid);
     clearSessionRoutes(uid);
 }
@@ -2602,7 +2721,6 @@
     }
 }
 
-
 void AudioPolicyManager::checkStrategyRoute(routing_strategy strategy,
                                             audio_io_handle_t ouptutToSkip)
 {
@@ -2668,7 +2786,7 @@
     SortedVector<audio_io_handle_t> inputsToClose;
     for (size_t i = 0; i < mInputs.size(); i++) {
         sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(i);
-        if (affectedSources.indexOf(inputDesc->mInputSource) >= 0) {
+        if (affectedSources.indexOf(inputDesc->inputSource()) >= 0) {
             inputsToClose.add(inputDesc->mIoHandle);
         }
     }
@@ -2677,6 +2795,15 @@
     }
 }
 
+void AudioPolicyManager::clearAudioSources(uid_t uid)
+{
+    for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--)  {
+        sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
+        if (sourceDesc->mUid == uid) {
+            stopAudioSource(mAudioSources.keyAt(i));
+        }
+    }
+}
 
 status_t AudioPolicyManager::acquireSoundTriggerSession(audio_session_t *session,
                                        audio_io_handle_t *ioHandle,
@@ -2689,16 +2816,219 @@
     return mSoundTriggerSessions.acquireSession(*session, *ioHandle);
 }
 
-status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source __unused,
-                                       const audio_attributes_t *attributes __unused,
-                                       audio_io_handle_t *handle __unused)
+status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source,
+                                  const audio_attributes_t *attributes,
+                                  audio_io_handle_t *handle,
+                                  uid_t uid)
 {
-    return INVALID_OPERATION;
+    ALOGV("%s source %p attributes %p handle %p", __FUNCTION__, source, attributes, handle);
+    if (source == NULL || attributes == NULL || handle == NULL) {
+        return BAD_VALUE;
+    }
+
+    *handle = AUDIO_IO_HANDLE_NONE;
+
+    if (source->role != AUDIO_PORT_ROLE_SOURCE ||
+            source->type != AUDIO_PORT_TYPE_DEVICE) {
+        ALOGV("%s INVALID_OPERATION source->role %d source->type %d", __FUNCTION__, source->role, source->type);
+        return INVALID_OPERATION;
+    }
+
+    sp<DeviceDescriptor> srcDeviceDesc =
+            mAvailableInputDevices.getDevice(source->ext.device.type,
+                                              String8(source->ext.device.address));
+    if (srcDeviceDesc == 0) {
+        ALOGV("%s source->ext.device.type %08x not found", __FUNCTION__, source->ext.device.type);
+        return BAD_VALUE;
+    }
+    sp<AudioSourceDescriptor> sourceDesc =
+            new AudioSourceDescriptor(srcDeviceDesc, attributes, uid);
+
+    struct audio_patch dummyPatch;
+    sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
+    sourceDesc->mPatchDesc = patchDesc;
+
+    status_t status = connectAudioSource(sourceDesc);
+    if (status == NO_ERROR) {
+        mAudioSources.add(sourceDesc->getHandle(), sourceDesc);
+        *handle = sourceDesc->getHandle();
+    }
+    return status;
+}
+
+status_t AudioPolicyManager::connectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
+{
+    ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
+
+    // make sure we only have one patch per source.
+    disconnectAudioSource(sourceDesc);
+
+    routing_strategy strategy = (routing_strategy) getStrategyForAttr(&sourceDesc->mAttributes);
+    audio_stream_type_t stream = audio_attributes_to_stream_type(&sourceDesc->mAttributes);
+    sp<DeviceDescriptor> srcDeviceDesc = sourceDesc->mDevice;
+
+    audio_devices_t sinkDevice = getDeviceForStrategy(strategy, true);
+    sp<DeviceDescriptor> sinkDeviceDesc =
+            mAvailableOutputDevices.getDevice(sinkDevice, String8(""));
+
+    audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+    struct audio_patch *patch = &sourceDesc->mPatchDesc->mPatch;
+
+    if (srcDeviceDesc->getAudioPort()->mModule->getHandle() ==
+            sinkDeviceDesc->getAudioPort()->mModule->getHandle() &&
+            srcDeviceDesc->getAudioPort()->mModule->getHalVersion() >= AUDIO_DEVICE_API_VERSION_3_0 &&
+            srcDeviceDesc->getAudioPort()->mGains.size() > 0) {
+        ALOGV("%s AUDIO_DEVICE_API_VERSION_3_0", __FUNCTION__);
+        //   create patch between src device and output device
+        //   create Hwoutput and add to mHwOutputs
+    } else {
+        SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(sinkDevice, mOutputs);
+        audio_io_handle_t output =
+                selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID);
+        if (output == AUDIO_IO_HANDLE_NONE) {
+            ALOGV("%s no output for device %08x", __FUNCTION__, sinkDevice);
+            return INVALID_OPERATION;
+        }
+        sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
+        if (outputDesc->isDuplicated()) {
+            ALOGV("%s output for device %08x is duplicated", __FUNCTION__, sinkDevice);
+            return INVALID_OPERATION;
+        }
+        // create a special patch with no sink and two sources:
+        // - the second source indicates to PatchPanel through which output mix this patch should
+        // be connected as well as the stream type for volume control
+        // - the sink is defined by whatever output device is currently selected for the output
+        // though which this patch is routed.
+        patch->num_sinks = 0;
+        patch->num_sources = 2;
+        srcDeviceDesc->toAudioPortConfig(&patch->sources[0], NULL);
+        outputDesc->toAudioPortConfig(&patch->sources[1], NULL);
+        patch->sources[1].ext.mix.usecase.stream = stream;
+        status_t status = mpClientInterface->createAudioPatch(patch,
+                                                              &afPatchHandle,
+                                                              0);
+        ALOGV("%s patch panel returned %d patchHandle %d", __FUNCTION__,
+                                                              status, afPatchHandle);
+        if (status != NO_ERROR) {
+            ALOGW("%s patch panel could not connect device patch, error %d",
+                  __FUNCTION__, status);
+            return INVALID_OPERATION;
+        }
+        uint32_t delayMs = 0;
+        status = startSource(outputDesc, stream, sinkDevice, &delayMs);
+
+        if (status != NO_ERROR) {
+            mpClientInterface->releaseAudioPatch(sourceDesc->mPatchDesc->mAfPatchHandle, 0);
+            return status;
+        }
+        sourceDesc->mSwOutput = outputDesc;
+        if (delayMs != 0) {
+            usleep(delayMs * 1000);
+        }
+    }
+
+    sourceDesc->mPatchDesc->mAfPatchHandle = afPatchHandle;
+    addAudioPatch(sourceDesc->mPatchDesc->mHandle, sourceDesc->mPatchDesc);
+
+    return NO_ERROR;
 }
 
 status_t AudioPolicyManager::stopAudioSource(audio_io_handle_t handle __unused)
 {
-    return INVALID_OPERATION;
+    sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueFor(handle);
+    ALOGV("%s handle %d", __FUNCTION__, handle);
+    if (sourceDesc == 0) {
+        ALOGW("%s unknown source for handle %d", __FUNCTION__, handle);
+        return BAD_VALUE;
+    }
+    status_t status = disconnectAudioSource(sourceDesc);
+
+    mAudioSources.removeItem(handle);
+    return status;
+}
+
+status_t AudioPolicyManager::setMasterMono(bool mono)
+{
+    if (mMasterMono == mono) {
+        return NO_ERROR;
+    }
+    mMasterMono = mono;
+    // if enabling mono we close all offloaded devices, which will invalidate the
+    // corresponding AudioTrack. The AudioTrack client/MediaPlayer is responsible
+    // for recreating the new AudioTrack as non-offloaded PCM.
+    //
+    // If disabling mono, we leave all tracks as is: we don't know which clients
+    // and tracks are able to be recreated as offloaded. The next "song" should
+    // play back offloaded.
+    if (mMasterMono) {
+        Vector<audio_io_handle_t> offloaded;
+        for (size_t i = 0; i < mOutputs.size(); ++i) {
+            sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+            if (desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+                offloaded.push(desc->mIoHandle);
+            }
+        }
+        for (size_t i = 0; i < offloaded.size(); ++i) {
+            closeOutput(offloaded[i]);
+        }
+    }
+    // update master mono for all remaining outputs
+    for (size_t i = 0; i < mOutputs.size(); ++i) {
+        updateMono(mOutputs.keyAt(i));
+    }
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getMasterMono(bool *mono)
+{
+    *mono = mMasterMono;
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
+{
+    ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
+
+    sp<AudioPatch> patchDesc = mAudioPatches.valueFor(sourceDesc->mPatchDesc->mHandle);
+    if (patchDesc == 0) {
+        ALOGW("%s source has no patch with handle %d", __FUNCTION__,
+              sourceDesc->mPatchDesc->mHandle);
+        return BAD_VALUE;
+    }
+    removeAudioPatch(sourceDesc->mPatchDesc->mHandle);
+
+    audio_stream_type_t stream = audio_attributes_to_stream_type(&sourceDesc->mAttributes);
+    sp<SwAudioOutputDescriptor> swOutputDesc = sourceDesc->mSwOutput.promote();
+    if (swOutputDesc != 0) {
+        stopSource(swOutputDesc, stream, false);
+        mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+    } else {
+        sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->mHwOutput.promote();
+        if (hwOutputDesc != 0) {
+          //   release patch between src device and output device
+          //   close Hwoutput and remove from mHwOutputs
+        } else {
+            ALOGW("%s source has neither SW nor HW output", __FUNCTION__);
+        }
+    }
+    return NO_ERROR;
+}
+
+sp<AudioSourceDescriptor> AudioPolicyManager::getSourceForStrategyOnOutput(
+        audio_io_handle_t output, routing_strategy strategy)
+{
+    sp<AudioSourceDescriptor> source;
+    for (size_t i = 0; i < mAudioSources.size(); i++)  {
+        sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
+        routing_strategy sourceStrategy =
+                (routing_strategy) getStrategyForAttr(&sourceDesc->mAttributes);
+        sp<SwAudioOutputDescriptor> outputDesc = sourceDesc->mSwOutput.promote();
+        if (sourceStrategy == strategy && outputDesc != 0 && outputDesc->mIoHandle == output) {
+            source = sourceDesc;
+            break;
+        }
+    }
+    return source;
 }
 
 // ----------------------------------------------------------------------------
@@ -2716,13 +3046,42 @@
 #endif //AUDIO_POLICY_TEST
     mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
     mA2dpSuspended(false),
-    mSpeakerDrcEnabled(false),
     mAudioPortGeneration(1),
     mBeaconMuteRefCount(0),
     mBeaconPlayingRefCount(0),
     mBeaconMuted(false),
-    mTtsOutputAvailable(false)
+    mTtsOutputAvailable(false),
+    mMasterMono(false)
 {
+    mUidCached = getuid();
+    mpClientInterface = clientInterface;
+
+    // TODO: remove when legacy conf file is removed. true on devices that use DRC on the
+    // DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
+    // Note: remove also speaker_drc_enabled from global configuration of XML config file.
+    bool speakerDrcEnabled = false;
+
+#ifdef USE_XML_AUDIO_POLICY_CONF
+    mVolumeCurves = new VolumeCurvesCollection();
+    AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
+                             mDefaultOutputDevice, speakerDrcEnabled,
+                             static_cast<VolumeCurvesCollection *>(mVolumeCurves));
+    PolicySerializer serializer;
+    if (serializer.deserialize(AUDIO_POLICY_XML_CONFIG_FILE, config) != NO_ERROR) {
+#else
+    mVolumeCurves = new StreamDescriptorCollection();
+    AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
+                             mDefaultOutputDevice, speakerDrcEnabled);
+    if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, config) != NO_ERROR) &&
+            (ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, config) != NO_ERROR)) {
+#endif
+        ALOGE("could not load audio policy configuration file, setting defaults");
+        config.setDefault();
+    }
+    // must be done after reading the policy (since conditionned by Speaker Drc Enabling)
+    mVolumeCurves->initializeVolumeCurves(speakerDrcEnabled);
+
+    // Once policy config has been parsed, retrieve an instance of the engine and initialize it.
     audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance();
     if (!engineInstance) {
         ALOGE("%s:  Could not get an instance of policy engine", __FUNCTION__);
@@ -2738,32 +3097,14 @@
     status_t status = mEngine->initCheck();
     ALOG_ASSERT(status == NO_ERROR, "Policy engine not initialized(err=%d)", status);
 
-    mUidCached = getuid();
-    mpClientInterface = clientInterface;
-
-    mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
-    if (ConfigParsingUtils::loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE,
-                 mHwModules, mAvailableInputDevices, mAvailableOutputDevices,
-                 mDefaultOutputDevice, mSpeakerDrcEnabled) != NO_ERROR) {
-        if (ConfigParsingUtils::loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE,
-                                  mHwModules, mAvailableInputDevices, mAvailableOutputDevices,
-                                  mDefaultOutputDevice, mSpeakerDrcEnabled) != NO_ERROR) {
-            ALOGE("could not load audio policy configuration file, setting defaults");
-            defaultAudioPolicyConfig();
-        }
-    }
     // mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices
-
-    // must be done after reading the policy (since conditionned by Speaker Drc Enabling)
-    mEngine->initializeVolumeCurves(mSpeakerDrcEnabled);
-
     // open all output streams needed to access attached devices
     audio_devices_t outputDeviceTypes = mAvailableOutputDevices.types();
     audio_devices_t inputDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
     for (size_t i = 0; i < mHwModules.size(); i++) {
-        mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);
+        mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->getName());
         if (mHwModules[i]->mHandle == 0) {
-            ALOGW("could not open HW module %s", mHwModules[i]->mName);
+            ALOGW("could not open HW module %s", mHwModules[i]->getName());
             continue;
         }
         // open all output streams needed to access attached devices
@@ -2774,29 +3115,24 @@
         {
             const sp<IOProfile> outProfile = mHwModules[i]->mOutputProfiles[j];
 
-            if (outProfile->mSupportedDevices.isEmpty()) {
-                ALOGW("Output profile contains no device on module %s", mHwModules[i]->mName);
+            if (!outProfile->hasSupportedDevices()) {
+                ALOGW("Output profile contains no device on module %s", mHwModules[i]->getName());
                 continue;
             }
-            if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_TTS) != 0) {
+            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0) {
                 mTtsOutputAvailable = true;
             }
 
-            if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
+            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
                 continue;
             }
-            audio_devices_t profileType = outProfile->mSupportedDevices.types();
+            audio_devices_t profileType = outProfile->getSupportedDevicesType();
             if ((profileType & mDefaultOutputDevice->type()) != AUDIO_DEVICE_NONE) {
                 profileType = mDefaultOutputDevice->type();
             } else {
-                // chose first device present in mSupportedDevices also part of
+                // chose first device present in profile's SupportedDevices also part of
                 // outputDeviceTypes
-                for (size_t k = 0; k  < outProfile->mSupportedDevices.size(); k++) {
-                    profileType = outProfile->mSupportedDevices[k]->type();
-                    if ((profileType & outputDeviceTypes) != 0) {
-                        break;
-                    }
-                }
+                profileType = outProfile->getSupportedDeviceForType(outputDeviceTypes);
             }
             if ((profileType & outputDeviceTypes) == 0) {
                 continue;
@@ -2821,23 +3157,22 @@
             if (status != NO_ERROR) {
                 ALOGW("Cannot open output stream for device %08x on hw module %s",
                       outputDesc->mDevice,
-                      mHwModules[i]->mName);
+                      mHwModules[i]->getName());
             } else {
                 outputDesc->mSamplingRate = config.sample_rate;
                 outputDesc->mChannelMask = config.channel_mask;
                 outputDesc->mFormat = config.format;
 
-                for (size_t k = 0; k  < outProfile->mSupportedDevices.size(); k++) {
-                    audio_devices_t type = outProfile->mSupportedDevices[k]->type();
-                    ssize_t index =
-                            mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[k]);
+                const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
+                for (size_t k = 0; k  < supportedDevices.size(); k++) {
+                    ssize_t index = mAvailableOutputDevices.indexOf(supportedDevices[k]);
                     // give a valid ID to an attached device once confirmed it is reachable
                     if (index >= 0 && !mAvailableOutputDevices[index]->isAttached()) {
                         mAvailableOutputDevices[index]->attach(mHwModules[i]);
                     }
                 }
                 if (mPrimaryOutput == 0 &&
-                        outProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+                        outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
                     mPrimaryOutput = outputDesc;
                 }
                 addOutput(output, outputDesc);
@@ -2852,25 +3187,20 @@
         {
             const sp<IOProfile> inProfile = mHwModules[i]->mInputProfiles[j];
 
-            if (inProfile->mSupportedDevices.isEmpty()) {
-                ALOGW("Input profile contains no device on module %s", mHwModules[i]->mName);
+            if (!inProfile->hasSupportedDevices()) {
+                ALOGW("Input profile contains no device on module %s", mHwModules[i]->getName());
                 continue;
             }
-            // chose first device present in mSupportedDevices also part of
+            // chose first device present in profile's SupportedDevices also part of
             // inputDeviceTypes
-            audio_devices_t profileType = AUDIO_DEVICE_NONE;
-            for (size_t k = 0; k  < inProfile->mSupportedDevices.size(); k++) {
-                profileType = inProfile->mSupportedDevices[k]->type();
-                if (profileType & inputDeviceTypes) {
-                    break;
-                }
-            }
+            audio_devices_t profileType = inProfile->getSupportedDeviceForType(inputDeviceTypes);
+
             if ((profileType & inputDeviceTypes) == 0) {
                 continue;
             }
-            sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(inProfile);
+            sp<AudioInputDescriptor> inputDesc =
+                    new AudioInputDescriptor(inProfile);
 
-            inputDesc->mInputSource = AUDIO_SOURCE_MIC;
             inputDesc->mDevice = profileType;
 
             // find the address
@@ -2895,10 +3225,9 @@
                                                            AUDIO_INPUT_FLAG_NONE);
 
             if (status == NO_ERROR) {
-                for (size_t k = 0; k  < inProfile->mSupportedDevices.size(); k++) {
-                    audio_devices_t type = inProfile->mSupportedDevices[k]->type();
-                    ssize_t index =
-                            mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]);
+                const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
+                for (size_t k = 0; k  < supportedDevices.size(); k++) {
+                    ssize_t index =  mAvailableInputDevices.indexOf(supportedDevices[k]);
                     // give a valid ID to an attached device once confirmed it is reachable
                     if (index >= 0) {
                         sp<DeviceDescriptor> devDesc = mAvailableInputDevices[index];
@@ -2912,14 +3241,14 @@
             } else {
                 ALOGW("Cannot open input stream for device %08x on hw module %s",
                       inputDesc->mDevice,
-                      mHwModules[i]->mName);
+                      mHwModules[i]->getName());
             }
         }
     }
     // make sure all attached devices have been allocated a unique ID
     for (size_t i = 0; i  < mAvailableOutputDevices.size();) {
         if (!mAvailableOutputDevices[i]->isAttached()) {
-            ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->type());
+            ALOGW("Output device %08x unreachable", mAvailableOutputDevices[i]->type());
             mAvailableOutputDevices.remove(mAvailableOutputDevices[i]);
             continue;
         }
@@ -2940,7 +3269,7 @@
         i++;
     }
     // make sure default device is reachable
-    if (mAvailableOutputDevices.indexOf(mDefaultOutputDevice) < 0) {
+    if (mDefaultOutputDevice == 0 || mAvailableOutputDevices.indexOf(mDefaultOutputDevice) < 0) {
         ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->type());
     }
 
@@ -3160,6 +3489,7 @@
 {
     outputDesc->setIoHandle(output);
     mOutputs.add(output, outputDesc);
+    updateMono(output); // update mono status when adding to output list
     nextAudioPortGeneration();
 }
 
@@ -3180,7 +3510,7 @@
         const String8 address /*in*/,
         SortedVector<audio_io_handle_t>& outputs /*out*/) {
     sp<DeviceDescriptor> devDesc =
-        desc->mProfile->mSupportedDevices.getDevice(device, address);
+        desc->mProfile->getSupportedDeviceByAddress(device, address);
     if (devDesc != 0) {
         ALOGV("findIoHandlesByAddress(): adding opened output %d on same address %s",
               desc->mIoHandle, address.string());
@@ -3198,7 +3528,7 @@
 
     if (audio_device_is_digital(device)) {
         // erase all current sample rates, formats and channel masks
-        devDesc->clearCapabilities();
+        devDesc->clearAudioProfiles();
     }
 
     if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
@@ -3225,9 +3555,9 @@
             for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
             {
                 sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
-                if (profile->mSupportedDevices.types() & device) {
+                if (profile->supportDevice(device)) {
                     if (!device_distinguishes_on_address(device) ||
-                            address == profile->mSupportedDevices[0]->mAddress) {
+                            profile->supportDeviceAddress(address)) {
                         profiles.add(profile);
                         ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i);
                     }
@@ -3235,7 +3565,7 @@
             }
         }
 
-        ALOGV("  found %d profiles, %d outputs", profiles.size(), outputs.size());
+        ALOGV("  found %zu profiles, %zu outputs", profiles.size(), outputs.size());
 
         if (profiles.isEmpty() && outputs.isEmpty()) {
             ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
@@ -3294,55 +3624,14 @@
                     mpClientInterface->setParameters(output, String8(param));
                     free(param);
                 }
-
-                // Here is where we step through and resolve any "dynamic" fields
-                String8 reply;
-                char *value;
-                if (profile->mSamplingRates[0] == 0) {
-                    reply = mpClientInterface->getParameters(output,
-                                            String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
-                    ALOGV("checkOutputsForDevice() supported sampling rates %s",
-                              reply.string());
-                    value = strpbrk((char *)reply.string(), "=");
-                    if (value != NULL) {
-                        profile->loadSamplingRates(value + 1);
-                    }
-                }
-                if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
-                    reply = mpClientInterface->getParameters(output,
-                                                   String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
-                    ALOGV("checkOutputsForDevice() supported formats %s",
-                              reply.string());
-                    value = strpbrk((char *)reply.string(), "=");
-                    if (value != NULL) {
-                        profile->loadFormats(value + 1);
-                    }
-                }
-                if (profile->mChannelMasks[0] == 0) {
-                    reply = mpClientInterface->getParameters(output,
-                                                  String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
-                    ALOGV("checkOutputsForDevice() supported channel masks %s",
-                              reply.string());
-                    value = strpbrk((char *)reply.string(), "=");
-                    if (value != NULL) {
-                        profile->loadOutChannels(value + 1);
-                    }
-                }
-                if (((profile->mSamplingRates[0] == 0) &&
-                         (profile->mSamplingRates.size() < 2)) ||
-                     ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) &&
-                         (profile->mFormats.size() < 2)) ||
-                     ((profile->mChannelMasks[0] == 0) &&
-                         (profile->mChannelMasks.size() < 2))) {
+                updateAudioProfiles(output, profile->getAudioProfiles());
+                if (!profile->hasValidAudioProfile()) {
                     ALOGW("checkOutputsForDevice() missing param");
                     mpClientInterface->closeOutput(output);
                     output = AUDIO_IO_HANDLE_NONE;
-                } else if (profile->mSamplingRates[0] == 0 || profile->mFormats[0] == 0 ||
-                            profile->mChannelMasks[0] == 0) {
+                } else if (profile->hasDynamicAudioProfile()) {
                     mpClientInterface->closeOutput(output);
-                    config.sample_rate = profile->pickSamplingRate();
-                    config.channel_mask = profile->pickChannelMask();
-                    config.format = profile->pickFormat();
+                    profile->pickAudioProfile(config.sample_rate, config.channel_mask, config.format);
                     config.offload_info.sample_rate = config.sample_rate;
                     config.offload_info.channel_mask = config.channel_mask;
                     config.offload_info.format = config.format;
@@ -3463,21 +3752,10 @@
             for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
             {
                 sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
-                if (profile->mSupportedDevices.types() & device) {
+                if (profile->supportDevice(device)) {
                     ALOGV("checkOutputsForDevice(): "
                             "clearing direct output profile %zu on module %zu", j, i);
-                    if (profile->mSamplingRates[0] == 0) {
-                        profile->mSamplingRates.clear();
-                        profile->mSamplingRates.add(0);
-                    }
-                    if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
-                        profile->mFormats.clear();
-                        profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
-                    }
-                    if (profile->mChannelMasks[0] == 0) {
-                        profile->mChannelMasks.clear();
-                        profile->mChannelMasks.add(0);
-                    }
+                    profile->clearAudioProfiles();
                 }
             }
         }
@@ -3495,14 +3773,14 @@
 
     if (audio_device_is_digital(device)) {
         // erase all current sample rates, formats and channel masks
-        devDesc->clearCapabilities();
+        devDesc->clearAudioProfiles();
     }
 
     if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
         // first list already open inputs that can be routed to this device
         for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
             desc = mInputs.valueAt(input_index);
-            if (desc->mProfile->mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN)) {
+            if (desc->mProfile->supportDevice(device)) {
                 ALOGV("checkInputsForDevice(): adding opened input %d", mInputs.keyAt(input_index));
                inputs.add(mInputs.keyAt(input_index));
             }
@@ -3521,9 +3799,9 @@
             {
                 sp<IOProfile> profile = mHwModules[module_idx]->mInputProfiles[profile_index];
 
-                if (profile->mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN)) {
+                if (profile->supportDevice(device)) {
                     if (!device_distinguishes_on_address(device) ||
-                            address == profile->mSupportedDevices[0]->mAddress) {
+                            profile->supportDeviceAddress(address)) {
                         profiles.add(profile);
                         ALOGV("checkInputsForDevice(): adding profile %zu from module %zu",
                               profile_index, module_idx);
@@ -3583,42 +3861,8 @@
                     mpClientInterface->setParameters(input, String8(param));
                     free(param);
                 }
-
-                // Here is where we step through and resolve any "dynamic" fields
-                String8 reply;
-                char *value;
-                if (profile->mSamplingRates[0] == 0) {
-                    reply = mpClientInterface->getParameters(input,
-                                            String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
-                    ALOGV("checkInputsForDevice() direct input sup sampling rates %s",
-                              reply.string());
-                    value = strpbrk((char *)reply.string(), "=");
-                    if (value != NULL) {
-                        profile->loadSamplingRates(value + 1);
-                    }
-                }
-                if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
-                    reply = mpClientInterface->getParameters(input,
-                                                   String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
-                    ALOGV("checkInputsForDevice() direct input sup formats %s", reply.string());
-                    value = strpbrk((char *)reply.string(), "=");
-                    if (value != NULL) {
-                        profile->loadFormats(value + 1);
-                    }
-                }
-                if (profile->mChannelMasks[0] == 0) {
-                    reply = mpClientInterface->getParameters(input,
-                                                  String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
-                    ALOGV("checkInputsForDevice() direct input sup channel masks %s",
-                              reply.string());
-                    value = strpbrk((char *)reply.string(), "=");
-                    if (value != NULL) {
-                        profile->loadInChannels(value + 1);
-                    }
-                }
-                if (((profile->mSamplingRates[0] == 0) && (profile->mSamplingRates.size() < 2)) ||
-                     ((profile->mFormats[0] == 0) && (profile->mFormats.size() < 2)) ||
-                     ((profile->mChannelMasks[0] == 0) && (profile->mChannelMasks.size() < 2))) {
+                updateAudioProfiles(input, profile->getAudioProfiles());
+                if (!profile->hasValidAudioProfile()) {
                     ALOGW("checkInputsForDevice() direct input missing param");
                     mpClientInterface->closeInput(input);
                     input = AUDIO_IO_HANDLE_NONE;
@@ -3651,8 +3895,7 @@
         // check if one opened input is not needed any more after disconnecting one device
         for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
             desc = mInputs.valueAt(input_index);
-            if (!(desc->mProfile->mSupportedDevices.types() & mAvailableInputDevices.types() &
-                    ~AUDIO_DEVICE_BIT_IN)) {
+            if (!(desc->mProfile->supportDevice(mAvailableInputDevices.types()))) {
                 ALOGV("checkInputsForDevice(): disconnecting adding input %d",
                       mInputs.keyAt(input_index));
                 inputs.add(mInputs.keyAt(input_index));
@@ -3667,21 +3910,10 @@
                  profile_index < mHwModules[module_index]->mInputProfiles.size();
                  profile_index++) {
                 sp<IOProfile> profile = mHwModules[module_index]->mInputProfiles[profile_index];
-                if (profile->mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN)) {
+                if (profile->supportDevice(device)) {
                     ALOGV("checkInputsForDevice(): clearing direct input profile %zu on module %zu",
                           profile_index, module_index);
-                    if (profile->mSamplingRates[0] == 0) {
-                        profile->mSamplingRates.clear();
-                        profile->mSamplingRates.add(0);
-                    }
-                    if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
-                        profile->mFormats.clear();
-                        profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
-                    }
-                    if (profile->mChannelMasks[0] == 0) {
-                        profile->mChannelMasks.clear();
-                        profile->mChannelMasks.add(0);
-                    }
+                    profile->clearAudioProfiles();
                 }
             }
         }
@@ -3841,6 +4073,11 @@
                 setStrategyMute(strategy, true, desc);
                 setStrategyMute(strategy, false, desc, MUTE_TIME_MS, newDevice);
             }
+            sp<AudioSourceDescriptor> source =
+                    getSourceForStrategyOnOutput(srcOutputs[i], strategy);
+            if (source != 0){
+                connectAudioSource(source);
+            }
         }
 
         // Move effects associated to this strategy from previous output to new output
@@ -3998,9 +4235,9 @@
     return device;
 }
 
-audio_devices_t AudioPolicyManager::getNewInputDevice(audio_io_handle_t input)
+audio_devices_t AudioPolicyManager::getNewInputDevice(const sp<AudioInputDescriptor>& inputDesc)
 {
-    sp<AudioInputDescriptor> inputDesc = mInputs.valueFor(input);
+    audio_devices_t device = AUDIO_DEVICE_NONE;
 
     ssize_t index = mAudioPatches.indexOfKey(inputDesc->mPatchHandle);
     if (index >= 0) {
@@ -4012,7 +4249,12 @@
         }
     }
 
-    audio_devices_t device = getDeviceAndMixForInputSource(inputDesc->mInputSource);
+    audio_source_t source = inputDesc->getHighestPrioritySource(true /*activeOnly*/);
+    if (isInCall()) {
+        device = getDeviceAndMixForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
+    } else if (source != AUDIO_SOURCE_DEFAULT) {
+        device = getDeviceAndMixForInputSource(source);
+    }
 
     return device;
 }
@@ -4046,7 +4288,6 @@
         devices |= AUDIO_DEVICE_OUT_SPEAKER;
         devices &= ~AUDIO_DEVICE_OUT_SPEAKER_SAFE;
     }
-
     return devices;
 }
 
@@ -4352,7 +4593,6 @@
                     patchDesc->mPatch = patch;
                 }
                 patchDesc->mAfPatchHandle = afPatchHandle;
-                patchDesc->mUid = mUidCached;
                 if (patchHandle) {
                     *patchHandle = patchDesc->mHandle;
                 }
@@ -4424,7 +4664,7 @@
             // AUDIO_SOURCE_HOTWORD is for internal use only:
             // handled as AUDIO_SOURCE_VOICE_RECOGNITION by the audio HAL
             if (patch.sinks[0].ext.mix.usecase.source == AUDIO_SOURCE_HOTWORD &&
-                    !inputDesc->mIsSoundTrigger) {
+                    !inputDesc->isSoundTrigger()) {
                 patch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_VOICE_RECOGNITION;
             }
             patch.num_sinks = 1;
@@ -4457,7 +4697,6 @@
                     patchDesc->mPatch = patch;
                 }
                 patchDesc->mAfPatchHandle = afPatchHandle;
-                patchDesc->mUid = mUidCached;
                 if (patchHandle) {
                     *patchHandle = patchDesc->mHandle;
                 }
@@ -4557,11 +4796,10 @@
 }
 
 float AudioPolicyManager::computeVolume(audio_stream_type_t stream,
-                                            int index,
-                                            audio_devices_t device)
+                                        int index,
+                                        audio_devices_t device)
 {
-    float volumeDb = mEngine->volIndexToDb(Volume::getDeviceCategory(device), stream, index);
-
+    float volumeDb = mVolumeCurves->volIndexToDb(stream, Volume::getDeviceCategory(device), index);
     // if a headset is connected, apply the following rules to ring tones and notifications
     // to avoid sound level bursts in user's ears:
     // - always attenuate ring tones and notifications volume by 6dB
@@ -4577,7 +4815,7 @@
                 || (stream == AUDIO_STREAM_SYSTEM)
                 || ((stream_strategy == STRATEGY_ENFORCED_AUDIBLE) &&
                     (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) &&
-            mStreams.canBeMuted(stream)) {
+            mVolumeCurves->canBeMuted(stream)) {
         volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
         // when the phone is ringing we must consider that music could have been paused just before
         // by the music application and behave as if music was active if the last music track was
@@ -4586,8 +4824,9 @@
                 mLimitRingtoneVolume) {
             audio_devices_t musicDevice = getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/);
             float musicVolDB = computeVolume(AUDIO_STREAM_MUSIC,
-                                 mStreams.valueFor(AUDIO_STREAM_MUSIC).getVolumeIndex(musicDevice),
-                               musicDevice);
+                                             mVolumeCurves->getVolumeIndex(AUDIO_STREAM_MUSIC,
+                                                                              musicDevice),
+                                             musicDevice);
             float minVolDB = (musicVolDB > SONIFICATION_HEADSET_VOLUME_MIN_DB) ?
                     musicVolDB : SONIFICATION_HEADSET_VOLUME_MIN_DB;
             if (volumeDb > minVolDB) {
@@ -4639,7 +4878,7 @@
         float voiceVolume;
         // Force voice volume to max for bluetooth SCO as volume is managed by the headset
         if (stream == AUDIO_STREAM_VOICE_CALL) {
-            voiceVolume = (float)index/(float)mStreams.valueFor(stream).getVolumeIndexMax();
+            voiceVolume = (float)index/(float)mVolumeCurves->getVolumeIndexMax(stream);
         } else {
             voiceVolume = 1.0;
         }
@@ -4665,7 +4904,7 @@
             continue;
         }
         checkAndSetVolume((audio_stream_type_t)stream,
-                          mStreams.valueFor((audio_stream_type_t)stream).getVolumeIndex(device),
+                          mVolumeCurves->getVolumeIndex((audio_stream_type_t)stream, device),
                           outputDesc,
                           device,
                           delayMs,
@@ -4697,7 +4936,6 @@
                                            int delayMs,
                                            audio_devices_t device)
 {
-    const StreamDescriptor& streamDesc = mStreams.valueFor(stream);
     if (device == AUDIO_DEVICE_NONE) {
         device = outputDesc->device();
     }
@@ -4707,7 +4945,7 @@
 
     if (on) {
         if (outputDesc->mMuteCount[stream] == 0) {
-            if (streamDesc.canBeMuted() &&
+            if (mVolumeCurves->canBeMuted(stream) &&
                     ((stream != AUDIO_STREAM_ENFORCED_AUDIBLE) ||
                      (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_NONE))) {
                 checkAndSetVolume(stream, 0, outputDesc, device, delayMs);
@@ -4722,7 +4960,7 @@
         }
         if (--outputDesc->mMuteCount[stream] == 0) {
             checkAndSetVolume(stream,
-                              streamDesc.getVolumeIndex(device),
+                              mVolumeCurves->getVolumeIndex(stream, device),
                               outputDesc,
                               device,
                               delayMs);
@@ -4779,39 +5017,6 @@
     }
 }
 
-
-
-void AudioPolicyManager::defaultAudioPolicyConfig(void)
-{
-    sp<HwModule> module;
-    sp<IOProfile> profile;
-    sp<DeviceDescriptor> defaultInputDevice =
-                    new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
-    mAvailableOutputDevices.add(mDefaultOutputDevice);
-    mAvailableInputDevices.add(defaultInputDevice);
-
-    module = new HwModule("primary");
-
-    profile = new IOProfile(String8("primary"), AUDIO_PORT_ROLE_SOURCE);
-    profile->attach(module);
-    profile->mSamplingRates.add(44100);
-    profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
-    profile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO);
-    profile->mSupportedDevices.add(mDefaultOutputDevice);
-    profile->mFlags = AUDIO_OUTPUT_FLAG_PRIMARY;
-    module->mOutputProfiles.add(profile);
-
-    profile = new IOProfile(String8("primary"), AUDIO_PORT_ROLE_SINK);
-    profile->attach(module);
-    profile->mSamplingRates.add(8000);
-    profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
-    profile->mChannelMasks.add(AUDIO_CHANNEL_IN_MONO);
-    profile->mSupportedDevices.add(defaultInputDevice);
-    module->mInputProfiles.add(profile);
-
-    mHwModules.add(module);
-}
-
 audio_stream_type_t AudioPolicyManager::streamTypefromAttributesInt(const audio_attributes_t *attr)
 {
     // flags to stream type mapping
@@ -4935,4 +5140,91 @@
     return is_state_in_call(state);
 }
 
+void AudioPolicyManager::cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc)
+{
+    for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--)  {
+        sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
+        if (sourceDesc->mDevice->equals(deviceDesc)) {
+            ALOGV("%s releasing audio source %d", __FUNCTION__, sourceDesc->getHandle());
+            stopAudioSource(sourceDesc->getHandle());
+        }
+    }
+
+    for (ssize_t i = (ssize_t)mAudioPatches.size() - 1; i >= 0; i--)  {
+        sp<AudioPatch> patchDesc = mAudioPatches.valueAt(i);
+        bool release = false;
+        for (size_t j = 0; j < patchDesc->mPatch.num_sources && !release; j++)  {
+            const struct audio_port_config *source = &patchDesc->mPatch.sources[j];
+            if (source->type == AUDIO_PORT_TYPE_DEVICE &&
+                    source->ext.device.type == deviceDesc->type()) {
+                release = true;
+            }
+        }
+        for (size_t j = 0; j < patchDesc->mPatch.num_sinks && !release; j++)  {
+            const struct audio_port_config *sink = &patchDesc->mPatch.sinks[j];
+            if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
+                    sink->ext.device.type == deviceDesc->type()) {
+                release = true;
+            }
+        }
+        if (release) {
+            ALOGV("%s releasing patch %u", __FUNCTION__, patchDesc->mHandle);
+            releaseAudioPatch(patchDesc->mHandle, patchDesc->mUid);
+        }
+    }
+}
+
+void AudioPolicyManager::updateAudioProfiles(audio_io_handle_t ioHandle,
+                                             AudioProfileVector &profiles)
+{
+    String8 reply;
+    char *value;
+    // Format MUST be checked first to update the list of AudioProfile
+    if (profiles.hasDynamicFormat()) {
+        reply = mpClientInterface->getParameters(ioHandle,
+                                                 String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+        ALOGV("%s: supported formats %s", __FUNCTION__, reply.string());
+        AudioParameter repliedParameters(reply);
+        if (repliedParameters.get(
+                String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS), reply) != NO_ERROR) {
+            ALOGE("%s: failed to retrieve format, bailing out", __FUNCTION__);
+            return;
+        }
+        profiles.setFormats(formatsFromString(reply.string()));
+    }
+    const FormatVector &supportedFormats = profiles.getSupportedFormats();
+
+    for (size_t formatIndex = 0; formatIndex < supportedFormats.size(); formatIndex++) {
+        audio_format_t format = supportedFormats[formatIndex];
+        ChannelsVector channelMasks;
+        SampleRateVector samplingRates;
+        AudioParameter requestedParameters;
+        requestedParameters.addInt(String8(AUDIO_PARAMETER_STREAM_FORMAT), format);
+
+        if (profiles.hasDynamicRateFor(format)) {
+            reply = mpClientInterface->getParameters(ioHandle,
+                                                     requestedParameters.toString() + ";" +
+                                                     AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES);
+            ALOGV("%s: supported sampling rates %s", __FUNCTION__, reply.string());
+            AudioParameter repliedParameters(reply);
+            if (repliedParameters.get(
+                    String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES), reply) == NO_ERROR) {
+                samplingRates = samplingRatesFromString(reply.string());
+            }
+        }
+        if (profiles.hasDynamicChannelsFor(format)) {
+            reply = mpClientInterface->getParameters(ioHandle,
+                                                     requestedParameters.toString() + ";" +
+                                                     AUDIO_PARAMETER_STREAM_SUP_CHANNELS);
+            ALOGV("%s: supported channel masks %s", __FUNCTION__, reply.string());
+            AudioParameter repliedParameters(reply);
+            if (repliedParameters.get(
+                    String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS), reply) == NO_ERROR) {
+                channelMasks = channelMasksFromString(reply.string());
+            }
+        }
+        profiles.addProfileFromHal(new AudioProfile(format, channelMasks, samplingRates));
+    }
+}
+
 }; // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index bbdf396..1b1a9b4 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -24,6 +24,7 @@
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/SortedVector.h>
+#include <media/AudioParameter.h>
 #include <media/AudioPolicy.h>
 #include "AudioPolicyInterface.h"
 
@@ -32,7 +33,6 @@
 #include <AudioGain.h>
 #include <AudioPort.h>
 #include <AudioPatch.h>
-#include <ConfigParsingUtils.h>
 #include <DeviceDescriptor.h>
 #include <IOProfile.h>
 #include <HwModule.h>
@@ -41,8 +41,8 @@
 #include <AudioPolicyMix.h>
 #include <EffectDescriptor.h>
 #include <SoundTriggerSession.h>
-#include <StreamDescriptor.h>
 #include <SessionRoute.h>
+#include <VolumeCurve.h>
 
 namespace android {
 
@@ -139,7 +139,8 @@
 
         // indicates to the audio policy manager that the input starts being used.
         virtual status_t startInput(audio_io_handle_t input,
-                                    audio_session_t session);
+                                    audio_session_t session,
+                                    concurrency_type__mask_t *concurrency);
 
         // indicates to the audio policy manager that the input stops being used.
         virtual status_t stopInput(audio_io_handle_t input,
@@ -211,6 +212,8 @@
                                           unsigned int *generation);
         virtual status_t setAudioPortConfig(const struct audio_port_config *config);
 
+        virtual void releaseResourcesForUid(uid_t uid);
+
         virtual status_t acquireSoundTriggerSession(audio_session_t *session,
                                                audio_io_handle_t *ioHandle,
                                                audio_devices_t *device);
@@ -225,14 +228,12 @@
 
         virtual status_t startAudioSource(const struct audio_port_config *source,
                                           const audio_attributes_t *attributes,
-                                          audio_io_handle_t *handle);
+                                          audio_io_handle_t *handle,
+                                          uid_t uid);
         virtual status_t stopAudioSource(audio_io_handle_t handle);
 
-        virtual void     releaseResourcesForUid(uid_t uid);
-
-        // Audio policy configuration file parsing (audio_policy.conf)
-        // TODO candidates to be moved to ConfigParsingUtils
-                void defaultAudioPolicyConfig(void);
+        virtual status_t setMasterMono(bool mono);
+        virtual status_t getMasterMono(bool *mono);
 
         // return the strategy corresponding to a given stream type
         routing_strategy getStrategy(audio_stream_type_t stream) const;
@@ -267,10 +268,7 @@
         {
             return mAvailableInputDevices;
         }
-        virtual StreamDescriptorCollection &getStreamDescriptors()
-        {
-            return mStreams;
-        }
+        virtual IVolumeCurvesCollection &getVolumeCurves() { return *mVolumeCurves; }
         virtual const sp<DeviceDescriptor> &getDefaultOutputDevice() const
         {
             return mDefaultOutputDevice;
@@ -408,7 +406,7 @@
         void updateDevicesAndOutputs();
 
         // selects the most appropriate device on input for current state
-        audio_devices_t getNewInputDevice(audio_io_handle_t input);
+        audio_devices_t getNewInputDevice(const sp<AudioInputDescriptor>& inputDesc);
 
         virtual uint32_t getMaxEffectsCpuLoad()
         {
@@ -498,6 +496,19 @@
 
         status_t hasPrimaryOutput() const { return mPrimaryOutput != 0; }
 
+        status_t connectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc);
+        status_t disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc);
+
+        sp<AudioSourceDescriptor> getSourceForStrategyOnOutput(audio_io_handle_t output,
+                                                               routing_strategy strategy);
+
+        void cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc);
+
+        void clearAudioSources(uid_t uid);
+
+        bool isConcurentCaptureAllowed(const sp<AudioInputDescriptor>& inputDesc,
+                const sp<AudioSession>& audioSession);
+
         uid_t mUidCached;
         AudioPolicyClientInterface *mpClientInterface;  // audio policy client interface
         sp<SwAudioOutputDescriptor> mPrimaryOutput;     // primary output descriptor
@@ -515,7 +526,8 @@
         SessionRouteMap mOutputRoutes = SessionRouteMap(SessionRouteMap::MAPTYPE_OUTPUT);
         SessionRouteMap mInputRoutes = SessionRouteMap(SessionRouteMap::MAPTYPE_INPUT);
 
-        StreamDescriptorCollection mStreams; // stream descriptors for volume control
+        IVolumeCurvesCollection *mVolumeCurves; // Volume Curves per use case and device category
+
         bool    mLimitRingtoneVolume;        // limit ringtone volume to music volume if headset connected
         audio_devices_t mDeviceForStrategy[NUM_STRATEGIES];
         float   mLastVoiceVolume;            // last voice volume value sent to audio HAL
@@ -523,9 +535,6 @@
         EffectDescriptorCollection mEffects;  // list of registered audio effects
         bool    mA2dpSuspended;  // true if A2DP output is suspended
         sp<DeviceDescriptor> mDefaultOutputDevice; // output device selected by default at boot time
-        bool mSpeakerDrcEnabled;// true on devices that use DRC on the DEVICE_CATEGORY_SPEAKER path
-                                // to boost soft sounds, used to adjust volume curves accordingly
-
         HwModuleCollection mHwModules;
 
         volatile int32_t mAudioPortGeneration;
@@ -537,6 +546,9 @@
         sp<AudioPatch> mCallTxPatch;
         sp<AudioPatch> mCallRxPatch;
 
+        HwAudioOutputCollection mHwOutputs;
+        AudioSourceCollection mAudioSources;
+
         // for supporting "beacon" streams, i.e. streams that only play on speaker, and never
         // when something other than STREAM_TTS (a.k.a. "Transmitted Through Speaker") is playing
         enum {
@@ -550,6 +562,7 @@
         bool mBeaconMuted;              // has STREAM_TTS been muted
         bool mTtsOutputAvailable;       // true if a dedicated output for TTS stream is available
 
+        bool mMasterMono;               // true if we wish to force all outputs to mono
         AudioPolicyMixCollection mPolicyMixes; // list of registered mixes
 
 #ifdef AUDIO_POLICY_TEST
@@ -572,6 +585,9 @@
         // Audio Policy Engine Interface.
         AudioPolicyManagerInterface *mEngine;
 private:
+        // If any, resolve any "dynamic" fields of an Audio Profiles collection
+        void updateAudioProfiles(audio_io_handle_t ioHandle, AudioProfileVector &profiles);
+
         // updates device caching and output for streams that can influence the
         //    routing of notifications
         void handleNotificationRoutingForStream(audio_stream_type_t stream);
@@ -595,6 +611,18 @@
                 audio_channel_mask_t channelMask,
                 audio_output_flags_t flags,
                 const audio_offload_info_t *offloadInfo);
+        // internal method to return the input handle for the given device and format
+        audio_io_handle_t getInputForDevice(audio_devices_t device,
+                String8 address,
+                audio_session_t session,
+                uid_t uid,
+                audio_source_t inputSource,
+                uint32_t samplingRate,
+                audio_format_t format,
+                audio_channel_mask_t channelMask,
+                audio_input_flags_t flags,
+                AudioMix *policyMix);
+
         // internal function to derive a stream type value from audio attributes
         audio_stream_type_t streamTypefromAttributesInt(const audio_attributes_t *attr);
         // event is one of STARTING_OUTPUT, STARTING_BEACON, STOPPING_OUTPUT, STOPPING_BEACON
@@ -614,6 +642,11 @@
                                                           audio_policy_dev_state_t state,
                                                           const char *device_address,
                                                           const char *device_name);
+        void updateMono(audio_io_handle_t output) {
+            AudioParameter param;
+            param.addInt(String8(AUDIO_PARAMETER_MONO_OUTPUT), (int)mMasterMono);
+            mpClientInterface->setParameters(output, param.toString());
+        }
 };
 
 };
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 489a9be..3d51f48 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -219,6 +219,12 @@
     mAudioPolicyService->onDynamicPolicyMixStateUpdate(regId, state);
 }
 
+void AudioPolicyService::AudioPolicyClient::onRecordingConfigurationUpdate(
+        int event, audio_session_t session, audio_source_t source)
+{
+    mAudioPolicyService->onRecordingConfigurationUpdate(event, session, source);
+}
+
 audio_unique_id_t AudioPolicyService::AudioPolicyClient::newAudioUniqueId()
 {
     return AudioSystem::newAudioUniqueId();
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 282ddeb..9a28137 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -57,11 +57,11 @@
     }
     mInputSources.clear();
 
-    for (i = 0; i < mInputs.size(); i++) {
-        mInputs.valueAt(i)->mEffects.clear();
-        delete mInputs.valueAt(i);
+    for (i = 0; i < mInputSessions.size(); i++) {
+        mInputSessions.valueAt(i)->mEffects.clear();
+        delete mInputSessions.valueAt(i);
     }
-    mInputs.clear();
+    mInputSessions.clear();
 
     // release audio output processing resources
     for (i = 0; i < mOutputStreams.size(); i++) {
@@ -79,7 +79,7 @@
 
 status_t AudioPolicyEffects::addInputEffects(audio_io_handle_t input,
                              audio_source_t inputSource,
-                             int audioSession)
+                             audio_session_t audioSession)
 {
     status_t status = NO_ERROR;
 
@@ -93,19 +93,19 @@
         ALOGV("addInputEffects(): no processing needs to be attached to this source");
         return status;
     }
-    ssize_t idx = mInputs.indexOfKey(input);
-    EffectVector *inputDesc;
+    ssize_t idx = mInputSessions.indexOfKey(audioSession);
+    EffectVector *sessionDesc;
     if (idx < 0) {
-        inputDesc = new EffectVector(audioSession);
-        mInputs.add(input, inputDesc);
+        sessionDesc = new EffectVector(audioSession);
+        mInputSessions.add(audioSession, sessionDesc);
     } else {
         // EffectVector is existing and we just need to increase ref count
-        inputDesc = mInputs.valueAt(idx);
+        sessionDesc = mInputSessions.valueAt(idx);
     }
-    inputDesc->mRefCount++;
+    sessionDesc->mRefCount++;
 
-    ALOGV("addInputEffects(): input: %d, refCount: %d", input, inputDesc->mRefCount);
-    if (inputDesc->mRefCount == 1) {
+    ALOGV("addInputEffects(): input: %d, refCount: %d", input, sessionDesc->mRefCount);
+    if (sessionDesc->mRefCount == 1) {
         Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
         for (size_t i = 0; i < effects.size(); i++) {
             EffectDesc *effect = effects[i];
@@ -123,36 +123,37 @@
             }
             ALOGV("addInputEffects(): added Fx %s on source: %d",
                   effect->mName, (int32_t)aliasSource);
-            inputDesc->mEffects.add(fx);
+            sessionDesc->mEffects.add(fx);
         }
-        inputDesc->setProcessorEnabled(true);
+        sessionDesc->setProcessorEnabled(true);
     }
     return status;
 }
 
 
-status_t AudioPolicyEffects::releaseInputEffects(audio_io_handle_t input)
+status_t AudioPolicyEffects::releaseInputEffects(audio_io_handle_t input,
+                                                 audio_session_t audioSession)
 {
     status_t status = NO_ERROR;
 
     Mutex::Autolock _l(mLock);
-    ssize_t index = mInputs.indexOfKey(input);
+    ssize_t index = mInputSessions.indexOfKey(audioSession);
     if (index < 0) {
         return status;
     }
-    EffectVector *inputDesc = mInputs.valueAt(index);
-    inputDesc->mRefCount--;
-    ALOGV("releaseInputEffects(): input: %d, refCount: %d", input, inputDesc->mRefCount);
-    if (inputDesc->mRefCount == 0) {
-        inputDesc->setProcessorEnabled(false);
-        delete inputDesc;
-        mInputs.removeItemsAt(index);
+    EffectVector *sessionDesc = mInputSessions.valueAt(index);
+    sessionDesc->mRefCount--;
+    ALOGV("releaseInputEffects(): input: %d, refCount: %d", input, sessionDesc->mRefCount);
+    if (sessionDesc->mRefCount == 0) {
+        sessionDesc->setProcessorEnabled(false);
+        delete sessionDesc;
+        mInputSessions.removeItemsAt(index);
         ALOGV("releaseInputEffects(): all effects released");
     }
     return status;
 }
 
-status_t AudioPolicyEffects::queryDefaultInputEffects(int audioSession,
+status_t AudioPolicyEffects::queryDefaultInputEffects(audio_session_t audioSession,
                                                       effect_descriptor_t *descriptors,
                                                       uint32_t *count)
 {
@@ -160,16 +161,16 @@
 
     Mutex::Autolock _l(mLock);
     size_t index;
-    for (index = 0; index < mInputs.size(); index++) {
-        if (mInputs.valueAt(index)->mSessionId == audioSession) {
+    for (index = 0; index < mInputSessions.size(); index++) {
+        if (mInputSessions.valueAt(index)->mSessionId == audioSession) {
             break;
         }
     }
-    if (index == mInputs.size()) {
+    if (index == mInputSessions.size()) {
         *count = 0;
         return BAD_VALUE;
     }
-    Vector< sp<AudioEffect> > effects = mInputs.valueAt(index)->mEffects;
+    Vector< sp<AudioEffect> > effects = mInputSessions.valueAt(index)->mEffects;
 
     for (size_t i = 0; i < effects.size(); i++) {
         effect_descriptor_t desc = effects[i]->descriptor();
@@ -185,7 +186,7 @@
 }
 
 
-status_t AudioPolicyEffects::queryDefaultOutputSessionEffects(int audioSession,
+status_t AudioPolicyEffects::queryDefaultOutputSessionEffects(audio_session_t audioSession,
                          effect_descriptor_t *descriptors,
                          uint32_t *count)
 {
@@ -220,7 +221,7 @@
 
 status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output,
                          audio_stream_type_t stream,
-                         int audioSession)
+                         audio_session_t audioSession)
 {
     status_t status = NO_ERROR;
 
@@ -275,7 +276,7 @@
 
 status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t output,
                          audio_stream_type_t stream,
-                         int audioSession)
+                         audio_session_t audioSession)
 {
     status_t status = NO_ERROR;
     (void) output; // argument not used for now
@@ -323,7 +324,8 @@
     VOICE_CALL_SRC_TAG,
     CAMCORDER_SRC_TAG,
     VOICE_REC_SRC_TAG,
-    VOICE_COMM_SRC_TAG
+    VOICE_COMM_SRC_TAG,
+    UNPROCESSED_SRC_TAG
 };
 
 // returns the audio_source_t enum corresponding to the input source name or
@@ -372,7 +374,7 @@
 // Audio Effect Config parser
 // ----------------------------------------------------------------------------
 
-size_t AudioPolicyEffects::growParamSize(char *param,
+size_t AudioPolicyEffects::growParamSize(char **param,
                                          size_t size,
                                          size_t *curSize,
                                          size_t *totSize)
@@ -384,55 +386,82 @@
         while (pos + size > *totSize) {
             *totSize += ((*totSize + 7) / 8) * 4;
         }
-        param = (char *)realloc(param, *totSize);
+        *param = (char *)realloc(*param, *totSize);
+        if (*param == NULL) {
+            ALOGE("%s realloc error for size %zu", __func__, *totSize);
+            return 0;
+        }
     }
     *curSize = pos + size;
     return pos;
 }
 
+
 size_t AudioPolicyEffects::readParamValue(cnode *node,
-                                          char *param,
+                                          char **param,
                                           size_t *curSize,
                                           size_t *totSize)
 {
+    size_t len = 0;
+    size_t pos;
+
     if (strncmp(node->name, SHORT_TAG, sizeof(SHORT_TAG) + 1) == 0) {
-        size_t pos = growParamSize(param, sizeof(short), curSize, totSize);
-        *(short *)((char *)param + pos) = (short)atoi(node->value);
-        ALOGV("readParamValue() reading short %d", *(short *)((char *)param + pos));
-        return sizeof(short);
-    } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) {
-        size_t pos = growParamSize(param, sizeof(int), curSize, totSize);
-        *(int *)((char *)param + pos) = atoi(node->value);
-        ALOGV("readParamValue() reading int %d", *(int *)((char *)param + pos));
-        return sizeof(int);
-    } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) {
-        size_t pos = growParamSize(param, sizeof(float), curSize, totSize);
-        *(float *)((char *)param + pos) = (float)atof(node->value);
-        ALOGV("readParamValue() reading float %f",*(float *)((char *)param + pos));
-        return sizeof(float);
-    } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) {
-        size_t pos = growParamSize(param, sizeof(bool), curSize, totSize);
-        if (strncmp(node->value, "false", strlen("false") + 1) == 0) {
-            *(bool *)((char *)param + pos) = false;
-        } else {
-            *(bool *)((char *)param + pos) = true;
+        pos = growParamSize(param, sizeof(short), curSize, totSize);
+        if (pos == 0) {
+            goto exit;
         }
-        ALOGV("readParamValue() reading bool %s",*(bool *)((char *)param + pos) ? "true" : "false");
-        return sizeof(bool);
+        *(short *)(*param + pos) = (short)atoi(node->value);
+        ALOGV("readParamValue() reading short %d", *(short *)(*param + pos));
+        len = sizeof(short);
+    } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) {
+        pos = growParamSize(param, sizeof(int), curSize, totSize);
+        if (pos == 0) {
+            goto exit;
+        }
+        *(int *)(*param + pos) = atoi(node->value);
+        ALOGV("readParamValue() reading int %d", *(int *)(*param + pos));
+        len = sizeof(int);
+    } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) {
+        pos = growParamSize(param, sizeof(float), curSize, totSize);
+        if (pos == 0) {
+            goto exit;
+        }
+        *(float *)(*param + pos) = (float)atof(node->value);
+        ALOGV("readParamValue() reading float %f",*(float *)(*param + pos));
+        len = sizeof(float);
+    } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) {
+        pos = growParamSize(param, sizeof(bool), curSize, totSize);
+        if (pos == 0) {
+            goto exit;
+        }
+        if (strncmp(node->value, "true", strlen("true") + 1) == 0) {
+            *(bool *)(*param + pos) = true;
+        } else {
+            *(bool *)(*param + pos) = false;
+        }
+        ALOGV("readParamValue() reading bool %s",
+              *(bool *)(*param + pos) ? "true" : "false");
+        len = sizeof(bool);
     } else if (strncmp(node->name, STRING_TAG, sizeof(STRING_TAG) + 1) == 0) {
-        size_t len = strnlen(node->value, EFFECT_STRING_LEN_MAX);
+        len = strnlen(node->value, EFFECT_STRING_LEN_MAX);
         if (*curSize + len + 1 > *totSize) {
             *totSize = *curSize + len + 1;
-            param = (char *)realloc(param, *totSize);
+            *param = (char *)realloc(*param, *totSize);
+            if (*param == NULL) {
+                len = 0;
+                ALOGE("%s realloc error for string len %zu", __func__, *totSize);
+                goto exit;
+            }
         }
-        strncpy(param + *curSize, node->value, len);
+        strncpy(*param + *curSize, node->value, len);
         *curSize += len;
-        param[*curSize] = '\0';
-        ALOGV("readParamValue() reading string %s", param + *curSize - len);
-        return len;
+        (*param)[*curSize] = '\0';
+        ALOGV("readParamValue() reading string %s", *param + *curSize - len);
+    } else {
+        ALOGW("readParamValue() unknown param type %s", node->name);
     }
-    ALOGW("readParamValue() unknown param type %s", node->name);
-    return 0;
+exit:
+    return len;
 }
 
 effect_param_t *AudioPolicyEffects::loadEffectParameter(cnode *root)
@@ -443,6 +472,12 @@
     size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int);
     effect_param_t *fx_param = (effect_param_t *)malloc(totSize);
 
+    if (fx_param == NULL) {
+        ALOGE("%s malloc error for effect structure of size %zu",
+              __func__, totSize);
+        return NULL;
+    }
+
     param = config_find(root, PARAM_TAG);
     value = config_find(root, VALUE_TAG);
     if (param == NULL && value == NULL) {
@@ -451,8 +486,10 @@
         if (param != NULL) {
             // Note: that a pair of random strings is read as 0 0
             int *ptr = (int *)fx_param->data;
+#if LOG_NDEBUG == 0
             int *ptr2 = (int *)((char *)param + sizeof(effect_param_t));
-            ALOGW("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2);
+            ALOGV("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2);
+#endif
             *ptr++ = atoi(param->name);
             *ptr = atoi(param->value);
             fx_param->psize = sizeof(int);
@@ -461,7 +498,8 @@
         }
     }
     if (param == NULL || value == NULL) {
-        ALOGW("loadEffectParameter() invalid parameter description %s", root->name);
+        ALOGW("loadEffectParameter() invalid parameter description %s",
+              root->name);
         goto error;
     }
 
@@ -469,7 +507,8 @@
     param = param->first_child;
     while (param) {
         ALOGV("loadEffectParameter() reading param of type %s", param->name);
-        size_t size = readParamValue(param, (char *)fx_param, &curSize, &totSize);
+        size_t size =
+                readParamValue(param, (char **)&fx_param, &curSize, &totSize);
         if (size == 0) {
             goto error;
         }
@@ -484,7 +523,8 @@
     value = value->first_child;
     while (value) {
         ALOGV("loadEffectParameter() reading value of type %s", value->name);
-        size_t size = readParamValue(value, (char *)fx_param, &curSize, &totSize);
+        size_t size =
+                readParamValue(value, (char **)&fx_param, &curSize, &totSize);
         if (size == 0) {
             goto error;
         }
@@ -495,7 +535,7 @@
     return fx_param;
 
 error:
-    delete fx_param;
+    free(fx_param);
     return NULL;
 }
 
@@ -505,11 +545,9 @@
     while (node) {
         ALOGV("loadEffectParameters() loading param %s", node->name);
         effect_param_t *param = loadEffectParameter(node);
-        if (param == NULL) {
-            node = node->next;
-            continue;
+        if (param != NULL) {
+            params.add(param);
         }
-        params.add(param);
         node = node->next;
     }
 }
@@ -527,6 +565,7 @@
     EffectDescVector *desc = new EffectDescVector();
     while (node) {
         size_t i;
+
         for (i = 0; i < effects.size(); i++) {
             if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) {
                 ALOGV("loadEffectConfig() found effect %s in list", node->name);
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index 3dec437..f302167 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -51,7 +51,7 @@
 
     // Return a list of effect descriptors for default input effects
     // associated with audioSession
-    status_t queryDefaultInputEffects(int audioSession,
+    status_t queryDefaultInputEffects(audio_session_t audioSession,
                              effect_descriptor_t *descriptors,
                              uint32_t *count);
 
@@ -59,15 +59,16 @@
     // Effects are attached depending on the audio_source_t
     status_t addInputEffects(audio_io_handle_t input,
                              audio_source_t inputSource,
-                             int audioSession);
+                             audio_session_t audioSession);
 
     // Add all input effects associated to this input
-    status_t releaseInputEffects(audio_io_handle_t input);
+    status_t releaseInputEffects(audio_io_handle_t input,
+                                 audio_session_t audioSession);
 
 
     // Return a list of effect descriptors for default output effects
     // associated with audioSession
-    status_t queryDefaultOutputSessionEffects(int audioSession,
+    status_t queryDefaultOutputSessionEffects(audio_session_t audioSession,
                              effect_descriptor_t *descriptors,
                              uint32_t *count);
 
@@ -75,12 +76,12 @@
     // Effects are attached depending on the audio_stream_type_t
     status_t addOutputSessionEffects(audio_io_handle_t output,
                              audio_stream_type_t stream,
-                             int audioSession);
+                             audio_session_t audioSession);
 
     // release all output effects associated with this output stream and audiosession
     status_t releaseOutputSessionEffects(audio_io_handle_t output,
                              audio_stream_type_t stream,
-                             int audioSession);
+                             audio_session_t audioSession);
 
 private:
 
@@ -170,25 +171,25 @@
     void loadEffectParameters(cnode *root, Vector <effect_param_t *>& params);
     effect_param_t *loadEffectParameter(cnode *root);
     size_t readParamValue(cnode *node,
-                          char *param,
+                          char **param,
                           size_t *curSize,
                           size_t *totSize);
-    size_t growParamSize(char *param,
+    size_t growParamSize(char **param,
                          size_t size,
                          size_t *curSize,
                          size_t *totSize);
 
-    // protects access to mInputSources, mInputs, mOutputStreams, mOutputSessions
+    // protects access to mInputSources, mInputSessions, mOutputStreams, mOutputSessions
     Mutex mLock;
     // Automatic input effects are configured per audio_source_t
     KeyedVector< audio_source_t, EffectDescVector* > mInputSources;
     // Automatic input effects are unique for audio_io_handle_t
-    KeyedVector< audio_io_handle_t, EffectVector* > mInputs;
+    KeyedVector< audio_session_t, EffectVector* > mInputSessions;
 
     // Automatic output effects are organized per audio_stream_type_t
     KeyedVector< audio_stream_type_t, EffectDescVector* > mOutputStreams;
     // Automatic output effects are unique for audiosession ID
-    KeyedVector< int32_t, EffectVector* > mOutputSessions;
+    KeyedVector< audio_session_t, EffectVector* > mOutputSessions;
 };
 
 }; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index a228798..ae5cf3d 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -164,13 +164,11 @@
     ALOGV("getOutput()");
     Mutex::Autolock _l(mLock);
 
-    // if the caller is us, trust the specified uid
-    if (IPCThreadState::self()->getCallingPid() != getpid_cached || uid == (uid_t)-1) {
-        uid_t newclientUid = IPCThreadState::self()->getCallingUid();
-        if (uid != (uid_t)-1 && uid != newclientUid) {
-            ALOGW("%s uid %d tried to pass itself off as %d", __FUNCTION__, newclientUid, uid);
-        }
-        uid = newclientUid;
+    const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+    if (!isTrustedCallingUid(callingUid) || uid == (uid_t)-1) {
+        ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
+                "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
+        uid = callingUid;
     }
     return mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, samplingRate,
                                     format, channelMask, flags, selectedDeviceId, offloadInfo);
@@ -284,13 +282,11 @@
     sp<AudioPolicyEffects>audioPolicyEffects;
     status_t status;
     AudioPolicyInterface::input_type_t inputType;
-    // if the caller is us, trust the specified uid
-    if (IPCThreadState::self()->getCallingPid() != getpid_cached || uid == (uid_t)-1) {
-        uid_t newclientUid = IPCThreadState::self()->getCallingUid();
-        if (uid != (uid_t)-1 && uid != newclientUid) {
-            ALOGW("%s uid %d tried to pass itself off as %d", __FUNCTION__, newclientUid, uid);
-        }
-        uid = newclientUid;
+    const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+    if (!isTrustedCallingUid(callingUid) || uid == (uid_t)-1) {
+        ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
+                "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
+        uid = callingUid;
     }
 
     {
@@ -353,8 +349,23 @@
         return NO_INIT;
     }
     Mutex::Autolock _l(mLock);
+    AudioPolicyInterface::concurrency_type__mask_t concurrency;
+    status_t status = mAudioPolicyManager->startInput(input, session, &concurrency);
 
-    return mAudioPolicyManager->startInput(input, session);
+    if (status == NO_ERROR) {
+        LOG_ALWAYS_FATAL_IF(concurrency & ~AudioPolicyInterface::API_INPUT_CONCURRENCY_ALL,
+                            "startInput(): invalid concurrency type %d", (int)concurrency);
+
+        // enforce permission (if any) required for each type of concurrency
+        if (concurrency & AudioPolicyInterface::API_INPUT_CONCURRENCY_CALL) {
+            //TODO: check incall capture permission
+        }
+        if (concurrency & AudioPolicyInterface::API_INPUT_CONCURRENCY_CAPTURE) {
+            //TODO: check concurrent capture permission
+        }
+    }
+
+    return status;
 }
 
 status_t AudioPolicyService::stopInput(audio_io_handle_t input,
@@ -382,7 +393,7 @@
     }
     if (audioPolicyEffects != 0) {
         // release audio processors from the input
-        status_t status = audioPolicyEffects->releaseInputEffects(input);
+        status_t status = audioPolicyEffects->releaseInputEffects(input, session);
         if(status != NO_ERROR) {
             ALOGW("Failed to release effects on input %d", input);
         }
@@ -555,7 +566,8 @@
         *count = 0;
         return NO_INIT;
     }
-    return audioPolicyEffects->queryDefaultInputEffects(audioSession, descriptors, count);
+    return audioPolicyEffects->queryDefaultInputEffects(
+            (audio_session_t)audioSession, descriptors, count);
 }
 
 bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info)
@@ -564,7 +576,7 @@
         ALOGV("mAudioPolicyManager == NULL");
         return false;
     }
-
+    Mutex::Autolock _l(mLock);
     return mAudioPolicyManager->isOffloadSupported(info);
 }
 
@@ -690,7 +702,8 @@
         return NO_INIT;
     }
 
-    return mAudioPolicyManager->startAudioSource(source, attributes, handle);
+    return mAudioPolicyManager->startAudioSource(source, attributes, handle,
+                                                 IPCThreadState::self()->getCallingUid());
 }
 
 status_t AudioPolicyService::stopAudioSource(audio_io_handle_t handle)
@@ -703,4 +716,25 @@
     return mAudioPolicyManager->stopAudioSource(handle);
 }
 
+status_t AudioPolicyService::setMasterMono(bool mono)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    Mutex::Autolock _l(mLock);
+    return mAudioPolicyManager->setMasterMono(mono);
+}
+
+status_t AudioPolicyService::getMasterMono(bool *mono)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    return mAudioPolicyManager->getMasterMono(mono);
+}
+
 }; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
index 13af3ef..42719f6 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
@@ -306,7 +306,7 @@
 }
 
 void AudioPolicyService::releaseInput(audio_io_handle_t input,
-                                      audio_session_t session __unused)
+                                      audio_session_t session)
 {
     if (mpAudioPolicy == NULL) {
         return;
@@ -320,7 +320,7 @@
     }
     if (audioPolicyEffects != 0) {
         // release audio processors from the input
-        status_t status = audioPolicyEffects->releaseInputEffects(input);
+        status_t status = audioPolicyEffects->releaseInputEffects(input, session);
         if(status != NO_ERROR) {
             ALOGW("Failed to release effects on input %d", input);
         }
@@ -619,4 +619,14 @@
     return INVALID_OPERATION;
 }
 
+status_t AudioPolicyService::setMasterMono(bool mono)
+{
+    return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::getMasterMono(bool *mono)
+{
+    return INVALID_OPERATION;
+}
+
 }; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index c77cc45..363968c 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -149,7 +149,10 @@
 // connects to AudioPolicyService.
 void AudioPolicyService::registerClient(const sp<IAudioPolicyServiceClient>& client)
 {
-
+    if (client == 0) {
+        ALOGW("%s got NULL client", __FUNCTION__);
+        return;
+    }
     Mutex::Autolock _l(mNotificationClientsLock);
 
     uid_t uid = IPCThreadState::self()->getCallingUid();
@@ -212,19 +215,6 @@
     mOutputCommandThread->updateAudioPatchListCommand();
 }
 
-status_t AudioPolicyService::clientCreateAudioPatch(const struct audio_patch *patch,
-                                                audio_patch_handle_t *handle,
-                                                int delayMs)
-{
-    return mAudioCommandThread->createAudioPatchCommand(patch, handle, delayMs);
-}
-
-status_t AudioPolicyService::clientReleaseAudioPatch(audio_patch_handle_t handle,
-                                                 int delayMs)
-{
-    return mAudioCommandThread->releaseAudioPatchCommand(handle, delayMs);
-}
-
 void AudioPolicyService::doOnAudioPatchListUpdate()
 {
     Mutex::Autolock _l(mNotificationClientsLock);
@@ -248,6 +238,34 @@
     }
 }
 
+void AudioPolicyService::onRecordingConfigurationUpdate(int event, audio_session_t session,
+        audio_source_t source)
+{
+    mOutputCommandThread->recordingConfigurationUpdateCommand(event, session, source);
+}
+
+void AudioPolicyService::doOnRecordingConfigurationUpdate(int event, audio_session_t session,
+        audio_source_t source)
+{
+    Mutex::Autolock _l(mNotificationClientsLock);
+    for (size_t i = 0; i < mNotificationClients.size(); i++) {
+        mNotificationClients.valueAt(i)->onRecordingConfigurationUpdate(event, session, source);
+    }
+}
+
+status_t AudioPolicyService::clientCreateAudioPatch(const struct audio_patch *patch,
+                                                audio_patch_handle_t *handle,
+                                                int delayMs)
+{
+    return mAudioCommandThread->createAudioPatchCommand(patch, handle, delayMs);
+}
+
+status_t AudioPolicyService::clientReleaseAudioPatch(audio_patch_handle_t handle,
+                                                 int delayMs)
+{
+    return mAudioCommandThread->releaseAudioPatchCommand(handle, delayMs);
+}
+
 status_t AudioPolicyService::clientSetAudioPortConfig(const struct audio_port_config *config,
                                                       int delayMs)
 {
@@ -293,7 +311,15 @@
         String8 regId, int32_t state)
 {
     if (mAudioPolicyServiceClient != 0) {
-            mAudioPolicyServiceClient->onDynamicPolicyMixStateUpdate(regId, state);
+        mAudioPolicyServiceClient->onDynamicPolicyMixStateUpdate(regId, state);
+    }
+}
+
+void AudioPolicyService::NotificationClient::onRecordingConfigurationUpdate(
+        int event, audio_session_t session, audio_source_t source)
+{
+    if (mAudioPolicyServiceClient != 0) {
+        mAudioPolicyServiceClient->onRecordingConfigurationUpdate(event, session, source);
     }
 }
 
@@ -423,7 +449,7 @@
 
 bool AudioPolicyService::AudioCommandThread::threadLoop()
 {
-    nsecs_t waitTime = INT64_MAX;
+    nsecs_t waitTime = -1;
 
     mLock.lock();
     while (!exitPending())
@@ -555,7 +581,6 @@
                 case DYN_POLICY_MIX_STATE_UPDATE: {
                     DynPolicyMixStateUpdateData *data =
                             (DynPolicyMixStateUpdateData *)command->mParam.get();
-                    //###ALOGV("AudioCommandThread() processing dyn policy mix state update");
                     ALOGV("AudioCommandThread() processing dyn policy mix state update %s %d",
                             data->mRegId.string(), data->mState);
                     svc = mService.promote();
@@ -566,6 +591,19 @@
                     svc->doOnDynamicPolicyMixStateUpdate(data->mRegId, data->mState);
                     mLock.lock();
                     } break;
+                case RECORDING_CONFIGURATION_UPDATE: {
+                    RecordingConfigurationUpdateData *data =
+                            (RecordingConfigurationUpdateData *)command->mParam.get();
+                    ALOGV("AudioCommandThread() processing recording configuration update");
+                    svc = mService.promote();
+                    if (svc == 0) {
+                        break;
+                    }
+                    mLock.unlock();
+                    svc->doOnRecordingConfigurationUpdate(data->mEvent, data->mSession,
+                            data->mSource);
+                    mLock.lock();
+                    } break;
                 default:
                     ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
                 }
@@ -576,7 +614,7 @@
                         command->mCond.signal();
                     }
                 }
-                waitTime = INT64_MAX;
+                waitTime = -1;
                 // release mLock before releasing strong reference on the service as
                 // AudioPolicyService destructor calls AudioCommandThread::exit() which
                 // acquires mLock.
@@ -598,7 +636,11 @@
         // has a finite delay. So unless we are exiting it is safe to wait.
         if (!exitPending()) {
             ALOGV("AudioCommandThread() going to sleep");
-            mWaitWorkCV.waitRelative(mLock, waitTime);
+            if (waitTime == -1) {
+                mWaitWorkCV.wait(mLock);
+            } else {
+                mWaitWorkCV.waitRelative(mLock, waitTime);
+            }
         }
     }
     // release delayed commands wake lock before quitting
@@ -822,6 +864,21 @@
     sendCommand(command);
 }
 
+void AudioPolicyService::AudioCommandThread::recordingConfigurationUpdateCommand(
+        int event, audio_session_t session, audio_source_t source)
+{
+    sp<AudioCommand>command = new AudioCommand();
+    command->mCommand = RECORDING_CONFIGURATION_UPDATE;
+    RecordingConfigurationUpdateData *data = new RecordingConfigurationUpdateData();
+    data->mEvent = event;
+    data->mSession = session;
+    data->mSource = source;
+    command->mParam = data;
+    ALOGV("AudioCommandThread() adding recording configuration update event %d, source %d",
+            event, source);
+    sendCommand(command);
+}
+
 status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
 {
     {
@@ -968,6 +1025,10 @@
 
         } break;
 
+        case RECORDING_CONFIGURATION_UPDATE: {
+
+        } break;
+
         case START_TONE:
         case STOP_TONE:
         default:
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index a0d5aa2..160f4f0 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -202,6 +202,9 @@
                                       audio_io_handle_t *handle);
     virtual status_t stopAudioSource(audio_io_handle_t handle);
 
+    virtual status_t setMasterMono(bool mono);
+    virtual status_t getMasterMono(bool *mono);
+
             status_t doStopOutput(audio_io_handle_t output,
                                   audio_stream_type_t stream,
                                   audio_session_t session);
@@ -225,6 +228,10 @@
 
             void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
             void doOnDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+            void onRecordingConfigurationUpdate(int event, audio_session_t session,
+                    audio_source_t source);
+            void doOnRecordingConfigurationUpdate(int event, audio_session_t session,
+                    audio_source_t source);
 
 private:
                         AudioPolicyService() ANDROID_API;
@@ -256,7 +263,8 @@
             UPDATE_AUDIOPORT_LIST,
             UPDATE_AUDIOPATCH_LIST,
             SET_AUDIOPORT_CONFIG,
-            DYN_POLICY_MIX_STATE_UPDATE
+            DYN_POLICY_MIX_STATE_UPDATE,
+            RECORDING_CONFIGURATION_UPDATE
         };
 
         AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -295,6 +303,9 @@
                     status_t    setAudioPortConfigCommand(const struct audio_port_config *config,
                                                           int delayMs);
                     void        dynamicPolicyMixStateUpdateCommand(String8 regId, int32_t state);
+                    void        recordingConfigurationUpdateCommand(
+                                                        int event, audio_session_t session,
+                                                        audio_source_t source);
                     void        insertCommand_l(AudioCommand *command, int delayMs = 0);
 
     private:
@@ -385,6 +396,13 @@
             int32_t mState;
         };
 
+        class RecordingConfigurationUpdateData : public AudioCommandData {
+        public:
+            int mEvent;
+            audio_session_t mSession;
+            audio_source_t mSource;
+        };
+
         Mutex   mLock;
         Condition mWaitWorkCV;
         Vector < sp<AudioCommand> > mAudioCommands; // list of pending commands
@@ -491,6 +509,8 @@
         virtual void onAudioPortListUpdate();
         virtual void onAudioPatchListUpdate();
         virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+        virtual void onRecordingConfigurationUpdate(int event,
+                        audio_session_t session, audio_source_t source);
 
         virtual audio_unique_id_t newAudioUniqueId();
 
@@ -509,6 +529,9 @@
                             void      onAudioPortListUpdate();
                             void      onAudioPatchListUpdate();
                             void      onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+                            void      onRecordingConfigurationUpdate(
+                                        int event, audio_session_t session,
+                                        audio_source_t source);
                             void      setAudioPortCallbacksEnabled(bool enabled);
 
                 // IBinder::DeathRecipient
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 45900c4..d416353 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -22,7 +22,6 @@
 
 LOCAL_SRC_FILES:=               \
     CameraService.cpp \
-    CameraDeviceFactory.cpp \
     CameraFlashlight.cpp \
     common/Camera2ClientBase.cpp \
     common/CameraDeviceBase.cpp \
@@ -35,14 +34,10 @@
     api1/client2/StreamingProcessor.cpp \
     api1/client2/JpegProcessor.cpp \
     api1/client2/CallbackProcessor.cpp \
-    api1/client2/ZslProcessor.cpp \
-    api1/client2/ZslProcessorInterface.cpp \
-    api1/client2/BurstCapture.cpp \
     api1/client2/JpegCompressor.cpp \
     api1/client2/CaptureSequencer.cpp \
-    api1/client2/ZslProcessor3.cpp \
+    api1/client2/ZslProcessor.cpp \
     api2/CameraDeviceClient.cpp \
-    device2/Camera2Device.cpp \
     device3/Camera3Device.cpp \
     device3/Camera3Stream.cpp \
     device3/Camera3IOStreamBase.cpp \
@@ -51,6 +46,7 @@
     device3/Camera3ZslStream.cpp \
     device3/Camera3DummyStream.cpp \
     device3/StatusTracker.cpp \
+    device3/Camera3BufferManager.cpp \
     gui/RingBufferConsumer.cpp \
     utils/CameraTraces.cpp \
     utils/AutoConditionLock.cpp
diff --git a/services/camera/libcameraservice/CameraDeviceFactory.cpp b/services/camera/libcameraservice/CameraDeviceFactory.cpp
deleted file mode 100644
index 6589e27..0000000
--- a/services/camera/libcameraservice/CameraDeviceFactory.cpp
+++ /dev/null
@@ -1,74 +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_NDEBUG 0
-#define LOG_TAG "CameraDeviceFactory"
-#include <utils/Log.h>
-
-#include "CameraService.h"
-#include "CameraDeviceFactory.h"
-#include "common/CameraDeviceBase.h"
-#include "device2/Camera2Device.h"
-#include "device3/Camera3Device.h"
-
-namespace android {
-
-wp<CameraService> CameraDeviceFactory::sService;
-
-sp<CameraDeviceBase> CameraDeviceFactory::createDevice(int cameraId) {
-
-    sp<CameraService> svc = sService.promote();
-    if (svc == 0) {
-        ALOGE("%s: No service registered", __FUNCTION__);
-        return NULL;
-    }
-
-    int deviceVersion = svc->getDeviceVersion(cameraId, /*facing*/NULL);
-
-    sp<CameraDeviceBase> device;
-
-    switch (deviceVersion) {
-        case CAMERA_DEVICE_API_VERSION_2_0:
-        case CAMERA_DEVICE_API_VERSION_2_1:
-            device = new Camera2Device(cameraId);
-            break;
-        case CAMERA_DEVICE_API_VERSION_3_0:
-        case CAMERA_DEVICE_API_VERSION_3_1:
-        case CAMERA_DEVICE_API_VERSION_3_2:
-        case CAMERA_DEVICE_API_VERSION_3_3:
-            device = new Camera3Device(cameraId);
-            break;
-        default:
-            ALOGE("%s: Camera %d: Unknown HAL device version %d",
-                  __FUNCTION__, cameraId, deviceVersion);
-            device = NULL;
-            break;
-    }
-
-    ALOGV_IF(device != 0, "Created a new camera device for version %d",
-                          deviceVersion);
-
-    return device;
-}
-
-void CameraDeviceFactory::registerService(wp<CameraService> service) {
-    ALOGV("%s: Registered service %p", __FUNCTION__,
-          service.promote().get());
-
-    sService = service;
-}
-
-}; // namespace android
diff --git a/services/camera/libcameraservice/CameraDeviceFactory.h b/services/camera/libcameraservice/CameraDeviceFactory.h
deleted file mode 100644
index 236dc56..0000000
--- a/services/camera/libcameraservice/CameraDeviceFactory.h
+++ /dev/null
@@ -1,45 +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_CAMERA_CAMERADEVICEFACTORY_H
-#define ANDROID_SERVERS_CAMERA_CAMERADEVICEFACTORY_H
-
-#include <utils/RefBase.h>
-
-namespace android {
-
-class CameraDeviceBase;
-class CameraService;
-
-/**
- * Create the right instance of Camera2Device or Camera3Device
- * automatically based on the device version.
- */
-class CameraDeviceFactory : public virtual RefBase {
-  public:
-    static void registerService(wp<CameraService> service);
-
-    // Prerequisite: Call registerService.
-    static sp<CameraDeviceBase> createDevice(int cameraId);
-  private:
-    CameraDeviceFactory(wp<CameraService> service);
-
-    static wp<CameraService> sService;
-};
-
-}; // namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
index 406c1c4..0afd945 100644
--- a/services/camera/libcameraservice/CameraFlashlight.cpp
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -27,7 +27,7 @@
 #include "gui/IGraphicBufferConsumer.h"
 #include "gui/BufferQueue.h"
 #include "camera/camera2/CaptureRequest.h"
-#include "CameraDeviceFactory.h"
+#include "device3/Camera3Device.h"
 
 
 namespace android {
@@ -78,7 +78,7 @@
             deviceVersion = info.device_version;
         }
 
-        if (deviceVersion >= CAMERA_DEVICE_API_VERSION_2_0) {
+        if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_0) {
             CameraDeviceClientFlashControl *flashControl =
                     new CameraDeviceClientFlashControl(*mCameraModule,
                                                        *mCallbacks);
@@ -193,8 +193,6 @@
 }
 
 bool CameraFlashlight::hasFlashUnit(const String8& cameraId) {
-    status_t res;
-
     Mutex::Autolock l(mLock);
     return hasFlashUnitLocked(cameraId);
 }
@@ -302,7 +300,8 @@
 /////////////////////////////////////////////////////////////////////
 ModuleFlashControl::ModuleFlashControl(CameraModule& cameraModule,
         const camera_module_callbacks_t& callbacks) :
-    mCameraModule(&cameraModule) {
+        mCameraModule(&cameraModule) {
+    (void) callbacks;
 }
 
 ModuleFlashControl::~ModuleFlashControl() {
@@ -478,7 +477,7 @@
     }
 
     sp<CameraDeviceBase> device =
-            CameraDeviceFactory::createDevice(atoi(cameraId.string()));
+            new Camera3Device(atoi(cameraId.string()));
     if (device == NULL) {
         return NO_MEMORY;
     }
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 1cf1512..ea19aa2 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -46,6 +46,7 @@
 #include <utils/Log.h>
 #include <utils/String16.h>
 #include <utils/Trace.h>
+#include <private/android_filesystem_config.h>
 #include <system/camera_vendor_tags.h>
 #include <system/camera_metadata.h>
 #include <system/camera.h>
@@ -55,7 +56,10 @@
 #include "api1/Camera2Client.h"
 #include "api2/CameraDeviceClient.h"
 #include "utils/CameraTraces.h"
-#include "CameraDeviceFactory.h"
+
+namespace {
+    const char* kPermissionServiceName = "permission";
+}; // namespace anonymous
 
 namespace android {
 
@@ -124,8 +128,10 @@
 // should be ok for now.
 static CameraService *gCameraService;
 
-CameraService::CameraService() : mEventLog(DEFAULT_EVENT_LOG_LENGTH), mAllowedUsers(),
-        mSoundRef(0), mModule(0), mFlashlight(0) {
+CameraService::CameraService() :
+        mEventLog(DEFAULT_EVENT_LOG_LENGTH),
+        mSoundRef(0), mModule(nullptr),
+        mNumberOfCameras(0), mNumberOfNormalCameras(0) {
     ALOGI("CameraService started (pid=%d)", getpid());
     gCameraService = this;
 
@@ -152,7 +158,6 @@
     if (err < 0) {
         ALOGE("Could not load camera HAL module: %d (%s)", err, strerror(-err));
         logServiceError("Could not load camera HAL module", err);
-        mNumberOfCameras = 0;
         return;
     }
 
@@ -163,7 +168,6 @@
             strerror(-err));
         logServiceError("Could not initialize camera HAL module", err);
 
-        mNumberOfCameras = 0;
         delete mModule;
         mModule = nullptr;
         return;
@@ -246,8 +250,6 @@
         mModule->setCallbacks(this);
     }
 
-    CameraDeviceFactory::registerService(this);
-
     CameraService::pingCameraServiceProxy();
 }
 
@@ -315,10 +317,8 @@
             clientToDisconnect = removeClientLocked(id);
 
             // Notify the client of disconnection
-            if (clientToDisconnect != nullptr) {
-                clientToDisconnect->notifyError(ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
-                        CaptureResultExtras{});
-            }
+            clientToDisconnect->notifyError(ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
+                    CaptureResultExtras{});
         }
 
         ALOGI("%s: Client for camera ID %s evicted due to device status change from HAL",
@@ -366,7 +366,8 @@
 
     res = setTorchStatusLocked(cameraId, newStatus);
     if (res) {
-        ALOGE("%s: Failed to set the torch status", __FUNCTION__, (uint32_t)newStatus);
+        ALOGE("%s: Failed to set the torch status to %d: %s (%d)", __FUNCTION__,
+                (uint32_t)newStatus, strerror(-res), res);
         return;
     }
 
@@ -483,7 +484,6 @@
     Vector<Size> sizes;
     Vector<Size> jpegSizes;
     Vector<int32_t> formats;
-    const char* supportedPreviewFormats;
     {
         shimParams.getSupportedPreviewSizes(/*out*/sizes);
         shimParams.getSupportedPreviewFormats(/*out*/formats);
@@ -561,7 +561,7 @@
     int facing;
     status_t ret = OK;
     if (mModule->getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_0 ||
-            getDeviceVersion(cameraId, &facing) <= CAMERA_DEVICE_API_VERSION_2_1 ) {
+            getDeviceVersion(cameraId, &facing) < CAMERA_DEVICE_API_VERSION_3_0) {
         /**
          * Backwards compatibility mode for old HALs:
          * - Convert CameraInfo into static CameraMetadata properties.
@@ -727,8 +727,6 @@
                 return -EOPNOTSUPP;
             }
             break;
-          case CAMERA_DEVICE_API_VERSION_2_0:
-          case CAMERA_DEVICE_API_VERSION_2_1:
           case CAMERA_DEVICE_API_VERSION_3_0:
           case CAMERA_DEVICE_API_VERSION_3_1:
           case CAMERA_DEVICE_API_VERSION_3_2:
@@ -786,13 +784,13 @@
 status_t CameraService::initializeShimMetadata(int cameraId) {
     int uid = getCallingUid();
 
-    String16 internalPackageName("media");
+    String16 internalPackageName("cameraserver");
     String8 id = String8::format("%d", cameraId);
     status_t ret = NO_ERROR;
     sp<Client> tmp = nullptr;
     if ((ret = connectHelper<ICameraClient,Client>(sp<ICameraClient>{nullptr}, id,
-            static_cast<int>(CAMERA_HAL_API_VERSION_UNSPECIFIED), internalPackageName, uid, API_1,
-            false, true, tmp)) != NO_ERROR) {
+            static_cast<int>(CAMERA_HAL_API_VERSION_UNSPECIFIED), internalPackageName, uid,
+            USE_CALLING_PID, API_1, false, true, tmp)) != NO_ERROR) {
         ALOGE("%s: Error %d (%s) initializing shim metadata.", __FUNCTION__, ret, strerror(ret));
         return ret;
     }
@@ -859,11 +857,29 @@
     return INVALID_OPERATION;
 }
 
-status_t CameraService::validateConnectLocked(const String8& cameraId, /*inout*/int& clientUid)
-        const {
+// Can camera service trust the caller based on the calling UID?
+static bool isTrustedCallingUid(uid_t uid) {
+    switch (uid) {
+        case AID_MEDIA:         // mediaserver
+        case AID_CAMERASERVER: // cameraserver
+            return true;
+        default:
+            return false;
+    }
+}
+
+status_t CameraService::validateConnectLocked(const String8& cameraId, /*inout*/int& clientUid,
+        /*inout*/int& clientPid) const {
 
     int callingPid = getCallingPid();
 
+#if !defined(__BRILLO__)
+    status_t allowed = validateClientPermissionsLocked(cameraId, clientUid, clientPid);
+    if (allowed != OK) {
+        return allowed;
+    }
+#endif  // defined(__BRILLO__)
+
     if (!mModule) {
         ALOGE("CameraService::connect X (PID %d) rejected (camera HAL module not loaded)",
                 callingPid);
@@ -876,43 +892,45 @@
         return -ENODEV;
     }
 
-#if !defined(__BRILLO__)
-    status_t allowed = validateClientPermissionsLocked(cameraId, clientUid);
-    if (allowed != OK) {
-        return allowed;
-    }
-#endif  // defined(__BRILLO__)
-
     return checkIfDeviceIsUsable(cameraId);
 }
 
-status_t CameraService::validateClientPermissionsLocked(const String8& cameraId, int& clientUid)
-        const {
+status_t CameraService::validateClientPermissionsLocked(const String8& cameraId, int& clientUid,
+        int& clientPid) const {
     int callingPid = getCallingPid();
+    int callingUid = getCallingUid();
 
+    // Check if we can trust clientUid
     if (clientUid == USE_CALLING_UID) {
-        clientUid = getCallingUid();
-    } else {
-        // We only trust our own process to forward client UIDs
-        if (callingPid != getpid()) {
-            ALOGE("CameraService::connect X (PID %d) rejected (don't trust clientUid %d)",
-                    callingPid, clientUid);
-            return PERMISSION_DENIED;
-        }
+        clientUid = callingUid;
+    } else if (!isTrustedCallingUid(callingUid)) {
+        ALOGE("CameraService::connect X (calling PID %d, calling UID %d) rejected "
+                "(don't trust clientUid %d)", callingPid, callingUid, clientUid);
+        return PERMISSION_DENIED;
     }
 
+    // Check if we can trust clientPid
+    if (clientPid == USE_CALLING_PID) {
+        clientPid = callingPid;
+    } else if (!isTrustedCallingUid(callingUid)) {
+        ALOGE("CameraService::connect X (calling PID %d, calling UID %d) rejected "
+                "(don't trust clientPid %d)", callingPid, callingUid, clientPid);
+        return PERMISSION_DENIED;
+    }
+
+    // If it's not calling from cameraserver, check the permission.
+    if (callingPid != getpid() &&
+            !checkPermission(String16("android.permission.CAMERA"), clientPid, clientUid)) {
+        ALOGE("Permission Denial: can't use the camera pid=%d, uid=%d", clientPid, clientUid);
+        return PERMISSION_DENIED;
+    }
+
+    // Only use passed in clientPid to check permission. Use calling PID as the client PID that's
+    // connected to camera service directly.
+    clientPid = callingPid;
+
     // Check device policy for this camera
-    char value[PROPERTY_VALUE_MAX];
-    char key[PROPERTY_KEY_MAX];
     userid_t clientUserId = multiuser_get_user_id(clientUid);
-    snprintf(key, PROPERTY_KEY_MAX, "sys.secpolicy.camera.off_%d", clientUserId);
-    property_get(key, value, "0");
-    if (strcmp(value, "1") == 0) {
-        // Camera is disabled by DevicePolicyManager.
-        ALOGE("CameraService::connect X (PID %d) rejected (camera %s is disabled by device "
-                "policy)", callingPid, cameraId.string());
-        return -EACCES;
-    }
 
     // Only allow clients who are being used by the current foreground device user, unless calling
     // from our own process.
@@ -1172,6 +1190,7 @@
         int cameraId,
         const String16& clientPackageName,
         int clientUid,
+        int clientPid,
         /*out*/
         sp<ICamera>& device) {
 
@@ -1180,7 +1199,7 @@
     String8 id = String8::format("%d", cameraId);
     sp<Client> client = nullptr;
     ret = connectHelper<ICameraClient,Client>(cameraClient, id, CAMERA_HAL_API_VERSION_UNSPECIFIED,
-            clientPackageName, clientUid, API_1, false, false, /*out*/client);
+            clientPackageName, clientUid, clientPid, API_1, false, false, /*out*/client);
 
     if(ret != NO_ERROR) {
         logRejected(id, getCallingPid(), String8(clientPackageName),
@@ -1221,7 +1240,7 @@
     status_t ret = NO_ERROR;
     sp<Client> client = nullptr;
     ret = connectHelper<ICameraClient,Client>(cameraClient, id, halVersion, clientPackageName,
-            clientUid, API_1, true, false, /*out*/client);
+            clientUid, USE_CALLING_PID, API_1, true, false, /*out*/client);
 
     if(ret != NO_ERROR) {
         logRejected(id, getCallingPid(), String8(clientPackageName),
@@ -1246,8 +1265,8 @@
     String8 id = String8::format("%d", cameraId);
     sp<CameraDeviceClient> client = nullptr;
     ret = connectHelper<ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
-            CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, API_2, false, false,
-            /*out*/client);
+            CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, USE_CALLING_PID,
+            API_2, false, false, /*out*/client);
 
     if(ret != NO_ERROR) {
         logRejected(id, getCallingPid(), String8(clientPackageName),
@@ -1333,7 +1352,6 @@
         // update the link to client's death
         Mutex::Autolock al(mTorchClientMapMutex);
         ssize_t index = mTorchClientMap.indexOfKey(id);
-        BatteryNotifier& notifier(BatteryNotifier::getInstance());
         if (enabled) {
             if (index == NAME_NOT_FOUND) {
                 mTorchClientMap.add(id, clientBinder);
@@ -1490,8 +1508,6 @@
 
     switch(deviceVersion) {
       case CAMERA_DEVICE_API_VERSION_1_0:
-      case CAMERA_DEVICE_API_VERSION_2_0:
-      case CAMERA_DEVICE_API_VERSION_2_1:
       case CAMERA_DEVICE_API_VERSION_3_0:
       case CAMERA_DEVICE_API_VERSION_3_1:
         if (apiVersion == API_VERSION_2) {
@@ -1582,8 +1598,34 @@
 
 /**
  * Check camera capabilities, such as support for basic color operation
+ * Also check that the device HAL version is still in support
  */
 int CameraService::checkCameraCapabilities(int id, camera_info info, int *latestStrangeCameraId) {
+    // device_version undefined in CAMERA_MODULE_API_VERSION_1_0,
+    // All CAMERA_MODULE_API_VERSION_1_0 devices are backward-compatible
+    if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_0) {
+        // Verify the device version is in the supported range
+        switch (info.device_version) {
+            case CAMERA_DEVICE_API_VERSION_1_0:
+            case CAMERA_DEVICE_API_VERSION_3_0:
+            case CAMERA_DEVICE_API_VERSION_3_1:
+            case CAMERA_DEVICE_API_VERSION_3_2:
+            case CAMERA_DEVICE_API_VERSION_3_3:
+                // in support
+                break;
+            case CAMERA_DEVICE_API_VERSION_2_0:
+            case CAMERA_DEVICE_API_VERSION_2_1:
+                // no longer supported
+            default:
+                ALOGE("%s: Device %d has HAL version %x, which is not supported",
+                        __FUNCTION__, id, info.device_version);
+                String8 msg = String8::format(
+                        "Unsupported device HAL version %x for device %d",
+                        info.device_version, id);
+                logServiceError(msg.string(), NO_INIT);
+                return NO_INIT;
+        }
+    }
 
     // Assume all devices pre-v3.3 are backward-compatible
     bool isBackwardCompatible = true;
@@ -1618,10 +1660,10 @@
             ALOGE("%s: Normal camera ID %d higher than strange camera ID %d. "
                     "This is not allowed due backward-compatibility requirements",
                     __FUNCTION__, id, *latestStrangeCameraId);
-            logServiceError("Invalid order of camera devices", ENODEV);
+            logServiceError("Invalid order of camera devices", NO_INIT);
             mNumberOfCameras = 0;
             mNumberOfNormalCameras = 0;
-            return INVALID_OPERATION;
+            return NO_INIT;
         }
     }
     return OK;
@@ -1779,7 +1821,7 @@
 
 void CameraService::logServiceError(const char* msg, int errorCode) {
     String8 curTime = getFormattedCurrentTime();
-    logEvent(String8::format("SERVICE ERROR: %s : %d (%s)", msg, errorCode, strerror(errorCode)));
+    logEvent(String8::format("SERVICE ERROR: %s : %d (%s)", msg, errorCode, strerror(-errorCode)));
 }
 
 status_t CameraService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
@@ -1790,21 +1832,6 @@
 
     // Permission checks
     switch (code) {
-        case BnCameraService::CONNECT:
-        case BnCameraService::CONNECT_DEVICE:
-        case BnCameraService::CONNECT_LEGACY: {
-            if (pid != selfPid) {
-                // we're called from a different process, do the real check
-                if (!checkCallingPermission(
-                        String16("android.permission.CAMERA"))) {
-                    const int uid = getCallingUid();
-                    ALOGE("Permission Denial: "
-                         "can't use the camera pid=%d, uid=%d", pid, uid);
-                    return PERMISSION_DENIED;
-                }
-            }
-            break;
-        }
         case BnCameraService::NOTIFY_SYSTEM_EVENT: {
             if (pid != selfPid) {
                 // Ensure we're being called by system_server, or similar process with
@@ -1929,6 +1956,37 @@
     mServicePid = servicePid;
     mOpsActive = false;
     mDestructionStarted = false;
+
+    // In some cases the calling code has no access to the package it runs under.
+    // For example, NDK camera API.
+    // In this case we will get the packages for the calling UID and pick the first one
+    // for attributing the app op. This will work correctly for runtime permissions
+    // as for legacy apps we will toggle the app op for all packages in the UID.
+    // The caveat is that the operation may be attributed to the wrong package and
+    // stats based on app ops may be slightly off.
+    if (mClientPackageName.size() <= 0) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder = sm->getService(String16(kPermissionServiceName));
+        if (binder == 0) {
+            ALOGE("Cannot get permission service");
+            // Leave mClientPackageName unchanged (empty) and the further interaction
+            // with camera will fail in BasicClient::startCameraOps
+            return;
+        }
+
+        sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder);
+        Vector<String16> packages;
+
+        permCtrl->getPackagesForUid(mClientUid, packages);
+
+        if (packages.isEmpty()) {
+            ALOGE("No packages for calling UID");
+            // Leave mClientPackageName unchanged (empty) and the further interaction
+            // with camera will fail in BasicClient::startCameraOps
+            return;
+        }
+        mClientPackageName = packages[0];
+    }
 }
 
 CameraService::BasicClient::~BasicClient() {
@@ -1958,6 +2016,14 @@
     mClientPid = 0;
 }
 
+status_t CameraService::BasicClient::dump(int, const Vector<String16>&) {
+    // No dumping of clients directly over Binder,
+    // must go through CameraService::dump
+    android_errorWriteWithInfoLog(SN_EVENT_LOG_ID, "26265403",
+            IPCThreadState::self()->getCallingUid(), NULL, 0);
+    return OK;
+}
+
 String16 CameraService::BasicClient::getPackageName() const {
     return mClientPackageName;
 }
@@ -2100,6 +2166,8 @@
 
 void CameraService::Client::notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
         const CaptureResultExtras& resultExtras) {
+    (void) errorCode;
+    (void) resultExtras;
     if (mRemoteCallback != NULL) {
         mRemoteCallback->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0);
     } else {
@@ -2317,6 +2385,7 @@
         result.appendFormat("Camera module name: %s\n", mModule->getModuleName());
         result.appendFormat("Camera module author: %s\n", mModule->getModuleAuthor());
         result.appendFormat("Number of camera devices: %d\n", mNumberOfCameras);
+        result.appendFormat("Number of normal camera devices: %d\n", mNumberOfNormalCameras);
         String8 activeClientString = mActiveClientManager.toString();
         result.appendFormat("Active Camera Clients:\n%s", activeClientString.string());
         result.appendFormat("Allowed users:\n%s\n", toString(mAllowedUsers).string());
@@ -2375,7 +2444,7 @@
                 result.appendFormat("\n");
 
                 result.appendFormat("  Device version: %#x\n", deviceVersion);
-                if (deviceVersion >= CAMERA_DEVICE_API_VERSION_2_0) {
+                if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_0) {
                     result.appendFormat("  Device static metadata:\n");
                     write(fd, result.string(), result.size());
                     dump_indented_camera_metadata(info.static_camera_characteristics,
@@ -2410,7 +2479,7 @@
                     String8(client->getPackageName()).string());
             write(fd, result.string(), result.size());
 
-            client->dump(fd, args);
+            client->dumpClient(fd, args);
         }
 
         if (stateLocked) mCameraStatesLock.unlock();
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 13f6f82..5616838 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -87,6 +87,9 @@
     // Default number of messages to store in eviction log
     static const size_t DEFAULT_EVENT_LOG_LENGTH = 100;
 
+    // Event log ID
+    static const int SN_EVENT_LOG_ID = 0x534e4554;
+
     // Implementation of BinderService<T>
     static char const* getServiceName() { return "media.camera"; }
 
@@ -113,7 +116,7 @@
     virtual status_t    getCameraVendorTagDescriptor(/*out*/ sp<VendorTagDescriptor>& desc);
 
     virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
-            const String16& clientPackageName, int clientUid,
+            const String16& clientPackageName, int clientUid, int clientPid,
             /*out*/
             sp<ICamera>& device);
 
@@ -201,7 +204,10 @@
             return mRemoteBinder;
         }
 
-        virtual status_t    dump(int fd, const Vector<String16>& args) = 0;
+        // Disallows dumping over binder interface
+        virtual status_t      dump(int fd, const Vector<String16>& args);
+        // Internal dump method to be called by CameraService
+        virtual status_t      dumpClient(int fd, const Vector<String16>& args) = 0;
 
         // Return the package name for this client
         virtual String16 getPackageName() const;
@@ -238,13 +244,13 @@
         bool                            mDestructionStarted;
 
         // these are initialized in the constructor.
-        sp<CameraService>               mCameraService;  // immutable after constructor
-        int                             mCameraId;       // immutable after constructor
-        int                             mCameraFacing;   // immutable after constructor
-        const String16                  mClientPackageName;
+        sp<CameraService>               mCameraService;     // immutable after constructor
+        int                             mCameraId;          // immutable after constructor
+        int                             mCameraFacing;      // immutable after constructor
+        String16                        mClientPackageName; // immutable after constructor
         pid_t                           mClientPid;
-        uid_t                           mClientUid;      // immutable after constructor
-        pid_t                           mServicePid;     // immutable after constructor
+        uid_t                           mClientUid;         // immutable after constructor
+        pid_t                           mServicePid;        // immutable after constructor
         bool                            mDisconnected;
 
         // - The app-side Binder interface to receive callbacks from us
@@ -293,7 +299,7 @@
         virtual status_t      startPreview() = 0;
         virtual void          stopPreview() = 0;
         virtual bool          previewEnabled() = 0;
-        virtual status_t      storeMetaDataInBuffers(bool enabled) = 0;
+        virtual status_t      setVideoBufferMode(int32_t videoBufferMode) = 0;
         virtual status_t      startRecording() = 0;
         virtual void          stopRecording() = 0;
         virtual bool          recordingEnabled() = 0;
@@ -304,6 +310,7 @@
         virtual status_t      setParameters(const String8& params) = 0;
         virtual String8       getParameters() const = 0;
         virtual status_t      sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) = 0;
+        virtual status_t      setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer) = 0;
 
         // Interface used by CameraService
         Client(const sp<CameraService>& cameraService,
@@ -481,8 +488,10 @@
     virtual void onFirstRef();
 
     // Check if we can connect, before we acquire the service lock.
-    status_t validateConnectLocked(const String8& cameraId, /*inout*/int& clientUid) const;
-    status_t validateClientPermissionsLocked(const String8& cameraId, /*inout*/int& clientUid) const;
+    status_t validateConnectLocked(const String8& cameraId, /*inout*/int& clientUid,
+            /*inout*/int& clientPid) const;
+    status_t validateClientPermissionsLocked(const String8& cameraId, /*inout*/int& clientUid,
+            /*inout*/int& clientPid) const;
 
     // Handle active client evictions, and update service state.
     // Only call with with mServiceLock held.
@@ -495,8 +504,9 @@
     // Single implementation shared between the various connect calls
     template<class CALLBACK, class CLIENT>
     status_t connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId, int halVersion,
-            const String16& clientPackageName, int clientUid, apiLevel effectiveApiLevel,
-            bool legacyMode, bool shimUpdateOnly, /*out*/sp<CLIENT>& device);
+            const String16& clientPackageName, int clientUid, int clientPid,
+            apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
+            /*out*/sp<CLIENT>& device);
 
     // Lock guarding camera service state
     Mutex               mServiceLock;
@@ -621,6 +631,7 @@
 
     /**
      * Add a event log message that a serious service-level error has occured
+     * The errorCode should be one of the Android Errors
      */
     void logServiceError(const char* msg, int errorCode);
 
@@ -794,12 +805,11 @@
 
 template<class CALLBACK, class CLIENT>
 status_t CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
-        int halVersion, const String16& clientPackageName, int clientUid,
+        int halVersion, const String16& clientPackageName, int clientUid, int clientPid,
         apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
         /*out*/sp<CLIENT>& device) {
     status_t ret = NO_ERROR;
     String8 clientName8(clientPackageName);
-    int clientPid = getCallingPid();
 
     ALOGI("CameraService::connect call (PID %d \"%s\", camera ID %s) for HAL version %s and "
             "Camera API version %d", clientPid, clientName8.string(), cameraId.string(),
@@ -819,7 +829,8 @@
         }
 
         // Enforce client permissions and do basic sanity checks
-        if((ret = validateConnectLocked(cameraId, /*inout*/clientUid)) != NO_ERROR) {
+        if((ret = validateConnectLocked(cameraId, /*inout*/clientUid, /*inout*/clientPid)) !=
+                NO_ERROR) {
             return ret;
         }
 
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 4338d64..5ac5743 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -32,7 +32,6 @@
 #include "api1/client2/CaptureSequencer.h"
 #include "api1/client2/CallbackProcessor.h"
 #include "api1/client2/ZslProcessor.h"
-#include "api1/client2/ZslProcessor3.h"
 
 #define ALOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
 #define ALOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
@@ -94,7 +93,6 @@
     mStreamingProcessor = new StreamingProcessor(this);
     threadName = String8::format("C2-%d-StreamProc",
             mCameraId);
-    mStreamingProcessor->run(threadName.string());
 
     mFrameProcessor = new FrameProcessor(mDevice, this);
     threadName = String8::format("C2-%d-FrameProc",
@@ -111,30 +109,11 @@
             mCameraId);
     mJpegProcessor->run(threadName.string());
 
-    switch (mDeviceVersion) {
-        case CAMERA_DEVICE_API_VERSION_2_0: {
-            sp<ZslProcessor> zslProc =
-                    new ZslProcessor(this, mCaptureSequencer);
-            mZslProcessor = zslProc;
-            mZslProcessorThread = zslProc;
-            break;
-        }
-        case CAMERA_DEVICE_API_VERSION_3_0:
-        case CAMERA_DEVICE_API_VERSION_3_1:
-        case CAMERA_DEVICE_API_VERSION_3_2:
-        case CAMERA_DEVICE_API_VERSION_3_3: {
-            sp<ZslProcessor3> zslProc =
-                    new ZslProcessor3(this, mCaptureSequencer);
-            mZslProcessor = zslProc;
-            mZslProcessorThread = zslProc;
-            break;
-        }
-        default:
-            break;
-    }
+    mZslProcessor = new ZslProcessor(this, mCaptureSequencer);
+
     threadName = String8::format("C2-%d-ZslProc",
             mCameraId);
-    mZslProcessorThread->run(threadName.string());
+    mZslProcessor->run(threadName.string());
 
     mCallbackProcessor = new CallbackProcessor(this);
     threadName = String8::format("C2-%d-CallbkProc",
@@ -163,6 +142,10 @@
 }
 
 status_t Camera2Client::dump(int fd, const Vector<String16>& args) {
+    return BasicClient::dump(fd, args);
+}
+
+status_t Camera2Client::dumpClient(int fd, const Vector<String16>& args) {
     String8 result;
     result.appendFormat("Client2[%d] (%p) PID: %d, dump:\n", mCameraId,
             (getRemoteCallback() != NULL ?
@@ -388,7 +371,7 @@
     ATRACE_CALL();
     Mutex::Autolock icl(mBinderSerializationLock);
 
-    // Allow both client and the media server to disconnect at all times
+    // Allow both client and the cameraserver to disconnect at all times
     int callingPid = getCallingPid();
     if (callingPid != mClientPid && callingPid != mServicePid) return;
 
@@ -410,11 +393,10 @@
         l.mParameters.state = Parameters::DISCONNECTED;
     }
 
-    mStreamingProcessor->requestExit();
     mFrameProcessor->requestExit();
     mCaptureSequencer->requestExit();
     mJpegProcessor->requestExit();
-    mZslProcessorThread->requestExit();
+    mZslProcessor->requestExit();
     mCallbackProcessor->requestExit();
 
     ALOGV("Camera %d: Waiting for threads", mCameraId);
@@ -424,11 +406,10 @@
         // complete callbacks that re-enter Camera2Client
         mBinderSerializationLock.unlock();
 
-        mStreamingProcessor->join();
         mFrameProcessor->join();
         mCaptureSequencer->join();
         mJpegProcessor->join();
-        mZslProcessorThread->join();
+        mZslProcessor->join();
         mCallbackProcessor->join();
 
         mBinderSerializationLock.lock();
@@ -442,9 +423,6 @@
     mCallbackProcessor->deleteStream();
     mZslProcessor->deleteStream();
 
-    // Remove all ZSL stream state before disconnect; needed to work around b/15408128.
-    mZslProcessor->disconnect();
-
     ALOGV("Camera %d: Disconnecting device", mCameraId);
 
     mDevice->disconnect();
@@ -761,8 +739,8 @@
 
     // We could wait to create the JPEG output stream until first actual use
     // (first takePicture call). However, this would substantially increase the
-    // first capture latency on HAL3 devices, and potentially on some HAL2
-    // devices. So create it unconditionally at preview start. As a drawback,
+    // first capture latency on HAL3 devices.
+    // So create it unconditionally at preview start. As a drawback,
     // this increases gralloc memory consumption for applications that don't
     // ever take a picture. Do not enter this mode when jpeg stream will slow
     // down preview.
@@ -967,7 +945,7 @@
     return l.mParameters.state == Parameters::PREVIEW;
 }
 
-status_t Camera2Client::storeMetaDataInBuffers(bool enabled) {
+status_t Camera2Client::setVideoBufferMode(int32_t videoBufferMode) {
     ATRACE_CALL();
     Mutex::Autolock icl(mBinderSerializationLock);
     status_t res;
@@ -986,7 +964,12 @@
             break;
     }
 
-    l.mParameters.storeMetadataInBuffers = enabled;
+    if (videoBufferMode != VIDEO_BUFFER_MODE_BUFFER_QUEUE) {
+        ALOGE("%s: %d: Only video buffer queue is supported", __FUNCTION__, __LINE__);
+        return BAD_VALUE;
+    }
+
+    l.mParameters.videoBufferMode = videoBufferMode;
 
     return OK;
 }
@@ -1032,10 +1015,14 @@
             return INVALID_OPERATION;
     };
 
-    if (!params.storeMetadataInBuffers) {
-        ALOGE("%s: Camera %d: Recording only supported in metadata mode, but "
-                "non-metadata recording mode requested!", __FUNCTION__,
-                mCameraId);
+    if (params.videoBufferMode != VIDEO_BUFFER_MODE_BUFFER_QUEUE) {
+        ALOGE("%s: Camera %d: Recording only supported buffer queue mode, but "
+                "mode %d is requested!", __FUNCTION__, mCameraId, params.videoBufferMode);
+        return INVALID_OPERATION;
+    }
+
+    if (!mStreamingProcessor->haveValidRecordingWindow()) {
+        ALOGE("%s: No valid recording window", __FUNCTION__);
         return INVALID_OPERATION;
     }
 
@@ -1069,35 +1056,33 @@
         }
     }
 
-    // On current HALs, clean up ZSL before transitioning into recording
-    if (mDeviceVersion != CAMERA_DEVICE_API_VERSION_2_0) {
-        if (mZslProcessor->getStreamId() != NO_STREAM) {
-            ALOGV("%s: Camera %d: Clearing out zsl stream before "
-                    "creating recording stream", __FUNCTION__, mCameraId);
-            res = mStreamingProcessor->stopStream();
-            if (res != OK) {
-                ALOGE("%s: Camera %d: Can't stop streaming to delete callback stream",
-                        __FUNCTION__, mCameraId);
-                return res;
-            }
-            res = mDevice->waitUntilDrained();
-            if (res != OK) {
-                ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
-                        __FUNCTION__, mCameraId, strerror(-res), res);
-            }
-            res = mZslProcessor->clearZslQueue();
-            if (res != OK) {
-                ALOGE("%s: Camera %d: Can't clear zsl queue",
-                        __FUNCTION__, mCameraId);
-                return res;
-            }
-            res = mZslProcessor->deleteStream();
-            if (res != OK) {
-                ALOGE("%s: Camera %d: Unable to delete zsl stream before "
-                        "record: %s (%d)", __FUNCTION__, mCameraId,
-                        strerror(-res), res);
-                return res;
-            }
+    // Clean up ZSL before transitioning into recording
+    if (mZslProcessor->getStreamId() != NO_STREAM) {
+        ALOGV("%s: Camera %d: Clearing out zsl stream before "
+                "creating recording stream", __FUNCTION__, mCameraId);
+        res = mStreamingProcessor->stopStream();
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Can't stop streaming to delete callback stream",
+                    __FUNCTION__, mCameraId);
+            return res;
+        }
+        res = mDevice->waitUntilDrained();
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
+                    __FUNCTION__, mCameraId, strerror(-res), res);
+        }
+        res = mZslProcessor->clearZslQueue();
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Can't clear zsl queue",
+                    __FUNCTION__, mCameraId);
+            return res;
+        }
+        res = mZslProcessor->deleteStream();
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Unable to delete zsl stream before "
+                    "record: %s (%d)", __FUNCTION__, mCameraId,
+                    strerror(-res), res);
+            return res;
         }
     }
 
@@ -1105,56 +1090,43 @@
     // and we can't fail record start without stagefright asserting.
     params.previewCallbackFlags = 0;
 
-    if (mDeviceVersion != CAMERA_DEVICE_API_VERSION_2_0) {
-        // For newer devices, may need to reconfigure video snapshot JPEG sizes
-        // during recording startup, so need a more complex sequence here to
-        // ensure an early stream reconfiguration doesn't happen
-        bool recordingStreamNeedsUpdate;
-        res = mStreamingProcessor->recordingStreamNeedsUpdate(params, &recordingStreamNeedsUpdate);
+    // May need to reconfigure video snapshot JPEG sizes
+    // during recording startup, so need a more complex sequence here to
+    // ensure an early stream reconfiguration doesn't happen
+    bool recordingStreamNeedsUpdate;
+    res = mStreamingProcessor->recordingStreamNeedsUpdate(params, &recordingStreamNeedsUpdate);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Can't query recording stream",
+                __FUNCTION__, mCameraId);
+        return res;
+    }
+
+    if (recordingStreamNeedsUpdate) {
+        // Need to stop stream here so updateProcessorStream won't trigger configureStream
+        // Right now camera device cannot handle configureStream failure gracefully
+        // when device is streaming
+        res = mStreamingProcessor->stopStream();
         if (res != OK) {
-            ALOGE("%s: Camera %d: Can't query recording stream",
-                    __FUNCTION__, mCameraId);
+            ALOGE("%s: Camera %d: Can't stop streaming to update record "
+                    "stream", __FUNCTION__, mCameraId);
             return res;
         }
-
-        if (recordingStreamNeedsUpdate) {
-            // Need to stop stream here so updateProcessorStream won't trigger configureStream
-            // Right now camera device cannot handle configureStream failure gracefully
-            // when device is streaming
-            res = mStreamingProcessor->stopStream();
-            if (res != OK) {
-                ALOGE("%s: Camera %d: Can't stop streaming to update record "
-                        "stream", __FUNCTION__, mCameraId);
-                return res;
-            }
-            res = mDevice->waitUntilDrained();
-            if (res != OK) {
-                ALOGE("%s: Camera %d: Waiting to stop streaming failed: "
-                        "%s (%d)", __FUNCTION__, mCameraId,
-                        strerror(-res), res);
-            }
-
-            res = updateProcessorStream<
-                    StreamingProcessor,
-                    &StreamingProcessor::updateRecordingStream>(
-                        mStreamingProcessor,
-                        params);
-            if (res != OK) {
-                ALOGE("%s: Camera %d: Unable to update recording stream: "
-                        "%s (%d)", __FUNCTION__, mCameraId,
-                        strerror(-res), res);
-                return res;
-            }
-        }
-    } else {
-        // Maintain call sequencing for HALv2 devices.
-        res = updateProcessorStream<
-                StreamingProcessor,
-                &StreamingProcessor::updateRecordingStream>(mStreamingProcessor,
-                    params);
+        res = mDevice->waitUntilDrained();
         if (res != OK) {
-            ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)",
-                    __FUNCTION__, mCameraId, strerror(-res), res);
+            ALOGE("%s: Camera %d: Waiting to stop streaming failed: "
+                    "%s (%d)", __FUNCTION__, mCameraId,
+                    strerror(-res), res);
+        }
+
+        res = updateProcessorStream<
+            StreamingProcessor,
+            &StreamingProcessor::updateRecordingStream>(
+                                                        mStreamingProcessor,
+                                                        params);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Unable to update recording stream: "
+                    "%s (%d)", __FUNCTION__, mCameraId,
+                    strerror(-res), res);
             return res;
         }
     }
@@ -1214,28 +1186,28 @@
 
     mCameraService->playSound(CameraService::SOUND_RECORDING_STOP);
 
-    // Remove recording stream to prevent it from slowing down takePicture later
-    if (!l.mParameters.recordingHint && l.mParameters.isJpegSizeOverridden()) {
-        res = stopStream();
-        if (res != OK) {
-            ALOGE("%s: Camera %d: Can't stop streaming: %s (%d)",
-                    __FUNCTION__, mCameraId, strerror(-res), res);
-        }
-        res = mDevice->waitUntilDrained();
-        if (res != OK) {
-            ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
-                    __FUNCTION__, mCameraId, strerror(-res), res);
-        }
-        // Clean up recording stream
-        res = mStreamingProcessor->deleteRecordingStream();
-        if (res != OK) {
-            ALOGE("%s: Camera %d: Unable to delete recording stream before "
-                    "stop preview: %s (%d)",
-                    __FUNCTION__, mCameraId, strerror(-res), res);
-        }
-        l.mParameters.recoverOverriddenJpegSize();
+    // Remove recording stream because the video target may be abandoned soon.
+    res = stopStream();
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Can't stop streaming: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
     }
 
+    res = mDevice->waitUntilDrained();
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+    }
+    // Clean up recording stream
+    res = mStreamingProcessor->deleteRecordingStream();
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to delete recording stream before "
+                "stop preview: %s (%d)",
+                __FUNCTION__, mCameraId, strerror(-res), res);
+    }
+    l.mParameters.recoverOverriddenJpegSize();
+
+    // Restart preview
     res = startPreviewL(l.mParameters, true);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to return to preview",
@@ -1261,11 +1233,9 @@
 }
 
 void Camera2Client::releaseRecordingFrame(const sp<IMemory>& mem) {
+    (void)mem;
     ATRACE_CALL();
-    Mutex::Autolock icl(mBinderSerializationLock);
-    if ( checkPid(__FUNCTION__) != OK) return;
-
-    mStreamingProcessor->releaseRecordingFrame(mem);
+    ALOGW("%s: Not supported in buffer queue mode.", __FUNCTION__);
 }
 
 status_t Camera2Client::autoFocus() {
@@ -1567,10 +1537,10 @@
         case CAMERA_CMD_PING:
             return commandPingL();
         case CAMERA_CMD_SET_VIDEO_BUFFER_COUNT:
-            return commandSetVideoBufferCountL(arg1);
         case CAMERA_CMD_SET_VIDEO_FORMAT:
-            return commandSetVideoFormatL(arg1,
-                    static_cast<android_dataspace>(arg2));
+            ALOGE("%s: command %d (arguments %d, %d) is not supported.",
+                    __FUNCTION__, cmd, arg1, arg2);
+            return BAD_VALUE;
         default:
             ALOGE("%s: Unknown command %d (arguments %d, %d)",
                     __FUNCTION__, cmd, arg1, arg2);
@@ -1712,27 +1682,6 @@
     }
 }
 
-status_t Camera2Client::commandSetVideoBufferCountL(size_t count) {
-    if (recordingEnabledL()) {
-        ALOGE("%s: Camera %d: Error setting video buffer count after "
-                "recording was started", __FUNCTION__, mCameraId);
-        return INVALID_OPERATION;
-    }
-
-    return mStreamingProcessor->setRecordingBufferCount(count);
-}
-
-status_t Camera2Client::commandSetVideoFormatL(int format,
-        android_dataspace dataspace) {
-    if (recordingEnabledL()) {
-        ALOGE("%s: Camera %d: Error setting video format after "
-                "recording was started", __FUNCTION__, mCameraId);
-        return INVALID_OPERATION;
-    }
-
-    return mStreamingProcessor->setRecordingFormat(format, dataspace);
-}
-
 void Camera2Client::notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
         const CaptureResultExtras& resultExtras) {
     int32_t err = CAMERA_ERROR_UNKNOWN;
@@ -2156,6 +2105,84 @@
     return res;
 }
 
+status_t Camera2Client::setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer) {
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock icl(mBinderSerializationLock);
+    status_t res;
+    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+    sp<IBinder> binder = IInterface::asBinder(bufferProducer);
+    if (binder == mVideoSurface) {
+        ALOGV("%s: Camera %d: New video window is same as old video window",
+                __FUNCTION__, mCameraId);
+        return NO_ERROR;
+    }
+
+    sp<Surface> window;
+    int format;
+    android_dataspace dataSpace;
+
+    if (bufferProducer != nullptr) {
+        // Using controlledByApp flag to ensure that the buffer queue remains in
+        // async mode for the old camera API, where many applications depend
+        // on that behavior.
+        window = new Surface(bufferProducer, /*controlledByApp*/ true);
+
+        ANativeWindow *anw = window.get();
+
+        if ((res = anw->query(anw, NATIVE_WINDOW_FORMAT, &format)) != OK) {
+            ALOGE("%s: Failed to query Surface format", __FUNCTION__);
+            return res;
+        }
+
+        if ((res = anw->query(anw, NATIVE_WINDOW_DEFAULT_DATASPACE,
+                                reinterpret_cast<int*>(&dataSpace))) != OK) {
+            ALOGE("%s: Failed to query Surface dataSpace", __FUNCTION__);
+            return res;
+        }
+    }
+
+    Parameters::State state;
+    {
+        SharedParameters::Lock l(mParameters);
+        state = l.mParameters.state;
+    }
+
+    switch (state) {
+        case Parameters::STOPPED:
+        case Parameters::WAITING_FOR_PREVIEW_WINDOW:
+        case Parameters::PREVIEW:
+            // OK
+            break;
+        case Parameters::DISCONNECTED:
+        case Parameters::RECORD:
+        case Parameters::STILL_CAPTURE:
+        case Parameters::VIDEO_SNAPSHOT:
+        default:
+            ALOGE("%s: Camera %d: Cannot set video target while in state %s",
+                    __FUNCTION__, mCameraId,
+                    Parameters::getStateName(state));
+            return INVALID_OPERATION;
+    }
+
+    mVideoSurface = binder;
+    res = mStreamingProcessor->setRecordingWindow(window);
+    if (res != OK) {
+        ALOGE("%s: Unable to set new recording window: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return res;
+    }
+
+    {
+        SharedParameters::Lock l(mParameters);
+        l.mParameters.videoFormat = format;
+        l.mParameters.videoDataSpace = dataSpace;
+    }
+
+    return OK;
+}
+
 const char* Camera2Client::kAutofocusLabel = "autofocus";
 const char* Camera2Client::kTakepictureLabel = "take_picture";
 
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index d50bf63..9155e43 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -24,7 +24,7 @@
 #include "api1/client2/FrameProcessor.h"
 //#include "api1/client2/StreamingProcessor.h"
 //#include "api1/client2/JpegProcessor.h"
-//#include "api1/client2/ZslProcessorInterface.h"
+//#include "api1/client2/ZslProcessor.h"
 //#include "api1/client2/CaptureSequencer.h"
 //#include "api1/client2/CallbackProcessor.h"
 
@@ -34,7 +34,7 @@
 
 class StreamingProcessor;
 class JpegProcessor;
-class ZslProcessorInterface;
+class ZslProcessor;
 class CaptureSequencer;
 class CallbackProcessor;
 
@@ -43,7 +43,7 @@
 class IMemory;
 /**
  * Interface between android.hardware.Camera API and Camera HAL device for versions
- * CAMERA_DEVICE_API_VERSION_2_0 and 3_0.
+ * CAMERA_DEVICE_API_VERSION_3_0 and above.
  */
 class Camera2Client :
         public Camera2ClientBase<CameraService::Client>
@@ -66,7 +66,7 @@
     virtual status_t        startPreview();
     virtual void            stopPreview();
     virtual bool            previewEnabled();
-    virtual status_t        storeMetaDataInBuffers(bool enabled);
+    virtual status_t        setVideoBufferMode(int32_t videoBufferMode);
     virtual status_t        startRecording();
     virtual void            stopRecording();
     virtual bool            recordingEnabled();
@@ -79,6 +79,7 @@
     virtual status_t        sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
     virtual void            notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
                                         const CaptureResultExtras& resultExtras);
+    virtual status_t        setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer);
 
     /**
      * Interface used by CameraService
@@ -100,6 +101,8 @@
 
     virtual status_t dump(int fd, const Vector<String16>& args);
 
+    virtual status_t dumpClient(int fd, const Vector<String16>& args);
+
     /**
      * Interface used by CameraDeviceBase
      */
@@ -194,6 +197,7 @@
     /* Preview/Recording related members */
 
     sp<IBinder> mPreviewSurface;
+    sp<IBinder> mVideoSurface;
     sp<camera2::StreamingProcessor> mStreamingProcessor;
 
     /** Preview callback related members */
@@ -204,12 +208,7 @@
 
     sp<camera2::CaptureSequencer> mCaptureSequencer;
     sp<camera2::JpegProcessor> mJpegProcessor;
-    sp<camera2::ZslProcessorInterface> mZslProcessor;
-    sp<Thread> mZslProcessorThread;
-
-    /** Notification-related members */
-
-    bool mAfInMotion;
+    sp<camera2::ZslProcessor> mZslProcessor;
 
     /** Utility members */
     bool mLegacyMode;
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index 4153658..8ab9a65 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -108,6 +108,10 @@
 }
 
 status_t CameraClient::dump(int fd, const Vector<String16>& args) {
+    return BasicClient::dump(fd, args);
+}
+
+status_t CameraClient::dumpClient(int fd, const Vector<String16>& args) {
     const size_t SIZE = 256;
     char buffer[SIZE];
 
@@ -230,7 +234,7 @@
     LOG1("disconnect E (pid %d)", callingPid);
     Mutex::Autolock lock(mLock);
 
-    // Allow both client and the media server to disconnect at all times
+    // Allow both client and the cameraserver to disconnect at all times
     if (callingPid != mClientPid && callingPid != mServicePid) {
         ALOGW("different client - don't disconnect");
         return;
@@ -291,9 +295,8 @@
     // If preview has been already started, register preview buffers now.
     if (mHardware->previewEnabled()) {
         if (window != 0) {
-            native_window_set_scaling_mode(window.get(),
-                    NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
-            native_window_set_buffers_transform(window.get(), mOrientation);
+            mHardware->setPreviewScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+            mHardware->setPreviewTransform(mOrientation);
             result = mHardware->setPreviewWindow(window);
         }
     }
@@ -400,10 +403,9 @@
     }
 
     if (mPreviewWindow != 0) {
-        native_window_set_scaling_mode(mPreviewWindow.get(),
-                NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
-        native_window_set_buffers_transform(mPreviewWindow.get(),
-                mOrientation);
+        mHardware->setPreviewScalingMode(
+            NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        mHardware->setPreviewTransform(mOrientation);
     }
     mHardware->setPreviewWindow(mPreviewWindow);
     result = mHardware->startPreview();
@@ -477,14 +479,24 @@
     mHardware->releaseRecordingFrame(mem);
 }
 
-status_t CameraClient::storeMetaDataInBuffers(bool enabled)
-{
-    LOG1("storeMetaDataInBuffers: %s", enabled? "true": "false");
+status_t CameraClient::setVideoBufferMode(int32_t videoBufferMode) {
+    LOG1("setVideoBufferMode: %d", videoBufferMode);
+    bool enableMetadataInBuffers = false;
+
+    if (videoBufferMode == VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA) {
+        enableMetadataInBuffers = true;
+    } else if (videoBufferMode != VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV) {
+        ALOGE("%s: %d: videoBufferMode %d is not supported.", __FUNCTION__, __LINE__,
+                videoBufferMode);
+        return BAD_VALUE;
+    }
+
     Mutex::Autolock lock(mLock);
     if (checkPidAndHardware() != NO_ERROR) {
         return UNKNOWN_ERROR;
     }
-    return mHardware->storeMetaDataInBuffers(enabled);
+
+    return mHardware->storeMetaDataInBuffers(enableMetadataInBuffers);
 }
 
 bool CameraClient::previewEnabled() {
@@ -627,8 +639,7 @@
         if (mOrientation != orientation) {
             mOrientation = orientation;
             if (mPreviewWindow != 0) {
-                native_window_set_buffers_transform(mPreviewWindow.get(),
-                        mOrientation);
+                mHardware->setPreviewTransform(mOrientation);
             }
         }
         return OK;
@@ -986,4 +997,10 @@
     return -1;
 }
 
+status_t CameraClient::setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer) {
+    (void)bufferProducer;
+    ALOGE("%s: %d: CameraClient doesn't support setting a video target.", __FUNCTION__, __LINE__);
+    return INVALID_OPERATION;
+}
+
 }; // namespace android
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 95616b2..9b32774 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -44,7 +44,7 @@
     virtual status_t        startPreview();
     virtual void            stopPreview();
     virtual bool            previewEnabled();
-    virtual status_t        storeMetaDataInBuffers(bool enabled);
+    virtual status_t        setVideoBufferMode(int32_t videoBufferMode);
     virtual status_t        startRecording();
     virtual void            stopRecording();
     virtual bool            recordingEnabled();
@@ -55,6 +55,7 @@
     virtual status_t        setParameters(const String8& params);
     virtual String8         getParameters() const;
     virtual status_t        sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
+    virtual status_t        setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer);
 
     // Interface used by CameraService
     CameraClient(const sp<CameraService>& cameraService,
@@ -70,7 +71,9 @@
 
     status_t initialize(CameraModule *module);
 
-    status_t dump(int fd, const Vector<String16>& args);
+    virtual status_t dump(int fd, const Vector<String16>& args);
+
+    virtual status_t dumpClient(int fd, const Vector<String16>& args);
 
 private:
 
diff --git a/services/camera/libcameraservice/api1/client2/BurstCapture.cpp b/services/camera/libcameraservice/api1/client2/BurstCapture.cpp
deleted file mode 100644
index 5502dcb..0000000
--- a/services/camera/libcameraservice/api1/client2/BurstCapture.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2012 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 "Camera2-BurstCapture"
-
-#include <utils/Log.h>
-#include <utils/Trace.h>
-
-#include "BurstCapture.h"
-
-#include "api1/Camera2Client.h"
-#include "api1/client2/JpegCompressor.h"
-
-namespace android {
-namespace camera2 {
-
-BurstCapture::BurstCapture(wp<Camera2Client> client, wp<CaptureSequencer> sequencer):
-    mCaptureStreamId(NO_STREAM),
-    mClient(client),
-    mSequencer(sequencer)
-{
-}
-
-BurstCapture::~BurstCapture() {
-}
-
-status_t BurstCapture::start(Vector<CameraMetadata> &/*metadatas*/,
-                             int32_t /*firstCaptureId*/) {
-    ALOGE("Not completely implemented");
-    return INVALID_OPERATION;
-}
-
-void BurstCapture::onFrameAvailable(const BufferItem &/*item*/) {
-    ALOGV("%s", __FUNCTION__);
-    Mutex::Autolock l(mInputMutex);
-    if(!mInputChanged) {
-        mInputChanged = true;
-        mInputSignal.signal();
-    }
-}
-
-bool BurstCapture::threadLoop() {
-    status_t res;
-    {
-        Mutex::Autolock l(mInputMutex);
-        while(!mInputChanged) {
-            res = mInputSignal.waitRelative(mInputMutex, kWaitDuration);
-            if(res == TIMED_OUT) return true;
-        }
-        mInputChanged = false;
-    }
-
-    do {
-        sp<Camera2Client> client = mClient.promote();
-        if(client == 0) return false;
-        ALOGV("%s: Calling processFrameAvailable()", __FUNCTION__);
-        res = processFrameAvailable(client);
-    } while(res == OK);
-
-    return true;
-}
-
-CpuConsumer::LockedBuffer* BurstCapture::jpegEncode(
-    CpuConsumer::LockedBuffer *imgBuffer,
-    int /*quality*/)
-{
-    ALOGV("%s", __FUNCTION__);
-
-    CpuConsumer::LockedBuffer *imgEncoded = new CpuConsumer::LockedBuffer;
-    uint8_t *data = new uint8_t[ANDROID_JPEG_MAX_SIZE];
-    imgEncoded->data = data;
-    imgEncoded->width = imgBuffer->width;
-    imgEncoded->height = imgBuffer->height;
-    imgEncoded->stride = imgBuffer->stride;
-
-    Vector<CpuConsumer::LockedBuffer*> buffers;
-    buffers.push_back(imgBuffer);
-    buffers.push_back(imgEncoded);
-
-    sp<JpegCompressor> jpeg = new JpegCompressor();
-    jpeg->start(buffers, 1);
-
-    bool success = jpeg->waitForDone(10 * 1e9);
-    if(success) {
-        return buffers[1];
-    }
-    else {
-        ALOGE("%s: JPEG encode timed out", __FUNCTION__);
-        return NULL;  // TODO: maybe change function return value to status_t
-    }
-}
-
-status_t BurstCapture::processFrameAvailable(sp<Camera2Client> &/*client*/) {
-    ALOGE("Not implemented");
-    return INVALID_OPERATION;
-}
-
-} // namespace camera2
-} // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/BurstCapture.h b/services/camera/libcameraservice/api1/client2/BurstCapture.h
deleted file mode 100644
index c3b7722..0000000
--- a/services/camera/libcameraservice/api1/client2/BurstCapture.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2012 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_CAMERA_BURST_CAPTURE_H
-#define ANDROID_SERVERS_CAMERA_BURST_CAPTURE_H
-
-#include <camera/CameraMetadata.h>
-#include <binder/MemoryBase.h>
-#include <binder/MemoryHeapBase.h>
-#include <gui/CpuConsumer.h>
-
-#include "device2/Camera2Device.h"
-
-namespace android {
-
-class Camera2Client;
-
-namespace camera2 {
-
-class CaptureSequencer;
-
-class BurstCapture : public virtual Thread,
-                     public virtual CpuConsumer::FrameAvailableListener
-{
-public:
-    BurstCapture(wp<Camera2Client> client, wp<CaptureSequencer> sequencer);
-    virtual ~BurstCapture();
-
-    virtual void onFrameAvailable(const BufferItem& item);
-    virtual status_t start(Vector<CameraMetadata> &metadatas, int32_t firstCaptureId);
-
-protected:
-    Mutex mInputMutex;
-    bool mInputChanged;
-    Condition mInputSignal;
-    int mCaptureStreamId;
-    wp<Camera2Client> mClient;
-    wp<CaptureSequencer> mSequencer;
-
-    // Should only be accessed by processing thread
-    enum {
-        NO_STREAM = -1
-    };
-
-    CpuConsumer::LockedBuffer* jpegEncode(
-        CpuConsumer::LockedBuffer *imgBuffer,
-        int quality);
-
-    virtual status_t processFrameAvailable(sp<Camera2Client> &client);
-
-private:
-    virtual bool threadLoop();
-    static const nsecs_t kWaitDuration = 10000000; // 10 ms
-};
-
-} // namespace camera2
-} // namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.h b/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
index a290536..a22442f 100644
--- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
@@ -33,7 +33,7 @@
 
 namespace camera2 {
 
-class Parameters;
+struct Parameters;
 
 /***
  * Still image capture output image processing
@@ -75,7 +75,6 @@
     sp<CpuConsumer>    mCallbackConsumer;
     sp<Surface>        mCallbackWindow;
     sp<Camera2Heap>    mCallbackHeap;
-    int mCallbackHeapId;
     size_t mCallbackHeapHead, mCallbackHeapFree;
 
     virtual bool threadLoop();
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index 5f7fd74..61e1442 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -26,9 +26,8 @@
 
 #include "api1/Camera2Client.h"
 #include "api1/client2/CaptureSequencer.h"
-#include "api1/client2/BurstCapture.h"
 #include "api1/client2/Parameters.h"
-#include "api1/client2/ZslProcessorInterface.h"
+#include "api1/client2/ZslProcessor.h"
 
 namespace android {
 namespace camera2 {
@@ -59,7 +58,7 @@
     ALOGV("%s: Exit", __FUNCTION__);
 }
 
-void CaptureSequencer::setZslProcessor(wp<ZslProcessorInterface> processor) {
+void CaptureSequencer::setZslProcessor(wp<ZslProcessor> processor) {
     Mutex::Autolock l(mInputMutex);
     mZslProcessor = processor;
 }
@@ -111,6 +110,7 @@
 void CaptureSequencer::notifyShutter(const CaptureResultExtras& resultExtras,
                                      nsecs_t timestamp) {
     ATRACE_CALL();
+    (void) timestamp;
     Mutex::Autolock l(mInputMutex);
     if (!mHalNotifiedShutter && resultExtras.requestId == mShutterCaptureId) {
         mHalNotifiedShutter = true;
@@ -174,8 +174,6 @@
     "STANDARD_PRECAPTURE_WAIT",
     "STANDARD_CAPTURE",
     "STANDARD_CAPTURE_WAIT",
-    "BURST_CAPTURE_START",
-    "BURST_CAPTURE_WAIT",
     "DONE",
     "ERROR",
     "UNKNOWN"
@@ -192,8 +190,6 @@
     &CaptureSequencer::manageStandardPrecaptureWait,
     &CaptureSequencer::manageStandardCapture,
     &CaptureSequencer::manageStandardCaptureWait,
-    &CaptureSequencer::manageBurstCaptureStart,
-    &CaptureSequencer::manageBurstCaptureWait,
     &CaptureSequencer::manageDone,
 };
 
@@ -293,7 +289,7 @@
         }
         takePictureCounter = l.mParameters.takePictureCounter;
     }
-    sp<ZslProcessorInterface> processor = mZslProcessor.promote();
+    sp<ZslProcessor> processor = mZslProcessor.promote();
     if (processor != 0) {
         ALOGV("%s: Memory optimization, clearing ZSL queue",
               __FUNCTION__);
@@ -336,10 +332,6 @@
         return DONE;
     }
 
-    if(l.mParameters.lightFx != Parameters::LIGHTFX_NONE &&
-            l.mParameters.state == Parameters::STILL_CAPTURE) {
-        nextState = BURST_CAPTURE_START;
-    }
     else if (l.mParameters.zslMode &&
             l.mParameters.state == Parameters::STILL_CAPTURE &&
             l.mParameters.flashMode != Parameters::FLASH_MODE_ON) {
@@ -361,7 +353,7 @@
         sp<Camera2Client> &client) {
     ALOGV("%s", __FUNCTION__);
     status_t res;
-    sp<ZslProcessorInterface> processor = mZslProcessor.promote();
+    sp<ZslProcessor> processor = mZslProcessor.promote();
     if (processor == 0) {
         ALOGE("%s: No ZSL queue to use!", __FUNCTION__);
         return DONE;
@@ -664,76 +656,6 @@
     return STANDARD_CAPTURE_WAIT;
 }
 
-CaptureSequencer::CaptureState CaptureSequencer::manageBurstCaptureStart(
-        sp<Camera2Client> &client) {
-    ALOGV("%s", __FUNCTION__);
-    status_t res;
-    ATRACE_CALL();
-
-    // check which burst mode is set, create respective burst object
-    {
-        SharedParameters::Lock l(client->getParameters());
-
-        res = updateCaptureRequest(l.mParameters, client);
-        if(res != OK) {
-            return DONE;
-        }
-
-        //
-        // check for burst mode type in mParameters here
-        //
-        mBurstCapture = new BurstCapture(client, this);
-    }
-
-    res = mCaptureRequest.update(ANDROID_REQUEST_ID, &mCaptureId, 1);
-    if (res == OK) {
-        res = mCaptureRequest.sort();
-    }
-    if (res != OK) {
-        ALOGE("%s: Camera %d: Unable to set up still capture request: %s (%d)",
-                __FUNCTION__, client->getCameraId(), strerror(-res), res);
-        return DONE;
-    }
-
-    CameraMetadata captureCopy = mCaptureRequest;
-    if (captureCopy.entryCount() == 0) {
-        ALOGE("%s: Camera %d: Unable to copy capture request for HAL device",
-                __FUNCTION__, client->getCameraId());
-        return DONE;
-    }
-
-    Vector<CameraMetadata> requests;
-    requests.push(mCaptureRequest);
-    res = mBurstCapture->start(requests, mCaptureId);
-    mTimeoutCount = kMaxTimeoutsForCaptureEnd * 10;
-    return BURST_CAPTURE_WAIT;
-}
-
-CaptureSequencer::CaptureState CaptureSequencer::manageBurstCaptureWait(
-        sp<Camera2Client> &/*client*/) {
-    status_t res;
-    ATRACE_CALL();
-    while (!mNewCaptureReceived) {
-        res = mNewCaptureSignal.waitRelative(mInputMutex, kWaitDuration);
-        if (res == TIMED_OUT) {
-            mTimeoutCount--;
-            break;
-        }
-    }
-
-    if (mTimeoutCount <= 0) {
-        ALOGW("Timed out waiting for burst capture to complete");
-        return DONE;
-    }
-    if (mNewCaptureReceived) {
-        mNewCaptureReceived = false;
-        // TODO: update mCaptureId to last burst's capture ID + 1?
-        return DONE;
-    }
-
-    return BURST_CAPTURE_WAIT;
-}
-
 status_t CaptureSequencer::updateCaptureRequest(const Parameters &params,
         sp<Camera2Client> &client) {
     ATRACE_CALL();
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index 10252fb..b05207e 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -34,8 +34,7 @@
 
 namespace camera2 {
 
-class ZslProcessorInterface;
-class BurstCapture;
+class ZslProcessor;
 
 /**
  * Manages the still image capture process for
@@ -49,7 +48,7 @@
     ~CaptureSequencer();
 
     // Get reference to the ZslProcessor, which holds the ZSL buffers and frames
-    void setZslProcessor(wp<ZslProcessorInterface> processor);
+    void setZslProcessor(wp<ZslProcessor> processor);
 
     // Begin still image capture
     status_t startCapture(int msgType);
@@ -113,8 +112,7 @@
     static const int kMaxTimeoutsForCaptureEnd    = 40;  // 4 sec
 
     wp<Camera2Client> mClient;
-    wp<ZslProcessorInterface> mZslProcessor;
-    sp<BurstCapture> mBurstCapture;
+    wp<ZslProcessor> mZslProcessor;
 
     enum CaptureState {
         IDLE,
@@ -126,8 +124,6 @@
         STANDARD_PRECAPTURE_WAIT,
         STANDARD_CAPTURE,
         STANDARD_CAPTURE_WAIT,
-        BURST_CAPTURE_START,
-        BURST_CAPTURE_WAIT,
         DONE,
         ERROR,
         NUM_CAPTURE_STATES
@@ -165,9 +161,6 @@
     CaptureState manageStandardCapture(sp<Camera2Client> &client);
     CaptureState manageStandardCaptureWait(sp<Camera2Client> &client);
 
-    CaptureState manageBurstCaptureStart(sp<Camera2Client> &client);
-    CaptureState manageBurstCaptureWait(sp<Camera2Client> &client);
-
     CaptureState manageDone(sp<Camera2Client> &client);
 
     // Utility methods
diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
index 40d53b3..6490682 100644
--- a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
@@ -170,7 +170,7 @@
 
         entry = frame.find(ANDROID_SCALER_CROP_REGION);
         if (entry.count < 4) {
-            ALOGE("%s: Camera %d: Unable to read crop region (count = %d)",
+            ALOGE("%s: Camera %d: Unable to read crop region (count = %zu)",
                     __FUNCTION__, client->getCameraId(), entry.count);
             return res;
         }
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index bd9786f..3923853 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -108,7 +108,7 @@
             return NO_MEMORY;
         }
     }
-    ALOGV("%s: Camera %d: JPEG capture heap now %d bytes; requested %d bytes",
+    ALOGV("%s: Camera %d: JPEG capture heap now %zu bytes; requested %zd bytes",
             __FUNCTION__, mId, mCaptureHeap->getSize(), maxJpegSize);
 
     if (mCaptureStreamId != NO_STREAM) {
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.h b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
index fbdae11..ac6f5c7 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
@@ -35,7 +35,7 @@
 namespace camera2 {
 
 class CaptureSequencer;
-class Parameters;
+struct Parameters;
 
 /***
  * Still image capture output image processing
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index fc5ebac..7a97396 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -30,6 +30,7 @@
 #include "Parameters.h"
 #include "system/camera.h"
 #include "hardware/camera_common.h"
+#include <camera/ICamera.h>
 #include <media/MediaProfiles.h>
 #include <media/mediarecorder.h>
 
@@ -870,8 +871,9 @@
     }
 
     // Set up initial state for non-Camera.Parameters state variables
-
-    storeMetadataInBuffers = true;
+    videoFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+    videoDataSpace = HAL_DATASPACE_BT709;
+    videoBufferMode = ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV;
     playShutterSound = true;
     enableFaceDetect = false;
 
@@ -913,8 +915,6 @@
 
     ALOGI("%s: zslMode: %d slowJpegMode %d", __FUNCTION__, zslMode, slowJpegMode);
 
-    lightFx = LIGHTFX_NONE;
-
     state = STOPPED;
 
     paramsFlattened = params.flatten();
@@ -1864,10 +1864,6 @@
         ALOGE("%s: Video stabilization not supported", __FUNCTION__);
     }
 
-    // LIGHTFX
-    validatedParams.lightFx = lightFxStringToEnum(
-        newParams.get(CameraParameters::KEY_LIGHTFX));
-
     /** Update internal parameters */
 
     *this = validatedParams;
@@ -1959,7 +1955,7 @@
     if (res != OK) return res;
 
     // android.hardware.Camera requires that when face detect is enabled, the
-    // camera is in a face-priority mode. HAL2 splits this into separate parts
+    // camera is in a face-priority mode. HAL3.x splits this into separate parts
     // (face detection statistics and face priority scene mode). Map from other
     // to the other.
     bool sceneModeActive =
@@ -2501,18 +2497,6 @@
     }
 }
 
-Parameters::Parameters::lightFxMode_t Parameters::lightFxStringToEnum(
-        const char *lightFxMode) {
-    return
-        !lightFxMode ?
-            Parameters::LIGHTFX_NONE :
-        !strcmp(lightFxMode, CameraParameters::LIGHTFX_LOWLIGHT) ?
-            Parameters::LIGHTFX_LOWLIGHT :
-        !strcmp(lightFxMode, CameraParameters::LIGHTFX_HDR) ?
-            Parameters::LIGHTFX_HDR :
-        Parameters::LIGHTFX_NONE;
-}
-
 status_t Parameters::parseAreas(const char *areasCStr,
         Vector<Parameters::Area> *areas) {
     static const size_t NUM_FIELDS = 5;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 972d007..c437722 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -131,23 +131,19 @@
 
     int zoom;
 
-    int videoWidth, videoHeight;
+    int videoWidth, videoHeight, videoFormat;
+    android_dataspace videoDataSpace;
 
     bool recordingHint;
     bool videoStabilization;
 
-    enum lightFxMode_t {
-        LIGHTFX_NONE = 0,
-        LIGHTFX_LOWLIGHT,
-        LIGHTFX_HDR
-    } lightFx;
-
     CameraParameters2 params;
     String8 paramsFlattened;
 
     // These parameters are also part of the camera API-visible state, but not
     // directly listed in Camera.Parameters
-    bool storeMetadataInBuffers;
+    // One of ICamera::VIDEO_BUFFER_MODE_*
+    int32_t videoBufferMode;
     bool playShutterSound;
     bool enableFaceDetect;
 
@@ -307,7 +303,6 @@
     static const char* flashModeEnumToString(flashMode_t flashMode);
     static focusMode_t focusModeStringToEnum(const char *focusMode);
     static const char* focusModeEnumToString(focusMode_t focusMode);
-    static lightFxMode_t lightFxStringToEnum(const char *lightFxMode);
 
     static status_t parseAreas(const char *areasCStr,
             Vector<Area> *areas);
@@ -330,7 +325,7 @@
     static const int kFpsToApiScale = 1000;
 
     // Transform from (-1000,-1000)-(1000,1000) normalized coords from camera
-    // API to HAL2 (0,0)-(activePixelArray.width/height) coordinates
+    // API to HAL3 (0,0)-(activePixelArray.width/height) coordinates
     int normalizedXToArray(int x) const;
     int normalizedYToArray(int y) const;
 
@@ -350,7 +345,7 @@
 private:
 
     // Convert from viewfinder crop-region relative array coordinates
-    // to HAL2 sensor array coordinates
+    // to HAL3 sensor array coordinates
     int cropXToArray(int x) const;
     int cropYToArray(int y) const;
 
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index 66d7b00..211bdae 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -49,13 +49,7 @@
         mPreviewRequestId(Camera2Client::kPreviewRequestIdStart),
         mPreviewStreamId(NO_STREAM),
         mRecordingRequestId(Camera2Client::kRecordingRequestIdStart),
-        mRecordingStreamId(NO_STREAM),
-        mRecordingFrameAvailable(false),
-        mRecordingHeapCount(kDefaultRecordingHeapCount),
-        mRecordingHeapFree(kDefaultRecordingHeapCount),
-        mRecordingFormat(kDefaultRecordingFormat),
-        mRecordingDataSpace(kDefaultRecordingDataSpace),
-        mRecordingGrallocUsage(kDefaultRecordingGrallocUsage)
+        mRecordingStreamId(NO_STREAM)
 {
 }
 
@@ -78,11 +72,30 @@
     return OK;
 }
 
+status_t StreamingProcessor::setRecordingWindow(sp<Surface> window) {
+    ATRACE_CALL();
+    status_t res;
+
+    res = deleteRecordingStream();
+    if (res != OK) return res;
+
+    Mutex::Autolock m(mMutex);
+
+    mRecordingWindow = window;
+
+    return OK;
+}
+
 bool StreamingProcessor::haveValidPreviewWindow() const {
     Mutex::Autolock m(mMutex);
     return mPreviewWindow != 0;
 }
 
+bool StreamingProcessor::haveValidRecordingWindow() const {
+    Mutex::Autolock m(mMutex);
+    return mRecordingWindow != nullptr;
+}
+
 status_t StreamingProcessor::updatePreviewRequest(const Parameters &params) {
     ATRACE_CALL();
     status_t res;
@@ -244,86 +257,6 @@
     return mPreviewStreamId;
 }
 
-status_t StreamingProcessor::setRecordingBufferCount(size_t count) {
-    ATRACE_CALL();
-    // Make sure we can support this many buffer slots
-    if (count > BufferQueue::NUM_BUFFER_SLOTS) {
-        ALOGE("%s: Camera %d: Too many recording buffers requested: %zu, max %d",
-                __FUNCTION__, mId, count, BufferQueue::NUM_BUFFER_SLOTS);
-        return BAD_VALUE;
-    }
-
-    Mutex::Autolock m(mMutex);
-
-    ALOGV("%s: Camera %d: New recording buffer count from encoder: %zu",
-            __FUNCTION__, mId, count);
-
-    // Need to re-size consumer and heap
-    if (mRecordingHeapCount != count) {
-        ALOGV("%s: Camera %d: Resetting recording heap and consumer",
-            __FUNCTION__, mId);
-
-        if (isStreamActive(mActiveStreamIds, mRecordingStreamId)) {
-            ALOGE("%s: Camera %d: Setting recording buffer count when "
-                    "recording stream is already active!", __FUNCTION__,
-                    mId);
-            return INVALID_OPERATION;
-        }
-
-        releaseAllRecordingFramesLocked();
-
-        if (mRecordingHeap != 0) {
-            mRecordingHeap.clear();
-        }
-        mRecordingHeapCount = count;
-        mRecordingHeapFree = count;
-
-        mRecordingConsumer.clear();
-    }
-
-    return OK;
-}
-
-status_t StreamingProcessor::setRecordingFormat(int format,
-        android_dataspace dataSpace) {
-    ATRACE_CALL();
-
-    Mutex::Autolock m(mMutex);
-
-    ALOGV("%s: Camera %d: New recording format/dataspace from encoder: %X, %X",
-            __FUNCTION__, mId, format, dataSpace);
-
-    mRecordingFormat = format;
-    mRecordingDataSpace = dataSpace;
-    int prevGrallocUsage = mRecordingGrallocUsage;
-    if (mRecordingFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
-        mRecordingGrallocUsage = GRALLOC_USAGE_HW_VIDEO_ENCODER;
-    } else {
-        mRecordingGrallocUsage = GRALLOC_USAGE_SW_READ_OFTEN;
-    }
-
-    ALOGV("%s: Camera %d: New recording gralloc usage: %08X", __FUNCTION__, mId,
-            mRecordingGrallocUsage);
-
-    if (prevGrallocUsage != mRecordingGrallocUsage) {
-        ALOGV("%s: Camera %d: Resetting recording consumer for new usage",
-            __FUNCTION__, mId);
-
-        if (isStreamActive(mActiveStreamIds, mRecordingStreamId)) {
-            ALOGE("%s: Camera %d: Changing recording format when "
-                    "recording stream is already active!", __FUNCTION__,
-                    mId);
-            return INVALID_OPERATION;
-        }
-
-        releaseAllRecordingFramesLocked();
-
-        mRecordingConsumer.clear();
-    }
-
-    return OK;
-}
-
 status_t StreamingProcessor::updateRecordingRequest(const Parameters &params) {
     ATRACE_CALL();
     status_t res;
@@ -395,11 +328,11 @@
         return res;
     }
 
-    if (mRecordingConsumer == 0 ||
+    if (mRecordingWindow == nullptr ||
             currentWidth != (uint32_t)params.videoWidth ||
             currentHeight != (uint32_t)params.videoHeight ||
-            currentFormat != (uint32_t)mRecordingFormat ||
-            currentDataSpace != mRecordingDataSpace) {
+            currentFormat != (uint32_t)params.videoFormat ||
+            currentDataSpace != params.videoDataSpace) {
         *needsUpdate = true;
     }
     *needsUpdate = false;
@@ -417,26 +350,6 @@
         return INVALID_OPERATION;
     }
 
-    bool newConsumer = false;
-    if (mRecordingConsumer == 0) {
-        ALOGV("%s: Camera %d: Creating recording consumer with %zu + 1 "
-                "consumer-side buffers", __FUNCTION__, mId, mRecordingHeapCount);
-        // Create CPU buffer queue endpoint. We need one more buffer here so that we can
-        // always acquire and free a buffer when the heap is full; otherwise the consumer
-        // will have buffers in flight we'll never clear out.
-        sp<IGraphicBufferProducer> producer;
-        sp<IGraphicBufferConsumer> consumer;
-        BufferQueue::createBufferQueue(&producer, &consumer);
-        mRecordingConsumer = new BufferItemConsumer(consumer,
-                mRecordingGrallocUsage,
-                mRecordingHeapCount + 1);
-        mRecordingConsumer->setFrameAvailableListener(this);
-        mRecordingConsumer->setName(String8("Camera2-RecordingConsumer"));
-        mRecordingWindow = new Surface(producer);
-        newConsumer = true;
-        // Allocate memory later, since we don't know buffer size until receipt
-    }
-
     if (mRecordingStreamId != NO_STREAM) {
         // Check if stream parameters have to change
         uint32_t currentWidth, currentHeight;
@@ -453,9 +366,8 @@
         }
         if (currentWidth != (uint32_t)params.videoWidth ||
                 currentHeight != (uint32_t)params.videoHeight ||
-                currentFormat != (uint32_t)mRecordingFormat ||
-                currentDataSpace != mRecordingDataSpace ||
-                newConsumer) {
+                currentFormat != (uint32_t)params.videoFormat ||
+                currentDataSpace != params.videoDataSpace) {
             // TODO: Should wait to be sure previous recording has finished
             res = device->deleteStream(mRecordingStreamId);
 
@@ -475,10 +387,9 @@
     }
 
     if (mRecordingStreamId == NO_STREAM) {
-        mRecordingFrameCount = 0;
         res = device->createStream(mRecordingWindow,
                 params.videoWidth, params.videoHeight,
-                mRecordingFormat, mRecordingDataSpace,
+                params.videoFormat, params.videoDataSpace,
                 CAMERA3_STREAM_ROTATION_0, &mRecordingStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Can't create output stream for recording: "
@@ -542,20 +453,6 @@
 
     Mutex::Autolock m(mMutex);
 
-    // If a recording stream is being started up and no recording
-    // stream is active yet, free up any outstanding buffers left
-    // from the previous recording session. There should never be
-    // any, so if there are, warn about it.
-    bool isRecordingStreamIdle = !isStreamActive(mActiveStreamIds, mRecordingStreamId);
-    bool startRecordingStream = isStreamActive(outputStreams, mRecordingStreamId);
-    if (startRecordingStream && isRecordingStreamIdle) {
-        releaseAllRecordingFramesLocked();
-    }
-
-    ALOGV("%s: Camera %d: %s started, recording heap has %zu free of %zu",
-            __FUNCTION__, mId, (type == PREVIEW) ? "preview" : "recording",
-            mRecordingHeapFree, mRecordingHeapCount);
-
     CameraMetadata &request = (type == PREVIEW) ?
             mPreviewRequest : mRecordingRequest;
 
@@ -692,272 +589,6 @@
     return OK;
 }
 
-void StreamingProcessor::onFrameAvailable(const BufferItem& /*item*/) {
-    ATRACE_CALL();
-    Mutex::Autolock l(mMutex);
-    if (!mRecordingFrameAvailable) {
-        mRecordingFrameAvailable = true;
-        mRecordingFrameAvailableSignal.signal();
-    }
-
-}
-
-bool StreamingProcessor::threadLoop() {
-    status_t res;
-
-    {
-        Mutex::Autolock l(mMutex);
-        while (!mRecordingFrameAvailable) {
-            res = mRecordingFrameAvailableSignal.waitRelative(
-                mMutex, kWaitDuration);
-            if (res == TIMED_OUT) return true;
-        }
-        mRecordingFrameAvailable = false;
-    }
-
-    do {
-        res = processRecordingFrame();
-    } while (res == OK);
-
-    return true;
-}
-
-status_t StreamingProcessor::processRecordingFrame() {
-    ATRACE_CALL();
-    status_t res;
-    sp<Camera2Heap> recordingHeap;
-    size_t heapIdx = 0;
-    nsecs_t timestamp;
-
-    sp<Camera2Client> client = mClient.promote();
-    if (client == 0) {
-        // Discard frames during shutdown
-        BufferItem imgBuffer;
-        res = mRecordingConsumer->acquireBuffer(&imgBuffer, 0);
-        if (res != OK) {
-            if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) {
-                ALOGE("%s: Camera %d: Can't acquire recording buffer: %s (%d)",
-                        __FUNCTION__, mId, strerror(-res), res);
-            }
-            return res;
-        }
-        mRecordingConsumer->releaseBuffer(imgBuffer);
-        return OK;
-    }
-
-    {
-        /* acquire SharedParameters before mMutex so we don't dead lock
-            with Camera2Client code calling into StreamingProcessor */
-        SharedParameters::Lock l(client->getParameters());
-        Mutex::Autolock m(mMutex);
-        BufferItem imgBuffer;
-        res = mRecordingConsumer->acquireBuffer(&imgBuffer, 0);
-        if (res != OK) {
-            if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) {
-                ALOGE("%s: Camera %d: Can't acquire recording buffer: %s (%d)",
-                        __FUNCTION__, mId, strerror(-res), res);
-            }
-            return res;
-        }
-        timestamp = imgBuffer.mTimestamp;
-
-        mRecordingFrameCount++;
-        ALOGVV("OnRecordingFrame: Frame %d", mRecordingFrameCount);
-
-        if (l.mParameters.state != Parameters::RECORD &&
-                l.mParameters.state != Parameters::VIDEO_SNAPSHOT) {
-            ALOGV("%s: Camera %d: Discarding recording image buffers "
-                    "received after recording done", __FUNCTION__,
-                    mId);
-            mRecordingConsumer->releaseBuffer(imgBuffer);
-            return INVALID_OPERATION;
-        }
-
-        if (mRecordingHeap == 0) {
-            size_t payloadSize = sizeof(VideoNativeMetadata);
-            ALOGV("%s: Camera %d: Creating recording heap with %zu buffers of "
-                    "size %zu bytes", __FUNCTION__, mId,
-                    mRecordingHeapCount, payloadSize);
-
-            mRecordingHeap = new Camera2Heap(payloadSize, mRecordingHeapCount,
-                    "Camera2Client::RecordingHeap");
-            if (mRecordingHeap->mHeap->getSize() == 0) {
-                ALOGE("%s: Camera %d: Unable to allocate memory for recording",
-                        __FUNCTION__, mId);
-                mRecordingConsumer->releaseBuffer(imgBuffer);
-                return NO_MEMORY;
-            }
-            for (size_t i = 0; i < mRecordingBuffers.size(); i++) {
-                if (mRecordingBuffers[i].mBuf !=
-                        BufferItemConsumer::INVALID_BUFFER_SLOT) {
-                    ALOGE("%s: Camera %d: Non-empty recording buffers list!",
-                            __FUNCTION__, mId);
-                }
-            }
-            mRecordingBuffers.clear();
-            mRecordingBuffers.setCapacity(mRecordingHeapCount);
-            mRecordingBuffers.insertAt(0, mRecordingHeapCount);
-
-            mRecordingHeapHead = 0;
-            mRecordingHeapFree = mRecordingHeapCount;
-        }
-
-        if (mRecordingHeapFree == 0) {
-            ALOGE("%s: Camera %d: No free recording buffers, dropping frame",
-                    __FUNCTION__, mId);
-            mRecordingConsumer->releaseBuffer(imgBuffer);
-            return NO_MEMORY;
-        }
-
-        heapIdx = mRecordingHeapHead;
-        mRecordingHeapHead = (mRecordingHeapHead + 1) % mRecordingHeapCount;
-        mRecordingHeapFree--;
-
-        ALOGVV("%s: Camera %d: Timestamp %lld",
-                __FUNCTION__, mId, timestamp);
-
-        ssize_t offset;
-        size_t size;
-        sp<IMemoryHeap> heap =
-                mRecordingHeap->mBuffers[heapIdx]->getMemory(&offset,
-                        &size);
-
-        VideoNativeMetadata *payload = reinterpret_cast<VideoNativeMetadata*>(
-            (uint8_t*)heap->getBase() + offset);
-        payload->eType = kMetadataBufferTypeANWBuffer;
-        payload->pBuffer = imgBuffer.mGraphicBuffer->getNativeBuffer();
-        payload->nFenceFd = -1;
-
-        ALOGVV("%s: Camera %d: Sending out ANWBuffer %p",
-                __FUNCTION__, mId, payload->pBuffer);
-
-        mRecordingBuffers.replaceAt(imgBuffer, heapIdx);
-        recordingHeap = mRecordingHeap;
-    }
-
-    // Call outside locked parameters to allow re-entrancy from notification
-    Camera2Client::SharedCameraCallbacks::Lock l(client->mSharedCameraCallbacks);
-    if (l.mRemoteCallback != 0) {
-        l.mRemoteCallback->dataCallbackTimestamp(timestamp,
-                CAMERA_MSG_VIDEO_FRAME,
-                recordingHeap->mBuffers[heapIdx]);
-    } else {
-        ALOGW("%s: Camera %d: Remote callback gone", __FUNCTION__, mId);
-    }
-
-    return OK;
-}
-
-void StreamingProcessor::releaseRecordingFrame(const sp<IMemory>& mem) {
-    ATRACE_CALL();
-    status_t res;
-
-    Mutex::Autolock m(mMutex);
-    // Make sure this is for the current heap
-    ssize_t offset;
-    size_t size;
-    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
-    if (heap->getHeapID() != mRecordingHeap->mHeap->getHeapID()) {
-        ALOGW("%s: Camera %d: Mismatched heap ID, ignoring release "
-                "(got %x, expected %x)", __FUNCTION__, mId,
-                heap->getHeapID(), mRecordingHeap->mHeap->getHeapID());
-        return;
-    }
-
-    VideoNativeMetadata *payload = reinterpret_cast<VideoNativeMetadata*>(
-        (uint8_t*)heap->getBase() + offset);
-
-    if (payload->eType != kMetadataBufferTypeANWBuffer) {
-        ALOGE("%s: Camera %d: Recording frame type invalid (got %x, expected %x)",
-                __FUNCTION__, mId, payload->eType,
-                kMetadataBufferTypeANWBuffer);
-        return;
-    }
-
-    // Release the buffer back to the recording queue
-    size_t itemIndex;
-    for (itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) {
-        const BufferItem item = mRecordingBuffers[itemIndex];
-        if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT &&
-                item.mGraphicBuffer->getNativeBuffer() == payload->pBuffer) {
-                break;
-        }
-    }
-
-    if (itemIndex == mRecordingBuffers.size()) {
-        ALOGE("%s: Camera %d: Can't find returned ANW Buffer %p in list of "
-                "outstanding buffers", __FUNCTION__, mId,
-                payload->pBuffer);
-        return;
-    }
-
-    ALOGVV("%s: Camera %d: Freeing returned ANW buffer %p index %d", __FUNCTION__,
-            mId, payload->pBuffer, itemIndex);
-
-    res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]);
-    if (res != OK) {
-        ALOGE("%s: Camera %d: Unable to free recording frame "
-                "(Returned ANW buffer: %p): %s (%d)", __FUNCTION__,
-                mId, payload->pBuffer, strerror(-res), res);
-        return;
-    }
-    mRecordingBuffers.replaceAt(itemIndex);
-
-    mRecordingHeapFree++;
-    ALOGV_IF(mRecordingHeapFree == mRecordingHeapCount,
-            "%s: Camera %d: All %d recording buffers returned",
-            __FUNCTION__, mId, mRecordingHeapCount);
-}
-
-void StreamingProcessor::releaseAllRecordingFramesLocked() {
-    ATRACE_CALL();
-    status_t res;
-
-    if (mRecordingConsumer == 0) {
-        return;
-    }
-
-    ALOGV("%s: Camera %d: Releasing all recording buffers", __FUNCTION__,
-            mId);
-
-    size_t releasedCount = 0;
-    for (size_t itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) {
-        const BufferItem item = mRecordingBuffers[itemIndex];
-        if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT) {
-            res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]);
-            if (res != OK) {
-                ALOGE("%s: Camera %d: Unable to free recording frame "
-                        "(buffer_handle_t: %p): %s (%d)", __FUNCTION__,
-                        mId, item.mGraphicBuffer->handle, strerror(-res), res);
-            }
-            mRecordingBuffers.replaceAt(itemIndex);
-            releasedCount++;
-        }
-    }
-
-    if (releasedCount > 0) {
-        ALOGW("%s: Camera %d: Force-freed %zu outstanding buffers "
-                "from previous recording session", __FUNCTION__, mId, releasedCount);
-        ALOGE_IF(releasedCount != mRecordingHeapCount - mRecordingHeapFree,
-            "%s: Camera %d: Force-freed %zu buffers, but expected %zu",
-            __FUNCTION__, mId, releasedCount, mRecordingHeapCount - mRecordingHeapFree);
-    }
-
-    mRecordingHeapHead = 0;
-    mRecordingHeapFree = mRecordingHeapCount;
-}
-
-bool StreamingProcessor::isStreamActive(const Vector<int32_t> &streams,
-        int32_t recordingStreamId) {
-    for (size_t i = 0; i < streams.size(); i++) {
-        if (streams[i] == recordingStreamId) {
-            return true;
-        }
-    }
-    return false;
-}
-
-
 status_t StreamingProcessor::dump(int fd, const Vector<String16>& /*args*/) {
     String8 result;
 
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
index e0cad3a..57e6389 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
@@ -31,30 +31,28 @@
 
 namespace camera2 {
 
-class Parameters;
+struct Parameters;
 class Camera2Heap;
 
 /**
  * Management and processing for preview and recording streams
  */
-class StreamingProcessor:
-            public Thread, public BufferItemConsumer::FrameAvailableListener {
+class StreamingProcessor : public virtual VirtualLightRefBase {
   public:
     StreamingProcessor(sp<Camera2Client> client);
     ~StreamingProcessor();
 
     status_t setPreviewWindow(sp<Surface> window);
+    status_t setRecordingWindow(sp<Surface> window);
 
     bool haveValidPreviewWindow() const;
+    bool haveValidRecordingWindow() const;
 
     status_t updatePreviewRequest(const Parameters &params);
     status_t updatePreviewStream(const Parameters &params);
     status_t deletePreviewStream();
     int getPreviewStreamId() const;
 
-    status_t setRecordingBufferCount(size_t count);
-    status_t setRecordingFormat(int format, android_dataspace_t dataspace);
-
     status_t updateRecordingRequest(const Parameters &params);
     // If needsUpdate is set to true, a updateRecordingStream call with params will recreate
     // recording stream
@@ -81,11 +79,6 @@
     status_t getActiveRequestId() const;
     status_t incrementStreamingIds();
 
-    // Callback for new recording frames from HAL
-    virtual void onFrameAvailable(const BufferItem& item);
-    // Callback from stagefright which returns used recording frames
-    void releaseRecordingFrame(const sp<IMemory>& mem);
-
     status_t dump(int fd, const Vector<String16>& args);
 
   private:
@@ -110,47 +103,10 @@
     CameraMetadata mPreviewRequest;
     sp<Surface> mPreviewWindow;
 
-    // Recording-related members
-    static const nsecs_t kWaitDuration = 50000000; // 50 ms
-
     int32_t mRecordingRequestId;
     int mRecordingStreamId;
-    int mRecordingFrameCount;
-    sp<BufferItemConsumer> mRecordingConsumer;
     sp<Surface>  mRecordingWindow;
     CameraMetadata mRecordingRequest;
-    sp<camera2::Camera2Heap> mRecordingHeap;
-
-    bool mRecordingFrameAvailable;
-    Condition mRecordingFrameAvailableSignal;
-
-    static const size_t kDefaultRecordingHeapCount = 8;
-    size_t mRecordingHeapCount;
-    Vector<BufferItem> mRecordingBuffers;
-    size_t mRecordingHeapHead, mRecordingHeapFree;
-
-    static const int kDefaultRecordingFormat =
-            HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
-    int mRecordingFormat;
-
-    static const android_dataspace kDefaultRecordingDataSpace =
-            HAL_DATASPACE_BT709;
-    android_dataspace mRecordingDataSpace;
-
-    static const int kDefaultRecordingGrallocUsage =
-            GRALLOC_USAGE_HW_VIDEO_ENCODER;
-    int mRecordingGrallocUsage;
-
-    virtual bool threadLoop();
-
-    status_t processRecordingFrame();
-
-    // Unilaterally free any buffers still outstanding to stagefright
-    void releaseAllRecordingFramesLocked();
-
-    // Determine if the specified stream is currently in use
-    static bool isStreamActive(const Vector<int32_t> &streams,
-            int32_t recordingStreamId);
 };
 
 
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 0b79b31..b127472 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * 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.
@@ -22,7 +22,7 @@
 #ifdef LOG_NNDEBUG
 #define ALOGVV(...) ALOGV(__VA_ARGS__)
 #else
-#define ALOGVV(...) ((void)0)
+#define ALOGVV(...) if (0) ALOGV(__VA_ARGS__)
 #endif
 
 #include <inttypes.h>
@@ -35,6 +35,7 @@
 #include "api1/Camera2Client.h"
 #include "api1/client2/CaptureSequencer.h"
 #include "api1/client2/ZslProcessor.h"
+#include "device3/Camera3Device.h"
 
 namespace android {
 namespace camera2 {
@@ -43,35 +44,55 @@
     sp<Camera2Client> client,
     wp<CaptureSequencer> sequencer):
         Thread(false),
+        mLatestClearedBufferTimestamp(0),
         mState(RUNNING),
         mClient(client),
-        mDevice(client->getCameraDevice()),
         mSequencer(sequencer),
         mId(client->getCameraId()),
-        mDeleted(false),
-        mZslBufferAvailable(false),
         mZslStreamId(NO_STREAM),
-        mZslReprocessStreamId(NO_STREAM),
         mFrameListHead(0),
-        mZslQueueHead(0),
-        mZslQueueTail(0) {
-    mZslQueue.insertAt(0, kZslBufferDepth);
-    mFrameList.insertAt(0, kFrameListDepth);
+        mHasFocuser(false) {
+    // Initialize buffer queue and frame list based on pipeline max depth.
+    size_t pipelineMaxDepth = kDefaultMaxPipelineDepth;
+    if (client != 0) {
+        sp<Camera3Device> device =
+        static_cast<Camera3Device*>(client->getCameraDevice().get());
+        if (device != 0) {
+            camera_metadata_ro_entry_t entry =
+                device->info().find(ANDROID_REQUEST_PIPELINE_MAX_DEPTH);
+            if (entry.count == 1) {
+                pipelineMaxDepth = entry.data.u8[0];
+            } else {
+                ALOGW("%s: Unable to find the android.request.pipelineMaxDepth,"
+                        " use default pipeline max depth %d", __FUNCTION__,
+                        kDefaultMaxPipelineDepth);
+            }
+
+            entry = device->info().find(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE);
+            if (entry.count > 0 && entry.data.f[0] != 0.) {
+                mHasFocuser = true;
+            }
+        }
+    }
+
+    ALOGV("%s: Initialize buffer queue and frame list depth based on max pipeline depth (%zu)",
+          __FUNCTION__, pipelineMaxDepth);
+    // Need to keep buffer queue longer than metadata queue because sometimes buffer arrives
+    // earlier than metadata which causes the buffer corresponding to oldest metadata being
+    // removed.
+    mFrameListDepth = pipelineMaxDepth;
+    mBufferQueueDepth = mFrameListDepth + 1;
+
+
+    mZslQueue.insertAt(0, mBufferQueueDepth);
+    mFrameList.insertAt(0, mFrameListDepth);
     sp<CaptureSequencer> captureSequencer = mSequencer.promote();
     if (captureSequencer != 0) captureSequencer->setZslProcessor(this);
 }
 
 ZslProcessor::~ZslProcessor() {
     ALOGV("%s: Exit", __FUNCTION__);
-    disconnect();
-}
-
-void ZslProcessor::onFrameAvailable(const BufferItem& /*item*/) {
-    Mutex::Autolock l(mInputMutex);
-    if (!mZslBufferAvailable) {
-        mZslBufferAvailable = true;
-        mZslBufferAvailableSignal.signal();
-    }
+    deleteStream();
 }
 
 void ZslProcessor::onResultAvailable(const CaptureResult &result) {
@@ -81,35 +102,27 @@
     camera_metadata_ro_entry_t entry;
     entry = result.mMetadata.find(ANDROID_SENSOR_TIMESTAMP);
     nsecs_t timestamp = entry.data.i64[0];
-    (void)timestamp;
-    ALOGVV("Got preview frame for timestamp %" PRId64, timestamp);
+    if (entry.count == 0) {
+        ALOGE("%s: metadata doesn't have timestamp, skip this result", __FUNCTION__);
+        return;
+    }
+
+    entry = result.mMetadata.find(ANDROID_REQUEST_FRAME_COUNT);
+    if (entry.count == 0) {
+        ALOGE("%s: metadata doesn't have frame number, skip this result", __FUNCTION__);
+        return;
+    }
+    int32_t frameNumber = entry.data.i32[0];
+
+    ALOGVV("Got preview metadata for frame %d with timestamp %" PRId64, frameNumber, timestamp);
 
     if (mState != RUNNING) return;
 
+    // Corresponding buffer has been cleared. No need to push into mFrameList
+    if (timestamp <= mLatestClearedBufferTimestamp) return;
+
     mFrameList.editItemAt(mFrameListHead) = result.mMetadata;
-    mFrameListHead = (mFrameListHead + 1) % kFrameListDepth;
-
-    findMatchesLocked();
-}
-
-void ZslProcessor::onBufferReleased(buffer_handle_t *handle) {
-    Mutex::Autolock l(mInputMutex);
-
-    // Verify that the buffer is in our queue
-    size_t i = 0;
-    for (; i < mZslQueue.size(); i++) {
-        if (&(mZslQueue[i].buffer.mGraphicBuffer->handle) == handle) break;
-    }
-    if (i == mZslQueue.size()) {
-        ALOGW("%s: Released buffer %p not found in queue",
-                __FUNCTION__, handle);
-    }
-
-    // Erase entire ZSL queue since we've now completed the capture and preview
-    // is stopped.
-    clearZslQueueLocked();
-
-    mState = RUNNING;
+    mFrameListHead = (mFrameListHead + 1) % mFrameListDepth;
 }
 
 status_t ZslProcessor::updateStream(const Parameters &params) {
@@ -124,25 +137,13 @@
         ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
         return INVALID_OPERATION;
     }
-    sp<CameraDeviceBase> device = mDevice.promote();
+    sp<Camera3Device> device =
+        static_cast<Camera3Device*>(client->getCameraDevice().get());
     if (device == 0) {
         ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
         return INVALID_OPERATION;
     }
 
-    if (mZslConsumer == 0) {
-        // Create CPU buffer queue endpoint
-        sp<IGraphicBufferProducer> producer;
-        sp<IGraphicBufferConsumer> consumer;
-        BufferQueue::createBufferQueue(&producer, &consumer);
-        mZslConsumer = new BufferItemConsumer(consumer,
-            GRALLOC_USAGE_HW_CAMERA_ZSL,
-            kZslBufferDepth);
-        mZslConsumer->setFrameAvailableListener(this);
-        mZslConsumer->setName(String8("Camera2-ZslConsumer"));
-        mZslWindow = new Surface(producer);
-    }
-
     if (mZslStreamId != NO_STREAM) {
         // Check if stream parameters have to change
         uint32_t currentWidth, currentHeight;
@@ -151,57 +152,50 @@
         if (res != OK) {
             ALOGE("%s: Camera %d: Error querying capture output stream info: "
                     "%s (%d)", __FUNCTION__,
-                    mId, strerror(-res), res);
+                    client->getCameraId(), strerror(-res), res);
             return res;
         }
         if (currentWidth != (uint32_t)params.fastInfo.arrayWidth ||
                 currentHeight != (uint32_t)params.fastInfo.arrayHeight) {
-            res = device->deleteReprocessStream(mZslReprocessStreamId);
-            if (res != OK) {
-                ALOGE("%s: Camera %d: Unable to delete old reprocess stream "
-                        "for ZSL: %s (%d)", __FUNCTION__,
-                        mId, strerror(-res), res);
-                return res;
-            }
-            ALOGV("%s: Camera %d: Deleting stream %d since the buffer dimensions changed",
-                __FUNCTION__, mId, mZslStreamId);
+            ALOGV("%s: Camera %d: Deleting stream %d since the buffer "
+                  "dimensions changed",
+                __FUNCTION__, client->getCameraId(), mZslStreamId);
             res = device->deleteStream(mZslStreamId);
-            if (res != OK) {
+            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__,
-                        mId, strerror(-res), res);
+                        client->getCameraId(), strerror(-res), res);
                 return res;
             }
             mZslStreamId = NO_STREAM;
         }
     }
 
-    mDeleted = false;
-
     if (mZslStreamId == NO_STREAM) {
         // Create stream for HAL production
         // TODO: Sort out better way to select resolution for ZSL
-        int streamType = params.quirks.useZslFormat ?
-                (int)CAMERA2_HAL_PIXEL_FORMAT_ZSL :
-                (int)HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
-        res = device->createStream(mZslWindow,
-                params.fastInfo.arrayWidth, params.fastInfo.arrayHeight, streamType,
-                HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0, &mZslStreamId);
+
+        // Note that format specified internally in Camera3ZslStream
+        res = device->createZslStream(
+                params.fastInfo.arrayWidth, params.fastInfo.arrayHeight,
+                mBufferQueueDepth,
+                &mZslStreamId,
+                &mZslStream);
         if (res != OK) {
-            ALOGE("%s: Camera %d: Can't create output stream for ZSL: "
-                    "%s (%d)", __FUNCTION__, mId,
+            ALOGE("%s: Camera %d: Can't create ZSL stream: "
+                    "%s (%d)", __FUNCTION__, client->getCameraId(),
                     strerror(-res), res);
             return res;
         }
-        res = device->createReprocessStreamFromStream(mZslStreamId,
-                &mZslReprocessStreamId);
-        if (res != OK) {
-            ALOGE("%s: Camera %d: Can't create reprocess stream for ZSL: "
-                    "%s (%d)", __FUNCTION__, mId,
-                    strerror(-res), res);
-            return res;
-        }
+
+        // Only add the camera3 buffer listener when the stream is created.
+        mZslStream->addBufferListener(this);
     }
+
     client->registerFrameListener(Camera2Client::kPreviewRequestIdStart,
             Camera2Client::kPreviewRequestIdEnd,
             this,
@@ -212,47 +206,32 @@
 
 status_t ZslProcessor::deleteStream() {
     ATRACE_CALL();
-    Mutex::Autolock l(mInputMutex);
-    // WAR(b/15408128): do not delete stream unless client is being disconnected.
-    mDeleted = true;
-    return OK;
-}
-
-status_t ZslProcessor::disconnect() {
-    ATRACE_CALL();
     status_t res;
 
     Mutex::Autolock l(mInputMutex);
 
     if (mZslStreamId != NO_STREAM) {
-        sp<CameraDeviceBase> device = mDevice.promote();
+        sp<Camera2Client> client = mClient.promote();
+        if (client == 0) {
+            ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
+            return INVALID_OPERATION;
+        }
+
+        sp<Camera3Device> device =
+            reinterpret_cast<Camera3Device*>(client->getCameraDevice().get());
         if (device == 0) {
             ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
             return INVALID_OPERATION;
         }
 
-        clearZslQueueLocked();
-
-        res = device->deleteReprocessStream(mZslReprocessStreamId);
-        if (res != OK) {
-            ALOGE("%s: Camera %d: Cannot delete ZSL reprocessing stream %d: "
-                    "%s (%d)", __FUNCTION__, mId,
-                    mZslReprocessStreamId, strerror(-res), res);
-            return res;
-        }
-
-        mZslReprocessStreamId = NO_STREAM;
         res = device->deleteStream(mZslStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Cannot delete ZSL output stream %d: "
-                    "%s (%d)", __FUNCTION__, mId,
+                    "%s (%d)", __FUNCTION__, client->getCameraId(),
                     mZslStreamId, strerror(-res), res);
             return res;
         }
 
-        mZslWindow.clear();
-        mZslConsumer.clear();
-
         mZslStreamId = NO_STREAM;
     }
     return OK;
@@ -263,6 +242,46 @@
     return mZslStreamId;
 }
 
+status_t ZslProcessor::updateRequestWithDefaultStillRequest(CameraMetadata &request) const {
+    sp<Camera2Client> client = mClient.promote();
+    if (client == 0) {
+        ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
+    sp<Camera3Device> device =
+        static_cast<Camera3Device*>(client->getCameraDevice().get());
+    if (device == 0) {
+        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
+
+    CameraMetadata stillTemplate;
+    device->createDefaultRequest(CAMERA3_TEMPLATE_STILL_CAPTURE, &stillTemplate);
+
+    // Find some of the post-processing tags, and assign the value from template to the request.
+    // Only check the aberration mode and noise reduction mode for now, as they are very important
+    // for image quality.
+    uint32_t postProcessingTags[] = {
+            ANDROID_NOISE_REDUCTION_MODE,
+            ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+            ANDROID_COLOR_CORRECTION_MODE,
+            ANDROID_TONEMAP_MODE,
+            ANDROID_SHADING_MODE,
+            ANDROID_HOT_PIXEL_MODE,
+            ANDROID_EDGE_MODE
+    };
+
+    camera_metadata_entry_t entry;
+    for (size_t i = 0; i < sizeof(postProcessingTags) / sizeof(uint32_t); i++) {
+        entry = stillTemplate.find(postProcessingTags[i]);
+        if (entry.count > 0) {
+            request.update(postProcessingTags[i], entry.data.u8, 1);
+        }
+    }
+
+    return OK;
+}
+
 status_t ZslProcessor::pushToReprocess(int32_t requestId) {
     ALOGV("%s: Send in reprocess request with id %d",
             __FUNCTION__, requestId);
@@ -279,21 +298,30 @@
         dumpZslQueue(-1);
     }
 
-    if (mZslQueueTail != mZslQueueHead) {
-        CameraMetadata request;
-        size_t index = mZslQueueTail;
-        while (index != mZslQueueHead) {
-            if (!mZslQueue[index].frame.isEmpty()) {
-                request = mZslQueue[index].frame;
-                break;
-            }
-            index = (index + 1) % kZslBufferDepth;
-        }
-        if (index == mZslQueueHead) {
-            ALOGV("%s: ZSL queue has no valid frames to send yet.",
-                  __FUNCTION__);
-            return NOT_ENOUGH_DATA;
-        }
+    size_t metadataIdx;
+    nsecs_t candidateTimestamp = getCandidateTimestampLocked(&metadataIdx);
+
+    if (candidateTimestamp == -1) {
+        ALOGE("%s: Could not find good candidate for ZSL reprocessing",
+              __FUNCTION__);
+        return NOT_ENOUGH_DATA;
+    }
+
+    res = mZslStream->enqueueInputBufferByTimestamp(candidateTimestamp,
+                                                    /*actualTimestamp*/NULL);
+
+    if (res == mZslStream->NO_BUFFER_AVAILABLE) {
+        ALOGV("%s: No ZSL buffers yet", __FUNCTION__);
+        return NOT_ENOUGH_DATA;
+    } else if (res != OK) {
+        ALOGE("%s: Unable to push buffer for reprocessing: %s (%d)",
+                __FUNCTION__, strerror(-res), res);
+        return res;
+    }
+
+    {
+        CameraMetadata request = mFrameList[metadataIdx];
+
         // Verify that the frame is reasonable for reprocessing
 
         camera_metadata_entry_t entry;
@@ -310,25 +338,51 @@
             return NOT_ENOUGH_DATA;
         }
 
-        buffer_handle_t *handle =
-            &(mZslQueue[index].buffer.mGraphicBuffer->handle);
-
         uint8_t requestType = ANDROID_REQUEST_TYPE_REPROCESS;
         res = request.update(ANDROID_REQUEST_TYPE,
                 &requestType, 1);
+        if (res != OK) {
+            ALOGE("%s: Unable to update request type",
+                  __FUNCTION__);
+            return INVALID_OPERATION;
+        }
+
         int32_t inputStreams[1] =
-                { mZslReprocessStreamId };
-        if (res == OK) request.update(ANDROID_REQUEST_INPUT_STREAMS,
+                { mZslStreamId };
+        res = request.update(ANDROID_REQUEST_INPUT_STREAMS,
                 inputStreams, 1);
+        if (res != OK) {
+            ALOGE("%s: Unable to update request input streams",
+                  __FUNCTION__);
+            return INVALID_OPERATION;
+        }
+
+        uint8_t captureIntent =
+                static_cast<uint8_t>(ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE);
+        res = request.update(ANDROID_CONTROL_CAPTURE_INTENT,
+                &captureIntent, 1);
+        if (res != OK ) {
+            ALOGE("%s: Unable to update request capture intent",
+                  __FUNCTION__);
+            return INVALID_OPERATION;
+        }
+
+        // TODO: Shouldn't we also update the latest preview frame?
         int32_t outputStreams[1] =
                 { client->getCaptureStreamId() };
-        if (res == OK) request.update(ANDROID_REQUEST_OUTPUT_STREAMS,
+        res = request.update(ANDROID_REQUEST_OUTPUT_STREAMS,
                 outputStreams, 1);
+        if (res != OK) {
+            ALOGE("%s: Unable to update request output streams",
+                  __FUNCTION__);
+            return INVALID_OPERATION;
+        }
+
         res = request.update(ANDROID_REQUEST_ID,
                 &requestId, 1);
-
         if (res != OK ) {
-            ALOGE("%s: Unable to update frame to a reprocess request", __FUNCTION__);
+            ALOGE("%s: Unable to update frame to a reprocess request",
+                  __FUNCTION__);
             return INVALID_OPERATION;
         }
 
@@ -336,17 +390,9 @@
         if (res != OK) {
             ALOGE("%s: Camera %d: Unable to stop preview for ZSL capture: "
                 "%s (%d)",
-                __FUNCTION__, mId, strerror(-res), res);
+                __FUNCTION__, client->getCameraId(), strerror(-res), res);
             return INVALID_OPERATION;
         }
-        // TODO: have push-and-clear be atomic
-        res = client->getCameraDevice()->pushReprocessBuffer(mZslReprocessStreamId,
-                handle, this);
-        if (res != OK) {
-            ALOGE("%s: Unable to push buffer for reprocessing: %s (%d)",
-                    __FUNCTION__, strerror(-res), res);
-            return res;
-        }
 
         // Update JPEG settings
         {
@@ -355,25 +401,30 @@
             if (res != OK) {
                 ALOGE("%s: Camera %d: Unable to update JPEG entries of ZSL "
                         "capture request: %s (%d)", __FUNCTION__,
-                        mId,
+                        client->getCameraId(),
                         strerror(-res), res);
                 return res;
             }
         }
 
+        // Update post-processing settings
+        res = updateRequestWithDefaultStillRequest(request);
+        if (res != OK) {
+            ALOGW("%s: Unable to update post-processing tags, the reprocessed image quality "
+                    "may be compromised", __FUNCTION__);
+        }
+
         mLatestCapturedRequest = request;
         res = client->getCameraDevice()->capture(request);
         if (res != OK ) {
-            ALOGE("%s: Unable to send ZSL reprocess request to capture: %s (%d)",
-                    __FUNCTION__, strerror(-res), res);
+            ALOGE("%s: Unable to send ZSL reprocess request to capture: %s"
+                  " (%d)", __FUNCTION__, strerror(-res), res);
             return res;
         }
 
         mState = LOCKED;
-    } else {
-        ALOGV("%s: No ZSL buffers yet", __FUNCTION__);
-        return NOT_ENOUGH_DATA;
     }
+
     return OK;
 }
 
@@ -386,17 +437,20 @@
 }
 
 status_t ZslProcessor::clearZslQueueLocked() {
-    for (size_t i = 0; i < mZslQueue.size(); i++) {
-        if (mZslQueue[i].buffer.mTimestamp != 0) {
-            mZslConsumer->releaseBuffer(mZslQueue[i].buffer);
-        }
-        mZslQueue.replaceAt(i);
+    if (mZslStream != 0) {
+        // clear result metadata list first.
+        clearZslResultQueueLocked();
+        return mZslStream->clearInputRingBuffer(&mLatestClearedBufferTimestamp);
     }
-    mZslQueueHead = 0;
-    mZslQueueTail = 0;
     return OK;
 }
 
+void ZslProcessor::clearZslResultQueueLocked() {
+    mFrameList.clear();
+    mFrameListHead = 0;
+    mFrameList.insertAt(0, mFrameListDepth);
+}
+
 void ZslProcessor::dump(int fd, const Vector<String16>& /*args*/) const {
     Mutex::Autolock l(mInputMutex);
     if (!mLatestCapturedRequest.isEmpty()) {
@@ -411,128 +465,9 @@
 }
 
 bool ZslProcessor::threadLoop() {
-    status_t res;
-
-    {
-        Mutex::Autolock l(mInputMutex);
-        while (!mZslBufferAvailable) {
-            res = mZslBufferAvailableSignal.waitRelative(mInputMutex,
-                    kWaitDuration);
-            if (res == TIMED_OUT) return true;
-        }
-        mZslBufferAvailable = false;
-    }
-
-    do {
-        res = processNewZslBuffer();
-    } while (res == OK);
-
-    return true;
-}
-
-status_t ZslProcessor::processNewZslBuffer() {
-    ATRACE_CALL();
-    status_t res;
-    sp<BufferItemConsumer> zslConsumer;
-    {
-        Mutex::Autolock l(mInputMutex);
-        if (mZslConsumer == 0) return OK;
-        zslConsumer = mZslConsumer;
-    }
-    ALOGVV("Trying to get next buffer");
-    BufferItem item;
-    res = zslConsumer->acquireBuffer(&item, 0);
-    if (res != OK) {
-        if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) {
-            ALOGE("%s: Camera %d: Error receiving ZSL image buffer: "
-                    "%s (%d)", __FUNCTION__,
-                    mId, strerror(-res), res);
-        } else {
-            ALOGVV("  No buffer");
-        }
-        return res;
-    }
-
-    Mutex::Autolock l(mInputMutex);
-
-    if (mState == LOCKED) {
-        ALOGVV("In capture, discarding new ZSL buffers");
-        zslConsumer->releaseBuffer(item);
-        return OK;
-    }
-
-    ALOGVV("Got ZSL buffer: head: %d, tail: %d", mZslQueueHead, mZslQueueTail);
-
-    if ( (mZslQueueHead + 1) % kZslBufferDepth == mZslQueueTail) {
-        ALOGVV("Releasing oldest buffer");
-        zslConsumer->releaseBuffer(mZslQueue[mZslQueueTail].buffer);
-        mZslQueue.replaceAt(mZslQueueTail);
-        mZslQueueTail = (mZslQueueTail + 1) % kZslBufferDepth;
-    }
-
-    ZslPair &queueHead = mZslQueue.editItemAt(mZslQueueHead);
-
-    queueHead.buffer = item;
-    queueHead.frame.release();
-
-    mZslQueueHead = (mZslQueueHead + 1) % kZslBufferDepth;
-
-    ALOGVV("  Acquired buffer, timestamp %" PRId64, queueHead.buffer.mTimestamp);
-
-    findMatchesLocked();
-
-    return OK;
-}
-
-void ZslProcessor::findMatchesLocked() {
-    ALOGVV("Scanning");
-    for (size_t i = 0; i < mZslQueue.size(); i++) {
-        ZslPair &queueEntry = mZslQueue.editItemAt(i);
-        nsecs_t bufferTimestamp = queueEntry.buffer.mTimestamp;
-        IF_ALOGV() {
-            camera_metadata_entry_t entry;
-            nsecs_t frameTimestamp = 0;
-            if (!queueEntry.frame.isEmpty()) {
-                entry = queueEntry.frame.find(ANDROID_SENSOR_TIMESTAMP);
-                frameTimestamp = entry.data.i64[0];
-            }
-            ALOGVV("   %d: b: %" PRId64 "\tf: %" PRId64, i,
-                    bufferTimestamp, frameTimestamp );
-        }
-        if (queueEntry.frame.isEmpty() && bufferTimestamp != 0) {
-            // Have buffer, no matching frame. Look for one
-            for (size_t j = 0; j < mFrameList.size(); j++) {
-                bool match = false;
-                CameraMetadata &frame = mFrameList.editItemAt(j);
-                if (!frame.isEmpty()) {
-                    camera_metadata_entry_t entry;
-                    entry = frame.find(ANDROID_SENSOR_TIMESTAMP);
-                    if (entry.count == 0) {
-                        ALOGE("%s: Can't find timestamp in frame!",
-                                __FUNCTION__);
-                        continue;
-                    }
-                    nsecs_t frameTimestamp = entry.data.i64[0];
-                    if (bufferTimestamp == frameTimestamp) {
-                        ALOGVV("%s: Found match %" PRId64, __FUNCTION__,
-                                frameTimestamp);
-                        match = true;
-                    } else {
-                        int64_t delta = abs(bufferTimestamp - frameTimestamp);
-                        if ( delta < 1000000) {
-                            ALOGVV("%s: Found close match %" PRId64 " (delta %" PRId64 ")",
-                                    __FUNCTION__, bufferTimestamp, delta);
-                            match = true;
-                        }
-                    }
-                }
-                if (match) {
-                    queueEntry.frame.acquire(frame);
-                    break;
-                }
-            }
-        }
-    }
+    // TODO: remove dependency on thread. For now, shut thread down right
+    // away.
+    return false;
 }
 
 void ZslProcessor::dumpZslQueue(int fd) const {
@@ -567,5 +502,174 @@
     }
 }
 
+bool ZslProcessor::isFixedFocusMode(uint8_t afMode) const {
+    switch (afMode) {
+        case ANDROID_CONTROL_AF_MODE_AUTO:
+        case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
+        case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
+        case ANDROID_CONTROL_AF_MODE_MACRO:
+            return false;
+            break;
+        case ANDROID_CONTROL_AF_MODE_OFF:
+        case ANDROID_CONTROL_AF_MODE_EDOF:
+            return true;
+        default:
+            ALOGE("%s: unknown focus mode %d", __FUNCTION__, afMode);
+            return false;
+    }
+}
+
+nsecs_t ZslProcessor::getCandidateTimestampLocked(size_t* metadataIdx) const {
+    /**
+     * Find the smallest timestamp we know about so far
+     * - ensure that aeState is either converged or locked
+     */
+
+    size_t idx = 0;
+    nsecs_t minTimestamp = -1;
+
+    size_t emptyCount = mFrameList.size();
+
+    for (size_t j = 0; j < mFrameList.size(); j++) {
+        const CameraMetadata &frame = mFrameList[j];
+        if (!frame.isEmpty()) {
+
+            emptyCount--;
+
+            camera_metadata_ro_entry_t entry;
+            entry = frame.find(ANDROID_SENSOR_TIMESTAMP);
+            if (entry.count == 0) {
+                ALOGE("%s: Can't find timestamp in frame!",
+                        __FUNCTION__);
+                continue;
+            }
+            nsecs_t frameTimestamp = entry.data.i64[0];
+            if (minTimestamp > frameTimestamp || minTimestamp == -1) {
+
+                entry = frame.find(ANDROID_CONTROL_AE_STATE);
+
+                if (entry.count == 0) {
+                    /**
+                     * This is most likely a HAL bug. The aeState field is
+                     * mandatory, so it should always be in a metadata packet.
+                     */
+                    ALOGW("%s: ZSL queue frame has no AE state field!",
+                            __FUNCTION__);
+                    continue;
+                }
+                if (entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_CONVERGED &&
+                        entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_LOCKED) {
+                    ALOGVV("%s: ZSL queue frame AE state is %d, need "
+                           "full capture",  __FUNCTION__, entry.data.u8[0]);
+                    continue;
+                }
+
+                entry = frame.find(ANDROID_CONTROL_AF_MODE);
+                if (entry.count == 0) {
+                    ALOGW("%s: ZSL queue frame has no AF mode field!",
+                            __FUNCTION__);
+                    continue;
+                }
+                uint8_t afMode = entry.data.u8[0];
+                if (afMode == ANDROID_CONTROL_AF_MODE_OFF) {
+                    // Skip all the ZSL buffer for manual AF mode, as we don't really
+                    // know the af state.
+                    continue;
+                }
+
+                // Check AF state if device has focuser and focus mode isn't fixed
+                if (mHasFocuser && !isFixedFocusMode(afMode)) {
+                    // Make sure the candidate frame has good focus.
+                    entry = frame.find(ANDROID_CONTROL_AF_STATE);
+                    if (entry.count == 0) {
+                        ALOGW("%s: ZSL queue frame has no AF state field!",
+                                __FUNCTION__);
+                        continue;
+                    }
+                    uint8_t afState = entry.data.u8[0];
+                    if (afState != ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED &&
+                            afState != ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED &&
+                            afState != ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
+                        ALOGVV("%s: ZSL queue frame AF state is %d is not good for capture, skip it",
+                                __FUNCTION__, afState);
+                        continue;
+                    }
+                }
+
+                minTimestamp = frameTimestamp;
+                idx = j;
+            }
+
+            ALOGVV("%s: Saw timestamp %" PRId64, __FUNCTION__, frameTimestamp);
+        }
+    }
+
+    if (emptyCount == mFrameList.size()) {
+        /**
+         * This could be mildly bad and means our ZSL was triggered before
+         * there were any frames yet received by the camera framework.
+         *
+         * This is a fairly corner case which can happen under:
+         * + a user presses the shutter button real fast when the camera starts
+         *     (startPreview followed immediately by takePicture).
+         * + burst capture case (hitting shutter button as fast possible)
+         *
+         * If this happens in steady case (preview running for a while, call
+         *     a single takePicture) then this might be a fwk bug.
+         */
+        ALOGW("%s: ZSL queue has no metadata frames", __FUNCTION__);
+    }
+
+    ALOGV("%s: Candidate timestamp %" PRId64 " (idx %zu), empty frames: %zu",
+          __FUNCTION__, minTimestamp, idx, emptyCount);
+
+    if (metadataIdx) {
+        *metadataIdx = idx;
+    }
+
+    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 5870bd3..86c06c6 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * 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.
@@ -25,11 +25,9 @@
 #include <gui/BufferItem.h>
 #include <gui/BufferItemConsumer.h>
 #include <camera/CameraMetadata.h>
-#include <camera/CaptureResult.h>
 
-#include "common/CameraDeviceBase.h"
-#include "api1/client2/ZslProcessorInterface.h"
 #include "api1/client2/FrameProcessor.h"
+#include "device3/Camera3ZslStream.h"
 
 namespace android {
 
@@ -38,45 +36,66 @@
 namespace camera2 {
 
 class CaptureSequencer;
-class Parameters;
+struct Parameters;
 
 /***
- * ZSL queue processing
+ * ZSL queue processing for HALv3.0 or newer
  */
-class ZslProcessor:
+class ZslProcessor :
+                    public camera3::Camera3StreamBufferListener,
             virtual public Thread,
-            virtual public BufferItemConsumer::FrameAvailableListener,
-            virtual public FrameProcessor::FilteredListener,
-            virtual public CameraDeviceBase::BufferReleasedListener,
-                    public ZslProcessorInterface {
+            virtual public FrameProcessor::FilteredListener {
   public:
     ZslProcessor(sp<Camera2Client> client, wp<CaptureSequencer> sequencer);
     ~ZslProcessor();
 
-    // From mZslConsumer
-    virtual void onFrameAvailable(const BufferItem& item);
-    // From FrameProcessor
+    // From FrameProcessor::FilteredListener
     virtual void onResultAvailable(const CaptureResult &result);
 
-    virtual void onBufferReleased(buffer_handle_t *handle);
-
     /**
      ****************************************
      * ZslProcessorInterface implementation *
      ****************************************
      */
 
+    // Update the streams by recreating them if the size/format has changed
     status_t updateStream(const Parameters &params);
+
+    // Delete the underlying CameraDevice streams
     status_t deleteStream();
-    status_t disconnect();
+
+    // Get ID for use with android.request.outputStreams / inputStreams
     int getStreamId() const;
 
+    /**
+     * Submits a ZSL capture request (id = requestId)
+     *
+     * An appropriate ZSL buffer is selected by the closest timestamp,
+     * then we push that buffer to be reprocessed by the HAL.
+     * A capture request is created and submitted on behalf of the client.
+     */
     status_t pushToReprocess(int32_t requestId);
+
+    // Flush the ZSL buffer queue, freeing up all the buffers
     status_t clearZslQueue();
 
     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:
     static const nsecs_t kWaitDuration = 10000000; // 10 ms
+    nsecs_t mLatestClearedBufferTimestamp;
 
     enum {
         RUNNING,
@@ -84,53 +103,52 @@
     } mState;
 
     wp<Camera2Client> mClient;
-    wp<CameraDeviceBase> mDevice;
     wp<CaptureSequencer> mSequencer;
-    int mId;
 
-    bool mDeleted;
+    const int mId;
 
     mutable Mutex mInputMutex;
-    bool mZslBufferAvailable;
-    Condition mZslBufferAvailableSignal;
 
     enum {
         NO_STREAM = -1
     };
 
     int mZslStreamId;
-    int mZslReprocessStreamId;
-    sp<BufferItemConsumer> mZslConsumer;
-    sp<Surface>            mZslWindow;
+    sp<camera3::Camera3ZslStream> mZslStream;
 
     struct ZslPair {
         BufferItem buffer;
         CameraMetadata frame;
     };
 
-    static const size_t kZslBufferDepth = 4;
-    static const size_t kFrameListDepth = kZslBufferDepth * 2;
+    static const int32_t kDefaultMaxPipelineDepth = 4;
+    size_t mBufferQueueDepth;
+    size_t mFrameListDepth;
     Vector<CameraMetadata> mFrameList;
     size_t mFrameListHead;
 
     ZslPair mNextPair;
 
     Vector<ZslPair> mZslQueue;
-    size_t mZslQueueHead;
-    size_t mZslQueueTail;
 
     CameraMetadata mLatestCapturedRequest;
 
+    bool mHasFocuser;
+
     virtual bool threadLoop();
 
-    status_t processNewZslBuffer();
-
-    // Match up entries from frame list to buffers in ZSL queue
-    void findMatchesLocked();
-
     status_t clearZslQueueLocked();
 
+    void clearZslResultQueueLocked();
+
     void dumpZslQueue(int id) const;
+
+    nsecs_t getCandidateTimestampLocked(size_t* metadataIdx) const;
+
+    bool isFixedFocusMode(uint8_t afMode) const;
+
+    // Update the post-processing metadata with the default still capture request template
+    status_t updateRequestWithDefaultStillRequest(CameraMetadata &request) const;
 };
 
 
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
deleted file mode 100644
index 69620ac..0000000
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
+++ /dev/null
@@ -1,677 +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 "Camera2-ZslProcessor3"
-#define ATRACE_TAG ATRACE_TAG_CAMERA
-//#define LOG_NDEBUG 0
-//#define LOG_NNDEBUG 0
-
-#ifdef LOG_NNDEBUG
-#define ALOGVV(...) ALOGV(__VA_ARGS__)
-#else
-#define ALOGVV(...) ((void)0)
-#endif
-
-#include <inttypes.h>
-
-#include <utils/Log.h>
-#include <utils/Trace.h>
-#include <gui/Surface.h>
-
-#include "common/CameraDeviceBase.h"
-#include "api1/Camera2Client.h"
-#include "api1/client2/CaptureSequencer.h"
-#include "api1/client2/ZslProcessor3.h"
-#include "device3/Camera3Device.h"
-
-namespace android {
-namespace camera2 {
-
-ZslProcessor3::ZslProcessor3(
-    sp<Camera2Client> client,
-    wp<CaptureSequencer> sequencer):
-        Thread(false),
-        mLatestClearedBufferTimestamp(0),
-        mState(RUNNING),
-        mClient(client),
-        mSequencer(sequencer),
-        mId(client->getCameraId()),
-        mZslStreamId(NO_STREAM),
-        mFrameListHead(0),
-        mZslQueueHead(0),
-        mZslQueueTail(0),
-        mHasFocuser(false) {
-    // Initialize buffer queue and frame list based on pipeline max depth.
-    size_t pipelineMaxDepth = kDefaultMaxPipelineDepth;
-    if (client != 0) {
-        sp<Camera3Device> device =
-        static_cast<Camera3Device*>(client->getCameraDevice().get());
-        if (device != 0) {
-            camera_metadata_ro_entry_t entry =
-                device->info().find(ANDROID_REQUEST_PIPELINE_MAX_DEPTH);
-            if (entry.count == 1) {
-                pipelineMaxDepth = entry.data.u8[0];
-            } else {
-                ALOGW("%s: Unable to find the android.request.pipelineMaxDepth,"
-                        " use default pipeline max depth %zu", __FUNCTION__,
-                        kDefaultMaxPipelineDepth);
-            }
-
-            entry = device->info().find(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE);
-            if (entry.count > 0 && entry.data.f[0] != 0.) {
-                mHasFocuser = true;
-            }
-        }
-    }
-
-    ALOGV("%s: Initialize buffer queue and frame list depth based on max pipeline depth (%d)",
-          __FUNCTION__, pipelineMaxDepth);
-    // Need to keep buffer queue longer than metadata queue because sometimes buffer arrives
-    // earlier than metadata which causes the buffer corresponding to oldest metadata being
-    // removed.
-    mFrameListDepth = pipelineMaxDepth;
-    mBufferQueueDepth = mFrameListDepth + 1;
-
-
-    mZslQueue.insertAt(0, mBufferQueueDepth);
-    mFrameList.insertAt(0, mFrameListDepth);
-    sp<CaptureSequencer> captureSequencer = mSequencer.promote();
-    if (captureSequencer != 0) captureSequencer->setZslProcessor(this);
-}
-
-ZslProcessor3::~ZslProcessor3() {
-    ALOGV("%s: Exit", __FUNCTION__);
-    deleteStream();
-}
-
-void ZslProcessor3::onResultAvailable(const CaptureResult &result) {
-    ATRACE_CALL();
-    ALOGV("%s:", __FUNCTION__);
-    Mutex::Autolock l(mInputMutex);
-    camera_metadata_ro_entry_t entry;
-    entry = result.mMetadata.find(ANDROID_SENSOR_TIMESTAMP);
-    nsecs_t timestamp = entry.data.i64[0];
-    if (entry.count == 0) {
-        ALOGE("%s: metadata doesn't have timestamp, skip this result", __FUNCTION__);
-        return;
-    }
-
-    entry = result.mMetadata.find(ANDROID_REQUEST_FRAME_COUNT);
-    if (entry.count == 0) {
-        ALOGE("%s: metadata doesn't have frame number, skip this result", __FUNCTION__);
-        return;
-    }
-    int32_t frameNumber = entry.data.i32[0];
-
-    ALOGVV("Got preview metadata for frame %d with timestamp %" PRId64, frameNumber, timestamp);
-
-    if (mState != RUNNING) return;
-
-    // Corresponding buffer has been cleared. No need to push into mFrameList
-    if (timestamp <= mLatestClearedBufferTimestamp) return;
-
-    mFrameList.editItemAt(mFrameListHead) = result.mMetadata;
-    mFrameListHead = (mFrameListHead + 1) % mFrameListDepth;
-}
-
-status_t ZslProcessor3::updateStream(const Parameters &params) {
-    ATRACE_CALL();
-    ALOGV("%s: Configuring ZSL streams", __FUNCTION__);
-    status_t res;
-
-    Mutex::Autolock l(mInputMutex);
-
-    sp<Camera2Client> client = mClient.promote();
-    if (client == 0) {
-        ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
-        return INVALID_OPERATION;
-    }
-    sp<Camera3Device> device =
-        static_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) {
-        // Check if stream parameters have to change
-        uint32_t currentWidth, currentHeight;
-        res = device->getStreamInfo(mZslStreamId,
-                &currentWidth, &currentHeight, 0, 0);
-        if (res != OK) {
-            ALOGE("%s: Camera %d: Error querying capture output stream info: "
-                    "%s (%d)", __FUNCTION__,
-                    client->getCameraId(), strerror(-res), res);
-            return res;
-        }
-        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;
-            }
-            mZslStreamId = NO_STREAM;
-        }
-    }
-
-    if (mZslStreamId == NO_STREAM) {
-        // 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);
-        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,
-            Camera2Client::kPreviewRequestIdEnd,
-            this,
-            /*sendPartials*/false);
-
-    return OK;
-}
-
-status_t ZslProcessor3::deleteStream() {
-    ATRACE_CALL();
-    status_t res;
-
-    Mutex::Autolock l(mInputMutex);
-
-    if (mZslStreamId != NO_STREAM) {
-        sp<Camera2Client> client = mClient.promote();
-        if (client == 0) {
-            ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
-            return INVALID_OPERATION;
-        }
-
-        sp<Camera3Device> device =
-            reinterpret_cast<Camera3Device*>(client->getCameraDevice().get());
-        if (device == 0) {
-            ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
-            return INVALID_OPERATION;
-        }
-
-        res = device->deleteStream(mZslStreamId);
-        if (res != OK) {
-            ALOGE("%s: Camera %d: Cannot delete ZSL output stream %d: "
-                    "%s (%d)", __FUNCTION__, client->getCameraId(),
-                    mZslStreamId, strerror(-res), res);
-            return res;
-        }
-
-        mZslStreamId = NO_STREAM;
-    }
-    return OK;
-}
-
-int ZslProcessor3::getStreamId() const {
-    Mutex::Autolock l(mInputMutex);
-    return mZslStreamId;
-}
-
-status_t ZslProcessor3::updateRequestWithDefaultStillRequest(CameraMetadata &request) const {
-    sp<Camera2Client> client = mClient.promote();
-    if (client == 0) {
-        ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
-        return INVALID_OPERATION;
-    }
-    sp<Camera3Device> device =
-        static_cast<Camera3Device*>(client->getCameraDevice().get());
-    if (device == 0) {
-        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
-        return INVALID_OPERATION;
-    }
-
-    CameraMetadata stillTemplate;
-    device->createDefaultRequest(CAMERA3_TEMPLATE_STILL_CAPTURE, &stillTemplate);
-
-    // Find some of the post-processing tags, and assign the value from template to the request.
-    // Only check the aberration mode and noise reduction mode for now, as they are very important
-    // for image quality.
-    uint32_t postProcessingTags[] = {
-            ANDROID_NOISE_REDUCTION_MODE,
-            ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
-            ANDROID_COLOR_CORRECTION_MODE,
-            ANDROID_TONEMAP_MODE,
-            ANDROID_SHADING_MODE,
-            ANDROID_HOT_PIXEL_MODE,
-            ANDROID_EDGE_MODE
-    };
-
-    camera_metadata_entry_t entry;
-    for (size_t i = 0; i < sizeof(postProcessingTags) / sizeof(uint32_t); i++) {
-        entry = stillTemplate.find(postProcessingTags[i]);
-        if (entry.count > 0) {
-            request.update(postProcessingTags[i], entry.data.u8, 1);
-        }
-    }
-
-    return OK;
-}
-
-status_t ZslProcessor3::pushToReprocess(int32_t requestId) {
-    ALOGV("%s: Send in reprocess request with id %d",
-            __FUNCTION__, requestId);
-    Mutex::Autolock l(mInputMutex);
-    status_t res;
-    sp<Camera2Client> client = mClient.promote();
-
-    if (client == 0) {
-        ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
-        return INVALID_OPERATION;
-    }
-
-    IF_ALOGV() {
-        dumpZslQueue(-1);
-    }
-
-    size_t metadataIdx;
-    nsecs_t candidateTimestamp = getCandidateTimestampLocked(&metadataIdx);
-
-    if (candidateTimestamp == -1) {
-        ALOGE("%s: Could not find good candidate for ZSL reprocessing",
-              __FUNCTION__);
-        return NOT_ENOUGH_DATA;
-    }
-
-    res = mZslStream->enqueueInputBufferByTimestamp(candidateTimestamp,
-                                                    /*actualTimestamp*/NULL);
-
-    if (res == mZslStream->NO_BUFFER_AVAILABLE) {
-        ALOGV("%s: No ZSL buffers yet", __FUNCTION__);
-        return NOT_ENOUGH_DATA;
-    } else if (res != OK) {
-        ALOGE("%s: Unable to push buffer for reprocessing: %s (%d)",
-                __FUNCTION__, strerror(-res), res);
-        return res;
-    }
-
-    {
-        CameraMetadata request = mFrameList[metadataIdx];
-
-        // Verify that the frame is reasonable for reprocessing
-
-        camera_metadata_entry_t entry;
-        entry = request.find(ANDROID_CONTROL_AE_STATE);
-        if (entry.count == 0) {
-            ALOGE("%s: ZSL queue frame has no AE state field!",
-                    __FUNCTION__);
-            return BAD_VALUE;
-        }
-        if (entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_CONVERGED &&
-                entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_LOCKED) {
-            ALOGV("%s: ZSL queue frame AE state is %d, need full capture",
-                    __FUNCTION__, entry.data.u8[0]);
-            return NOT_ENOUGH_DATA;
-        }
-
-        uint8_t requestType = ANDROID_REQUEST_TYPE_REPROCESS;
-        res = request.update(ANDROID_REQUEST_TYPE,
-                &requestType, 1);
-        if (res != OK) {
-            ALOGE("%s: Unable to update request type",
-                  __FUNCTION__);
-            return INVALID_OPERATION;
-        }
-
-        int32_t inputStreams[1] =
-                { mZslStreamId };
-        res = request.update(ANDROID_REQUEST_INPUT_STREAMS,
-                inputStreams, 1);
-        if (res != OK) {
-            ALOGE("%s: Unable to update request input streams",
-                  __FUNCTION__);
-            return INVALID_OPERATION;
-        }
-
-        uint8_t captureIntent =
-                static_cast<uint8_t>(ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE);
-        res = request.update(ANDROID_CONTROL_CAPTURE_INTENT,
-                &captureIntent, 1);
-        if (res != OK ) {
-            ALOGE("%s: Unable to update request capture intent",
-                  __FUNCTION__);
-            return INVALID_OPERATION;
-        }
-
-        // TODO: Shouldn't we also update the latest preview frame?
-        int32_t outputStreams[1] =
-                { client->getCaptureStreamId() };
-        res = request.update(ANDROID_REQUEST_OUTPUT_STREAMS,
-                outputStreams, 1);
-        if (res != OK) {
-            ALOGE("%s: Unable to update request output streams",
-                  __FUNCTION__);
-            return INVALID_OPERATION;
-        }
-
-        res = request.update(ANDROID_REQUEST_ID,
-                &requestId, 1);
-        if (res != OK ) {
-            ALOGE("%s: Unable to update frame to a reprocess request",
-                  __FUNCTION__);
-            return INVALID_OPERATION;
-        }
-
-        res = client->stopStream();
-        if (res != OK) {
-            ALOGE("%s: Camera %d: Unable to stop preview for ZSL capture: "
-                "%s (%d)",
-                __FUNCTION__, client->getCameraId(), strerror(-res), res);
-            return INVALID_OPERATION;
-        }
-
-        // Update JPEG settings
-        {
-            SharedParameters::Lock l(client->getParameters());
-            res = l.mParameters.updateRequestJpeg(&request);
-            if (res != OK) {
-                ALOGE("%s: Camera %d: Unable to update JPEG entries of ZSL "
-                        "capture request: %s (%d)", __FUNCTION__,
-                        client->getCameraId(),
-                        strerror(-res), res);
-                return res;
-            }
-        }
-
-        // Update post-processing settings
-        res = updateRequestWithDefaultStillRequest(request);
-        if (res != OK) {
-            ALOGW("%s: Unable to update post-processing tags, the reprocessed image quality "
-                    "may be compromised", __FUNCTION__);
-        }
-
-        mLatestCapturedRequest = request;
-        res = client->getCameraDevice()->capture(request);
-        if (res != OK ) {
-            ALOGE("%s: Unable to send ZSL reprocess request to capture: %s"
-                  " (%d)", __FUNCTION__, strerror(-res), res);
-            return res;
-        }
-
-        mState = LOCKED;
-    }
-
-    return OK;
-}
-
-status_t ZslProcessor3::clearZslQueue() {
-    Mutex::Autolock l(mInputMutex);
-    // If in middle of capture, can't clear out queue
-    if (mState == LOCKED) return OK;
-
-    return clearZslQueueLocked();
-}
-
-status_t ZslProcessor3::clearZslQueueLocked() {
-    if (mZslStream != 0) {
-        // clear result metadata list first.
-        clearZslResultQueueLocked();
-        return mZslStream->clearInputRingBuffer(&mLatestClearedBufferTimestamp);
-    }
-    return OK;
-}
-
-void ZslProcessor3::clearZslResultQueueLocked() {
-    mFrameList.clear();
-    mFrameListHead = 0;
-    mFrameList.insertAt(0, mFrameListDepth);
-}
-
-void ZslProcessor3::dump(int fd, const Vector<String16>& /*args*/) const {
-    Mutex::Autolock l(mInputMutex);
-    if (!mLatestCapturedRequest.isEmpty()) {
-        String8 result("    Latest ZSL capture request:\n");
-        write(fd, result.string(), result.size());
-        mLatestCapturedRequest.dump(fd, 2, 6);
-    } else {
-        String8 result("    Latest ZSL capture request: none yet\n");
-        write(fd, result.string(), result.size());
-    }
-    dumpZslQueue(fd);
-}
-
-bool ZslProcessor3::threadLoop() {
-    // TODO: remove dependency on thread. For now, shut thread down right
-    // away.
-    return false;
-}
-
-void ZslProcessor3::dumpZslQueue(int fd) const {
-    String8 header("ZSL queue contents:");
-    String8 indent("    ");
-    ALOGV("%s", header.string());
-    if (fd != -1) {
-        header = indent + header + "\n";
-        write(fd, header.string(), header.size());
-    }
-    for (size_t i = 0; i < mZslQueue.size(); i++) {
-        const ZslPair &queueEntry = mZslQueue[i];
-        nsecs_t bufferTimestamp = queueEntry.buffer.mTimestamp;
-        camera_metadata_ro_entry_t entry;
-        nsecs_t frameTimestamp = 0;
-        int frameAeState = -1;
-        if (!queueEntry.frame.isEmpty()) {
-            entry = queueEntry.frame.find(ANDROID_SENSOR_TIMESTAMP);
-            if (entry.count > 0) frameTimestamp = entry.data.i64[0];
-            entry = queueEntry.frame.find(ANDROID_CONTROL_AE_STATE);
-            if (entry.count > 0) frameAeState = entry.data.u8[0];
-        }
-        String8 result =
-                String8::format("   %zu: b: %" PRId64 "\tf: %" PRId64 ", AE state: %d", i,
-                        bufferTimestamp, frameTimestamp, frameAeState);
-        ALOGV("%s", result.string());
-        if (fd != -1) {
-            result = indent + result + "\n";
-            write(fd, result.string(), result.size());
-        }
-
-    }
-}
-
-bool ZslProcessor3::isFixedFocusMode(uint8_t afMode) const {
-    switch (afMode) {
-        case ANDROID_CONTROL_AF_MODE_AUTO:
-        case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
-        case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
-        case ANDROID_CONTROL_AF_MODE_MACRO:
-            return false;
-            break;
-        case ANDROID_CONTROL_AF_MODE_OFF:
-        case ANDROID_CONTROL_AF_MODE_EDOF:
-            return true;
-        default:
-            ALOGE("%s: unknown focus mode %d", __FUNCTION__, afMode);
-            return false;
-    }
-}
-
-nsecs_t ZslProcessor3::getCandidateTimestampLocked(size_t* metadataIdx) const {
-    /**
-     * Find the smallest timestamp we know about so far
-     * - ensure that aeState is either converged or locked
-     */
-
-    size_t idx = 0;
-    nsecs_t minTimestamp = -1;
-
-    size_t emptyCount = mFrameList.size();
-
-    for (size_t j = 0; j < mFrameList.size(); j++) {
-        const CameraMetadata &frame = mFrameList[j];
-        if (!frame.isEmpty()) {
-
-            emptyCount--;
-
-            camera_metadata_ro_entry_t entry;
-            entry = frame.find(ANDROID_SENSOR_TIMESTAMP);
-            if (entry.count == 0) {
-                ALOGE("%s: Can't find timestamp in frame!",
-                        __FUNCTION__);
-                continue;
-            }
-            nsecs_t frameTimestamp = entry.data.i64[0];
-            if (minTimestamp > frameTimestamp || minTimestamp == -1) {
-
-                entry = frame.find(ANDROID_CONTROL_AE_STATE);
-
-                if (entry.count == 0) {
-                    /**
-                     * This is most likely a HAL bug. The aeState field is
-                     * mandatory, so it should always be in a metadata packet.
-                     */
-                    ALOGW("%s: ZSL queue frame has no AE state field!",
-                            __FUNCTION__);
-                    continue;
-                }
-                if (entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_CONVERGED &&
-                        entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_LOCKED) {
-                    ALOGVV("%s: ZSL queue frame AE state is %d, need "
-                           "full capture",  __FUNCTION__, entry.data.u8[0]);
-                    continue;
-                }
-
-                entry = frame.find(ANDROID_CONTROL_AF_MODE);
-                if (entry.count == 0) {
-                    ALOGW("%s: ZSL queue frame has no AF mode field!",
-                            __FUNCTION__);
-                    continue;
-                }
-                uint8_t afMode = entry.data.u8[0];
-                if (afMode == ANDROID_CONTROL_AF_MODE_OFF) {
-                    // Skip all the ZSL buffer for manual AF mode, as we don't really
-                    // know the af state.
-                    continue;
-                }
-
-                // Check AF state if device has focuser and focus mode isn't fixed
-                if (mHasFocuser && !isFixedFocusMode(afMode)) {
-                    // Make sure the candidate frame has good focus.
-                    entry = frame.find(ANDROID_CONTROL_AF_STATE);
-                    if (entry.count == 0) {
-                        ALOGW("%s: ZSL queue frame has no AF state field!",
-                                __FUNCTION__);
-                        continue;
-                    }
-                    uint8_t afState = entry.data.u8[0];
-                    if (afState != ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED &&
-                            afState != ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED &&
-                            afState != ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
-                        ALOGVV("%s: ZSL queue frame AF state is %d is not good for capture, skip it",
-                                __FUNCTION__, afState);
-                        continue;
-                    }
-                }
-
-                minTimestamp = frameTimestamp;
-                idx = j;
-            }
-
-            ALOGVV("%s: Saw timestamp %" PRId64, __FUNCTION__, frameTimestamp);
-        }
-    }
-
-    if (emptyCount == mFrameList.size()) {
-        /**
-         * This could be mildly bad and means our ZSL was triggered before
-         * there were any frames yet received by the camera framework.
-         *
-         * This is a fairly corner case which can happen under:
-         * + a user presses the shutter button real fast when the camera starts
-         *     (startPreview followed immediately by takePicture).
-         * + burst capture case (hitting shutter button as fast possible)
-         *
-         * If this happens in steady case (preview running for a while, call
-         *     a single takePicture) then this might be a fwk bug.
-         */
-        ALOGW("%s: ZSL queue has no metadata frames", __FUNCTION__);
-    }
-
-    ALOGV("%s: Candidate timestamp %" PRId64 " (idx %zu), empty frames: %zu",
-          __FUNCTION__, minTimestamp, idx, emptyCount);
-
-    if (metadataIdx) {
-        *metadataIdx = idx;
-    }
-
-    return minTimestamp;
-}
-
-void ZslProcessor3::onBufferAcquired(const BufferInfo& /*bufferInfo*/) {
-    // Intentionally left empty
-    // Although theoretically we could use this to get better dump info
-}
-
-void ZslProcessor3::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/ZslProcessor3.h b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
deleted file mode 100644
index 2960478..0000000
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
+++ /dev/null
@@ -1,148 +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_CAMERA_CAMERA2_ZSLPROCESSOR3_H
-#define ANDROID_SERVERS_CAMERA_CAMERA2_ZSLPROCESSOR3_H
-
-#include <utils/Thread.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-#include <utils/Mutex.h>
-#include <utils/Condition.h>
-#include <gui/BufferItem.h>
-#include <gui/BufferItemConsumer.h>
-#include <camera/CameraMetadata.h>
-
-#include "api1/client2/FrameProcessor.h"
-#include "api1/client2/ZslProcessorInterface.h"
-#include "device3/Camera3ZslStream.h"
-
-namespace android {
-
-class Camera2Client;
-
-namespace camera2 {
-
-class CaptureSequencer;
-class Parameters;
-
-/***
- * ZSL queue processing
- */
-class ZslProcessor3 :
-                    public ZslProcessorInterface,
-                    public camera3::Camera3StreamBufferListener,
-            virtual public Thread,
-            virtual public FrameProcessor::FilteredListener {
-  public:
-    ZslProcessor3(sp<Camera2Client> client, wp<CaptureSequencer> sequencer);
-    ~ZslProcessor3();
-
-    // From FrameProcessor::FilteredListener
-    virtual void onResultAvailable(const CaptureResult &result);
-
-    /**
-     ****************************************
-     * ZslProcessorInterface implementation *
-     ****************************************
-     */
-
-    virtual status_t updateStream(const Parameters &params);
-    virtual status_t deleteStream();
-    virtual int getStreamId() const;
-
-    virtual status_t pushToReprocess(int32_t requestId);
-    virtual status_t clearZslQueue();
-
-    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:
-    static const nsecs_t kWaitDuration = 10000000; // 10 ms
-    nsecs_t mLatestClearedBufferTimestamp;
-
-    enum {
-        RUNNING,
-        LOCKED
-    } mState;
-
-    wp<Camera2Client> mClient;
-    wp<CaptureSequencer> mSequencer;
-
-    const int mId;
-
-    mutable Mutex mInputMutex;
-
-    enum {
-        NO_STREAM = -1
-    };
-
-    int mZslStreamId;
-    sp<camera3::Camera3ZslStream> mZslStream;
-
-    struct ZslPair {
-        BufferItem buffer;
-        CameraMetadata frame;
-    };
-
-    static const int32_t kDefaultMaxPipelineDepth = 4;
-    size_t mBufferQueueDepth;
-    size_t mFrameListDepth;
-    Vector<CameraMetadata> mFrameList;
-    size_t mFrameListHead;
-
-    ZslPair mNextPair;
-
-    Vector<ZslPair> mZslQueue;
-    size_t mZslQueueHead;
-    size_t mZslQueueTail;
-
-    CameraMetadata mLatestCapturedRequest;
-
-    bool mHasFocuser;
-
-    virtual bool threadLoop();
-
-    status_t clearZslQueueLocked();
-
-    void clearZslResultQueueLocked();
-
-    void dumpZslQueue(int id) const;
-
-    nsecs_t getCandidateTimestampLocked(size_t* metadataIdx) const;
-
-    bool isFixedFocusMode(uint8_t afMode) const;
-
-    // Update the post-processing metadata with the default still capture request template
-    status_t updateRequestWithDefaultStillRequest(CameraMetadata &request) const;
-};
-
-
-}; //namespace camera2
-}; //namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.cpp
deleted file mode 100644
index 9efeaba..0000000
--- a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ZslProcessorInterface.h"
-
-namespace android {
-namespace camera2 {
-
-status_t ZslProcessorInterface::disconnect() {
-    return OK;
-}
-
-}; //namespace camera2
-}; //namespace android
-
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h b/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h
deleted file mode 100644
index 9e266e7..0000000
--- a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h
+++ /dev/null
@@ -1,64 +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_CAMERA_CAMERA2_ZSLPROCESSORINTERFACE_H
-#define ANDROID_SERVERS_CAMERA_CAMERA2_ZSLPROCESSORINTERFACE_H
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-namespace android {
-namespace camera2 {
-
-class Parameters;
-
-class ZslProcessorInterface : virtual public RefBase {
-public:
-
-    // Get ID for use with android.request.outputStreams / inputStreams
-    virtual int getStreamId() const = 0;
-
-    // Update the streams by recreating them if the size/format has changed
-    virtual status_t updateStream(const Parameters& params) = 0;
-
-    // Delete the underlying CameraDevice streams
-    virtual status_t deleteStream() = 0;
-
-    // Clear any additional state necessary before the CameraDevice is disconnected
-    virtual status_t disconnect();
-
-    /**
-     * Submits a ZSL capture request (id = requestId)
-     *
-     * An appropriate ZSL buffer is selected by the closest timestamp,
-     * then we push that buffer to be reprocessed by the HAL.
-     * A capture request is created and submitted on behalf of the client.
-     */
-    virtual status_t pushToReprocess(int32_t requestId) = 0;
-
-    // Flush the ZSL buffer queue, freeing up all the buffers
-    virtual status_t clearZslQueue() = 0;
-
-    // (Debugging only) Dump the current state to the specified file descriptor
-    virtual void dump(int fd, const Vector<String16>& args) const = 0;
-};
-
-}; //namespace camera2
-}; //namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 0c531c3..7be5696 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -456,11 +456,11 @@
         return BAD_VALUE;
     }
 
-    int streamId = -1;
+    int streamId = camera3::CAMERA3_STREAM_ID_INVALID;
     res = mDevice->createStream(surface, width, height, format, dataSpace,
                                 static_cast<camera3_stream_rotation_t>
                                         (outputConfiguration.getRotation()),
-                                &streamId);
+                                &streamId, outputConfiguration.getSurfaceSetID());
 
     if (res == OK) {
         mStreamMap.add(binder, streamId);
@@ -787,8 +787,11 @@
     return res;
 }
 
-
 status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) {
+    return BasicClient::dump(fd, args);
+}
+
+status_t CameraDeviceClient::dumpClient(int fd, const Vector<String16>& args) {
     String8 result;
     result.appendFormat("CameraDeviceClient[%d] (%p) dump:\n",
             mCameraId,
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index d1e692c..b1d1762 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -135,6 +135,8 @@
 
     virtual status_t      dump(int fd, const Vector<String16>& args);
 
+    virtual status_t      dumpClient(int fd, const Vector<String16>& args);
+
     /**
      * Device listener interface
      */
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 5732f80..4a812b4 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -31,7 +31,7 @@
 
 #include "api2/CameraDeviceClient.h"
 
-#include "CameraDeviceFactory.h"
+#include "device3/Camera3Device.h"
 
 namespace android {
 using namespace camera2;
@@ -62,7 +62,7 @@
             String8(clientPackageName).string(), clientPid, clientUid);
 
     mInitialClientPid = clientPid;
-    mDevice = CameraDeviceFactory::createDevice(cameraId);
+    mDevice = new Camera3Device(cameraId);
     LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
 }
 
@@ -124,7 +124,7 @@
 }
 
 template <typename TClientBase>
-status_t Camera2ClientBase<TClientBase>::dump(int fd,
+status_t Camera2ClientBase<TClientBase>::dumpClient(int fd,
                                               const Vector<String16>& args) {
     String8 result;
     result.appendFormat("Camera2ClientBase[%d] (%p) PID: %d, dump:\n",
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 220c5ad..81bae7b 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -57,7 +57,7 @@
     virtual ~Camera2ClientBase();
 
     virtual status_t      initialize(CameraModule *module);
-    virtual status_t      dump(int fd, const Vector<String16>& args);
+    virtual status_t      dumpClient(int fd, const Vector<String16>& args);
 
     /**
      * CameraDeviceBase::NotificationListener implementation
@@ -125,7 +125,7 @@
     // that mBinderSerializationLock is locked when they're called
     mutable Mutex         mBinderSerializationLock;
 
-    /** CameraDeviceBase instance wrapping HAL2+ entry */
+    /** CameraDeviceBase instance wrapping HAL3+ entry */
 
     const int mDeviceVersion;
     sp<CameraDeviceBase>  mDevice;
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 7b083a3..6fd2b39 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -31,6 +31,7 @@
 #include "camera/CaptureResult.h"
 #include "common/CameraModule.h"
 #include "gui/IGraphicBufferProducer.h"
+#include "device3/Camera3StreamInterface.h"
 
 namespace android {
 
@@ -108,7 +109,8 @@
      */
     virtual status_t createStream(sp<Surface> consumer,
             uint32_t width, uint32_t height, int format,
-            android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id) = 0;
+            android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
+            int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID) = 0;
 
     /**
      * Create an input stream of width, height, and format.
diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp
index 16b8aba..f33d1ba 100644
--- a/services/camera/libcameraservice/common/CameraModule.cpp
+++ b/services/camera/libcameraservice/common/CameraModule.cpp
@@ -27,15 +27,10 @@
 void CameraModule::deriveCameraCharacteristicsKeys(
         uint32_t deviceVersion, CameraMetadata &chars) {
     ATRACE_CALL();
-    // HAL1 devices should not reach here
-    if (deviceVersion < CAMERA_DEVICE_API_VERSION_2_0) {
-        ALOGV("%s: Cannot derive keys for HAL version < 2.0");
-        return;
-    }
 
+    Vector<int32_t> derivedCharKeys;
     // Keys added in HAL3.3
     if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_3) {
-        const size_t NUM_DERIVED_KEYS_HAL3_3 = 5;
         Vector<uint8_t> controlModes;
         uint8_t data = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE;
         chars.update(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &data, /*count*/1);
@@ -107,18 +102,11 @@
         chars.update(ANDROID_SHADING_AVAILABLE_MODES, lscModes);
         chars.update(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, lscMapModes);
 
-        entry = chars.find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
-        Vector<int32_t> availableCharsKeys;
-        availableCharsKeys.setCapacity(entry.count + NUM_DERIVED_KEYS_HAL3_3);
-        for (size_t i = 0; i < entry.count; i++) {
-            availableCharsKeys.push(entry.data.i32[i]);
-        }
-        availableCharsKeys.push(ANDROID_CONTROL_AE_LOCK_AVAILABLE);
-        availableCharsKeys.push(ANDROID_CONTROL_AWB_LOCK_AVAILABLE);
-        availableCharsKeys.push(ANDROID_CONTROL_AVAILABLE_MODES);
-        availableCharsKeys.push(ANDROID_SHADING_AVAILABLE_MODES);
-        availableCharsKeys.push(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES);
-        chars.update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, availableCharsKeys);
+        derivedCharKeys.push(ANDROID_CONTROL_AE_LOCK_AVAILABLE);
+        derivedCharKeys.push(ANDROID_CONTROL_AWB_LOCK_AVAILABLE);
+        derivedCharKeys.push(ANDROID_CONTROL_AVAILABLE_MODES);
+        derivedCharKeys.push(ANDROID_SHADING_AVAILABLE_MODES);
+        derivedCharKeys.push(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES);
 
         // Need update android.control.availableHighSpeedVideoConfigurations since HAL3.3
         // adds batch size to this array.
@@ -137,6 +125,65 @@
         }
     }
 
+    // Keys added in HAL3.4
+    if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_4) {
+        // Check if HAL supports RAW_OPAQUE output
+        camera_metadata_entry entry = chars.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+        bool supportRawOpaque = false;
+        bool supportAnyRaw = false;
+        const int STREAM_CONFIGURATION_SIZE = 4;
+        const int STREAM_FORMAT_OFFSET = 0;
+        const int STREAM_WIDTH_OFFSET = 1;
+        const int STREAM_HEIGHT_OFFSET = 2;
+        const int STREAM_IS_INPUT_OFFSET = 3;
+        Vector<int32_t> rawOpaqueSizes;
+
+        for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+            int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
+            int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
+            int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
+            int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
+            if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
+                supportRawOpaque = true;
+                rawOpaqueSizes.push(width);
+                rawOpaqueSizes.push(height);
+                // 2 bytes per pixel. This rough estimation is only used when
+                // HAL does not fill in the opaque raw size
+                rawOpaqueSizes.push(width * height *2);
+            }
+            if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    (format == HAL_PIXEL_FORMAT_RAW16 ||
+                     format == HAL_PIXEL_FORMAT_RAW10 ||
+                     format == HAL_PIXEL_FORMAT_RAW12 ||
+                     format == HAL_PIXEL_FORMAT_RAW_OPAQUE)) {
+                supportAnyRaw = true;
+            }
+        }
+
+        if (supportRawOpaque) {
+            entry = chars.find(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+            if (entry.count == 0) {
+                // Fill in estimated value if HAL does not list it
+                chars.update(ANDROID_SENSOR_OPAQUE_RAW_SIZE, rawOpaqueSizes);
+                derivedCharKeys.push(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+            }
+        }
+
+        // Check if HAL supports any RAW output, if so, fill in postRawSensitivityBoost range
+        if (supportAnyRaw) {
+            int32_t defaultRange[2] = {100, 100};
+            entry = chars.find(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE);
+            if (entry.count == 0) {
+                // Fill in default value (100, 100)
+                chars.update(
+                        ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE,
+                        defaultRange, 2);
+                derivedCharKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE);
+            }
+        }
+    }
+
     // Always add a default for the pre-correction active array if the vendor chooses to omit this
     camera_metadata_entry entry = chars.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
     if (entry.count == 0) {
@@ -144,8 +191,21 @@
         entry = chars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
         preCorrectionArray.appendArray(entry.data.i32, entry.count);
         chars.update(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, preCorrectionArray);
+        derivedCharKeys.push(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
     }
 
+    // Add those newly added keys to AVAILABLE_CHARACTERISTICS_KEYS
+    // This has to be done at this end of this function.
+    entry = chars.find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
+    Vector<int32_t> availableCharsKeys;
+    availableCharsKeys.setCapacity(entry.count + derivedCharKeys.size());
+    for (size_t i = 0; i < entry.count; i++) {
+        availableCharsKeys.push(entry.data.i32[i]);
+    }
+    for (size_t i = 0; i < derivedCharKeys.size(); i++) {
+        availableCharsKeys.push(derivedCharKeys[i]);
+    }
+    chars.update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, availableCharsKeys);
     return;
 }
 
@@ -196,6 +256,9 @@
         int ret;
         ATRACE_BEGIN("camera_module->get_camera_info");
         ret = mModule->get_camera_info(cameraId, info);
+        // Fill in this so CameraService won't be confused by
+        // possibly 0 device_version
+        info->device_version = CAMERA_DEVICE_API_VERSION_1_0;
         ATRACE_END();
         return ret;
     }
@@ -211,7 +274,7 @@
             return ret;
         }
         int deviceVersion = rawInfo.device_version;
-        if (deviceVersion < CAMERA_DEVICE_API_VERSION_2_0) {
+        if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_0) {
             // static_camera_characteristics is invalid
             *info = rawInfo;
             return ret;
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
index 7f14cd4..0fe76e5 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
@@ -73,10 +73,18 @@
 
 class CameraHardwareInterface : public virtual RefBase {
 public:
-    CameraHardwareInterface(const char *name)
+    CameraHardwareInterface(const char *name):
+            mDevice(nullptr),
+            mName(name),
+            mPreviewScalingMode(NOT_SET),
+            mPreviewTransform(NOT_SET),
+            mPreviewWidth(NOT_SET),
+            mPreviewHeight(NOT_SET),
+            mPreviewFormat(NOT_SET),
+            mPreviewUsage(0),
+            mPreviewSwapInterval(NOT_SET),
+            mPreviewCrop{NOT_SET,NOT_SET,NOT_SET,NOT_SET}
     {
-        mDevice = 0;
-        mName = name;
     }
 
     ~CameraHardwareInterface()
@@ -118,9 +126,16 @@
     status_t setPreviewWindow(const sp<ANativeWindow>& buf)
     {
         ALOGV("%s(%s) buf %p", __FUNCTION__, mName.string(), buf.get());
-
         if (mDevice->ops->set_preview_window) {
             mPreviewWindow = buf;
+            if (buf != nullptr) {
+                if (mPreviewScalingMode != NOT_SET) {
+                    setPreviewScalingMode(mPreviewScalingMode);
+                }
+                if (mPreviewTransform != NOT_SET) {
+                    setPreviewTransform(mPreviewTransform);
+                }
+            }
             mHalPreviewWindow.user = this;
             ALOGV("%s &mHalPreviewWindow %p mHalPreviewWindow.user %p", __FUNCTION__,
                     &mHalPreviewWindow, mHalPreviewWindow.user);
@@ -130,6 +145,27 @@
         return INVALID_OPERATION;
     }
 
+    status_t setPreviewScalingMode(int scalingMode)
+    {
+        int rc = OK;
+        mPreviewScalingMode = scalingMode;
+        if (mPreviewWindow != nullptr) {
+            rc = native_window_set_scaling_mode(mPreviewWindow.get(),
+                    scalingMode);
+        }
+        return rc;
+    }
+
+    status_t setPreviewTransform(int transform) {
+        int rc = OK;
+        mPreviewTransform = transform;
+        if (mPreviewWindow != nullptr) {
+            rc = native_window_set_buffers_transform(mPreviewWindow.get(),
+                    mPreviewTransform);
+        }
+        return rc;
+    }
+
     /** Set the notification and data callbacks */
     void setCallbacks(notify_callback notify_cb,
                       data_callback data_cb,
@@ -569,6 +605,8 @@
         return __this->mPreviewWindow.get();
     }
 #define anw(n) __to_anw(((struct camera_preview_window *)n)->user)
+#define hwi(n) reinterpret_cast<CameraHardwareInterface *>(\
+        ((struct camera_preview_window *)n)->user)
 
     static int __dequeue_buffer(struct preview_stream_ops* w,
                                 buffer_handle_t** buffer, int *stride)
@@ -617,6 +655,44 @@
     static int __set_buffer_count(struct preview_stream_ops* w, int count)
     {
         ANativeWindow *a = anw(w);
+
+        if (a != nullptr) {
+            // Workaround for b/27039775
+            // Previously, setting the buffer count would reset the buffer
+            // queue's flag that allows for all buffers to be dequeued on the
+            // producer side, instead of just the producer's declared max count,
+            // if no filled buffers have yet been queued by the producer.  This
+            // reset no longer happens, but some HALs depend on this behavior,
+            // so it needs to be maintained for HAL backwards compatibility.
+            // Simulate the prior behavior by disconnecting/reconnecting to the
+            // window and setting the values again.  This has the drawback of
+            // actually causing memory reallocation, which may not have happened
+            // in the past.
+            CameraHardwareInterface *hw = hwi(w);
+            native_window_api_disconnect(a, NATIVE_WINDOW_API_CAMERA);
+            native_window_api_connect(a, NATIVE_WINDOW_API_CAMERA);
+            if (hw->mPreviewScalingMode != NOT_SET) {
+                native_window_set_scaling_mode(a, hw->mPreviewScalingMode);
+            }
+            if (hw->mPreviewTransform != NOT_SET) {
+                native_window_set_buffers_transform(a, hw->mPreviewTransform);
+            }
+            if (hw->mPreviewWidth != NOT_SET) {
+                native_window_set_buffers_dimensions(a,
+                        hw->mPreviewWidth, hw->mPreviewHeight);
+                native_window_set_buffers_format(a, hw->mPreviewFormat);
+            }
+            if (hw->mPreviewUsage != 0) {
+                native_window_set_usage(a, hw->mPreviewUsage);
+            }
+            if (hw->mPreviewSwapInterval != NOT_SET) {
+                a->setSwapInterval(a, hw->mPreviewSwapInterval);
+            }
+            if (hw->mPreviewCrop.left != NOT_SET) {
+                native_window_set_crop(a, &(hw->mPreviewCrop));
+            }
+        }
+
         return native_window_set_buffer_count(a, count);
     }
 
@@ -625,7 +701,10 @@
     {
         int rc;
         ANativeWindow *a = anw(w);
-
+        CameraHardwareInterface *hw = hwi(w);
+        hw->mPreviewWidth = width;
+        hw->mPreviewHeight = height;
+        hw->mPreviewFormat = format;
         rc = native_window_set_buffers_dimensions(a, width, height);
         if (!rc) {
             rc = native_window_set_buffers_format(a, format);
@@ -637,12 +716,12 @@
                       int left, int top, int right, int bottom)
     {
         ANativeWindow *a = anw(w);
-        android_native_rect_t crop;
-        crop.left = left;
-        crop.top = top;
-        crop.right = right;
-        crop.bottom = bottom;
-        return native_window_set_crop(a, &crop);
+        CameraHardwareInterface *hw = hwi(w);
+        hw->mPreviewCrop.left = left;
+        hw->mPreviewCrop.top = top;
+        hw->mPreviewCrop.right = right;
+        hw->mPreviewCrop.bottom = bottom;
+        return native_window_set_crop(a, &(hw->mPreviewCrop));
     }
 
     static int __set_timestamp(struct preview_stream_ops *w,
@@ -654,12 +733,16 @@
     static int __set_usage(struct preview_stream_ops* w, int usage)
     {
         ANativeWindow *a = anw(w);
+        CameraHardwareInterface *hw = hwi(w);
+        hw->mPreviewUsage = usage;
         return native_window_set_usage(a, usage);
     }
 
     static int __set_swap_interval(struct preview_stream_ops *w, int interval)
     {
         ANativeWindow *a = anw(w);
+        CameraHardwareInterface *hw = hwi(w);
+        hw->mPreviewSwapInterval = interval;
         return a->setSwapInterval(a, interval);
     }
 
@@ -701,6 +784,17 @@
     data_callback           mDataCb;
     data_callback_timestamp mDataCbTimestamp;
     void *mCbUser;
+
+    // Cached values for preview stream parameters
+    static const int NOT_SET = -1;
+    int mPreviewScalingMode;
+    int mPreviewTransform;
+    int mPreviewWidth;
+    int mPreviewHeight;
+    int mPreviewFormat;
+    int mPreviewUsage;
+    int mPreviewSwapInterval;
+    android_native_rect_t mPreviewCrop;
 };
 
 };  // namespace android
diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp
deleted file mode 100644
index d74f976..0000000
--- a/services/camera/libcameraservice/device2/Camera2Device.cpp
+++ /dev/null
@@ -1,1618 +0,0 @@
-/*
- * Copyright (C) 2012 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 "Camera2-Device"
-#define ATRACE_TAG ATRACE_TAG_CAMERA
-//#define LOG_NDEBUG 0
-//#define LOG_NNDEBUG 0  // Per-frame verbose logging
-
-#ifdef LOG_NNDEBUG
-#define ALOGVV(...) ALOGV(__VA_ARGS__)
-#else
-#define ALOGVV(...) ((void)0)
-#endif
-
-#include <inttypes.h>
-#include <utils/Log.h>
-#include <utils/Trace.h>
-#include <utils/Timers.h>
-#include "Camera2Device.h"
-#include "CameraService.h"
-
-namespace android {
-
-Camera2Device::Camera2Device(int id):
-        mId(id),
-        mHal2Device(NULL)
-{
-    ATRACE_CALL();
-    ALOGV("%s: Created device for camera %d", __FUNCTION__, id);
-}
-
-Camera2Device::~Camera2Device()
-{
-    ATRACE_CALL();
-    ALOGV("%s: Tearing down for camera id %d", __FUNCTION__, mId);
-    disconnect();
-}
-
-int Camera2Device::getId() const {
-    return mId;
-}
-
-status_t Camera2Device::initialize(CameraModule *module)
-{
-    ATRACE_CALL();
-    ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId);
-    if (mHal2Device != NULL) {
-        ALOGE("%s: Already initialized!", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-
-    status_t res;
-    char name[10];
-    snprintf(name, sizeof(name), "%d", mId);
-
-    camera2_device_t *device;
-
-    res = module->open(name, reinterpret_cast<hw_device_t**>(&device));
-
-    if (res != OK) {
-        ALOGE("%s: Could not open camera %d: %s (%d)", __FUNCTION__,
-                mId, strerror(-res), res);
-        return res;
-    }
-
-    if (device->common.version != CAMERA_DEVICE_API_VERSION_2_0) {
-        ALOGE("%s: Could not open camera %d: "
-                "Camera device is not version %x, reports %x instead",
-                __FUNCTION__, mId, CAMERA_DEVICE_API_VERSION_2_0,
-                device->common.version);
-        device->common.close(&device->common);
-        return BAD_VALUE;
-    }
-
-    camera_info info;
-    res = module->getCameraInfo(mId, &info);
-    if (res != OK ) return res;
-
-    if (info.device_version != device->common.version) {
-        ALOGE("%s: HAL reporting mismatched camera_info version (%x)"
-                " and device version (%x).", __FUNCTION__,
-                device->common.version, info.device_version);
-        device->common.close(&device->common);
-        return BAD_VALUE;
-    }
-
-    res = mRequestQueue.setConsumerDevice(device);
-    if (res != OK) {
-        ALOGE("%s: Camera %d: Unable to connect request queue to device: %s (%d)",
-                __FUNCTION__, mId, strerror(-res), res);
-        device->common.close(&device->common);
-        return res;
-    }
-    res = mFrameQueue.setProducerDevice(device);
-    if (res != OK) {
-        ALOGE("%s: Camera %d: Unable to connect frame queue to device: %s (%d)",
-                __FUNCTION__, mId, strerror(-res), res);
-        device->common.close(&device->common);
-        return res;
-    }
-
-    res = device->ops->set_notify_callback(device, notificationCallback,
-            NULL);
-    if (res != OK) {
-        ALOGE("%s: Camera %d: Unable to initialize notification callback!",
-                __FUNCTION__, mId);
-        device->common.close(&device->common);
-        return res;
-    }
-
-    mDeviceInfo = info.static_camera_characteristics;
-    mHal2Device = device;
-    mDeviceVersion = device->common.version;
-
-    return OK;
-}
-
-status_t Camera2Device::disconnect() {
-    ATRACE_CALL();
-    status_t res = OK;
-    if (mHal2Device) {
-        ALOGV("%s: Closing device for camera %d", __FUNCTION__, mId);
-
-        int inProgressCount = mHal2Device->ops->get_in_progress_count(mHal2Device);
-        if (inProgressCount > 0) {
-            ALOGW("%s: Closing camera device %d with %d requests in flight!",
-                    __FUNCTION__, mId, inProgressCount);
-        }
-        mReprocessStreams.clear();
-        mStreams.clear();
-        res = mHal2Device->common.close(&mHal2Device->common);
-        if (res != OK) {
-            ALOGE("%s: Could not close camera %d: %s (%d)",
-                    __FUNCTION__,
-                    mId, strerror(-res), res);
-        }
-        mHal2Device = NULL;
-        ALOGV("%s: Shutdown complete", __FUNCTION__);
-    }
-    return res;
-}
-
-status_t Camera2Device::dump(int fd, const Vector<String16>& args) {
-    ATRACE_CALL();
-    String8 result;
-    int detailLevel = 0;
-    int n = args.size();
-    String16 detailOption("-d");
-    for (int i = 0; i + 1 < n; i++) {
-        if (args[i] == detailOption) {
-            String8 levelStr(args[i+1]);
-            detailLevel = atoi(levelStr.string());
-        }
-    }
-
-    result.appendFormat("  Camera2Device[%d] dump (detail level %d):\n",
-            mId, detailLevel);
-
-    if (detailLevel > 0) {
-        result = "    Request queue contents:\n";
-        write(fd, result.string(), result.size());
-        mRequestQueue.dump(fd, args);
-
-        result = "    Frame queue contents:\n";
-        write(fd, result.string(), result.size());
-        mFrameQueue.dump(fd, args);
-    }
-
-    result = "    Active streams:\n";
-    write(fd, result.string(), result.size());
-    for (StreamList::iterator s = mStreams.begin(); s != mStreams.end(); s++) {
-        (*s)->dump(fd, args);
-    }
-
-    result = "    HAL device dump:\n";
-    write(fd, result.string(), result.size());
-
-    status_t res;
-    res = mHal2Device->ops->dump(mHal2Device, fd);
-
-    return res;
-}
-
-const CameraMetadata& Camera2Device::info() const {
-    ALOGVV("%s: E", __FUNCTION__);
-
-    return mDeviceInfo;
-}
-
-status_t Camera2Device::capture(CameraMetadata &request, int64_t* /*lastFrameNumber*/) {
-    ATRACE_CALL();
-    ALOGV("%s: E", __FUNCTION__);
-
-    mRequestQueue.enqueue(request.release());
-    return OK;
-}
-
-status_t Camera2Device::captureList(const List<const CameraMetadata> &requests,
-                                    int64_t* /*lastFrameNumber*/) {
-    ATRACE_CALL();
-    ALOGE("%s: Camera2Device burst capture not implemented", __FUNCTION__);
-    return INVALID_OPERATION;
-}
-
-status_t Camera2Device::setStreamingRequest(const CameraMetadata &request,
-                                            int64_t* /*lastFrameNumber*/) {
-    ATRACE_CALL();
-    ALOGV("%s: E", __FUNCTION__);
-    CameraMetadata streamRequest(request);
-    return mRequestQueue.setStreamSlot(streamRequest.release());
-}
-
-status_t Camera2Device::setStreamingRequestList(const List<const CameraMetadata> &requests,
-                                                int64_t* /*lastFrameNumber*/) {
-    ATRACE_CALL();
-    ALOGE("%s, Camera2Device streaming burst not implemented", __FUNCTION__);
-    return INVALID_OPERATION;
-}
-
-status_t Camera2Device::clearStreamingRequest(int64_t* /*lastFrameNumber*/) {
-    ATRACE_CALL();
-    return mRequestQueue.setStreamSlot(NULL);
-}
-
-status_t Camera2Device::waitUntilRequestReceived(int32_t requestId, nsecs_t timeout) {
-    ATRACE_CALL();
-    return mRequestQueue.waitForDequeue(requestId, timeout);
-}
-
-status_t Camera2Device::createStream(sp<Surface> consumer,
-        uint32_t width, uint32_t height, int format,
-        android_dataspace /*dataSpace*/, camera3_stream_rotation_t rotation, int *id) {
-    ATRACE_CALL();
-    status_t res;
-    ALOGV("%s: E", __FUNCTION__);
-
-    sp<StreamAdapter> stream = new StreamAdapter(mHal2Device);
-    size_t size = 0;
-    if (format == HAL_PIXEL_FORMAT_BLOB) {
-        size = getJpegBufferSize(width, height);
-    }
-    res = stream->connectToDevice(consumer, width, height, format, size);
-    if (res != OK) {
-        ALOGE("%s: Camera %d: Unable to create stream (%d x %d, format %x):"
-                "%s (%d)",
-                __FUNCTION__, mId, width, height, format, strerror(-res), res);
-        return res;
-    }
-
-    *id = stream->getId();
-
-    mStreams.push_back(stream);
-    return OK;
-}
-
-ssize_t Camera2Device::getJpegBufferSize(uint32_t width, uint32_t height) const {
-    // Always give the max jpeg buffer size regardless of the actual jpeg resolution.
-    camera_metadata_ro_entry jpegBufMaxSize = mDeviceInfo.find(ANDROID_JPEG_MAX_SIZE);
-    if (jpegBufMaxSize.count == 0) {
-        ALOGE("%s: Camera %d: Can't find maximum JPEG size in static metadata!", __FUNCTION__, mId);
-        return BAD_VALUE;
-    }
-
-    return jpegBufMaxSize.data.i32[0];
-}
-
-status_t Camera2Device::createReprocessStreamFromStream(int outputId, int *id) {
-    ATRACE_CALL();
-    status_t res;
-    ALOGV("%s: E", __FUNCTION__);
-
-    bool found = false;
-    StreamList::iterator streamI;
-    for (streamI = mStreams.begin();
-         streamI != mStreams.end(); streamI++) {
-        if ((*streamI)->getId() == outputId) {
-            found = true;
-            break;
-        }
-    }
-    if (!found) {
-        ALOGE("%s: Camera %d: Output stream %d doesn't exist; can't create "
-                "reprocess stream from it!", __FUNCTION__, mId, outputId);
-        return BAD_VALUE;
-    }
-
-    sp<ReprocessStreamAdapter> stream = new ReprocessStreamAdapter(mHal2Device);
-
-    res = stream->connectToDevice((*streamI));
-    if (res != OK) {
-        ALOGE("%s: Camera %d: Unable to create reprocessing stream from "\
-                "stream %d: %s (%d)", __FUNCTION__, mId, outputId,
-                strerror(-res), res);
-        return res;
-    }
-
-    *id = stream->getId();
-
-    mReprocessStreams.push_back(stream);
-    return OK;
-}
-
-
-status_t Camera2Device::getStreamInfo(int id,
-        uint32_t *width, uint32_t *height,
-        uint32_t *format, android_dataspace *dataSpace) {
-    ATRACE_CALL();
-    ALOGV("%s: E", __FUNCTION__);
-    bool found = false;
-    StreamList::iterator streamI;
-    for (streamI = mStreams.begin();
-         streamI != mStreams.end(); streamI++) {
-        if ((*streamI)->getId() == id) {
-            found = true;
-            break;
-        }
-    }
-    if (!found) {
-        ALOGE("%s: Camera %d: Stream %d does not exist",
-                __FUNCTION__, mId, id);
-        return BAD_VALUE;
-    }
-
-    if (width) *width = (*streamI)->getWidth();
-    if (height) *height = (*streamI)->getHeight();
-    if (format) *format = (*streamI)->getFormat();
-    if (dataSpace) *dataSpace = HAL_DATASPACE_UNKNOWN;
-
-    return OK;
-}
-
-status_t Camera2Device::setStreamTransform(int id,
-        int transform) {
-    ATRACE_CALL();
-    ALOGV("%s: E", __FUNCTION__);
-    bool found = false;
-    StreamList::iterator streamI;
-    for (streamI = mStreams.begin();
-         streamI != mStreams.end(); streamI++) {
-        if ((*streamI)->getId() == id) {
-            found = true;
-            break;
-        }
-    }
-    if (!found) {
-        ALOGE("%s: Camera %d: Stream %d does not exist",
-                __FUNCTION__, mId, id);
-        return BAD_VALUE;
-    }
-
-    return (*streamI)->setTransform(transform);
-}
-
-status_t Camera2Device::deleteStream(int id) {
-    ATRACE_CALL();
-    ALOGV("%s: E", __FUNCTION__);
-    bool found = false;
-    for (StreamList::iterator streamI = mStreams.begin();
-         streamI != mStreams.end(); streamI++) {
-        if ((*streamI)->getId() == id) {
-            status_t res = (*streamI)->release();
-            if (res != OK) {
-                ALOGE("%s: Unable to release stream %d from HAL device: "
-                        "%s (%d)", __FUNCTION__, id, strerror(-res), res);
-                return res;
-            }
-            mStreams.erase(streamI);
-            found = true;
-            break;
-        }
-    }
-    if (!found) {
-        ALOGE("%s: Camera %d: Unable to find stream %d to delete",
-                __FUNCTION__, mId, id);
-        return BAD_VALUE;
-    }
-    return OK;
-}
-
-status_t Camera2Device::deleteReprocessStream(int id) {
-    ATRACE_CALL();
-    ALOGV("%s: E", __FUNCTION__);
-    bool found = false;
-    for (ReprocessStreamList::iterator streamI = mReprocessStreams.begin();
-         streamI != mReprocessStreams.end(); streamI++) {
-        if ((*streamI)->getId() == id) {
-            status_t res = (*streamI)->release();
-            if (res != OK) {
-                ALOGE("%s: Unable to release reprocess stream %d from "
-                        "HAL device: %s (%d)", __FUNCTION__, id,
-                        strerror(-res), res);
-                return res;
-            }
-            mReprocessStreams.erase(streamI);
-            found = true;
-            break;
-        }
-    }
-    if (!found) {
-        ALOGE("%s: Camera %d: Unable to find stream %d to delete",
-                __FUNCTION__, mId, id);
-        return BAD_VALUE;
-    }
-    return OK;
-}
-
-status_t Camera2Device::configureStreams(bool isConstrainedHighSpeed) {
-    ATRACE_CALL();
-    ALOGV("%s: E", __FUNCTION__);
-
-    /**
-     * HAL2 devices do not need to configure streams;
-     * streams are created on the fly.
-     */
-    ALOGW("%s: No-op for HAL2 devices", __FUNCTION__);
-
-    return OK;
-}
-
-
-status_t Camera2Device::createDefaultRequest(int templateId,
-        CameraMetadata *request) {
-    ATRACE_CALL();
-    status_t err;
-    ALOGV("%s: E", __FUNCTION__);
-    camera_metadata_t *rawRequest;
-    err = mHal2Device->ops->construct_default_request(
-        mHal2Device, templateId, &rawRequest);
-    request->acquire(rawRequest);
-    return err;
-}
-
-status_t Camera2Device::waitUntilDrained() {
-    ATRACE_CALL();
-    static const uint32_t kSleepTime = 50000; // 50 ms
-    static const uint32_t kMaxSleepTime = 10000000; // 10 s
-    ALOGV("%s: Camera %d: Starting wait", __FUNCTION__, mId);
-    if (mRequestQueue.getBufferCount() ==
-            CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS) return INVALID_OPERATION;
-
-    // TODO: Set up notifications from HAL, instead of sleeping here
-    uint32_t totalTime = 0;
-    while (mHal2Device->ops->get_in_progress_count(mHal2Device) > 0) {
-        usleep(kSleepTime);
-        totalTime += kSleepTime;
-        if (totalTime > kMaxSleepTime) {
-            ALOGE("%s: Waited %d us, %d requests still in flight", __FUNCTION__,
-                    totalTime, mHal2Device->ops->get_in_progress_count(mHal2Device));
-            return TIMED_OUT;
-        }
-    }
-    ALOGV("%s: Camera %d: HAL is idle", __FUNCTION__, mId);
-    return OK;
-}
-
-status_t Camera2Device::setNotifyCallback(NotificationListener *listener) {
-    ATRACE_CALL();
-    status_t res;
-    res = mHal2Device->ops->set_notify_callback(mHal2Device, notificationCallback,
-            reinterpret_cast<void*>(listener) );
-    if (res != OK) {
-        ALOGE("%s: Unable to set notification callback!", __FUNCTION__);
-    }
-    return res;
-}
-
-bool Camera2Device::willNotify3A() {
-    return true;
-}
-
-void Camera2Device::notificationCallback(int32_t msg_type,
-        int32_t ext1,
-        int32_t ext2,
-        int32_t ext3,
-        void *user) {
-    ATRACE_CALL();
-    NotificationListener *listener = reinterpret_cast<NotificationListener*>(user);
-    ALOGV("%s: Notification %d, arguments %d, %d, %d", __FUNCTION__, msg_type,
-            ext1, ext2, ext3);
-    if (listener != NULL) {
-        switch (msg_type) {
-            case CAMERA2_MSG_ERROR:
-                // TODO: This needs to be fixed. ext2 and ext3 need to be considered.
-                listener->notifyError(
-                        ((ext1 == CAMERA2_MSG_ERROR_DEVICE)
-                        || (ext1 == CAMERA2_MSG_ERROR_HARDWARE)) ?
-                                ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE :
-                                ICameraDeviceCallbacks::ERROR_CAMERA_SERVICE,
-                        CaptureResultExtras());
-                break;
-            case CAMERA2_MSG_SHUTTER: {
-                // TODO: Only needed for camera2 API, which is unsupported
-                // by HAL2 directly.
-                // nsecs_t timestamp = (nsecs_t)ext2 | ((nsecs_t)(ext3) << 32 );
-                // listener->notifyShutter(requestId, timestamp);
-                break;
-            }
-            case CAMERA2_MSG_AUTOFOCUS:
-                listener->notifyAutoFocus(ext1, ext2);
-                break;
-            case CAMERA2_MSG_AUTOEXPOSURE:
-                listener->notifyAutoExposure(ext1, ext2);
-                break;
-            case CAMERA2_MSG_AUTOWB:
-                listener->notifyAutoWhitebalance(ext1, ext2);
-                break;
-            default:
-                ALOGE("%s: Unknown notification %d (arguments %d, %d, %d)!",
-                        __FUNCTION__, msg_type, ext1, ext2, ext3);
-        }
-    }
-}
-
-status_t Camera2Device::waitForNextFrame(nsecs_t timeout) {
-    return mFrameQueue.waitForBuffer(timeout);
-}
-
-status_t Camera2Device::getNextResult(CaptureResult *result) {
-    ATRACE_CALL();
-    ALOGV("%s: get CaptureResult", __FUNCTION__);
-    if (result == NULL) {
-        ALOGE("%s: result pointer is NULL", __FUNCTION__);
-        return BAD_VALUE;
-    }
-    status_t res;
-    camera_metadata_t *rawFrame;
-    res = mFrameQueue.dequeue(&rawFrame);
-    if (rawFrame == NULL) {
-        return NOT_ENOUGH_DATA;
-    } else if (res == OK) {
-        result->mMetadata.acquire(rawFrame);
-    }
-
-    return res;
-}
-
-status_t Camera2Device::triggerAutofocus(uint32_t id) {
-    ATRACE_CALL();
-    status_t res;
-    ALOGV("%s: Triggering autofocus, id %d", __FUNCTION__, id);
-    res = mHal2Device->ops->trigger_action(mHal2Device,
-            CAMERA2_TRIGGER_AUTOFOCUS, id, 0);
-    if (res != OK) {
-        ALOGE("%s: Error triggering autofocus (id %d)",
-                __FUNCTION__, id);
-    }
-    return res;
-}
-
-status_t Camera2Device::triggerCancelAutofocus(uint32_t id) {
-    ATRACE_CALL();
-    status_t res;
-    ALOGV("%s: Canceling autofocus, id %d", __FUNCTION__, id);
-    res = mHal2Device->ops->trigger_action(mHal2Device,
-            CAMERA2_TRIGGER_CANCEL_AUTOFOCUS, id, 0);
-    if (res != OK) {
-        ALOGE("%s: Error canceling autofocus (id %d)",
-                __FUNCTION__, id);
-    }
-    return res;
-}
-
-status_t Camera2Device::triggerPrecaptureMetering(uint32_t id) {
-    ATRACE_CALL();
-    status_t res;
-    ALOGV("%s: Triggering precapture metering, id %d", __FUNCTION__, id);
-    res = mHal2Device->ops->trigger_action(mHal2Device,
-            CAMERA2_TRIGGER_PRECAPTURE_METERING, id, 0);
-    if (res != OK) {
-        ALOGE("%s: Error triggering precapture metering (id %d)",
-                __FUNCTION__, id);
-    }
-    return res;
-}
-
-status_t Camera2Device::pushReprocessBuffer(int reprocessStreamId,
-        buffer_handle_t *buffer, wp<BufferReleasedListener> listener) {
-    ATRACE_CALL();
-    ALOGV("%s: E", __FUNCTION__);
-    bool found = false;
-    status_t res = OK;
-    for (ReprocessStreamList::iterator streamI = mReprocessStreams.begin();
-         streamI != mReprocessStreams.end(); streamI++) {
-        if ((*streamI)->getId() == reprocessStreamId) {
-            res = (*streamI)->pushIntoStream(buffer, listener);
-            if (res != OK) {
-                ALOGE("%s: Unable to push buffer to reprocess stream %d: %s (%d)",
-                        __FUNCTION__, reprocessStreamId, strerror(-res), res);
-                return res;
-            }
-            found = true;
-            break;
-        }
-    }
-    if (!found) {
-        ALOGE("%s: Camera %d: Unable to find reprocess stream %d",
-                __FUNCTION__, mId, reprocessStreamId);
-        res = BAD_VALUE;
-    }
-    return res;
-}
-
-status_t Camera2Device::flush(int64_t* /*lastFrameNumber*/) {
-    ATRACE_CALL();
-
-    mRequestQueue.clear();
-    return waitUntilDrained();
-}
-
-status_t Camera2Device::prepare(int streamId) {
-    ATRACE_CALL();
-    ALOGE("%s: Camera %d: unimplemented", __FUNCTION__, mId);
-    return NO_INIT;
-}
-
-status_t Camera2Device::tearDown(int streamId) {
-    ATRACE_CALL();
-    ALOGE("%s: Camera %d: unimplemented", __FUNCTION__, mId);
-    return NO_INIT;
-}
-
-status_t Camera2Device::prepare(int maxCount, int streamId) {
-    ATRACE_CALL();
-    ALOGE("%s: Camera %d: unimplemented", __FUNCTION__, mId);
-    return NO_INIT;
-}
-
-uint32_t Camera2Device::getDeviceVersion() {
-    ATRACE_CALL();
-    return mDeviceVersion;
-}
-
-/**
- * Camera2Device::MetadataQueue
- */
-
-Camera2Device::MetadataQueue::MetadataQueue():
-            mHal2Device(NULL),
-            mFrameCount(0),
-            mLatestRequestId(0),
-            mCount(0),
-            mStreamSlotCount(0),
-            mSignalConsumer(true)
-{
-    ATRACE_CALL();
-    camera2_request_queue_src_ops::dequeue_request = consumer_dequeue;
-    camera2_request_queue_src_ops::request_count = consumer_buffer_count;
-    camera2_request_queue_src_ops::free_request = consumer_free;
-
-    camera2_frame_queue_dst_ops::dequeue_frame = producer_dequeue;
-    camera2_frame_queue_dst_ops::cancel_frame = producer_cancel;
-    camera2_frame_queue_dst_ops::enqueue_frame = producer_enqueue;
-}
-
-Camera2Device::MetadataQueue::~MetadataQueue() {
-    ATRACE_CALL();
-    clear();
-}
-
-// Connect to camera2 HAL as consumer (input requests/reprocessing)
-status_t Camera2Device::MetadataQueue::setConsumerDevice(camera2_device_t *d) {
-    ATRACE_CALL();
-    status_t res;
-    res = d->ops->set_request_queue_src_ops(d,
-            this);
-    if (res != OK) return res;
-    mHal2Device = d;
-    return OK;
-}
-
-status_t Camera2Device::MetadataQueue::setProducerDevice(camera2_device_t *d) {
-    ATRACE_CALL();
-    status_t res;
-    res = d->ops->set_frame_queue_dst_ops(d,
-            this);
-    return res;
-}
-
-// Real interfaces
-status_t Camera2Device::MetadataQueue::enqueue(camera_metadata_t *buf) {
-    ATRACE_CALL();
-    ALOGVV("%s: E", __FUNCTION__);
-    Mutex::Autolock l(mMutex);
-
-    mCount++;
-    mEntries.push_back(buf);
-
-    return signalConsumerLocked();
-}
-
-int Camera2Device::MetadataQueue::getBufferCount() {
-    ATRACE_CALL();
-    Mutex::Autolock l(mMutex);
-    if (mStreamSlotCount > 0) {
-        return CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS;
-    }
-    return mCount;
-}
-
-status_t Camera2Device::MetadataQueue::dequeue(camera_metadata_t **buf,
-        bool incrementCount)
-{
-    ATRACE_CALL();
-    ALOGVV("%s: E", __FUNCTION__);
-    status_t res;
-    Mutex::Autolock l(mMutex);
-
-    if (mCount == 0) {
-        if (mStreamSlotCount == 0) {
-            ALOGVV("%s: Empty", __FUNCTION__);
-            *buf = NULL;
-            mSignalConsumer = true;
-            return OK;
-        }
-        ALOGVV("%s: Streaming %d frames to queue", __FUNCTION__,
-              mStreamSlotCount);
-
-        for (List<camera_metadata_t*>::iterator slotEntry = mStreamSlot.begin();
-                slotEntry != mStreamSlot.end();
-                slotEntry++ ) {
-            size_t entries = get_camera_metadata_entry_count(*slotEntry);
-            size_t dataBytes = get_camera_metadata_data_count(*slotEntry);
-
-            camera_metadata_t *copy =
-                    allocate_camera_metadata(entries, dataBytes);
-            append_camera_metadata(copy, *slotEntry);
-            mEntries.push_back(copy);
-        }
-        mCount = mStreamSlotCount;
-    }
-    ALOGVV("MetadataQueue: deque (%d buffers)", mCount);
-    camera_metadata_t *b = *(mEntries.begin());
-    mEntries.erase(mEntries.begin());
-
-    if (incrementCount) {
-        ATRACE_INT("cam2_request", mFrameCount);
-        camera_metadata_entry_t frameCount;
-        res = find_camera_metadata_entry(b,
-                ANDROID_REQUEST_FRAME_COUNT,
-                &frameCount);
-        if (res != OK) {
-            ALOGE("%s: Unable to add frame count: %s (%d)",
-                    __FUNCTION__, strerror(-res), res);
-        } else {
-            *frameCount.data.i32 = mFrameCount;
-        }
-        mFrameCount++;
-    }
-
-    // Check for request ID, and if present, signal waiters.
-    camera_metadata_entry_t requestId;
-    res = find_camera_metadata_entry(b,
-            ANDROID_REQUEST_ID,
-            &requestId);
-    if (res == OK) {
-        mLatestRequestId = requestId.data.i32[0];
-        mNewRequestId.signal();
-    }
-
-    *buf = b;
-    mCount--;
-
-    return OK;
-}
-
-status_t Camera2Device::MetadataQueue::waitForBuffer(nsecs_t timeout)
-{
-    Mutex::Autolock l(mMutex);
-    status_t res;
-    while (mCount == 0) {
-        res = notEmpty.waitRelative(mMutex,timeout);
-        if (res != OK) return res;
-    }
-    return OK;
-}
-
-status_t Camera2Device::MetadataQueue::waitForDequeue(int32_t id,
-        nsecs_t timeout) {
-    Mutex::Autolock l(mMutex);
-    status_t res;
-    while (mLatestRequestId != id) {
-        nsecs_t startTime = systemTime();
-
-        res = mNewRequestId.waitRelative(mMutex, timeout);
-        if (res != OK) return res;
-
-        timeout -= (systemTime() - startTime);
-    }
-
-    return OK;
-}
-
-status_t Camera2Device::MetadataQueue::setStreamSlot(camera_metadata_t *buf)
-{
-    ATRACE_CALL();
-    ALOGV("%s: E", __FUNCTION__);
-    Mutex::Autolock l(mMutex);
-    if (buf == NULL) {
-        freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
-        mStreamSlotCount = 0;
-        return OK;
-    }
-
-    if (mStreamSlotCount > 1) {
-        List<camera_metadata_t*>::iterator deleter = ++mStreamSlot.begin();
-        freeBuffers(++mStreamSlot.begin(), mStreamSlot.end());
-        mStreamSlotCount = 1;
-    }
-    if (mStreamSlotCount == 1) {
-        free_camera_metadata( *(mStreamSlot.begin()) );
-        *(mStreamSlot.begin()) = buf;
-    } else {
-        mStreamSlot.push_front(buf);
-        mStreamSlotCount = 1;
-    }
-    return signalConsumerLocked();
-}
-
-status_t Camera2Device::MetadataQueue::setStreamSlot(
-        const List<camera_metadata_t*> &bufs)
-{
-    ATRACE_CALL();
-    ALOGV("%s: E", __FUNCTION__);
-    Mutex::Autolock l(mMutex);
-
-    if (mStreamSlotCount > 0) {
-        freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
-    }
-    mStreamSlotCount = 0;
-    for (List<camera_metadata_t*>::const_iterator r = bufs.begin();
-         r != bufs.end(); r++) {
-        mStreamSlot.push_back(*r);
-        mStreamSlotCount++;
-    }
-    return signalConsumerLocked();
-}
-
-status_t Camera2Device::MetadataQueue::clear()
-{
-    ATRACE_CALL();
-    ALOGV("%s: E", __FUNCTION__);
-
-    Mutex::Autolock l(mMutex);
-
-    // Clear streaming slot
-    freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
-    mStreamSlotCount = 0;
-
-    // Clear request queue
-    freeBuffers(mEntries.begin(), mEntries.end());
-    mCount = 0;
-    return OK;
-}
-
-status_t Camera2Device::MetadataQueue::dump(int fd,
-        const Vector<String16>& /*args*/) {
-    ATRACE_CALL();
-    String8 result;
-    status_t notLocked;
-    notLocked = mMutex.tryLock();
-    if (notLocked) {
-        result.append("    (Unable to lock queue mutex)\n");
-    }
-    result.appendFormat("      Current frame number: %d\n", mFrameCount);
-    if (mStreamSlotCount == 0) {
-        result.append("      Stream slot: Empty\n");
-        write(fd, result.string(), result.size());
-    } else {
-        result.appendFormat("      Stream slot: %zu entries\n",
-                mStreamSlot.size());
-        int i = 0;
-        for (List<camera_metadata_t*>::iterator r = mStreamSlot.begin();
-             r != mStreamSlot.end(); r++) {
-            result = String8::format("       Stream slot buffer %d:\n", i);
-            write(fd, result.string(), result.size());
-            dump_indented_camera_metadata(*r, fd, 2, 10);
-            i++;
-        }
-    }
-    if (mEntries.size() == 0) {
-        result = "      Main queue is empty\n";
-        write(fd, result.string(), result.size());
-    } else {
-        result = String8::format("      Main queue has %zu entries:\n",
-                mEntries.size());
-        int i = 0;
-        for (List<camera_metadata_t*>::iterator r = mEntries.begin();
-             r != mEntries.end(); r++) {
-            result = String8::format("       Queue entry %d:\n", i);
-            write(fd, result.string(), result.size());
-            dump_indented_camera_metadata(*r, fd, 2, 10);
-            i++;
-        }
-    }
-
-    if (notLocked == 0) {
-        mMutex.unlock();
-    }
-
-    return OK;
-}
-
-status_t Camera2Device::MetadataQueue::signalConsumerLocked() {
-    ATRACE_CALL();
-    status_t res = OK;
-    notEmpty.signal();
-    if (mSignalConsumer && mHal2Device != NULL) {
-        mSignalConsumer = false;
-
-        mMutex.unlock();
-        ALOGV("%s: Signaling consumer", __FUNCTION__);
-        res = mHal2Device->ops->notify_request_queue_not_empty(mHal2Device);
-        mMutex.lock();
-    }
-    return res;
-}
-
-status_t Camera2Device::MetadataQueue::freeBuffers(
-        List<camera_metadata_t*>::iterator start,
-        List<camera_metadata_t*>::iterator end)
-{
-    ATRACE_CALL();
-    while (start != end) {
-        free_camera_metadata(*start);
-        start = mStreamSlot.erase(start);
-    }
-    return OK;
-}
-
-Camera2Device::MetadataQueue* Camera2Device::MetadataQueue::getInstance(
-        const camera2_request_queue_src_ops_t *q)
-{
-    const MetadataQueue* cmq = static_cast<const MetadataQueue*>(q);
-    return const_cast<MetadataQueue*>(cmq);
-}
-
-Camera2Device::MetadataQueue* Camera2Device::MetadataQueue::getInstance(
-        const camera2_frame_queue_dst_ops_t *q)
-{
-    const MetadataQueue* cmq = static_cast<const MetadataQueue*>(q);
-    return const_cast<MetadataQueue*>(cmq);
-}
-
-int Camera2Device::MetadataQueue::consumer_buffer_count(
-        const camera2_request_queue_src_ops_t *q)
-{
-    MetadataQueue *queue = getInstance(q);
-    return queue->getBufferCount();
-}
-
-int Camera2Device::MetadataQueue::consumer_dequeue(
-        const camera2_request_queue_src_ops_t *q,
-        camera_metadata_t **buffer)
-{
-    MetadataQueue *queue = getInstance(q);
-    return queue->dequeue(buffer, true);
-}
-
-int Camera2Device::MetadataQueue::consumer_free(
-        const camera2_request_queue_src_ops_t *q,
-        camera_metadata_t *old_buffer)
-{
-    ATRACE_CALL();
-    MetadataQueue *queue = getInstance(q);
-    (void)queue;
-    free_camera_metadata(old_buffer);
-    return OK;
-}
-
-int Camera2Device::MetadataQueue::producer_dequeue(
-        const camera2_frame_queue_dst_ops_t * /*q*/,
-        size_t entries, size_t bytes,
-        camera_metadata_t **buffer)
-{
-    ATRACE_CALL();
-    camera_metadata_t *new_buffer =
-            allocate_camera_metadata(entries, bytes);
-    if (new_buffer == NULL) return NO_MEMORY;
-    *buffer = new_buffer;
-        return OK;
-}
-
-int Camera2Device::MetadataQueue::producer_cancel(
-        const camera2_frame_queue_dst_ops_t * /*q*/,
-        camera_metadata_t *old_buffer)
-{
-    ATRACE_CALL();
-    free_camera_metadata(old_buffer);
-    return OK;
-}
-
-int Camera2Device::MetadataQueue::producer_enqueue(
-        const camera2_frame_queue_dst_ops_t *q,
-        camera_metadata_t *filled_buffer)
-{
-    MetadataQueue *queue = getInstance(q);
-    return queue->enqueue(filled_buffer);
-}
-
-/**
- * Camera2Device::StreamAdapter
- */
-
-#ifndef container_of
-#define container_of(ptr, type, member) \
-    (type *)((char*)(ptr) - offsetof(type, member))
-#endif
-
-Camera2Device::StreamAdapter::StreamAdapter(camera2_device_t *d):
-        mState(RELEASED),
-        mHal2Device(d),
-        mId(-1),
-        mWidth(0), mHeight(0), mFormat(0), mSize(0), mUsage(0),
-        mMaxProducerBuffers(0), mMaxConsumerBuffers(0),
-        mTotalBuffers(0),
-        mFormatRequested(0),
-        mActiveBuffers(0),
-        mFrameCount(0),
-        mLastTimestamp(0)
-{
-    camera2_stream_ops::dequeue_buffer = dequeue_buffer;
-    camera2_stream_ops::enqueue_buffer = enqueue_buffer;
-    camera2_stream_ops::cancel_buffer = cancel_buffer;
-    camera2_stream_ops::set_crop = set_crop;
-}
-
-Camera2Device::StreamAdapter::~StreamAdapter() {
-    ATRACE_CALL();
-    if (mState != RELEASED) {
-        release();
-    }
-}
-
-status_t Camera2Device::StreamAdapter::connectToDevice(
-        sp<ANativeWindow> consumer,
-        uint32_t width, uint32_t height, int format, size_t size) {
-    ATRACE_CALL();
-    status_t res;
-    ALOGV("%s: E", __FUNCTION__);
-
-    if (mState != RELEASED) return INVALID_OPERATION;
-    if (consumer == NULL) {
-        ALOGE("%s: Null consumer passed to stream adapter", __FUNCTION__);
-        return BAD_VALUE;
-    }
-
-    ALOGV("%s: New stream parameters %d x %d, format 0x%x, size %zu",
-            __FUNCTION__, width, height, format, size);
-
-    mConsumerInterface = consumer;
-    mWidth = width;
-    mHeight = height;
-    mSize = (format == HAL_PIXEL_FORMAT_BLOB) ? size : 0;
-    mFormatRequested = format;
-
-    // Allocate device-side stream interface
-
-    uint32_t id;
-    uint32_t formatActual;
-    uint32_t usage;
-    uint32_t maxBuffers = 2;
-    res = mHal2Device->ops->allocate_stream(mHal2Device,
-            mWidth, mHeight, mFormatRequested, getStreamOps(),
-            &id, &formatActual, &usage, &maxBuffers);
-    if (res != OK) {
-        ALOGE("%s: Device stream allocation failed: %s (%d)",
-                __FUNCTION__, strerror(-res), res);
-        return res;
-    }
-
-    ALOGV("%s: Allocated stream id %d, actual format 0x%x, "
-            "usage 0x%x, producer wants %d buffers", __FUNCTION__,
-            id, formatActual, usage, maxBuffers);
-
-    mId = id;
-    mFormat = formatActual;
-    mUsage = usage;
-    mMaxProducerBuffers = maxBuffers;
-
-    mState = ALLOCATED;
-
-    // Configure consumer-side ANativeWindow interface
-    res = native_window_api_connect(mConsumerInterface.get(),
-            NATIVE_WINDOW_API_CAMERA);
-    if (res != OK) {
-        ALOGE("%s: Unable to connect to native window for stream %d",
-                __FUNCTION__, mId);
-
-        return res;
-    }
-
-    mState = CONNECTED;
-
-    res = native_window_set_usage(mConsumerInterface.get(), mUsage);
-    if (res != OK) {
-        ALOGE("%s: Unable to configure usage %08x for stream %d",
-                __FUNCTION__, mUsage, mId);
-        return res;
-    }
-
-    res = native_window_set_scaling_mode(mConsumerInterface.get(),
-            NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
-    if (res != OK) {
-        ALOGE("%s: Unable to configure stream scaling: %s (%d)",
-                __FUNCTION__, strerror(-res), res);
-        return res;
-    }
-
-    res = setTransform(0);
-    if (res != OK) {
-        return res;
-    }
-
-    if (mFormat == HAL_PIXEL_FORMAT_BLOB) {
-        res = native_window_set_buffers_dimensions(mConsumerInterface.get(),
-                mSize, 1);
-        if (res != OK) {
-            ALOGE("%s: Unable to configure compressed stream buffer dimensions"
-                    " %d x %d, size %zu for stream %d",
-                    __FUNCTION__, mWidth, mHeight, mSize, mId);
-            return res;
-        }
-    } else {
-        res = native_window_set_buffers_dimensions(mConsumerInterface.get(),
-                mWidth, mHeight);
-        if (res != OK) {
-            ALOGE("%s: Unable to configure stream buffer dimensions"
-                    " %d x %d for stream %d",
-                    __FUNCTION__, mWidth, mHeight, mId);
-            return res;
-        }
-    }
-
-    res = native_window_set_buffers_format(mConsumerInterface.get(), mFormat);
-    if (res != OK) {
-        ALOGE("%s: Unable to configure stream buffer format"
-                " %#x for stream %d",
-                __FUNCTION__, mFormat, mId);
-        return res;
-    }
-
-    int maxConsumerBuffers;
-    res = mConsumerInterface->query(mConsumerInterface.get(),
-            NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
-    if (res != OK) {
-        ALOGE("%s: Unable to query consumer undequeued"
-                " buffer count for stream %d", __FUNCTION__, mId);
-        return res;
-    }
-    mMaxConsumerBuffers = maxConsumerBuffers;
-
-    ALOGV("%s: Consumer wants %d buffers", __FUNCTION__,
-            mMaxConsumerBuffers);
-
-    mTotalBuffers = mMaxConsumerBuffers + mMaxProducerBuffers;
-    mActiveBuffers = 0;
-    mFrameCount = 0;
-    mLastTimestamp = 0;
-
-    res = native_window_set_buffer_count(mConsumerInterface.get(),
-            mTotalBuffers);
-    if (res != OK) {
-        ALOGE("%s: Unable to set buffer count for stream %d",
-                __FUNCTION__, mId);
-        return res;
-    }
-
-    // Register allocated buffers with HAL device
-    buffer_handle_t *buffers = new buffer_handle_t[mTotalBuffers];
-    ANativeWindowBuffer **anwBuffers = new ANativeWindowBuffer*[mTotalBuffers];
-    uint32_t bufferIdx = 0;
-    for (; bufferIdx < mTotalBuffers; bufferIdx++) {
-        res = native_window_dequeue_buffer_and_wait(mConsumerInterface.get(),
-                &anwBuffers[bufferIdx]);
-        if (res != OK) {
-            ALOGE("%s: Unable to dequeue buffer %d for initial registration for "
-                    "stream %d", __FUNCTION__, bufferIdx, mId);
-            goto cleanUpBuffers;
-        }
-
-        buffers[bufferIdx] = anwBuffers[bufferIdx]->handle;
-        ALOGV("%s: Buffer %p allocated", __FUNCTION__, (void*)buffers[bufferIdx]);
-    }
-
-    ALOGV("%s: Registering %d buffers with camera HAL", __FUNCTION__, mTotalBuffers);
-    res = mHal2Device->ops->register_stream_buffers(mHal2Device,
-            mId,
-            mTotalBuffers,
-            buffers);
-    if (res != OK) {
-        ALOGE("%s: Unable to register buffers with HAL device for stream %d",
-                __FUNCTION__, mId);
-    } else {
-        mState = ACTIVE;
-    }
-
-cleanUpBuffers:
-    ALOGV("%s: Cleaning up %d buffers", __FUNCTION__, bufferIdx);
-    for (uint32_t i = 0; i < bufferIdx; i++) {
-        res = mConsumerInterface->cancelBuffer(mConsumerInterface.get(),
-                anwBuffers[i], -1);
-        if (res != OK) {
-            ALOGE("%s: Unable to cancel buffer %d after registration",
-                    __FUNCTION__, i);
-        }
-    }
-    delete[] anwBuffers;
-    delete[] buffers;
-
-    return res;
-}
-
-status_t Camera2Device::StreamAdapter::release() {
-    ATRACE_CALL();
-    status_t res;
-    ALOGV("%s: Releasing stream %d (%d x %d, format %d)", __FUNCTION__, mId,
-            mWidth, mHeight, mFormat);
-    if (mState >= ALLOCATED) {
-        res = mHal2Device->ops->release_stream(mHal2Device, mId);
-        if (res != OK) {
-            ALOGE("%s: Unable to release stream %d",
-                    __FUNCTION__, mId);
-            return res;
-        }
-    }
-    if (mState >= CONNECTED) {
-        res = native_window_api_disconnect(mConsumerInterface.get(),
-                NATIVE_WINDOW_API_CAMERA);
-
-        /* this is not an error. if client calling process dies,
-           the window will also die and all calls to it will return
-           DEAD_OBJECT, thus it's already "disconnected" */
-        if (res == DEAD_OBJECT) {
-            ALOGW("%s: While disconnecting stream %d from native window, the"
-                  " native window died from under us", __FUNCTION__, mId);
-        }
-        else if (res != OK) {
-            ALOGE("%s: Unable to disconnect stream %d from native window (error %d %s)",
-                    __FUNCTION__, mId, res, strerror(-res));
-            return res;
-        }
-    }
-    mId = -1;
-    mState = RELEASED;
-    return OK;
-}
-
-status_t Camera2Device::StreamAdapter::setTransform(int transform) {
-    ATRACE_CALL();
-    status_t res;
-    if (mState < CONNECTED) {
-        ALOGE("%s: Cannot set transform on unconnected stream", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-    res = native_window_set_buffers_transform(mConsumerInterface.get(),
-                                              transform);
-    if (res != OK) {
-        ALOGE("%s: Unable to configure stream transform to %x: %s (%d)",
-                __FUNCTION__, transform, strerror(-res), res);
-    }
-    return res;
-}
-
-status_t Camera2Device::StreamAdapter::dump(int fd,
-        const Vector<String16>& /*args*/) {
-    ATRACE_CALL();
-    String8 result = String8::format("      Stream %d: %d x %d, format 0x%x\n",
-            mId, mWidth, mHeight, mFormat);
-    result.appendFormat("        size %zu, usage 0x%x, requested format 0x%x\n",
-            mSize, mUsage, mFormatRequested);
-    result.appendFormat("        total buffers: %d, dequeued buffers: %d\n",
-            mTotalBuffers, mActiveBuffers);
-    result.appendFormat("        frame count: %d, last timestamp %" PRId64 "\n",
-            mFrameCount, mLastTimestamp);
-    write(fd, result.string(), result.size());
-    return OK;
-}
-
-const camera2_stream_ops *Camera2Device::StreamAdapter::getStreamOps() {
-    return static_cast<camera2_stream_ops *>(this);
-}
-
-ANativeWindow* Camera2Device::StreamAdapter::toANW(
-        const camera2_stream_ops_t *w) {
-    return static_cast<const StreamAdapter*>(w)->mConsumerInterface.get();
-}
-
-int Camera2Device::StreamAdapter::dequeue_buffer(const camera2_stream_ops_t *w,
-        buffer_handle_t** buffer) {
-    ATRACE_CALL();
-    int res;
-    StreamAdapter* stream =
-            const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w));
-    if (stream->mState != ACTIVE) {
-        ALOGE("%s: Called when in bad state: %d", __FUNCTION__, stream->mState);
-        return INVALID_OPERATION;
-    }
-
-    ANativeWindow *a = toANW(w);
-    ANativeWindowBuffer* anb;
-    res = native_window_dequeue_buffer_and_wait(a, &anb);
-    if (res != OK) {
-        ALOGE("Stream %d dequeue: Error from native_window: %s (%d)", stream->mId,
-                strerror(-res), res);
-        return res;
-    }
-
-    *buffer = &(anb->handle);
-    stream->mActiveBuffers++;
-
-    ALOGVV("Stream %d dequeue: Buffer %p dequeued", stream->mId, (void*)(**buffer));
-    return res;
-}
-
-int Camera2Device::StreamAdapter::enqueue_buffer(const camera2_stream_ops_t* w,
-        int64_t timestamp,
-        buffer_handle_t* buffer) {
-    ATRACE_CALL();
-    StreamAdapter *stream =
-            const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w));
-    stream->mFrameCount++;
-    ALOGVV("Stream %d enqueue: Frame %d (%p) captured at %lld ns",
-            stream->mId, stream->mFrameCount, (void*)(*buffer), timestamp);
-    int state = stream->mState;
-    if (state != ACTIVE) {
-        ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
-        return INVALID_OPERATION;
-    }
-    ANativeWindow *a = toANW(w);
-    status_t err;
-
-    err = native_window_set_buffers_timestamp(a, timestamp);
-    if (err != OK) {
-        ALOGE("%s: Error setting timestamp on native window: %s (%d)",
-                __FUNCTION__, strerror(-err), err);
-        return err;
-    }
-    err = a->queueBuffer(a,
-            container_of(buffer, ANativeWindowBuffer, handle), -1);
-    if (err != OK) {
-        ALOGE("%s: Error queueing buffer to native window: %s (%d)",
-                __FUNCTION__, strerror(-err), err);
-        return err;
-    }
-
-    stream->mActiveBuffers--;
-    stream->mLastTimestamp = timestamp;
-    return OK;
-}
-
-int Camera2Device::StreamAdapter::cancel_buffer(const camera2_stream_ops_t* w,
-        buffer_handle_t* buffer) {
-    ATRACE_CALL();
-    StreamAdapter *stream =
-            const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w));
-    ALOGVV("Stream %d cancel: Buffer %p",
-            stream->mId, (void*)(*buffer));
-    if (stream->mState != ACTIVE) {
-        ALOGE("%s: Called when in bad state: %d", __FUNCTION__, stream->mState);
-        return INVALID_OPERATION;
-    }
-
-    ANativeWindow *a = toANW(w);
-    int err = a->cancelBuffer(a,
-            container_of(buffer, ANativeWindowBuffer, handle), -1);
-    if (err != OK) {
-        ALOGE("%s: Error canceling buffer to native window: %s (%d)",
-                __FUNCTION__, strerror(-err), err);
-        return err;
-    }
-
-    stream->mActiveBuffers--;
-    return OK;
-}
-
-int Camera2Device::StreamAdapter::set_crop(const camera2_stream_ops_t* w,
-        int left, int top, int right, int bottom) {
-    ATRACE_CALL();
-    int state = static_cast<const StreamAdapter*>(w)->mState;
-    if (state != ACTIVE) {
-        ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
-        return INVALID_OPERATION;
-    }
-    ANativeWindow *a = toANW(w);
-    android_native_rect_t crop = { left, top, right, bottom };
-    return native_window_set_crop(a, &crop);
-}
-
-/**
- * Camera2Device::ReprocessStreamAdapter
- */
-
-#ifndef container_of
-#define container_of(ptr, type, member) \
-    (type *)((char*)(ptr) - offsetof(type, member))
-#endif
-
-Camera2Device::ReprocessStreamAdapter::ReprocessStreamAdapter(camera2_device_t *d):
-        mState(RELEASED),
-        mHal2Device(d),
-        mId(-1),
-        mWidth(0), mHeight(0), mFormat(0),
-        mActiveBuffers(0),
-        mFrameCount(0)
-{
-    ATRACE_CALL();
-    camera2_stream_in_ops::acquire_buffer = acquire_buffer;
-    camera2_stream_in_ops::release_buffer = release_buffer;
-}
-
-Camera2Device::ReprocessStreamAdapter::~ReprocessStreamAdapter() {
-    ATRACE_CALL();
-    if (mState != RELEASED) {
-        release();
-    }
-}
-
-status_t Camera2Device::ReprocessStreamAdapter::connectToDevice(
-        const sp<StreamAdapter> &outputStream) {
-    ATRACE_CALL();
-    status_t res;
-    ALOGV("%s: E", __FUNCTION__);
-
-    if (mState != RELEASED) return INVALID_OPERATION;
-    if (outputStream == NULL) {
-        ALOGE("%s: Null base stream passed to reprocess stream adapter",
-                __FUNCTION__);
-        return BAD_VALUE;
-    }
-
-    mBaseStream = outputStream;
-    mWidth = outputStream->getWidth();
-    mHeight = outputStream->getHeight();
-    mFormat = outputStream->getFormat();
-
-    ALOGV("%s: New reprocess stream parameters %d x %d, format 0x%x",
-            __FUNCTION__, mWidth, mHeight, mFormat);
-
-    // Allocate device-side stream interface
-
-    uint32_t id;
-    res = mHal2Device->ops->allocate_reprocess_stream_from_stream(mHal2Device,
-            outputStream->getId(), getStreamOps(),
-            &id);
-    if (res != OK) {
-        ALOGE("%s: Device reprocess stream allocation failed: %s (%d)",
-                __FUNCTION__, strerror(-res), res);
-        return res;
-    }
-
-    ALOGV("%s: Allocated reprocess stream id %d based on stream %d",
-            __FUNCTION__, id, outputStream->getId());
-
-    mId = id;
-
-    mState = ACTIVE;
-
-    return OK;
-}
-
-status_t Camera2Device::ReprocessStreamAdapter::release() {
-    ATRACE_CALL();
-    status_t res;
-    ALOGV("%s: Releasing stream %d", __FUNCTION__, mId);
-    if (mState >= ACTIVE) {
-        res = mHal2Device->ops->release_reprocess_stream(mHal2Device, mId);
-        if (res != OK) {
-            ALOGE("%s: Unable to release stream %d",
-                    __FUNCTION__, mId);
-            return res;
-        }
-    }
-
-    List<QueueEntry>::iterator s;
-    for (s = mQueue.begin(); s != mQueue.end(); s++) {
-        sp<BufferReleasedListener> listener = s->releaseListener.promote();
-        if (listener != 0) listener->onBufferReleased(s->handle);
-    }
-    for (s = mInFlightQueue.begin(); s != mInFlightQueue.end(); s++) {
-        sp<BufferReleasedListener> listener = s->releaseListener.promote();
-        if (listener != 0) listener->onBufferReleased(s->handle);
-    }
-    mQueue.clear();
-    mInFlightQueue.clear();
-
-    mState = RELEASED;
-    return OK;
-}
-
-status_t Camera2Device::ReprocessStreamAdapter::pushIntoStream(
-    buffer_handle_t *handle, const wp<BufferReleasedListener> &releaseListener) {
-    ATRACE_CALL();
-    // TODO: Some error checking here would be nice
-    ALOGV("%s: Pushing buffer %p to stream", __FUNCTION__, (void*)(*handle));
-
-    QueueEntry entry;
-    entry.handle = handle;
-    entry.releaseListener = releaseListener;
-    mQueue.push_back(entry);
-    return OK;
-}
-
-status_t Camera2Device::ReprocessStreamAdapter::dump(int fd,
-        const Vector<String16>& /*args*/) {
-    ATRACE_CALL();
-    String8 result =
-            String8::format("      Reprocess stream %d: %d x %d, fmt 0x%x\n",
-                    mId, mWidth, mHeight, mFormat);
-    result.appendFormat("        acquired buffers: %d\n",
-            mActiveBuffers);
-    result.appendFormat("        frame count: %d\n",
-            mFrameCount);
-    write(fd, result.string(), result.size());
-    return OK;
-}
-
-const camera2_stream_in_ops *Camera2Device::ReprocessStreamAdapter::getStreamOps() {
-    return static_cast<camera2_stream_in_ops *>(this);
-}
-
-int Camera2Device::ReprocessStreamAdapter::acquire_buffer(
-    const camera2_stream_in_ops_t *w,
-        buffer_handle_t** buffer) {
-    ATRACE_CALL();
-
-    ReprocessStreamAdapter* stream =
-            const_cast<ReprocessStreamAdapter*>(
-                static_cast<const ReprocessStreamAdapter*>(w));
-    if (stream->mState != ACTIVE) {
-        ALOGE("%s: Called when in bad state: %d", __FUNCTION__, stream->mState);
-        return INVALID_OPERATION;
-    }
-
-    if (stream->mQueue.empty()) {
-        *buffer = NULL;
-        return OK;
-    }
-
-    QueueEntry &entry = *(stream->mQueue.begin());
-
-    *buffer = entry.handle;
-
-    stream->mInFlightQueue.push_back(entry);
-    stream->mQueue.erase(stream->mQueue.begin());
-
-    stream->mActiveBuffers++;
-
-    ALOGV("Stream %d acquire: Buffer %p acquired", stream->mId,
-            (void*)(**buffer));
-    return OK;
-}
-
-int Camera2Device::ReprocessStreamAdapter::release_buffer(
-    const camera2_stream_in_ops_t* w,
-    buffer_handle_t* buffer) {
-    ATRACE_CALL();
-    ReprocessStreamAdapter *stream =
-            const_cast<ReprocessStreamAdapter*>(
-                static_cast<const ReprocessStreamAdapter*>(w) );
-    stream->mFrameCount++;
-    ALOGV("Reprocess stream %d release: Frame %d (%p)",
-            stream->mId, stream->mFrameCount, (void*)*buffer);
-    int state = stream->mState;
-    if (state != ACTIVE) {
-        ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
-        return INVALID_OPERATION;
-    }
-    stream->mActiveBuffers--;
-
-    List<QueueEntry>::iterator s;
-    for (s = stream->mInFlightQueue.begin(); s != stream->mInFlightQueue.end(); s++) {
-        if ( s->handle == buffer ) break;
-    }
-    if (s == stream->mInFlightQueue.end()) {
-        ALOGE("%s: Can't find buffer %p in in-flight list!", __FUNCTION__,
-                buffer);
-        return INVALID_OPERATION;
-    }
-
-    sp<BufferReleasedListener> listener = s->releaseListener.promote();
-    if (listener != 0) {
-        listener->onBufferReleased(s->handle);
-    } else {
-        ALOGE("%s: Can't free buffer - missing listener", __FUNCTION__);
-    }
-    stream->mInFlightQueue.erase(s);
-
-    return OK;
-}
-
-// camera 2 devices don't support reprocessing
-status_t Camera2Device::createInputStream(
-    uint32_t width, uint32_t height, int format, int *id) {
-    ALOGE("%s: camera 2 devices don't support reprocessing", __FUNCTION__);
-    return INVALID_OPERATION;
-}
-
-// camera 2 devices don't support reprocessing
-status_t Camera2Device::getInputBufferProducer(
-        sp<IGraphicBufferProducer> *producer) {
-    ALOGE("%s: camera 2 devices don't support reprocessing", __FUNCTION__);
-    return INVALID_OPERATION;
-}
-
-}; // namespace android
diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h
deleted file mode 100644
index b4d343c..0000000
--- a/services/camera/libcameraservice/device2/Camera2Device.h
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * Copyright (C) 2012 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_CAMERA_CAMERA2DEVICE_H
-#define ANDROID_SERVERS_CAMERA_CAMERA2DEVICE_H
-
-#include <utils/Condition.h>
-#include <utils/Errors.h>
-#include <utils/List.h>
-#include <utils/Mutex.h>
-
-#include "common/CameraDeviceBase.h"
-
-namespace android {
-
-/**
- * CameraDevice for HAL devices with version CAMERA_DEVICE_API_VERSION_2_0
- *
- * TODO for camera2 API implementation:
- * Does not produce notifyShutter / notifyIdle callbacks to NotificationListener
- * Use waitUntilDrained for idle.
- */
-class Camera2Device: public CameraDeviceBase {
-  public:
-    Camera2Device(int id);
-
-    virtual ~Camera2Device();
-
-    /**
-     * CameraDevice interface
-     */
-    virtual int      getId() const;
-    virtual status_t initialize(CameraModule *module);
-    virtual status_t disconnect();
-    virtual status_t dump(int fd, const Vector<String16>& args);
-    virtual const CameraMetadata& info() const;
-    virtual status_t capture(CameraMetadata &request, int64_t *lastFrameNumber = NULL);
-    virtual status_t captureList(const List<const CameraMetadata> &requests,
-                                 int64_t *lastFrameNumber = NULL);
-    virtual status_t setStreamingRequest(const CameraMetadata &request,
-                                         int64_t *lastFrameNumber = NULL);
-    virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests,
-                                             int64_t *lastFrameNumber = NULL);
-    virtual status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL);
-    virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout);
-    virtual status_t createStream(sp<Surface> consumer,
-            uint32_t width, uint32_t height, int format,
-            android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id);
-    virtual status_t createInputStream(
-            uint32_t width, uint32_t height, int format, int *id);
-    virtual status_t createReprocessStreamFromStream(int outputId, int *id);
-    virtual status_t getStreamInfo(int id,
-            uint32_t *width, uint32_t *height,
-            uint32_t *format, android_dataspace *dataSpace);
-    virtual status_t setStreamTransform(int id, int transform);
-    virtual status_t deleteStream(int id);
-    virtual status_t deleteReprocessStream(int id);
-    // No-op on HAL2 devices
-    virtual status_t configureStreams(bool isConstrainedHighSpeed = false);
-    virtual status_t getInputBufferProducer(
-            sp<IGraphicBufferProducer> *producer);
-    virtual status_t createDefaultRequest(int templateId, CameraMetadata *request);
-    virtual status_t waitUntilDrained();
-    virtual status_t setNotifyCallback(NotificationListener *listener);
-    virtual bool     willNotify3A();
-    virtual status_t waitForNextFrame(nsecs_t timeout);
-    virtual status_t getNextResult(CaptureResult *frame);
-    virtual status_t triggerAutofocus(uint32_t id);
-    virtual status_t triggerCancelAutofocus(uint32_t id);
-    virtual status_t triggerPrecaptureMetering(uint32_t id);
-    virtual status_t pushReprocessBuffer(int reprocessStreamId,
-            buffer_handle_t *buffer, wp<BufferReleasedListener> listener);
-    // Flush implemented as just a wait
-    virtual status_t flush(int64_t *lastFrameNumber = NULL);
-    // Prepare and tearDown are no-ops
-    virtual status_t prepare(int streamId);
-    virtual status_t tearDown(int streamId);
-    virtual status_t prepare(int maxCount, int streamId);
-
-    virtual uint32_t getDeviceVersion();
-    virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
-
-  private:
-    const int mId;
-    camera2_device_t *mHal2Device;
-
-    CameraMetadata mDeviceInfo;
-
-    uint32_t mDeviceVersion;
-
-    /**
-     * Queue class for both sending requests to a camera2 device, and for
-     * receiving frames from a camera2 device.
-     */
-    class MetadataQueue: public camera2_request_queue_src_ops_t,
-                         public camera2_frame_queue_dst_ops_t {
-      public:
-        MetadataQueue();
-        ~MetadataQueue();
-
-        // Interface to camera2 HAL device, either for requests (device is
-        // consumer) or for frames (device is producer)
-        const camera2_request_queue_src_ops_t*   getToConsumerInterface();
-        void setFromConsumerInterface(camera2_device_t *d);
-
-        // Connect queue consumer endpoint to a camera2 device
-        status_t setConsumerDevice(camera2_device_t *d);
-        // Connect queue producer endpoint to a camera2 device
-        status_t setProducerDevice(camera2_device_t *d);
-
-        const camera2_frame_queue_dst_ops_t* getToProducerInterface();
-
-        // Real interfaces. On enqueue, queue takes ownership of buffer pointer
-        // On dequeue, user takes ownership of buffer pointer.
-        status_t enqueue(camera_metadata_t *buf);
-        status_t dequeue(camera_metadata_t **buf, bool incrementCount = false);
-        int      getBufferCount();
-        status_t waitForBuffer(nsecs_t timeout);
-        // Wait until a buffer with the given ID is dequeued. Will return
-        // immediately if the latest buffer dequeued has that ID.
-        status_t waitForDequeue(int32_t id, nsecs_t timeout);
-
-        // Set repeating buffer(s); if the queue is empty on a dequeue call, the
-        // queue copies the contents of the stream slot into the queue, and then
-        // dequeues the first new entry. The methods take the ownership of the
-        // metadata buffers passed in.
-        status_t setStreamSlot(camera_metadata_t *buf);
-        status_t setStreamSlot(const List<camera_metadata_t*> &bufs);
-
-        // Clear the request queue and the streaming slot
-        status_t clear();
-
-        status_t dump(int fd, const Vector<String16>& args);
-
-      private:
-        status_t signalConsumerLocked();
-        status_t freeBuffers(List<camera_metadata_t*>::iterator start,
-                List<camera_metadata_t*>::iterator end);
-
-        camera2_device_t *mHal2Device;
-
-        Mutex mMutex;
-        Condition notEmpty;
-
-        int mFrameCount;
-        int32_t mLatestRequestId;
-        Condition mNewRequestId;
-
-        int mCount;
-        List<camera_metadata_t*> mEntries;
-        int mStreamSlotCount;
-        List<camera_metadata_t*> mStreamSlot;
-
-        bool mSignalConsumer;
-
-        static MetadataQueue* getInstance(
-            const camera2_frame_queue_dst_ops_t *q);
-        static MetadataQueue* getInstance(
-            const camera2_request_queue_src_ops_t *q);
-
-        static int consumer_buffer_count(
-            const camera2_request_queue_src_ops_t *q);
-
-        static int consumer_dequeue(const camera2_request_queue_src_ops_t *q,
-            camera_metadata_t **buffer);
-
-        static int consumer_free(const camera2_request_queue_src_ops_t *q,
-                camera_metadata_t *old_buffer);
-
-        static int producer_dequeue(const camera2_frame_queue_dst_ops_t *q,
-                size_t entries, size_t bytes,
-                camera_metadata_t **buffer);
-
-        static int producer_cancel(const camera2_frame_queue_dst_ops_t *q,
-            camera_metadata_t *old_buffer);
-
-        static int producer_enqueue(const camera2_frame_queue_dst_ops_t *q,
-                camera_metadata_t *filled_buffer);
-
-    }; // class MetadataQueue
-
-    MetadataQueue mRequestQueue;
-    MetadataQueue mFrameQueue;
-
-    /**
-     * Adapter from an ANativeWindow interface to camera2 device stream ops.
-     * Also takes care of allocating/deallocating stream in device interface
-     */
-    class StreamAdapter: public camera2_stream_ops, public virtual RefBase {
-      public:
-        StreamAdapter(camera2_device_t *d);
-
-        ~StreamAdapter();
-
-        /**
-         * Create a HAL device stream of the requested size and format.
-         *
-         * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device
-         * selects an appropriate format; it can be queried with getFormat.
-         *
-         * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must
-         * be equal to the size in bytes of the buffers to allocate for the
-         * stream. For other formats, the size parameter is ignored.
-         */
-        status_t connectToDevice(sp<ANativeWindow> consumer,
-                uint32_t width, uint32_t height, int format, size_t size);
-
-        status_t release();
-
-        status_t setTransform(int transform);
-
-        // Get stream parameters.
-        // Only valid after a successful connectToDevice call.
-        int      getId() const     { return mId; }
-        uint32_t getWidth() const  { return mWidth; }
-        uint32_t getHeight() const { return mHeight; }
-        uint32_t getFormat() const { return mFormat; }
-
-        // Dump stream information
-        status_t dump(int fd, const Vector<String16>& args);
-
-      private:
-        enum {
-            ERROR = -1,
-            RELEASED = 0,
-            ALLOCATED,
-            CONNECTED,
-            ACTIVE
-        } mState;
-
-        sp<ANativeWindow> mConsumerInterface;
-        camera2_device_t *mHal2Device;
-
-        uint32_t mId;
-        uint32_t mWidth;
-        uint32_t mHeight;
-        uint32_t mFormat;
-        size_t   mSize;
-        uint32_t mUsage;
-        uint32_t mMaxProducerBuffers;
-        uint32_t mMaxConsumerBuffers;
-        uint32_t mTotalBuffers;
-        int mFormatRequested;
-
-        /** Debugging information */
-        uint32_t mActiveBuffers;
-        uint32_t mFrameCount;
-        int64_t  mLastTimestamp;
-
-        const camera2_stream_ops *getStreamOps();
-
-        static ANativeWindow* toANW(const camera2_stream_ops_t *w);
-
-        static int dequeue_buffer(const camera2_stream_ops_t *w,
-                buffer_handle_t** buffer);
-
-        static int enqueue_buffer(const camera2_stream_ops_t* w,
-                int64_t timestamp,
-                buffer_handle_t* buffer);
-
-        static int cancel_buffer(const camera2_stream_ops_t* w,
-                buffer_handle_t* buffer);
-
-        static int set_crop(const camera2_stream_ops_t* w,
-                int left, int top, int right, int bottom);
-    }; // class StreamAdapter
-
-    typedef List<sp<StreamAdapter> > StreamList;
-    StreamList mStreams;
-
-    /**
-     * Adapter from an ANativeWindow interface to camera2 device stream ops.
-     * Also takes care of allocating/deallocating stream in device interface
-     */
-    class ReprocessStreamAdapter: public camera2_stream_in_ops, public virtual RefBase {
-      public:
-        ReprocessStreamAdapter(camera2_device_t *d);
-
-        ~ReprocessStreamAdapter();
-
-        /**
-         * Create a HAL device reprocess stream based on an existing output stream.
-         */
-        status_t connectToDevice(const sp<StreamAdapter> &outputStream);
-
-        status_t release();
-
-        /**
-         * Push buffer into stream for reprocessing. Takes ownership until it notifies
-         * that the buffer has been released
-         */
-        status_t pushIntoStream(buffer_handle_t *handle,
-                const wp<BufferReleasedListener> &releaseListener);
-
-        /**
-         * Get stream parameters.
-         * Only valid after a successful connectToDevice call.
-         */
-        int      getId() const     { return mId; }
-        uint32_t getWidth() const  { return mWidth; }
-        uint32_t getHeight() const { return mHeight; }
-        uint32_t getFormat() const { return mFormat; }
-
-        // Dump stream information
-        status_t dump(int fd, const Vector<String16>& args);
-
-      private:
-        enum {
-            ERROR = -1,
-            RELEASED = 0,
-            ACTIVE
-        } mState;
-
-        sp<ANativeWindow> mConsumerInterface;
-        wp<StreamAdapter> mBaseStream;
-
-        struct QueueEntry {
-            buffer_handle_t *handle;
-            wp<BufferReleasedListener> releaseListener;
-        };
-
-        List<QueueEntry> mQueue;
-
-        List<QueueEntry> mInFlightQueue;
-
-        camera2_device_t *mHal2Device;
-
-        uint32_t mId;
-        uint32_t mWidth;
-        uint32_t mHeight;
-        uint32_t mFormat;
-
-        /** Debugging information */
-        uint32_t mActiveBuffers;
-        uint32_t mFrameCount;
-        int64_t  mLastTimestamp;
-
-        const camera2_stream_in_ops *getStreamOps();
-
-        static int acquire_buffer(const camera2_stream_in_ops_t *w,
-                buffer_handle_t** buffer);
-
-        static int release_buffer(const camera2_stream_in_ops_t* w,
-                buffer_handle_t* buffer);
-
-    }; // class ReprocessStreamAdapter
-
-    typedef List<sp<ReprocessStreamAdapter> > ReprocessStreamList;
-    ReprocessStreamList mReprocessStreams;
-
-    // Receives HAL notifications and routes them to the NotificationListener
-    static void notificationCallback(int32_t msg_type,
-            int32_t ext1,
-            int32_t ext2,
-            int32_t ext3,
-            void *user);
-
-}; // class Camera2Device
-
-}; // namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.cpp b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
new file mode 100644
index 0000000..ae20887
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
@@ -0,0 +1,438 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Camera3-BufferManager"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <gui/ISurfaceComposer.h>
+#include <private/gui/ComposerService.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include "utils/CameraTraces.h"
+#include "Camera3BufferManager.h"
+
+namespace android {
+
+namespace camera3 {
+
+Camera3BufferManager::Camera3BufferManager(const sp<IGraphicBufferAlloc>& allocator) :
+        mAllocator(allocator) {
+    if (allocator == NULL) {
+        sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+        mAllocator = composer->createGraphicBufferAlloc();
+        if (mAllocator == NULL) {
+            ALOGE("createGraphicBufferAlloc failed");
+        }
+    }
+}
+
+Camera3BufferManager::~Camera3BufferManager() {
+}
+
+status_t Camera3BufferManager::registerStream(const StreamInfo& streamInfo) {
+    ATRACE_CALL();
+
+    int streamId = streamInfo.streamId;
+    int streamSetId = streamInfo.streamSetId;
+
+    if (streamId == CAMERA3_STREAM_ID_INVALID || streamSetId == CAMERA3_STREAM_SET_ID_INVALID) {
+        ALOGE("%s: Stream id (%d) or stream set id (%d) is invalid",
+                __FUNCTION__, streamId, streamSetId);
+        return BAD_VALUE;
+    }
+    if (streamInfo.totalBufferCount > kMaxBufferCount || streamInfo.totalBufferCount == 0) {
+        ALOGE("%s: Stream id (%d) with stream set id (%d) total buffer count %zu is invalid",
+                __FUNCTION__, streamId, streamSetId, streamInfo.totalBufferCount);
+        return BAD_VALUE;
+    }
+    if (!streamInfo.isConfigured) {
+        ALOGE("%s: Stream (%d) is not configured", __FUNCTION__, streamId);
+        return BAD_VALUE;
+    }
+
+    // For Gralloc v1, try to allocate a buffer and see if it is successful, otherwise, stream
+    // buffer sharing for this newly added stream is not supported. For Gralloc v0, we don't
+    // need check this, as the buffers are not really shared between streams, the buffers are
+    // allocated for each stream individually, the allocation failure will be checked in
+    // getBufferForStream() call.
+    if (mGrallocVersion > HARDWARE_DEVICE_API_VERSION(0,1)) {
+        // TODO: To be implemented.
+
+        // In case allocation fails, return invalid operation
+        return INVALID_OPERATION;
+    }
+
+    Mutex::Autolock l(mLock);
+    if (mAllocator == NULL) {
+        ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    // Check if this stream was registered with different stream set ID, if so, error out.
+    for (size_t i = 0; i < mStreamSetMap.size(); i++) {
+        ssize_t streamIdx = mStreamSetMap[i].streamInfoMap.indexOfKey(streamId);
+        if (streamIdx != NAME_NOT_FOUND &&
+            mStreamSetMap[i].streamInfoMap[streamIdx].streamSetId != streamInfo.streamSetId) {
+            ALOGE("%s: It is illegal to register the same stream id with different stream set",
+                    __FUNCTION__);
+            return BAD_VALUE;
+        }
+    }
+    // Check if there is an existing stream set registered; if not, create one; otherwise, add this
+    // stream info to the existing stream set entry.
+    ssize_t setIdx = mStreamSetMap.indexOfKey(streamSetId);
+    if (setIdx == NAME_NOT_FOUND) {
+        ALOGV("%s: stream set %d is not registered to stream set map yet, create it.",
+                __FUNCTION__, streamSetId);
+        // Create stream info map, then add to mStreamsetMap.
+        StreamSet newStreamSet;
+        setIdx = mStreamSetMap.add(streamSetId, newStreamSet);
+    }
+    // Update stream set map and water mark.
+    StreamSet& currentStreamSet = mStreamSetMap.editValueAt(setIdx);
+    ssize_t streamIdx = currentStreamSet.streamInfoMap.indexOfKey(streamId);
+    if (streamIdx != NAME_NOT_FOUND) {
+        ALOGW("%s: stream %d was already registered with stream set %d",
+                __FUNCTION__, streamId, streamSetId);
+        return OK;
+    }
+    currentStreamSet.streamInfoMap.add(streamId, streamInfo);
+    currentStreamSet.handoutBufferCountMap.add(streamId, 0);
+
+    // The max allowed buffer count should be the max of buffer count of each stream inside a stream
+    // set.
+    if (streamInfo.totalBufferCount > currentStreamSet.maxAllowedBufferCount) {
+       currentStreamSet.maxAllowedBufferCount = streamInfo.totalBufferCount;
+    }
+
+    return OK;
+}
+
+status_t Camera3BufferManager::unregisterStream(int streamId, int streamSetId) {
+    ATRACE_CALL();
+    Mutex::Autolock l(mLock);
+    ALOGV("%s: unregister stream %d with stream set %d", __FUNCTION__,
+            streamId, streamSetId);
+    if (mAllocator == NULL) {
+        ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    if (!checkIfStreamRegisteredLocked(streamId, streamSetId)){
+        ALOGE("%s: stream %d with set id %d wasn't properly registered to this buffer manager!",
+                __FUNCTION__, streamId, streamSetId);
+        return BAD_VALUE;
+    }
+
+    // De-list all the buffers associated with this stream first.
+    StreamSet& currentSet = mStreamSetMap.editValueFor(streamSetId);
+    BufferList& freeBufs = currentSet.freeBuffers;
+    BufferCountMap& handOutBufferCounts = currentSet.handoutBufferCountMap;
+    InfoMap& infoMap = currentSet.streamInfoMap;
+    removeBuffersFromBufferListLocked(freeBufs, streamId);
+    handOutBufferCounts.removeItem(streamId);
+
+    // Remove the stream info from info map and recalculate the buffer count water mark.
+    infoMap.removeItem(streamId);
+    currentSet.maxAllowedBufferCount = 0;
+    for (size_t i = 0; i < infoMap.size(); i++) {
+        if (infoMap[i].totalBufferCount > currentSet.maxAllowedBufferCount) {
+            currentSet.maxAllowedBufferCount = infoMap[i].totalBufferCount;
+        }
+    }
+    // Lazy solution: when a stream is unregistered, the streams will be reconfigured, reset
+    // the water mark and let it grow again.
+    currentSet.allocatedBufferWaterMark = 0;
+
+    // Remove this stream set if all its streams have been removed.
+    if (freeBufs.size() == 0 && handOutBufferCounts.size() == 0 && infoMap.size() == 0) {
+        mStreamSetMap.removeItem(streamSetId);
+    }
+
+    return OK;
+}
+
+status_t Camera3BufferManager::getBufferForStream(int streamId, int streamSetId,
+        sp<GraphicBuffer>* gb, int* fenceFd) {
+    ATRACE_CALL();
+
+    Mutex::Autolock l(mLock);
+    ALOGV("%s: get buffer for stream %d with stream set %d", __FUNCTION__,
+            streamId, streamSetId);
+    if (mAllocator == NULL) {
+        ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    if (!checkIfStreamRegisteredLocked(streamId, streamSetId)) {
+        ALOGE("%s: stream %d is not registered with stream set %d yet!!!",
+                __FUNCTION__, streamId, streamSetId);
+        return BAD_VALUE;
+    }
+
+    StreamSet &streamSet = mStreamSetMap.editValueFor(streamSetId);
+    BufferCountMap& handOutBufferCounts = streamSet.handoutBufferCountMap;
+    size_t& bufferCount = handOutBufferCounts.editValueFor(streamId);
+    if (bufferCount >= streamSet.maxAllowedBufferCount) {
+        ALOGE("%s: bufferCount (%zu) exceeds the max allowed buffer count (%zu) of this stream set",
+                __FUNCTION__, bufferCount, streamSet.maxAllowedBufferCount);
+        return INVALID_OPERATION;
+    }
+
+    GraphicBufferEntry buffer =
+            getFirstBufferFromBufferListLocked(streamSet.freeBuffers, streamId);
+
+    if (mGrallocVersion < HARDWARE_DEVICE_API_VERSION(1,0)) {
+        // Allocate one if there is no free buffer available.
+        if (buffer.graphicBuffer == nullptr) {
+            const StreamInfo& info = streamSet.streamInfoMap.valueFor(streamId);
+            status_t res = OK;
+            buffer.fenceFd = -1;
+            buffer.graphicBuffer = mAllocator->createGraphicBuffer(
+                    info.width, info.height, info.format, info.combinedUsage, &res);
+            ALOGV("%s: allocating a new graphic buffer (%dx%d, format 0x%x) %p with handle %p",
+                    __FUNCTION__, info.width, info.height, info.format,
+                    buffer.graphicBuffer.get(), buffer.graphicBuffer->handle);
+            if (res != OK) {
+                ALOGE("%s: graphic buffer allocation failed: (error %d %s) ",
+                        __FUNCTION__, res, strerror(-res));
+                return res;
+            }
+            ALOGV("%s: allocation done", __FUNCTION__);
+        }
+
+        // Increase the hand-out buffer count for tracking purpose.
+        bufferCount++;
+        // Update the water mark to be the max hand-out buffer count + 1. An additional buffer is
+        // added to reduce the chance of buffer allocation during stream steady state, especially
+        // for cases where one stream is active, the other stream may request some buffers randomly.
+        if (bufferCount + 1 > streamSet.allocatedBufferWaterMark) {
+            streamSet.allocatedBufferWaterMark = bufferCount + 1;
+        }
+        *gb = buffer.graphicBuffer;
+        *fenceFd = buffer.fenceFd;
+        ALOGV("%s: get buffer (%p) with handle (%p).",
+                __FUNCTION__, buffer.graphicBuffer.get(), buffer.graphicBuffer->handle);
+
+        // Proactively free buffers for other streams if the current number of allocated buffers
+        // exceeds the water mark. This only for Gralloc V1, for V2, this logic can also be handled
+        // in returnBufferForStream() if we want to free buffer more quickly.
+        // TODO: probably should find out all the inactive stream IDs, and free the firstly found
+        // buffers for them.
+        StreamId firstOtherStreamId = CAMERA3_STREAM_ID_INVALID;
+        if (streamSet.streamInfoMap.size() > 1) {
+            for (size_t i = 0; i < streamSet.streamInfoMap.size(); i++) {
+                firstOtherStreamId = streamSet.streamInfoMap[i].streamId;
+                if (firstOtherStreamId != streamId &&
+                        hasBufferForStreamLocked(streamSet.freeBuffers, firstOtherStreamId)) {
+                    break;
+                }
+            }
+            if (firstOtherStreamId == CAMERA3_STREAM_ID_INVALID) {
+                return OK;
+            }
+
+            // This will drop the reference to one free buffer, which will effectively free one
+            // buffer (from the free buffer list) for the inactive streams.
+            size_t totalAllocatedBufferCount = streamSet.freeBuffers.size();
+            for (size_t i = 0; i < streamSet.handoutBufferCountMap.size(); i++) {
+                totalAllocatedBufferCount += streamSet.handoutBufferCountMap[i];
+            }
+            if (totalAllocatedBufferCount > streamSet.allocatedBufferWaterMark) {
+                ALOGV("%s: free a buffer from stream %d", __FUNCTION__, firstOtherStreamId);
+                getFirstBufferFromBufferListLocked(streamSet.freeBuffers, firstOtherStreamId);
+            }
+        }
+    } else {
+        // TODO: implement this.
+        return BAD_VALUE;
+    }
+
+    return OK;
+}
+
+status_t Camera3BufferManager::returnBufferForStream(int streamId,
+        int streamSetId, const sp<GraphicBuffer>& buffer, int fenceFd) {
+    ATRACE_CALL();
+    Mutex::Autolock l(mLock);
+    ALOGV_IF(buffer != 0, "%s: return buffer (%p) with handle (%p) for stream %d and stream set %d",
+            __FUNCTION__, buffer.get(), buffer->handle, streamId, streamSetId);
+    if (mAllocator == NULL) {
+        ALOGE("%s: allocator is NULL, buffer manager is bad state.", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    if (!checkIfStreamRegisteredLocked(streamId, streamSetId)){
+        ALOGV("%s: returning buffer for an already unregistered stream (stream %d with set id %d),"
+                "buffer will be dropped right away!", __FUNCTION__, streamId, streamSetId);
+        return OK;
+    }
+
+    if (mGrallocVersion < HARDWARE_DEVICE_API_VERSION(1,0)) {
+        // Add to the freeBuffer list.
+        StreamSet& streamSet = mStreamSetMap.editValueFor(streamSetId);
+        if (buffer != 0) {
+            BufferEntry entry;
+            entry.add(streamId, GraphicBufferEntry(buffer, fenceFd));
+            status_t res = addBufferToBufferListLocked(streamSet.freeBuffers, entry);
+            if (res != OK) {
+                ALOGE("%s: add buffer to free buffer list failed", __FUNCTION__);
+                return res;
+            }
+        }
+
+        // Update the hand-out buffer count for this buffer.
+        BufferCountMap& handOutBufferCounts = streamSet.handoutBufferCountMap;
+        size_t& bufferCount = handOutBufferCounts.editValueFor(streamId);
+        bufferCount--;
+    } else {
+        // TODO: implement this.
+        return BAD_VALUE;
+    }
+
+    return OK;
+}
+
+void Camera3BufferManager::dump(int fd, const Vector<String16>& args) const {
+    Mutex::Autolock l(mLock);
+
+    (void) args;
+    String8 lines;
+    lines.appendFormat("      Total stream sets: %zu\n", mStreamSetMap.size());
+    for (size_t i = 0; i < mStreamSetMap.size(); i++) {
+        lines.appendFormat("        Stream set %d has below streams:\n", mStreamSetMap.keyAt(i));
+        for (size_t j = 0; j < mStreamSetMap[i].streamInfoMap.size(); j++) {
+            lines.appendFormat("          Stream %d\n", mStreamSetMap[i].streamInfoMap[j].streamId);
+        }
+        lines.appendFormat("          Stream set max allowed buffer count: %zu\n",
+                mStreamSetMap[i].maxAllowedBufferCount);
+        lines.appendFormat("          Stream set buffer count water mark: %zu\n",
+                mStreamSetMap[i].allocatedBufferWaterMark);
+        lines.appendFormat("          Handout buffer counts:\n");
+        for (size_t m = 0; m < mStreamSetMap[i].handoutBufferCountMap.size(); m++) {
+            int streamId = mStreamSetMap[i].handoutBufferCountMap.keyAt(m);
+            size_t bufferCount = mStreamSetMap[i].handoutBufferCountMap.valueAt(m);
+            lines.appendFormat("            stream id: %d, buffer count: %zu.\n",
+                    streamId, bufferCount);
+        }
+
+        lines.appendFormat("          Free buffer count: %zu\n",
+                mStreamSetMap[i].freeBuffers.size());
+        for (auto& bufEntry : mStreamSetMap[i].freeBuffers) {
+            for (size_t m = 0; m < bufEntry.size(); m++) {
+                const sp<GraphicBuffer>& buffer = bufEntry.valueAt(m).graphicBuffer;
+                int streamId = bufEntry.keyAt(m);
+                lines.appendFormat("            stream id: %d, buffer: %p, handle: %p.\n",
+                        streamId, buffer.get(), buffer->handle);
+            }
+        }
+    }
+    write(fd, lines.string(), lines.size());
+}
+
+bool Camera3BufferManager::checkIfStreamRegisteredLocked(int streamId, int streamSetId) const {
+    ssize_t setIdx = mStreamSetMap.indexOfKey(streamSetId);
+    if (setIdx == NAME_NOT_FOUND) {
+        ALOGV("%s: stream set %d is not registered to stream set map yet!",
+                __FUNCTION__, streamSetId);
+        return false;
+    }
+
+    ssize_t streamIdx = mStreamSetMap.valueAt(setIdx).streamInfoMap.indexOfKey(streamId);
+    if (streamIdx == NAME_NOT_FOUND) {
+        ALOGV("%s: stream %d is not registered to stream info map yet!", __FUNCTION__, streamId);
+        return false;
+    }
+
+    size_t bufferWaterMark = mStreamSetMap[setIdx].maxAllowedBufferCount;
+    if (bufferWaterMark == 0 || bufferWaterMark > kMaxBufferCount) {
+        ALOGW("%s: stream %d with stream set %d is not registered correctly to stream set map,"
+                " as the water mark (%zu) is wrong!",
+                __FUNCTION__, streamId, streamSetId, bufferWaterMark);
+        return false;
+    }
+
+    return true;
+}
+
+status_t Camera3BufferManager::addBufferToBufferListLocked(BufferList& bufList,
+        const BufferEntry& buffer) {
+    // TODO: need add some sanity check here.
+    bufList.push_back(buffer);
+
+    return OK;
+}
+
+status_t Camera3BufferManager::removeBuffersFromBufferListLocked(BufferList& bufferList,
+        int streamId) {
+    BufferList::iterator i = bufferList.begin();
+    while (i != bufferList.end()) {
+        ssize_t idx = i->indexOfKey(streamId);
+        if (idx != NAME_NOT_FOUND) {
+            ALOGV("%s: Remove a buffer for stream %d, free buffer total count: %zu",
+                    __FUNCTION__, streamId, bufferList.size());
+            i->removeItem(streamId);
+            if (i->isEmpty()) {
+                i = bufferList.erase(i);
+            }
+        } else {
+            i++;
+        }
+    }
+
+    ALOGW_IF(i == bufferList.end(), "%s: Unable to find buffers for stream %d",
+            __FUNCTION__, streamId);
+
+    return OK;
+}
+
+bool Camera3BufferManager::hasBufferForStreamLocked(BufferList& buffers, int streamId) {
+    BufferList::iterator i = buffers.begin();
+    while (i != buffers.end()) {
+        ssize_t idx = i->indexOfKey(streamId);
+        if (idx != NAME_NOT_FOUND) {
+            return true;
+        }
+        i++;
+    }
+
+    return false;
+}
+
+Camera3BufferManager::GraphicBufferEntry Camera3BufferManager::getFirstBufferFromBufferListLocked(
+        BufferList& buffers, int streamId) {
+    // Try to get the first buffer from the free buffer list if there is one.
+    GraphicBufferEntry entry;
+    BufferList::iterator i = buffers.begin();
+    while (i != buffers.end()) {
+        ssize_t idx = i->indexOfKey(streamId);
+        if (idx != NAME_NOT_FOUND) {
+            entry = GraphicBufferEntry(i->valueAt(idx));
+            i = buffers.erase(i);
+            break;
+        } else {
+            i++;
+        }
+    }
+
+    ALOGV_IF(entry.graphicBuffer == 0, "%s: Unable to find free buffer for stream %d",
+            __FUNCTION__, streamId);
+    return entry;
+}
+
+} // namespace camera3
+} // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.h b/services/camera/libcameraservice/device3/Camera3BufferManager.h
new file mode 100644
index 0000000..7942ae6
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.h
@@ -0,0 +1,307 @@
+/*
+ * 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_SERVERS_CAMERA3_BUFFER_MANAGER_H
+#define ANDROID_SERVERS_CAMERA3_BUFFER_MANAGER_H
+
+#include <list>
+#include <algorithm>
+#include <ui/GraphicBuffer.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include "Camera3OutputStream.h"
+
+namespace android {
+
+namespace camera3 {
+
+struct StreamInfo;
+
+/**
+ * A class managing the graphic buffers that is used by camera output streams. It allocates and
+ * hands out Gralloc buffers to the clients (e.g., Camera3OutputStream) based on the requests.
+ * When clients request a buffer, buffer manager will pick a buffer if there are some already
+ * allocated buffer available, will allocate a buffer otherwise. When there are too many allocated
+ * buffer maintained by the buffer manager, it will dynamically deallocate some buffers that are
+ * solely owned by this buffer manager.
+ * In doing so, it reduces the memory footprint unless it is already minimal without impacting
+ * performance.
+ *
+ */
+class Camera3BufferManager: public virtual RefBase {
+public:
+    Camera3BufferManager(const sp<IGraphicBufferAlloc>& allocator = NULL);
+
+    virtual ~Camera3BufferManager();
+
+    /**
+     * This method registers an output stream to this buffer manager by using the provided stream
+     * information.
+     *
+     * The stream info includes the necessary information such as stream size, format, buffer count,
+     * usage flags, etc. for the buffer manager to allocate and hand out buffers for this stream.
+     *
+     * It's illegal to call this method if the stream is not CONFIGURED yet, as some critical
+     * stream properties (e.g., combined usage flags) are only available in this state. It is also
+     * illegal to call this method with an invalid stream set ID (CAMERA3_STREAM_SET_ID_INVALID),
+     * as the invalid stream set ID indicates that this stream doesn't intend to use buffer manager.
+     *
+     *
+     * Once a stream is successfully registered to this buffer manager, the buffer manager takes
+     * over the buffer allocation role and provides buffers to this stream via getBufferForStream().
+     * The returned buffer can be sent to the camera HAL for image output, and then queued to the
+     * ANativeWindow (Surface) for downstream consumer to acquire. Once the image buffer is released
+     * by the consumer end point, the BufferQueueProducer callback onBufferReleased will call
+     * returnBufferForStream() to return the free buffer to this buffer manager. If the stream
+     * uses buffer manager to manage the stream buffers, it should disable the BufferQueue
+     * allocation via IGraphicBufferProducer::allowAllocation(false).
+     *
+     * Registering an already registered stream has no effect.
+     *
+     * Return values:
+     *
+     *  OK:                Registration of the new stream was successful.
+     *  BAD_VALUE:         This stream is not at CONFIGURED state, or the stream ID or stream set
+     *                     ID are invalid, or attempting to register the same stream to multiple
+     *                     stream sets, or other stream properties are invalid.
+     *  INVALID_OPERATION: This buffer manager doesn't support buffer sharing across this stream
+     *                     and other streams that were already registered with the same stream set
+     *                     ID.
+     */
+    status_t registerStream(const StreamInfo &streamInfo);
+
+    /**
+     * This method unregisters a stream from this buffer manager.
+     *
+     * After a stream is unregistered, further getBufferForStream() calls will fail for this stream.
+     * After all streams for a given stream set are unregistered, all the buffers solely owned (for
+     * this stream set) by this buffer manager will be freed; all buffers subsequently returned to
+     * this buffer manager for this stream set will be freed immediately.
+     *
+     * Return values:
+     *
+     *  OK:        Removal of the a stream from this buffer manager was successful.
+     *  BAD_VALUE: stream ID or stream set ID are invalid, or stream ID and stream set ID
+     *             combination doesn't match what was registered, or this stream wasn't registered
+     *             to this buffer manager before.
+     */
+    status_t unregisterStream(int streamId, int streamSetId);
+
+    /**
+     * This method obtains a buffer for a stream from this buffer manager.
+     *
+     * This method returns the first free buffer from the free buffer list (associated with this
+     * stream set) if there is any. Otherwise, it will allocate a buffer for this stream, return
+     * it and increment its count of handed-out buffers. When the total number of allocated buffers
+     * is too high, it may deallocate the unused buffers to save memory footprint of this stream
+     * set.
+     *
+     * After this call, the client takes over the ownership of this buffer if it is not freed.
+     *
+     * Return values:
+     *
+     *  OK:        Getting buffer for this stream was successful.
+     *  BAD_VALUE: stream ID or streamSetId are invalid, or stream ID and stream set ID
+     *             combination doesn't match what was registered, or this stream wasn't registered
+     *             to this buffer manager before.
+     *  NO_MEMORY: Unable to allocate a buffer for this stream at this time.
+     */
+    status_t getBufferForStream(int streamId, int streamSetId, sp<GraphicBuffer>* gb, int* fenceFd);
+
+    /**
+     * This method returns a buffer for a stream to this buffer manager.
+     *
+     * When a buffer is returned, it is treated as a free buffer and may either be reused for future
+     * getBufferForStream() calls, or freed if there total number of outstanding allocated buffers
+     * is too large. The latter only applies to the case where the buffer are physically shared
+     * between streams in the same stream set. A physically shared buffer is the buffer that has one
+     * physical back store but multiple handles. Multiple stream can access the same physical memory
+     * with their own handles. Physically shared buffer can only be supported by Gralloc HAL V1.
+     * See hardware/libhardware/include/hardware/gralloc1.h for more details.
+     *
+     *
+     * This call takes the ownership of the returned buffer if it was allocated by this buffer
+     * manager; clients should not use this buffer after this call. Attempting to access this buffer
+     * after this call will have undefined behavior. Holding a reference to this buffer after this
+     * call may cause memory leakage. If a BufferQueue is used to track the buffers handed out by
+     * this buffer queue, it is recommended to call detachNextBuffer() from the buffer queue after
+     * BufferQueueProducer onBufferReleased callback is fired, and return it to this buffer manager.
+     *
+     *  OK:        Buffer return for this stream was successful.
+     *  BAD_VALUE: stream ID or streamSetId are invalid, or stream ID and stream set ID combination
+     *             doesn't match what was registered, or this stream wasn't registered to this
+     *             buffer manager before.
+     */
+    status_t returnBufferForStream(int streamId, int streamSetId, const sp<GraphicBuffer>& buffer,
+            int fenceFd);
+
+    /**
+     * Dump the buffer manager statistics.
+     */
+    void     dump(int fd, const Vector<String16> &args) const;
+
+private:
+    /**
+     * Lock to synchronize the access to the methods of this class.
+     */
+    mutable Mutex mLock;
+
+    static const size_t kMaxBufferCount = BufferQueueDefs::NUM_BUFFER_SLOTS;
+
+    /**
+     * mAllocator is the connection to SurfaceFlinger that is used to allocate new GraphicBuffer
+     * objects.
+     */
+    sp<IGraphicBufferAlloc> mAllocator;
+
+    struct GraphicBufferEntry {
+        sp<GraphicBuffer> graphicBuffer;
+        int fenceFd;
+        GraphicBufferEntry(const sp<GraphicBuffer>& gb = 0, int fd = -1) :
+            graphicBuffer(gb),
+            fenceFd(fd) {}
+    };
+
+    /**
+     * A buffer entry (indexed by stream ID) represents a single physically allocated buffer. For
+     * Gralloc V0, since each physical buffer is associated with one stream, this is
+     * a single entry map. For Gralloc V1, one physical buffer can be shared between different
+     * streams in one stream set, so this entry may include multiple entries, where the different
+     * graphic buffers have the same common Gralloc backing store.
+     */
+    typedef int StreamId;
+    typedef KeyedVector<StreamId, GraphicBufferEntry> BufferEntry;
+
+    typedef std::list<BufferEntry> BufferList;
+
+    /**
+     * Stream info map (indexed by stream ID) tracks all the streams registered to a particular
+     * stream set.
+     */
+    typedef KeyedVector<StreamId, StreamInfo> InfoMap;
+
+    /**
+     * Stream set buffer count map (indexed by stream ID) tracks all buffer counts of the streams
+     * registered to a particular stream set.
+     */
+    typedef KeyedVector<StreamId, size_t> BufferCountMap;
+
+    /**
+     * StreamSet keeps track of the stream info, free buffer list and hand-out buffer counts for
+     * each stream set.
+     */
+    struct StreamSet {
+        /**
+         * Stream set buffer count water mark representing the max number of allocated buffers
+         * (hand-out buffers + free buffers) count for each stream set. For a given stream set, when
+         * getBufferForStream() is called on this buffer manager, if the total allocated buffer
+         * count exceeds this water mark, the buffer manager will attempt to reduce it as follows:
+         *
+         * In getBufferForStream(), find a buffer associated with other streams (inside the same
+         * stream set) on the free buffer list and free it. For Gralloc V1, can just free the top
+         * of the free buffer list if the physical buffer sharing in this stream is supported.
+         *
+         * For a particular stream set, a larger allocatedBufferWaterMark increases the memory
+         * footprint of the stream set, but reduces the chance that getBufferForStream() will have
+         * to allocate a new buffer. We assume that the streams in one stream set are not streaming
+         * simultaneously, the max allocated buffer count water mark for a stream set will the max
+         * of all streams' total buffer counts. This will avoid new buffer allocation in steady
+         * streaming state.
+         *
+         * This water mark can be dynamically changed, and will grow when the hand-out buffer count
+         * of each stream increases, until it reaches the maxAllowedBufferCount.
+         */
+        size_t allocatedBufferWaterMark;
+
+        /**
+         * The max allowed buffer count for this stream set. It is the max of total number of
+         * buffers for each stream. This is the upper bound of the allocatedBufferWaterMark.
+         */
+        size_t maxAllowedBufferCount;
+
+        /**
+         * The stream info for all streams in this set
+         */
+        InfoMap streamInfoMap;
+        /**
+         * The free buffer list for all the buffers belong to this set. The free buffers are
+         * returned by the returnBufferForStream() call, and available for reuse.
+         */
+        BufferList freeBuffers;
+        /**
+         * The count of the buffers that were handed out to the streams of this set.
+         */
+        BufferCountMap handoutBufferCountMap;
+        StreamSet() {
+            allocatedBufferWaterMark = 0;
+            maxAllowedBufferCount = 0;
+        }
+    };
+
+    /**
+     * Stream set map managed by this buffer manager.
+     */
+    typedef int StreamSetId;
+    KeyedVector<StreamSetId, StreamSet> mStreamSetMap;
+
+    // TODO: There is no easy way to query the Gralloc version in this code yet, we have different
+    // code paths for different Gralloc versions, hardcode something here for now.
+    const uint32_t mGrallocVersion = GRALLOC_DEVICE_API_VERSION_0_1;
+
+    /**
+     * Check if this stream was successfully registered already. This method needs to be called with
+     * mLock held.
+     */
+    bool checkIfStreamRegisteredLocked(int streamId, int streamSetId) const;
+
+    /**
+     * Add a buffer entry to the BufferList. This method needs to be called with mLock held.
+     */
+    status_t addBufferToBufferListLocked(BufferList &bufList, const BufferEntry &buffer);
+
+    /**
+     * Remove all buffers from the BufferList.
+     *
+     * Note that this doesn't mean that the buffers are freed after this call. A buffer is freed
+     * only if all other references to it are dropped.
+     *
+     * This method needs to be called with mLock held.
+     */
+    status_t removeBuffersFromBufferListLocked(BufferList &bufList, int streamId);
+
+    /**
+     * Get the first available buffer from the buffer list for this stream. The graphicBuffer inside
+     * this entry will be NULL if there is no any GraphicBufferEntry found. After this call, the
+     * GraphicBufferEntry will be removed from the BufferList if a GraphicBufferEntry is found.
+     *
+     * This method needs to be called with mLock held.
+     *
+     */
+    GraphicBufferEntry getFirstBufferFromBufferListLocked(BufferList& buffers, int streamId);
+
+    /**
+     * Check if there is any buffer associated with this stream in the given buffer list.
+     *
+     * This method needs to be called with mLock held.
+     *
+     */
+    bool inline hasBufferForStreamLocked(BufferList& buffers, int streamId);
+};
+
+} // namespace camera3
+} // namespace android
+
+#endif // ANDROID_SERVERS_CAMERA3_BUFFER_MANAGER_H
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 50d9d75..b524f61 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -64,6 +64,7 @@
         mStatusWaiters(0),
         mUsePartialResult(false),
         mNumPartialResults(1),
+        mTimestampOffset(0),
         mNextResultFrameNumber(0),
         mNextReprocessResultFrameNumber(0),
         mNextShutterFrameNumber(0),
@@ -167,6 +168,9 @@
         return res;
     }
 
+    /** Create buffer manager */
+    mBufferManager = new Camera3BufferManager();
+
     bool aeLockAvailable = false;
     camera_metadata_ro_entry aeLockAvailableEntry;
     res = find_camera_metadata_ro_entry(info.static_camera_characteristics,
@@ -201,6 +205,14 @@
     mNeedConfig = true;
     mPauseStateNotify = false;
 
+    // Measure the clock domain offset between camera and video/hw_composer
+    camera_metadata_entry timestampSource =
+            mDeviceInfo.find(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE);
+    if (timestampSource.count > 0 && timestampSource.data.u8[0] ==
+            ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME) {
+        mTimestampOffset = getMonoToBoottimeOffset();
+    }
+
     // Will the HAL be sending in early partial result metadata?
     if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
         camera_metadata_entry partialResultsCount =
@@ -293,6 +305,7 @@
 
         mRequestThread.clear();
         mStatusTracker.clear();
+        mBufferManager.clear();
 
         hal3Device = mHal3Device;
     }
@@ -378,6 +391,24 @@
     return Size(maxJpegWidth, maxJpegHeight);
 }
 
+nsecs_t Camera3Device::getMonoToBoottimeOffset() {
+    // try three times to get the clock offset, choose the one
+    // with the minimum gap in measurements.
+    const int tries = 3;
+    nsecs_t bestGap, measured;
+    for (int i = 0; i < tries; ++i) {
+        const nsecs_t tmono = systemTime(SYSTEM_TIME_MONOTONIC);
+        const nsecs_t tbase = systemTime(SYSTEM_TIME_BOOTTIME);
+        const nsecs_t tmono2 = systemTime(SYSTEM_TIME_MONOTONIC);
+        const nsecs_t gap = tmono2 - tmono;
+        if (i == 0 || gap < bestGap) {
+            bestGap = gap;
+            measured = tbase - ((tmono + tmono2) >> 1);
+        }
+    }
+    return measured;
+}
+
 ssize_t Camera3Device::getJpegBufferSize(uint32_t width, uint32_t height) const {
     // Get max jpeg size (area-wise).
     Size maxJpegResolution = getMaxJpegResolution();
@@ -422,7 +453,31 @@
     return maxBytesForPointCloud;
 }
 
+ssize_t Camera3Device::getRawOpaqueBufferSize(uint32_t width, uint32_t height) const {
+    const int PER_CONFIGURATION_SIZE = 3;
+    const int WIDTH_OFFSET = 0;
+    const int HEIGHT_OFFSET = 1;
+    const int SIZE_OFFSET = 2;
+    camera_metadata_ro_entry rawOpaqueSizes =
+        mDeviceInfo.find(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+    int count = rawOpaqueSizes.count;
+    if (count == 0 || (count % PER_CONFIGURATION_SIZE)) {
+        ALOGE("%s: Camera %d: bad opaque RAW size static metadata length(%d)!",
+                __FUNCTION__, mId, count);
+        return BAD_VALUE;
+    }
 
+    for (size_t i = 0; i < count; i += PER_CONFIGURATION_SIZE) {
+        if (width == rawOpaqueSizes.data.i32[i + WIDTH_OFFSET] &&
+                height == rawOpaqueSizes.data.i32[i + HEIGHT_OFFSET]) {
+            return rawOpaqueSizes.data.i32[i + SIZE_OFFSET];
+        }
+    }
+
+    ALOGE("%s: Camera %d: cannot find size for %dx%d opaque RAW image!",
+            __FUNCTION__, mId, width, height);
+    return BAD_VALUE;
+}
 
 status_t Camera3Device::dump(int fd, const Vector<String16> &args) {
     ATRACE_CALL();
@@ -440,6 +495,15 @@
             "Camera %d: %s: Unable to lock main lock, proceeding anyway",
             mId, __FUNCTION__);
 
+    bool dumpTemplates = false;
+    String16 templatesOption("-t");
+    int n = args.size();
+    for (int i = 0; i < n; i++) {
+        if (args[i] == templatesOption) {
+            dumpTemplates = true;
+        }
+    }
+
     String8 lines;
 
     const char *status =
@@ -469,6 +533,10 @@
         mOutputStreams[i]->dump(fd,args);
     }
 
+    lines = String8("    Camera3 Buffer Manager:\n");
+    write(fd, lines.string(), lines.size());
+    mBufferManager->dump(fd, args);
+
     lines = String8("    In-flight requests:\n");
     if (mInFlightMap.size() == 0) {
         lines.append("      None\n");
@@ -491,6 +559,33 @@
         lastRequest.dump(fd, /*verbosity*/2, /*indentation*/6);
     }
 
+    if (dumpTemplates) {
+        const char *templateNames[] = {
+            "TEMPLATE_PREVIEW",
+            "TEMPLATE_STILL_CAPTURE",
+            "TEMPLATE_VIDEO_RECORD",
+            "TEMPLATE_VIDEO_SNAPSHOT",
+            "TEMPLATE_ZERO_SHUTTER_LAG",
+            "TEMPLATE_MANUAL"
+        };
+
+        for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; i++) {
+            const camera_metadata_t *templateRequest;
+            templateRequest =
+                mHal3Device->ops->construct_default_request_settings(
+                    mHal3Device, i);
+            lines = String8::format("    HAL Request %s:\n", templateNames[i-1]);
+            if (templateRequest == NULL) {
+                lines.append("       Not supported\n");
+                write(fd, lines.string(), lines.size());
+            } else {
+                write(fd, lines.string(), lines.size());
+                dump_indented_camera_metadata(templateRequest,
+                        fd, /*verbosity*/2, /*indentation*/8);
+            }
+        }
+    }
+
     if (mHal3Device != NULL) {
         lines = String8("    HAL device dump:\n");
         write(fd, lines.string(), lines.size());
@@ -866,7 +961,7 @@
 
 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) {
+        camera3_stream_rotation_t rotation, int *id, int streamSetId) {
     ATRACE_CALL();
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
@@ -903,6 +998,11 @@
     assert(mStatus != STATUS_ACTIVE);
 
     sp<Camera3OutputStream> newStream;
+    // Overwrite stream set id to invalid for HAL3.2 or lower, as buffer manager does support
+    // such devices.
+    if (mDeviceVersion <= CAMERA_DEVICE_API_VERSION_3_2) {
+        streamSetId = CAMERA3_STREAM_SET_ID_INVALID;
+    }
     if (format == HAL_PIXEL_FORMAT_BLOB) {
         ssize_t blobBufferSize;
         if (dataSpace != HAL_DATASPACE_DEPTH) {
@@ -919,13 +1019,34 @@
             }
         }
         newStream = new Camera3OutputStream(mNextStreamId, consumer,
-                width, height, blobBufferSize, format, dataSpace, rotation);
+                width, height, blobBufferSize, format, dataSpace, rotation,
+                mTimestampOffset, streamSetId);
+    } else if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
+        ssize_t rawOpaqueBufferSize = getRawOpaqueBufferSize(width, height);
+        if (rawOpaqueBufferSize <= 0) {
+            SET_ERR_L("Invalid RAW opaque buffer size %zd", rawOpaqueBufferSize);
+            return BAD_VALUE;
+        }
+        newStream = new Camera3OutputStream(mNextStreamId, consumer,
+                width, height, rawOpaqueBufferSize, format, dataSpace, rotation,
+                mTimestampOffset, streamSetId);
     } else {
         newStream = new Camera3OutputStream(mNextStreamId, consumer,
-                width, height, format, dataSpace, rotation);
+                width, height, format, dataSpace, rotation,
+                mTimestampOffset, streamSetId);
     }
     newStream->setStatusTracker(mStatusTracker);
 
+    /**
+     * Camera3 Buffer manager is only supported by HAL3.3 onwards, as the older HALs ( < HAL3.2)
+     * requires buffers to be statically allocated for internal static buffer registration, while
+     * the buffers provided by buffer manager are really dynamically allocated. For HAL3.2, because
+     * not all HAL implementation supports dynamic buffer registeration, exlude it as well.
+     */
+    if (mDeviceVersion > CAMERA_DEVICE_API_VERSION_3_2) {
+        newStream->setBufferManager(mBufferManager);
+    }
+
     res = mOutputStreams.add(mNextStreamId, newStream);
     if (res < 0) {
         SET_ERR_L("Can't add new stream to set: %s (%d)", strerror(-res), res);
@@ -3266,7 +3387,7 @@
     }
 
     if (mNextRequests.size() < batchSize) {
-        ALOGE("RequestThread: only get %d out of %d requests. Skipping requests.",
+        ALOGE("RequestThread: only get %zu out of %zu requests. Skipping requests.",
                 mNextRequests.size(), batchSize);
         cleanUpFailedRequests(/*sendRequestError*/true);
     }
@@ -3586,7 +3707,7 @@
 
 status_t Camera3Device::RequestThread::addDummyTriggerIds(
         const sp<CaptureRequest> &request) {
-    // Trigger ID 0 has special meaning in the HAL2 spec, so avoid it here
+    // Trigger ID 0 had special meaning in the HAL2 spec, so avoid it here
     static const int32_t dummyTriggerId = 1;
     status_t res;
 
@@ -3680,8 +3801,6 @@
 }
 
 status_t Camera3Device::PreparerThread::clear() {
-    status_t res;
-
     Mutex::Autolock l(mLock);
 
     for (const auto& stream : mPendingStreams) {
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 2cd5af3..3848200 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -23,12 +23,14 @@
 #include <utils/Mutex.h>
 #include <utils/Thread.h>
 #include <utils/KeyedVector.h>
+#include <utils/Timers.h>
 #include <hardware/camera3.h>
 #include <camera/CaptureResult.h>
 #include <camera/camera2/ICameraDeviceUser.h>
 
 #include "common/CameraDeviceBase.h"
 #include "device3/StatusTracker.h"
+#include "device3/Camera3BufferManager.h"
 
 /**
  * Function pointer types with C calling convention to
@@ -97,7 +99,8 @@
     // stream, reconfiguring device, and unpausing.
     virtual status_t createStream(sp<Surface> consumer,
             uint32_t width, uint32_t height, int format,
-            android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id);
+            android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
+            int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID);
     virtual status_t createInputStream(
             uint32_t width, uint32_t height, int format,
             int *id);
@@ -150,6 +153,7 @@
 
     virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
     ssize_t getPointCloudBufferSize() const;
+    ssize_t getRawOpaqueBufferSize(uint32_t width, uint32_t height) const;
 
     // Methods called by subclasses
     void             notifyStatus(bool idle); // updates from StatusTracker
@@ -248,6 +252,12 @@
 
     /**** End scope for mLock ****/
 
+    // The offset converting from clock domain of other subsystem
+    // (video/hardware composer) to that of camera. Assumption is that this
+    // offset won't change during the life cycle of the camera device. In other
+    // words, camera device shouldn't be open during CPU suspend.
+    nsecs_t                    mTimestampOffset;
+
     typedef struct AeTriggerCancelOverride {
         bool applyAeLock;
         uint8_t aeLock;
@@ -389,6 +399,12 @@
      */
     Size getMaxJpegResolution() const;
 
+    /**
+     * Helper function to get the offset between MONOTONIC and BOOTTIME
+     * timestamp.
+     */
+    static nsecs_t getMonoToBoottimeOffset();
+
     struct RequestTrigger {
         // Metadata tag number, e.g. android.control.aePrecaptureTrigger
         uint32_t metadataTag;
@@ -720,6 +736,13 @@
     sp<camera3::StatusTracker> mStatusTracker;
 
     /**
+     * Graphic buffer manager for output streams. Each device has a buffer manager, which is used
+     * by the output streams to get and return buffers if these streams are registered to this
+     * buffer manager.
+     */
+    sp<camera3::Camera3BufferManager> mBufferManager;
+
+    /**
      * Thread for preparing streams
      */
     class PreparerThread : private Thread, public virtual RefBase {
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
index 1d9d04f..fe04eb1 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -38,7 +38,7 @@
 
 status_t Camera3DummyStream::getBufferLocked(camera3_stream_buffer *buffer) {
     ATRACE_CALL();
-    ALOGE("%s: Stream %d: Dummy stream cannot produce buffers!", mId);
+    ALOGE("%s: Stream %d: Dummy stream cannot produce buffers!", __FUNCTION__, mId);
     return INVALID_OPERATION;
 }
 
@@ -46,7 +46,7 @@
         const camera3_stream_buffer &buffer,
         nsecs_t timestamp) {
     ATRACE_CALL();
-    ALOGE("%s: Stream %d: Dummy stream cannot return buffers!", mId);
+    ALOGE("%s: Stream %d: Dummy stream cannot return buffers!", __FUNCTION__, mId);
     return INVALID_OPERATION;
 }
 
@@ -57,7 +57,7 @@
             /*out*/
             sp<Fence> *releaseFenceOut) {
     ATRACE_CALL();
-    ALOGE("%s: Stream %d: Dummy stream cannot return buffers!", mId);
+    ALOGE("%s: Stream %d: Dummy stream cannot return buffers!", __FUNCTION__, mId);
     return INVALID_OPERATION;
 }
 
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index 23b1c45..4824974 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -31,9 +31,9 @@
 
 Camera3IOStreamBase::Camera3IOStreamBase(int id, camera3_stream_type_t type,
         uint32_t width, uint32_t height, size_t maxSize, int format,
-        android_dataspace dataSpace, camera3_stream_rotation_t rotation) :
+        android_dataspace dataSpace, camera3_stream_rotation_t rotation, int setId) :
         Camera3Stream(id, type,
-                width, height, maxSize, format, dataSpace, rotation),
+                width, height, maxSize, format, dataSpace, rotation, setId),
         mTotalBufferCount(0),
         mHandoutTotalBufferCount(0),
         mHandoutOutputBufferCount(0),
@@ -42,7 +42,8 @@
 
     mCombinedFence = new Fence();
 
-    if (maxSize > 0 && format != HAL_PIXEL_FORMAT_BLOB) {
+    if (maxSize > 0 &&
+            (format != HAL_PIXEL_FORMAT_BLOB && format != HAL_PIXEL_FORMAT_RAW_OPAQUE)) {
         ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__,
                 format);
         mState = STATE_ERROR;
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index f5727e8..35dda39 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -34,7 +34,8 @@
   protected:
     Camera3IOStreamBase(int id, camera3_stream_type_t type,
             uint32_t width, uint32_t height, size_t maxSize, int format,
-            android_dataspace dataSpace, camera3_stream_rotation_t rotation);
+            android_dataspace dataSpace, camera3_stream_rotation_t rotation,
+            int setId = CAMERA3_STREAM_SET_ID_INVALID);
 
   public:
 
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index 2504bfd..7dab2e3 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -169,7 +169,7 @@
     if (producer == NULL) {
         return BAD_VALUE;
     } else if (mProducer == NULL) {
-        ALOGE("%s: No input stream is configured");
+        ALOGE("%s: No input stream is configured", __FUNCTION__);
         return INVALID_OPERATION;
     }
 
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 3f0a736..1e6452f 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -34,30 +34,41 @@
 Camera3OutputStream::Camera3OutputStream(int id,
         sp<Surface> consumer,
         uint32_t width, uint32_t height, int format,
-        android_dataspace dataSpace, camera3_stream_rotation_t rotation) :
+        android_dataspace dataSpace, camera3_stream_rotation_t rotation,
+        nsecs_t timestampOffset, int setId) :
         Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height,
-                            /*maxSize*/0, format, dataSpace, rotation),
+                            /*maxSize*/0, format, dataSpace, rotation, setId),
         mConsumer(consumer),
         mTransform(0),
-        mTraceFirstBuffer(true) {
+        mTraceFirstBuffer(true),
+        mUseBufferManager(false),
+        mTimestampOffset(timestampOffset) {
 
     if (mConsumer == NULL) {
         ALOGE("%s: Consumer is NULL!", __FUNCTION__);
         mState = STATE_ERROR;
     }
+
+    if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
+        mBufferReleasedListener = new BufferReleasedListener(this);
+    }
 }
 
 Camera3OutputStream::Camera3OutputStream(int id,
         sp<Surface> consumer,
         uint32_t width, uint32_t height, size_t maxSize, int format,
-        android_dataspace dataSpace, camera3_stream_rotation_t rotation) :
+        android_dataspace dataSpace, camera3_stream_rotation_t rotation,
+        nsecs_t timestampOffset, int setId) :
         Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height, maxSize,
-                            format, dataSpace, rotation),
+                            format, dataSpace, rotation, setId),
         mConsumer(consumer),
         mTransform(0),
-        mTraceFirstBuffer(true) {
+        mTraceFirstBuffer(true),
+        mUseMonoTimestamp(false),
+        mUseBufferManager(false),
+        mTimestampOffset(timestampOffset) {
 
-    if (format != HAL_PIXEL_FORMAT_BLOB) {
+    if (format != HAL_PIXEL_FORMAT_BLOB && format != HAL_PIXEL_FORMAT_RAW_OPAQUE) {
         ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__,
                 format);
         mState = STATE_ERROR;
@@ -67,17 +78,29 @@
         ALOGE("%s: Consumer is NULL!", __FUNCTION__);
         mState = STATE_ERROR;
     }
+
+    if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
+        mBufferReleasedListener = new BufferReleasedListener(this);
+    }
 }
 
 Camera3OutputStream::Camera3OutputStream(int id, camera3_stream_type_t type,
                                          uint32_t width, uint32_t height,
                                          int format,
                                          android_dataspace dataSpace,
-                                         camera3_stream_rotation_t rotation) :
+                                         camera3_stream_rotation_t rotation,
+                                         int setId) :
         Camera3IOStreamBase(id, type, width, height,
                             /*maxSize*/0,
-                            format, dataSpace, rotation),
-        mTransform(0) {
+                            format, dataSpace, rotation, setId),
+        mTransform(0),
+        mTraceFirstBuffer(true),
+        mUseMonoTimestamp(false),
+        mUseBufferManager(false) {
+
+    if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
+        mBufferReleasedListener = new BufferReleasedListener(this);
+    }
 
     // Subclasses expected to initialize mConsumer themselves
 }
@@ -96,28 +119,46 @@
     }
 
     ANativeWindowBuffer* anb;
-    int fenceFd;
+    int fenceFd = -1;
+    if (mUseBufferManager) {
+        sp<GraphicBuffer> gb;
+        res = mBufferManager->getBufferForStream(getId(), getStreamSetId(), &gb, &fenceFd);
+        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;
+        }
+        // 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;
+        }
+    } else {
+        /**
+         * 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();
 
-    /**
-     * 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);
-        return res;
+        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);
+            return res;
+        }
     }
 
     /**
@@ -183,6 +224,11 @@
             ALOGE("%s: Stream %d: Error cancelling buffer to native window:"
                   " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
         }
+
+        if (mUseBufferManager) {
+            // Return this buffer back to buffer manager.
+            mBufferReleasedListener->onBufferReleased();
+        }
     } else {
         if (mTraceFirstBuffer && (stream_type == CAMERA3_STREAM_OUTPUT)) {
             {
@@ -193,7 +239,11 @@
             mTraceFirstBuffer = false;
         }
 
-        res = native_window_set_buffers_timestamp(mConsumer.get(), timestamp);
+        /* Certain consumers (such as AudioSource or HardwareComposer) use
+         * MONOTONIC time, causing time misalignment if camera timestamp is
+         * in BOOTTIME. Do the conversion if necessary. */
+        res = native_window_set_buffers_timestamp(mConsumer.get(),
+                mUseMonoTimestamp ? timestamp - mTimestampOffset : timestamp);
         if (res != OK) {
             ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
                   __FUNCTION__, mId, strerror(-res), res);
@@ -270,9 +320,9 @@
 
     ALOG_ASSERT(mConsumer != 0, "mConsumer should never be NULL");
 
-    // Configure consumer-side ANativeWindow interface
-    res = native_window_api_connect(mConsumer.get(),
-            NATIVE_WINDOW_API_CAMERA);
+    // Configure consumer-side ANativeWindow interface. The listener may be used
+    // to notify buffer manager (if it is used) of the returned buffers.
+    res = mConsumer->connect(NATIVE_WINDOW_API_CAMERA, /*listener*/mBufferReleasedListener);
     if (res != OK) {
         ALOGE("%s: Unable to connect to native window for stream %d",
                 __FUNCTION__, mId);
@@ -350,6 +400,7 @@
     mHandoutTotalBufferCount = 0;
     mFrameCount = 0;
     mLastTimestamp = 0;
+    mUseMonoTimestamp = (isConsumedByHWComposer() | isVideoStream());
 
     res = native_window_set_buffer_count(mConsumer.get(),
             mTotalBufferCount);
@@ -366,6 +417,31 @@
                 __FUNCTION__, mTransform, strerror(-res), res);
     }
 
+    /**
+     * Camera3 Buffer manager is only supported by HAL3.3 onwards, as the older HALs requires
+     * buffers to be statically allocated for internal static buffer registration, while the
+     * buffers provided by buffer manager are really dynamically allocated. Camera3Device only
+     * sets the mBufferManager if device version is > HAL3.2, which guarantees that the buffer
+     * manager setup is skipped in below code. Note that HAL3.2 is also excluded here, as some
+     * HAL3.2 devices may not support the dynamic buffer registeration.
+     */
+    if (mBufferManager != 0 && mSetId > CAMERA3_STREAM_SET_ID_INVALID) {
+        StreamInfo streamInfo(
+                getId(), getStreamSetId(), getWidth(), getHeight(), getFormat(), getDataSpace(),
+                camera3_stream::usage, mTotalBufferCount, /*isConfigured*/true);
+        res = mBufferManager->registerStream(streamInfo);
+        if (res == OK) {
+            // Disable buffer allocation for this BufferQueue, buffer manager will take over
+            // the buffer allocation responsibility.
+            mConsumer->getIGraphicBufferProducer()->allowAllocation(false);
+            mUseBufferManager = true;
+        } else {
+            ALOGE("%s: Unable to register stream %d to camera3 buffer manager, "
+                  "(error %d %s), fall back to BufferQueue for buffer management!",
+                  __FUNCTION__, mId, res, strerror(-res));
+        }
+    }
+
     return OK;
 }
 
@@ -376,6 +452,8 @@
         return res;
     }
 
+    ALOGV("%s: disconnecting stream %d from native window", __FUNCTION__, getId());
+
     res = native_window_api_disconnect(mConsumer.get(),
                                        NATIVE_WINDOW_API_CAMERA);
 
@@ -396,6 +474,21 @@
         return res;
     }
 
+    // Since device is already idle, there is no getBuffer call to buffer manager, unregister the
+    // stream at this point should be safe.
+    if (mUseBufferManager) {
+        res = mBufferManager->unregisterStream(getId(), getStreamSetId());
+        if (res != OK) {
+            ALOGE("%s: Unable to unregister stream %d from buffer manager "
+                    "(error %d %s)", __FUNCTION__, mId, res, strerror(-res));
+            mState = STATE_ERROR;
+            return res;
+        }
+        // Note that, to make prepare/teardown case work, we must not mBufferManager.clear(), as
+        // the stream is still in usable state after this call.
+        mUseBufferManager = false;
+    }
+
     mState = (mState == STATE_IN_RECONFIG) ? STATE_IN_CONFIG
                                            : STATE_CONSTRUCTED;
     return OK;
@@ -437,6 +530,71 @@
     return (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) != 0;
 }
 
+status_t Camera3OutputStream::setBufferManager(sp<Camera3BufferManager> bufferManager) {
+    Mutex::Autolock l(mLock);
+    if (mState != STATE_CONSTRUCTED) {
+        ALOGE("%s: this method can only be called when stream in in CONSTRUCTED state.",
+                __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    mBufferManager = bufferManager;
+
+    return OK;
+}
+
+void Camera3OutputStream::BufferReleasedListener::onBufferReleased() {
+    sp<Camera3OutputStream> stream = mParent.promote();
+    if (stream == nullptr) {
+        ALOGV("%s: Parent camera3 output stream was destroyed", __FUNCTION__);
+        return;
+    }
+
+    Mutex::Autolock l(stream->mLock);
+    if (!(stream->mUseBufferManager)) {
+        return;
+    }
+
+    sp<Fence> fence;
+    sp<GraphicBuffer> buffer;
+    int fenceFd = -1;
+    status_t res = stream->mConsumer->detachNextBuffer(&buffer, &fence);
+    if (res == NO_MEMORY) {
+        // This may rarely happen, which indicates that the released buffer was freed by other
+        // call (e.g., attachBuffer, dequeueBuffer etc.) before reaching here. We should notify the
+        // buffer manager that this buffer has been freed. It's not fatal, but should be avoided,
+        // therefore log a warning.
+        buffer = 0;
+        ALOGW("%s: the released buffer has already been freed by the buffer queue!", __FUNCTION__);
+    } else if (res != OK) {
+        // Other errors are fatal.
+        ALOGE("%s: detach next buffer failed: %s (%d).", __FUNCTION__, strerror(-res), res);
+        stream->mState = STATE_ERROR;
+        return;
+    }
+
+    if (fence!= 0 && fence->isValid()) {
+        fenceFd = fence->dup();
+    }
+    res = stream->mBufferManager->returnBufferForStream(stream->getId(), stream->getStreamSetId(),
+                buffer, fenceFd);
+    if (res != OK) {
+        ALOGE("%s: return buffer to buffer manager failed: %s (%d).", __FUNCTION__,
+                strerror(-res), res);
+       stream->mState = STATE_ERROR;
+    }
+}
+
+bool Camera3OutputStream::isConsumedByHWComposer() const {
+    uint32_t usage = 0;
+    status_t res = getEndpointUsage(&usage);
+    if (res != OK) {
+        ALOGE("%s: getting end point usage failed: %s (%d).", __FUNCTION__, strerror(-res), res);
+        return false;
+    }
+
+    return (usage & GRALLOC_USAGE_HW_COMPOSER) != 0;
+}
+
 }; // namespace camera3
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 3c083ec..a883448 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -18,16 +18,54 @@
 #define ANDROID_SERVERS_CAMERA3_OUTPUT_STREAM_H
 
 #include <utils/RefBase.h>
+#include <gui/IProducerListener.h>
 #include <gui/Surface.h>
 
 #include "Camera3Stream.h"
 #include "Camera3IOStreamBase.h"
 #include "Camera3OutputStreamInterface.h"
+#include "Camera3BufferManager.h"
 
 namespace android {
 
 namespace camera3 {
 
+class Camera3BufferManager;
+
+/**
+ * Stream info structure that holds the necessary stream info for buffer manager to use for
+ * buffer allocation and management.
+ */
+struct StreamInfo {
+    int streamId;
+    int streamSetId;
+    uint32_t width;
+    uint32_t height;
+    uint32_t format;
+    android_dataspace dataSpace;
+    uint32_t combinedUsage;
+    size_t totalBufferCount;
+    bool isConfigured;
+    StreamInfo(int id = CAMERA3_STREAM_ID_INVALID,
+            int setId = CAMERA3_STREAM_SET_ID_INVALID,
+            uint32_t w = 0,
+            uint32_t h = 0,
+            uint32_t fmt = 0,
+            android_dataspace ds = HAL_DATASPACE_UNKNOWN,
+            uint32_t usage = 0,
+            size_t bufferCount = 0,
+            bool configured = false) :
+                streamId(id),
+                streamSetId(setId),
+                width(w),
+                height(h),
+                format(fmt),
+                dataSpace(ds),
+                combinedUsage(usage),
+                totalBufferCount(bufferCount),
+                isConfigured(configured){}
+};
+
 /**
  * A class for managing a single stream of output data from the camera device.
  */
@@ -37,18 +75,24 @@
   public:
     /**
      * Set up a stream for formats that have 2 dimensions, such as RAW and YUV.
+     * A valid stream set id needs to be set to support buffer sharing between multiple
+     * streams.
      */
     Camera3OutputStream(int id, sp<Surface> consumer,
             uint32_t width, uint32_t height, int format,
-            android_dataspace dataSpace, camera3_stream_rotation_t rotation);
+            android_dataspace dataSpace, camera3_stream_rotation_t rotation,
+            nsecs_t timestampOffset, int setId = CAMERA3_STREAM_SET_ID_INVALID);
 
     /**
      * Set up a stream for formats that have a variable buffer size for the same
      * dimensions, such as compressed JPEG.
+     * A valid stream set id needs to be set to support buffer sharing between multiple
+     * streams.
      */
     Camera3OutputStream(int id, sp<Surface> consumer,
             uint32_t width, uint32_t height, size_t maxSize, int format,
-            android_dataspace dataSpace, camera3_stream_rotation_t rotation);
+            android_dataspace dataSpace, camera3_stream_rotation_t rotation,
+            nsecs_t timestampOffset, int setId = CAMERA3_STREAM_SET_ID_INVALID);
 
     virtual ~Camera3OutputStream();
 
@@ -68,11 +112,37 @@
      * Return if this output stream is for video encoding.
      */
     bool isVideoStream() const;
+    /**
+     * Return if this output stream is consumed by hardware composer.
+     */
+    bool isConsumedByHWComposer() const;
+
+    class BufferReleasedListener : public BnProducerListener {
+        public:
+          BufferReleasedListener(wp<Camera3OutputStream> parent) : mParent(parent) {}
+
+          /**
+          * Implementation of IProducerListener, used to notify this stream that the consumer
+          * has returned a buffer and it is ready to return to Camera3BufferManager for reuse.
+          */
+          virtual void onBufferReleased();
+
+        private:
+          wp<Camera3OutputStream> mParent;
+    };
+
+    /**
+     * Set the graphic buffer manager to get/return the stream buffers.
+     *
+     * It is only legal to call this method when stream is in STATE_CONSTRUCTED state.
+     */
+    status_t setBufferManager(sp<Camera3BufferManager> bufferManager);
 
   protected:
     Camera3OutputStream(int id, camera3_stream_type_t type,
             uint32_t width, uint32_t height, int format,
-            android_dataspace dataSpace, camera3_stream_rotation_t rotation);
+            android_dataspace dataSpace, camera3_stream_rotation_t rotation,
+            int setId = CAMERA3_STREAM_SET_ID_INVALID);
 
     /**
      * Note that we release the lock briefly in this function
@@ -97,6 +167,31 @@
     // Name of Surface consumer
     String8           mConsumerName;
 
+    // Whether consumer assumes MONOTONIC timestamp
+    bool mUseMonoTimestamp;
+
+    /**
+     * GraphicBuffer manager this stream is registered to. Used to replace the buffer
+     * allocation/deallocation role of BufferQueue.
+     */
+    sp<Camera3BufferManager> mBufferManager;
+
+    /**
+     * Buffer released listener, used to notify the buffer manager that a buffer is released
+     * from consumer side.
+     */
+    sp<BufferReleasedListener> mBufferReleasedListener;
+
+    /**
+     * Flag indicating if the buffer manager is used to allocate the stream buffers
+     */
+    bool mUseBufferManager;
+
+    /**
+     * Timestamp offset for video and hardware composer consumed streams
+     */
+    nsecs_t mTimestampOffset;
+
     /**
      * Internal Camera3Stream interface
      */
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 96299b3..ed3ab97 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -47,13 +47,19 @@
 Camera3Stream::Camera3Stream(int id,
         camera3_stream_type type,
         uint32_t width, uint32_t height, size_t maxSize, int format,
-        android_dataspace dataSpace, camera3_stream_rotation_t rotation) :
+        android_dataspace dataSpace, camera3_stream_rotation_t rotation, int setId) :
     camera3_stream(),
     mId(id),
+    mSetId(setId),
     mName(String8::format("Camera3Stream[%d]", id)),
     mMaxSize(maxSize),
     mState(STATE_CONSTRUCTED),
     mStatusId(StatusTracker::NO_STATUS_ID),
+    oldUsage(0),
+    oldMaxBuffers(0),
+    mStreamUnpreparable(false),
+    mPrepared(false),
+    mPreparedBufferIdx(0),
     mLastMaxCount(Camera3StreamInterface::ALLOCATE_PIPELINE_MAX) {
 
     camera3_stream::stream_type = type;
@@ -66,8 +72,9 @@
     camera3_stream::max_buffers = 0;
     camera3_stream::priv = NULL;
 
-    if (format == HAL_PIXEL_FORMAT_BLOB && maxSize == 0) {
-        ALOGE("%s: BLOB format with size == 0", __FUNCTION__);
+    if ((format == HAL_PIXEL_FORMAT_BLOB || format == HAL_PIXEL_FORMAT_RAW_OPAQUE) &&
+            maxSize == 0) {
+        ALOGE("%s: BLOB or RAW_OPAQUE format with size == 0", __FUNCTION__);
         mState = STATE_ERROR;
     }
 }
@@ -76,6 +83,10 @@
     return mId;
 }
 
+int Camera3Stream::getStreamSetId() const {
+    return mSetId;
+}
+
 uint32_t Camera3Stream::getWidth() const {
     return camera3_stream::width;
 }
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 753280b..fe51ab5 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -130,6 +130,11 @@
     int              getId() const;
 
     /**
+     * Get the output stream set id.
+     */
+    int              getStreamSetId() const;
+
+    /**
      * Get the stream's dimensions and format
      */
     uint32_t          getWidth() const;
@@ -350,6 +355,21 @@
 
   protected:
     const int mId;
+    /**
+     * Stream set id, used to indicate which group of this stream belongs to for buffer sharing
+     * across multiple streams.
+     *
+     * The default value is set to CAMERA3_STREAM_SET_ID_INVALID, which indicates that this stream
+     * doesn't intend to share buffers with any other streams, and this stream will fall back to
+     * the existing BufferQueue mechanism to manage the buffer allocations and buffer circulation.
+     * When a valid stream set id is set, this stream intends to use the Camera3BufferManager to
+     * manage the buffer allocations; the BufferQueue will only handle the buffer transaction
+     * between the producer and consumer. For this case, upon successfully registration, the streams
+     * with the same stream set id will potentially share the buffers allocated by
+     * Camera3BufferManager.
+     */
+    const int mSetId;
+
     const String8 mName;
     // Zero for formats with fixed buffer size for given dimensions.
     const size_t mMaxSize;
@@ -367,7 +387,8 @@
 
     Camera3Stream(int id, camera3_stream_type type,
             uint32_t width, uint32_t height, size_t maxSize, int format,
-            android_dataspace dataSpace, camera3_stream_rotation_t rotation);
+            android_dataspace dataSpace, camera3_stream_rotation_t rotation,
+            int setId);
 
     /**
      * Interface to be implemented by derived classes
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 54009ae..3f7e7a7 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -26,6 +26,20 @@
 
 namespace camera3 {
 
+enum {
+    /**
+     * This stream set ID indicates that the set ID is invalid, and this stream doesn't intend to
+     * share buffers with any other stream. It is illegal to register this kind of stream to
+     * Camera3BufferManager.
+     */
+    CAMERA3_STREAM_SET_ID_INVALID = -1,
+
+    /**
+     * Invalid output stream ID.
+     */
+    CAMERA3_STREAM_ID_INVALID = -1,
+};
+
 class StatusTracker;
 
 /**
@@ -45,6 +59,11 @@
     virtual int      getId() const = 0;
 
     /**
+     * Get the output stream set id.
+     */
+    virtual int      getStreamSetId() const = 0;
+
+    /**
      * Get the stream's dimensions and format
      */
     virtual uint32_t getWidth() const = 0;
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
index 8cd6800..65816e0 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
@@ -229,7 +229,7 @@
 
         // item.mGraphicBuffer was populated with the proper graphic-buffer
         // at acquire even if it was previously acquired
-        err = addReleaseFenceLocked(item.mBuf,
+        err = addReleaseFenceLocked(item.mSlot,
                 item.mGraphicBuffer, item.mFence);
 
         if (err != OK) {
@@ -244,7 +244,7 @@
 
         // item.mGraphicBuffer was populated with the proper graphic-buffer
         // at acquire even if it was previously acquired
-        err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer,
+        err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer,
                                   EGL_NO_DISPLAY,
                                   EGL_NO_SYNC_KHR);
         if (err != OK) {
@@ -318,7 +318,7 @@
 
         mLatestTimestamp = item.mTimestamp;
 
-        item.mGraphicBuffer = mSlots[item.mBuf].mGraphicBuffer;
+        item.mGraphicBuffer = mSlots[item.mSlot].mGraphicBuffer;
     } // end of mMutex lock
 
     ConsumerBase::onFrameAvailable(item);
@@ -335,7 +335,7 @@
 
         RingBufferItem& find = *it;
         if (item.mGraphicBuffer == find.mGraphicBuffer) {
-            status_t res = addReleaseFenceLocked(item.mBuf,
+            status_t res = addReleaseFenceLocked(item.mSlot,
                     item.mGraphicBuffer, item.mFence);
 
             if (res != OK) {
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.h b/services/camera/libcameraservice/gui/RingBufferConsumer.h
index 83e7298..28dc5d5 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.h
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.h
@@ -133,7 +133,7 @@
         }
 
         bool isEmpty() {
-            return mBufferItem.mBuf == BufferQueue::INVALID_BUFFER_SLOT;
+            return mBufferItem.mSlot == BufferQueue::INVALID_BUFFER_SLOT;
         }
 
         BufferItem& getBufferItem() { return mBufferItem; }
@@ -189,4 +189,4 @@
 
 } // namespace android
 
-#endif // ANDROID_GUI_CPUCONSUMER_H
+#endif // ANDROID_GUI_RINGBUFFERCONSUMER_H
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
new file mode 100644
index 0000000..239b4e1
--- /dev/null
+++ b/services/mediacodec/Android.mk
@@ -0,0 +1,27 @@
+LOCAL_PATH := $(call my-dir)
+
+# service library
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := MediaCodecService.cpp
+LOCAL_SHARED_LIBRARIES := libmedia libbinder libutils liblog libstagefright_omx
+LOCAL_C_INCLUDES := \
+    $(TOP)/frameworks/av/media/libstagefright \
+    $(TOP)/frameworks/native/include/media/openmax
+LOCAL_MODULE:= libmediacodecservice
+LOCAL_32_BIT_ONLY := true
+include $(BUILD_SHARED_LIBRARY)
+
+
+# service executable
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := main_codecservice.cpp
+LOCAL_SHARED_LIBRARIES := libmedia libmediacodecservice libbinder libutils liblog
+LOCAL_C_INCLUDES := \
+    $(TOP)/frameworks/av/media/libstagefright \
+    $(TOP)/frameworks/native/include/media/openmax
+LOCAL_MODULE:= mediacodec
+LOCAL_32_BIT_ONLY := true
+LOCAL_INIT_RC := mediacodec.rc
+include $(BUILD_EXECUTABLE)
+
+
diff --git a/services/mediacodec/MODULE_LICENSE_APACHE2 b/services/mediacodec/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/mediacodec/MODULE_LICENSE_APACHE2
diff --git a/services/mediacodec/MediaCodecService.cpp b/services/mediacodec/MediaCodecService.cpp
new file mode 100644
index 0000000..fc1e5d9
--- /dev/null
+++ b/services/mediacodec/MediaCodecService.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 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 "MediaCodecService"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "MediaCodecService.h"
+
+namespace android {
+
+sp<IOMX> MediaCodecService::getOMX() {
+
+    Mutex::Autolock autoLock(mLock);
+
+    if (mOMX.get() == NULL) {
+        mOMX = new OMX;
+    }
+
+    return mOMX;
+}
+
+
+status_t MediaCodecService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+        uint32_t flags)
+{
+    return BnMediaCodecService::onTransact(code, data, reply, flags);
+}
+
+}   // namespace android
diff --git a/services/mediacodec/MediaCodecService.h b/services/mediacodec/MediaCodecService.h
new file mode 100644
index 0000000..d64debb
--- /dev/null
+++ b/services/mediacodec/MediaCodecService.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 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 ANDROID_MEDIA_CODEC_SERVICE_H
+#define ANDROID_MEDIA_CODEC_SERVICE_H
+
+#include <binder/BinderService.h>
+#include <media/IMediaCodecService.h>
+#include <include/OMX.h>
+
+namespace android {
+
+class MediaCodecService : public BinderService<MediaCodecService>, public BnMediaCodecService
+{
+    friend class BinderService<MediaCodecService>;    // for MediaCodecService()
+public:
+    MediaCodecService() : BnMediaCodecService() { }
+    virtual ~MediaCodecService() { }
+    virtual void onFirstRef() { }
+
+    static const char*  getServiceName() { return "media.codec"; }
+
+    virtual sp<IOMX>    getOMX();
+
+    virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                uint32_t flags);
+
+private:
+    Mutex               mLock;
+    sp<IOMX>            mOMX;
+};
+
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_CODEC_SERVICE_H
diff --git a/services/mediacodec/NOTICE b/services/mediacodec/NOTICE
new file mode 100644
index 0000000..34bdaf1
--- /dev/null
+++ b/services/mediacodec/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
new file mode 100644
index 0000000..aedf0c3
--- /dev/null
+++ b/services/mediacodec/main_codecservice.cpp
@@ -0,0 +1,45 @@
+/*
+**
+** 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 "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>
+
+// from LOCAL_C_INCLUDES
+#include "MediaCodecService.h"
+
+using namespace android;
+
+int main(int argc __unused, char** argv)
+{
+    ALOGI("@@@ mediacodecservice starting");
+    signal(SIGPIPE, SIG_IGN);
+
+    strcpy(argv[0], "media.codec");
+    sp<ProcessState> proc(ProcessState::self());
+    sp<IServiceManager> sm = defaultServiceManager();
+    MediaCodecService::instantiate();
+    ProcessState::self()->startThreadPool();
+    IPCThreadState::self()->joinThreadPool();
+}
diff --git a/services/mediacodec/mediacodec.rc b/services/mediacodec/mediacodec.rc
new file mode 100644
index 0000000..e8df7be
--- /dev/null
+++ b/services/mediacodec/mediacodec.rc
@@ -0,0 +1,5 @@
+service mediacodec /system/bin/mediacodec
+    class main
+    user mediacodec
+    group camera drmrpc mediadrm
+    ioprio rt 4
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
new file mode 100644
index 0000000..cc78361
--- /dev/null
+++ b/services/mediadrm/Android.mk
@@ -0,0 +1,42 @@
+# Copyright 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+
+LOCAL_SRC_FILES:= \
+    MediaDrmService.cpp \
+    main_mediadrmserver.cpp
+
+LOCAL_SHARED_LIBRARIES:= \
+    libui \
+    liblog \
+    libutils \
+    libbinder \
+    libcutils \
+    libstagefright \
+    libmediaplayerservice \
+    libmedia \
+
+LOCAL_C_INCLUDES := \
+    frameworks/av/media/libmediaplayerservice \
+
+LOCAL_MODULE:= mediadrmserver
+LOCAL_32_BIT_ONLY := true
+
+LOCAL_INIT_RC := mediadrmserver.rc
+
+include $(BUILD_EXECUTABLE)
diff --git a/services/mediadrm/DrmSessionClientInterface.h b/services/mediadrm/DrmSessionClientInterface.h
new file mode 100644
index 0000000..17faf08
--- /dev/null
+++ b/services/mediadrm/DrmSessionClientInterface.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 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 DRM_PROXY_INTERFACE_H_
+#define DRM_PROXY_INTERFACE_H_
+
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+struct DrmSessionClientInterface : public RefBase {
+    virtual bool reclaimSession(const Vector<uint8_t>& sessionId) = 0;
+
+protected:
+    virtual ~DrmSessionClientInterface() {}
+};
+
+}  // namespace android
+
+#endif  // DRM_PROXY_INTERFACE_H_
diff --git a/services/mediadrm/MediaDrmService.cpp b/services/mediadrm/MediaDrmService.cpp
new file mode 100644
index 0000000..36ab8fe
--- /dev/null
+++ b/services/mediadrm/MediaDrmService.cpp
@@ -0,0 +1,45 @@
+/*
+**
+** Copyright 2008, 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.
+*/
+
+// Proxy for media player implementations
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaDrmService"
+#include <utils/Log.h>
+
+#include <binder/IServiceManager.h>
+#include "MediaDrmService.h"
+
+#include "Crypto.h"
+#include "Drm.h"
+
+namespace android {
+
+void MediaDrmService::instantiate() {
+    defaultServiceManager()->addService(
+            String16("media.drm"), new MediaDrmService());
+}
+
+sp<ICrypto> MediaDrmService::makeCrypto() {
+    return new Crypto;
+}
+
+sp<IDrm> MediaDrmService::makeDrm() {
+    return new Drm;
+}
+
+} // namespace android
diff --git a/services/mediadrm/MediaDrmService.h b/services/mediadrm/MediaDrmService.h
new file mode 100644
index 0000000..ecc2da7
--- /dev/null
+++ b/services/mediadrm/MediaDrmService.h
@@ -0,0 +1,48 @@
+/*
+**
+** Copyright 2008, 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_MEDIADRMSERVICE_H
+#define ANDROID_MEDIADRMSERVICE_H
+
+#include <arpa/inet.h>
+
+#include <utils/threads.h>
+
+#include <media/Metadata.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <media/IMediaDrmService.h>
+
+namespace android {
+
+class MediaDrmService : public BnMediaDrmService
+{
+public:
+    static void instantiate();
+
+    // IMediaDrmService interface
+    virtual sp<ICrypto> makeCrypto();
+    virtual sp<IDrm> makeDrm();
+private:
+    MediaDrmService() {}
+    virtual ~MediaDrmService() {}
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_MEDIADRMSERVICE_H
diff --git a/services/mediadrm/main_mediadrmserver.cpp b/services/mediadrm/main_mediadrmserver.cpp
new file mode 100644
index 0000000..4d0b644
--- /dev/null
+++ b/services/mediadrm/main_mediadrmserver.cpp
@@ -0,0 +1,43 @@
+/*
+**
+** Copyright 2008, 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 "mediaserver"
+//#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 <cutils/properties.h>
+#include <utils/Log.h>
+#include "MediaDrmService.h"
+
+using namespace android;
+
+int main(int argc __unused, char** argv)
+{
+    signal(SIGPIPE, SIG_IGN);
+
+    sp<ProcessState> proc(ProcessState::self());
+    sp<IServiceManager> sm = defaultServiceManager();
+    ALOGI("ServiceManager: %p", sm.get());
+    MediaDrmService::instantiate();
+    ProcessState::self()->startThreadPool();
+    IPCThreadState::self()->joinThreadPool();
+}
diff --git a/services/mediadrm/mediadrmserver.rc b/services/mediadrm/mediadrmserver.rc
new file mode 100644
index 0000000..c22ec7c
--- /dev/null
+++ b/services/mediadrm/mediadrmserver.rc
@@ -0,0 +1,5 @@
+service mediadrm /system/bin/mediadrmserver
+    class main
+    user mediadrm
+    group drmrpc
+    ioprio rt 4
diff --git a/services/mediadrm/tests/Android.mk b/services/mediadrm/tests/Android.mk
new file mode 100644
index 0000000..8cbf782
--- /dev/null
+++ b/services/mediadrm/tests/Android.mk
@@ -0,0 +1,27 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := DrmSessionManager_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+	DrmSessionManager_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+	liblog \
+	libmediaplayerservice \
+	libutils \
+
+LOCAL_C_INCLUDES := \
+	frameworks/av/include \
+	frameworks/av/media/libmediaplayerservice \
+
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CLANG := true
+
+LOCAL_32_BIT_ONLY := true
+
+include $(BUILD_NATIVE_TEST)
+
diff --git a/services/mediadrm/tests/DrmSessionManager_test.cpp b/services/mediadrm/tests/DrmSessionManager_test.cpp
new file mode 100644
index 0000000..de350a1
--- /dev/null
+++ b/services/mediadrm/tests/DrmSessionManager_test.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 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_NDEBUG 0
+#define LOG_TAG "DrmSessionManager_test"
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+
+#include "Drm.h"
+#include "DrmSessionClientInterface.h"
+#include "DrmSessionManager.h"
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/ProcessInfoInterface.h>
+
+namespace android {
+
+struct FakeProcessInfo : public ProcessInfoInterface {
+    FakeProcessInfo() {}
+    virtual ~FakeProcessInfo() {}
+
+    virtual bool getPriority(int pid, int* priority) {
+        // For testing, use pid as priority.
+        // Lower the value higher the priority.
+        *priority = pid;
+        return true;
+    }
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(FakeProcessInfo);
+};
+
+struct FakeDrm : public DrmSessionClientInterface {
+    FakeDrm() {}
+    virtual ~FakeDrm() {}
+
+    virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
+        mReclaimedSessions.push_back(sessionId);
+        return true;
+    }
+
+    const Vector<Vector<uint8_t> >& reclaimedSessions() const {
+        return mReclaimedSessions;
+    }
+
+private:
+    Vector<Vector<uint8_t> > mReclaimedSessions;
+
+    DISALLOW_EVIL_CONSTRUCTORS(FakeDrm);
+};
+
+static const int kTestPid1 = 30;
+static const int kTestPid2 = 20;
+static const uint8_t kTestSessionId1[] = {1, 2, 3};
+static const uint8_t kTestSessionId2[] = {4, 5, 6, 7, 8};
+static const uint8_t kTestSessionId3[] = {9, 0};
+
+class DrmSessionManagerTest : public ::testing::Test {
+public:
+    DrmSessionManagerTest()
+        : mDrmSessionManager(new DrmSessionManager(new FakeProcessInfo())),
+          mTestDrm1(new FakeDrm()),
+          mTestDrm2(new FakeDrm()) {
+        GetSessionId(kTestSessionId1, ARRAY_SIZE(kTestSessionId1), &mSessionId1);
+        GetSessionId(kTestSessionId2, ARRAY_SIZE(kTestSessionId2), &mSessionId2);
+        GetSessionId(kTestSessionId3, ARRAY_SIZE(kTestSessionId3), &mSessionId3);
+    }
+
+protected:
+    static void GetSessionId(const uint8_t* ids, size_t num, Vector<uint8_t>* sessionId) {
+        for (size_t i = 0; i < num; ++i) {
+            sessionId->push_back(ids[i]);
+        }
+    }
+
+    static void ExpectEqSessionInfo(const SessionInfo& info, sp<DrmSessionClientInterface> drm,
+            const Vector<uint8_t>& sessionId, int64_t timeStamp) {
+        EXPECT_EQ(drm, info.drm);
+        EXPECT_TRUE(isEqualSessionId(sessionId, info.sessionId));
+        EXPECT_EQ(timeStamp, info.timeStamp);
+    }
+
+    void addSession() {
+        mDrmSessionManager->addSession(kTestPid1, mTestDrm1, mSessionId1);
+        mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mSessionId2);
+        mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mSessionId3);
+        const PidSessionInfosMap& map = sessionMap();
+        EXPECT_EQ(2u, map.size());
+        ssize_t index1 = map.indexOfKey(kTestPid1);
+        ASSERT_GE(index1, 0);
+        const SessionInfos& infos1 = map[index1];
+        EXPECT_EQ(1u, infos1.size());
+        ExpectEqSessionInfo(infos1[0], mTestDrm1, mSessionId1, 0);
+
+        ssize_t index2 = map.indexOfKey(kTestPid2);
+        ASSERT_GE(index2, 0);
+        const SessionInfos& infos2 = map[index2];
+        EXPECT_EQ(2u, infos2.size());
+        ExpectEqSessionInfo(infos2[0], mTestDrm2, mSessionId2, 1);
+        ExpectEqSessionInfo(infos2[1], mTestDrm2, mSessionId3, 2);
+    }
+
+    const PidSessionInfosMap& sessionMap() {
+        return mDrmSessionManager->mSessionMap;
+    }
+
+    void testGetLowestPriority() {
+        int pid;
+        int priority;
+        EXPECT_FALSE(mDrmSessionManager->getLowestPriority_l(&pid, &priority));
+
+        addSession();
+        EXPECT_TRUE(mDrmSessionManager->getLowestPriority_l(&pid, &priority));
+
+        EXPECT_EQ(kTestPid1, pid);
+        FakeProcessInfo processInfo;
+        int priority1;
+        processInfo.getPriority(kTestPid1, &priority1);
+        EXPECT_EQ(priority1, priority);
+    }
+
+    void testGetLeastUsedSession() {
+        sp<DrmSessionClientInterface> drm;
+        Vector<uint8_t> sessionId;
+        EXPECT_FALSE(mDrmSessionManager->getLeastUsedSession_l(kTestPid1, &drm, &sessionId));
+
+        addSession();
+
+        EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid1, &drm, &sessionId));
+        EXPECT_EQ(mTestDrm1, drm);
+        EXPECT_TRUE(isEqualSessionId(mSessionId1, sessionId));
+
+        EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid2, &drm, &sessionId));
+        EXPECT_EQ(mTestDrm2, drm);
+        EXPECT_TRUE(isEqualSessionId(mSessionId2, sessionId));
+
+        // mSessionId2 is no longer the least used session.
+        mDrmSessionManager->useSession(mSessionId2);
+        EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid2, &drm, &sessionId));
+        EXPECT_EQ(mTestDrm2, drm);
+        EXPECT_TRUE(isEqualSessionId(mSessionId3, sessionId));
+    }
+
+    sp<DrmSessionManager> mDrmSessionManager;
+    sp<FakeDrm> mTestDrm1;
+    sp<FakeDrm> mTestDrm2;
+    Vector<uint8_t> mSessionId1;
+    Vector<uint8_t> mSessionId2;
+    Vector<uint8_t> mSessionId3;
+};
+
+TEST_F(DrmSessionManagerTest, addSession) {
+    addSession();
+}
+
+TEST_F(DrmSessionManagerTest, useSession) {
+    addSession();
+
+    mDrmSessionManager->useSession(mSessionId1);
+    mDrmSessionManager->useSession(mSessionId3);
+
+    const PidSessionInfosMap& map = sessionMap();
+    const SessionInfos& infos1 = map.valueFor(kTestPid1);
+    const SessionInfos& infos2 = map.valueFor(kTestPid2);
+    ExpectEqSessionInfo(infos1[0], mTestDrm1, mSessionId1, 3);
+    ExpectEqSessionInfo(infos2[1], mTestDrm2, mSessionId3, 4);
+}
+
+TEST_F(DrmSessionManagerTest, removeSession) {
+    addSession();
+
+    mDrmSessionManager->removeSession(mSessionId2);
+
+    const PidSessionInfosMap& map = sessionMap();
+    EXPECT_EQ(2u, map.size());
+    const SessionInfos& infos1 = map.valueFor(kTestPid1);
+    const SessionInfos& infos2 = map.valueFor(kTestPid2);
+    EXPECT_EQ(1u, infos1.size());
+    EXPECT_EQ(1u, infos2.size());
+    // mSessionId2 has been removed.
+    ExpectEqSessionInfo(infos2[0], mTestDrm2, mSessionId3, 2);
+}
+
+TEST_F(DrmSessionManagerTest, removeDrm) {
+    addSession();
+
+    sp<FakeDrm> drm = new FakeDrm;
+    const uint8_t ids[] = {123};
+    Vector<uint8_t> sessionId;
+    GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
+    mDrmSessionManager->addSession(kTestPid2, drm, sessionId);
+
+    mDrmSessionManager->removeDrm(mTestDrm2);
+
+    const PidSessionInfosMap& map = sessionMap();
+    const SessionInfos& infos2 = map.valueFor(kTestPid2);
+    EXPECT_EQ(1u, infos2.size());
+    // mTestDrm2 has been removed.
+    ExpectEqSessionInfo(infos2[0], drm, sessionId, 3);
+}
+
+TEST_F(DrmSessionManagerTest, reclaimSession) {
+    EXPECT_FALSE(mDrmSessionManager->reclaimSession(kTestPid1));
+    addSession();
+
+    // calling pid priority is too low
+    EXPECT_FALSE(mDrmSessionManager->reclaimSession(50));
+
+    EXPECT_TRUE(mDrmSessionManager->reclaimSession(10));
+    EXPECT_EQ(1u, mTestDrm1->reclaimedSessions().size());
+    EXPECT_TRUE(isEqualSessionId(mSessionId1, mTestDrm1->reclaimedSessions()[0]));
+
+    mDrmSessionManager->removeSession(mSessionId1);
+
+    // add a session from a higher priority process.
+    sp<FakeDrm> drm = new FakeDrm;
+    const uint8_t ids[] = {1, 3, 5};
+    Vector<uint8_t> sessionId;
+    GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
+    mDrmSessionManager->addSession(15, drm, sessionId);
+
+    EXPECT_TRUE(mDrmSessionManager->reclaimSession(18));
+    EXPECT_EQ(1u, mTestDrm2->reclaimedSessions().size());
+    // mSessionId2 is reclaimed.
+    EXPECT_TRUE(isEqualSessionId(mSessionId2, mTestDrm2->reclaimedSessions()[0]));
+}
+
+TEST_F(DrmSessionManagerTest, getLowestPriority) {
+    testGetLowestPriority();
+}
+
+TEST_F(DrmSessionManagerTest, getLeastUsedSession_l) {
+    testGetLeastUsedSession();
+}
+
+} // namespace android
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
new file mode 100644
index 0000000..bc2b641
--- /dev/null
+++ b/services/mediaextractor/Android.mk
@@ -0,0 +1,24 @@
+LOCAL_PATH := $(call my-dir)
+
+# service library
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := MediaExtractorService.cpp
+LOCAL_SHARED_LIBRARIES := libmedia libstagefright libbinder libutils liblog
+LOCAL_MODULE:= libmediaextractorservice
+LOCAL_32_BIT_ONLY := true
+include $(BUILD_SHARED_LIBRARY)
+
+
+# service executable
+include $(CLEAR_VARS)
+LOCAL_REQUIRED_MODULES_arm := mediaextractor-seccomp.policy
+LOCAL_REQUIRED_MODULES_x86 := mediaextractor-seccomp.policy
+LOCAL_SRC_FILES := main_extractorservice.cpp minijail/minijail.cpp
+LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libbinder libutils liblog libicuuc libminijail
+LOCAL_STATIC_LIBRARIES := libicuandroid_utils
+LOCAL_MODULE:= mediaextractor
+LOCAL_32_BIT_ONLY := true
+LOCAL_INIT_RC := mediaextractor.rc
+include $(BUILD_EXECUTABLE)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/mediaextractor/MODULE_LICENSE_APACHE2 b/services/mediaextractor/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/mediaextractor/MODULE_LICENSE_APACHE2
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
new file mode 100644
index 0000000..cd20635
--- /dev/null
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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 "MediaExtractorService"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaExtractor.h>
+#include "MediaExtractorService.h"
+
+namespace android {
+
+sp<IMediaExtractor> MediaExtractorService::makeExtractor(
+        const sp<IDataSource> &remoteSource, const char *mime) {
+    ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime);
+
+    sp<DataSource> localSource = DataSource::CreateFromIDataSource(remoteSource);
+
+    sp<MediaExtractor> ret = MediaExtractor::CreateFromService(localSource, mime);
+
+    ALOGV("extractor service created %p (%s)",
+            ret.get(),
+            ret == NULL ? "" : ret->name());
+
+    return ret;
+}
+
+
+status_t MediaExtractorService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+        uint32_t flags)
+{
+    return BnMediaExtractorService::onTransact(code, data, reply, flags);
+}
+
+}   // namespace android
diff --git a/services/mediaextractor/MediaExtractorService.h b/services/mediaextractor/MediaExtractorService.h
new file mode 100644
index 0000000..9c75042
--- /dev/null
+++ b/services/mediaextractor/MediaExtractorService.h
@@ -0,0 +1,47 @@
+/*
+ * 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_MEDIA_EXTRACTOR_SERVICE_H
+#define ANDROID_MEDIA_EXTRACTOR_SERVICE_H
+
+#include <binder/BinderService.h>
+#include <media/IMediaExtractorService.h>
+#include <media/IMediaExtractor.h>
+
+namespace android {
+
+class MediaExtractorService : public BinderService<MediaExtractorService>, public BnMediaExtractorService
+{
+    friend class BinderService<MediaExtractorService>;    // for MediaExtractorService()
+public:
+    MediaExtractorService() : BnMediaExtractorService() { }
+    virtual ~MediaExtractorService() { }
+    virtual void onFirstRef() { }
+
+    static const char*  getServiceName() { return "media.extractor"; }
+
+    virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime);
+
+    virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                uint32_t flags);
+
+private:
+    Mutex               mLock;
+};
+
+}   // namespace android
+
+#endif  // ANDROID_MEDIA_EXTRACTOR_SERVICE_H
diff --git a/services/mediaextractor/NOTICE b/services/mediaextractor/NOTICE
new file mode 100644
index 0000000..34bdaf1
--- /dev/null
+++ b/services/mediaextractor/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/services/mediaextractor/main_extractorservice.cpp b/services/mediaextractor/main_extractorservice.cpp
new file mode 100644
index 0000000..a7f3fbe
--- /dev/null
+++ b/services/mediaextractor/main_extractorservice.cpp
@@ -0,0 +1,49 @@
+/*
+**
+** Copyright 2008, 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 "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>
+
+// from LOCAL_C_INCLUDES
+#include "IcuUtils.h"
+#include "MediaExtractorService.h"
+#include "minijail/minijail.h"
+
+using namespace android;
+
+int main(int argc __unused, char** argv)
+{
+    signal(SIGPIPE, SIG_IGN);
+    MiniJail();
+
+    InitializeIcuOrDie();
+
+    strcpy(argv[0], "media.extractor");
+    sp<ProcessState> proc(ProcessState::self());
+    sp<IServiceManager> sm = defaultServiceManager();
+    MediaExtractorService::instantiate();
+    ProcessState::self()->startThreadPool();
+    IPCThreadState::self()->joinThreadPool();
+}
diff --git a/services/mediaextractor/mediaextractor.rc b/services/mediaextractor/mediaextractor.rc
new file mode 100644
index 0000000..f733a2b
--- /dev/null
+++ b/services/mediaextractor/mediaextractor.rc
@@ -0,0 +1,5 @@
+service mediaextractor /system/bin/mediaextractor
+    class main
+    user mediaex
+    group drmrpc mediadrm
+    ioprio rt 4
diff --git a/services/mediaextractor/minijail/Android.mk b/services/mediaextractor/minijail/Android.mk
new file mode 100644
index 0000000..79c5505
--- /dev/null
+++ b/services/mediaextractor/minijail/Android.mk
@@ -0,0 +1,28 @@
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64 x86 x86_64))
+include $(CLEAR_VARS)
+LOCAL_MODULE := mediaextractor-seccomp.policy
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
+
+# mediaextractor 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/mediaextractor-seccomp-$(TARGET_2ND_ARCH).policy
+else
+    LOCAL_SRC_FILES := $(LOCAL_PATH)/seccomp_policy/mediaextractor-seccomp-$(TARGET_ARCH).policy
+endif
+
+# allow device specific additions to the syscall whitelist
+ifneq (,$(wildcard $(BOARD_SECCOMP_POLICY)/mediaextractor-seccomp.policy))
+    LOCAL_SRC_FILES += $(BOARD_SECCOMP_POLICY)/mediaextractor-seccomp.policy
+endif
+
+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
new file mode 100644
index 0000000..421a1e0
--- /dev/null
+++ b/services/mediaextractor/minijail/minijail.cpp
@@ -0,0 +1,50 @@
+/*
+**
+** 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 <cutils/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
new file mode 100644
index 0000000..6ea4487
--- /dev/null
+++ b/services/mediaextractor/minijail/minijail.h
@@ -0,0 +1,20 @@
+/*
+**
+** 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/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy
new file mode 100644
index 0000000..66522cc
--- /dev/null
+++ b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy
@@ -0,0 +1,40 @@
+# Organized by frequency of systemcall - in descending order for
+# best performance.
+ioctl: 1
+futex: 1
+prctl: 1
+write: 1
+getpriority: 1
+mmap2: 1
+close: 1
+munmap: 1
+dup: 1
+mprotect: 1
+getuid32: 1
+setpriority: 1
+sigaltstack: 1
+openat: 1
+clone: 1
+read: 1
+clock_gettime: 1
+lseek: 1
+writev: 1
+fstatat64: 1
+fstat64: 1
+restart_syscall: 1
+exit: 1
+exit_group: 1
+rt_sigreturn: 1
+faccessat: 1
+madvise: 1
+brk: 1
+sched_setscheduler: 1
+gettid: 1
+rt_sigprocmask: 1
+
+# for attaching to debuggerd on process crash
+sigaction: 1
+tgkill: 1
+socket: 1
+connect: 1
+fcntl64: 1
diff --git a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy
new file mode 100644
index 0000000..f321366
--- /dev/null
+++ b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy
@@ -0,0 +1,30 @@
+# Organized by frequency of systemcall - in descending order for
+# best performance.
+ioctl: 1
+futex: 1
+prctl: 1
+write: 1
+getpriority: 1
+close: 1
+dup: 1
+munmap: 1
+mmap2: 1
+madvise: 1
+openat: 1
+clock_gettime: 1
+writev: 1
+brk: 1
+mprotect: 1
+read: 1
+lseek: 1
+getuid32: 1
+clone: 1
+setpriority: 1
+sigaltstack: 1
+fstatat64: 1
+fstat64: 1
+restart_syscall: 1
+exit: 1
+exit_group: 1
+rt_sigreturn: 1
+faccessat: 1
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 4790754..4f99860 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -19,6 +19,7 @@
 #define LOG_TAG "ResourceManagerService"
 #include <utils/Log.h>
 
+#include <binder/IMediaResourceMonitor.h>
 #include <binder/IServiceManager.h>
 #include <dirent.h>
 #include <media/stagefright/ProcessInfo.h>
@@ -89,12 +90,20 @@
     return infos.editItemAt(infos.size() - 1);
 }
 
-status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */) {
-    Mutex::Autolock lock(mLock);
+static void notifyResourceGranted(int pid, const Vector<MediaResource> &resources) {
+    static const char* const kServiceName = "media_resource_monitor";
+    sp<IBinder> binder = defaultServiceManager()->getService(String16(kServiceName));
+    if (binder != NULL) {
+        sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
+        for (size_t i = 0; i < resources.size(); ++i) {
+            service->notifyResourceGranted(pid, String16(resources[i].mType),
+                    String16(resources[i].mSubType), resources[i].mValue);
+        }
+    }
+}
 
+status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */) {
     String8 result;
-    const size_t SIZE = 256;
-    char buffer[SIZE];
 
     if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
         result.format("Permission Denial: "
@@ -105,20 +114,35 @@
         return PERMISSION_DENIED;
     }
 
+    PidResourceInfosMap mapCopy;
+    bool supportsMultipleSecureCodecs;
+    bool supportsSecureWithNonSecureCodec;
+    String8 serviceLog;
+    {
+        Mutex::Autolock lock(mLock);
+        mapCopy = mMap;  // Shadow copy, real copy will happen on write.
+        supportsMultipleSecureCodecs = mSupportsMultipleSecureCodecs;
+        supportsSecureWithNonSecureCodec = mSupportsSecureWithNonSecureCodec;
+        serviceLog = mServiceLog->toString("    " /* linePrefix */);
+    }
+
+    const size_t SIZE = 256;
+    char buffer[SIZE];
     snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this);
     result.append(buffer);
     result.append("  Policies:\n");
-    snprintf(buffer, SIZE, "    SupportsMultipleSecureCodecs: %d\n", mSupportsMultipleSecureCodecs);
+    snprintf(buffer, SIZE, "    SupportsMultipleSecureCodecs: %d\n", supportsMultipleSecureCodecs);
     result.append(buffer);
-    snprintf(buffer, SIZE, "    SupportsSecureWithNonSecureCodec: %d\n", mSupportsSecureWithNonSecureCodec);
+    snprintf(buffer, SIZE, "    SupportsSecureWithNonSecureCodec: %d\n",
+            supportsSecureWithNonSecureCodec);
     result.append(buffer);
 
     result.append("  Processes:\n");
-    for (size_t i = 0; i < mMap.size(); ++i) {
-        snprintf(buffer, SIZE, "    Pid: %d\n", mMap.keyAt(i));
+    for (size_t i = 0; i < mapCopy.size(); ++i) {
+        snprintf(buffer, SIZE, "    Pid: %d\n", mapCopy.keyAt(i));
         result.append(buffer);
 
-        const ResourceInfos &infos = mMap.valueAt(i);
+        const ResourceInfos &infos = mapCopy.valueAt(i);
         for (size_t j = 0; j < infos.size(); ++j) {
             result.append("      Client:\n");
             snprintf(buffer, SIZE, "        Id: %lld\n", (long long)infos[j].clientId);
@@ -136,7 +160,7 @@
         }
     }
     result.append("  Events logs (most recent at top):\n");
-    result.append(mServiceLog->toString("    " /* linePrefix */));
+    result.append(serviceLog);
 
     write(fd, result.string(), result.size());
     return OK;
@@ -186,6 +210,7 @@
     ResourceInfo& info = getResourceInfoForEdit(clientId, client, infos);
     // TODO: do the merge instead of append.
     info.resources.appendVector(resources);
+    notifyResourceGranted(pid, resources);
 }
 
 void ResourceManagerService::removeResource(int pid, int64_t clientId) {
@@ -307,6 +332,10 @@
         }
     }
 
+    if (failedClient == NULL) {
+        return true;
+    }
+
     {
         Mutex::Autolock lock(mLock);
         bool found = false;
@@ -329,7 +358,7 @@
         }
     }
 
-    return (failedClient == NULL);
+    return false;
 }
 
 bool ResourceManagerService::getAllClients_l(
diff --git a/services/radio/RadioService.cpp b/services/radio/RadioService.cpp
index cd0f5f3..57697f3 100644
--- a/services/radio/RadioService.cpp
+++ b/services/radio/RadioService.cpp
@@ -349,6 +349,7 @@
         }
         break;
     case RADIO_EVENT_TA:
+    case RADIO_EVENT_EA:
     case RADIO_EVENT_ANTENNA:
     case RADIO_EVENT_CONTROL:
         event->on = halEvent->on;
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 9de6fe2..c891fd6 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -61,13 +61,13 @@
     rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, &mod);
     if (rc != 0) {
         ALOGE("couldn't load sound trigger module %s.%s (%s)",
-              SOUND_TRIGGER_HARDWARE_MODULE_ID, "primary", strerror(-rc));
+              SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, strerror(-rc));
         return;
     }
     rc = sound_trigger_hw_device_open(mod, &dev);
     if (rc != 0) {
         ALOGE("couldn't open sound trigger hw device in %s.%s (%s)",
-              SOUND_TRIGGER_HARDWARE_MODULE_ID, "primary", strerror(-rc));
+              SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, strerror(-rc));
         return;
     }
     if (dev->common.version != SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
@@ -241,6 +241,13 @@
                     event->data_offset);
         event->data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
         break;
+    case SOUND_MODEL_TYPE_GENERIC:
+        ALOGW_IF(event->data_size != 0 && event->data_offset !=
+                    sizeof(struct sound_trigger_generic_recognition_event),
+                    "prepareRecognitionEvent_l(): invalid data offset %u for generic event type",
+                    event->data_offset);
+        event->data_offset = sizeof(struct sound_trigger_generic_recognition_event);
+        break;
     case SOUND_MODEL_TYPE_UNKNOWN:
         ALOGW_IF(event->data_size != 0 && event->data_offset !=
                     sizeof(struct sound_trigger_recognition_event),
@@ -786,26 +793,45 @@
             if (model->mState == Model::STATE_ACTIVE) {
                 mHwDevice->stop_recognition(mHwDevice, model->mHandle);
                 // keep model in ACTIVE state so that event is processed by onCallbackEvent()
-                struct sound_trigger_phrase_recognition_event phraseEvent;
-                memset(&phraseEvent, 0, sizeof(struct sound_trigger_phrase_recognition_event));
-                switch (model->mType) {
-                case SOUND_MODEL_TYPE_KEYPHRASE:
-                    phraseEvent.num_phrases = model->mConfig.num_phrases;
-                    for (size_t i = 0; i < phraseEvent.num_phrases; i++) {
-                        phraseEvent.phrase_extras[i] = model->mConfig.phrases[i];
+                if (model->mType == SOUND_MODEL_TYPE_KEYPHRASE) {
+                    struct sound_trigger_phrase_recognition_event event;
+                    memset(&event, 0, sizeof(struct sound_trigger_phrase_recognition_event));
+                    event.num_phrases = model->mConfig.num_phrases;
+                    for (size_t i = 0; i < event.num_phrases; i++) {
+                        event.phrase_extras[i] = model->mConfig.phrases[i];
                     }
-                    break;
-                case SOUND_MODEL_TYPE_UNKNOWN:
-                default:
-                    break;
-                }
-                phraseEvent.common.status = RECOGNITION_STATUS_ABORT;
-                phraseEvent.common.type = model->mType;
-                phraseEvent.common.model = model->mHandle;
-                phraseEvent.common.data_size = 0;
-                sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&phraseEvent.common);
-                if (eventMemory != 0) {
-                    events.add(eventMemory);
+                    event.common.status = RECOGNITION_STATUS_ABORT;
+                    event.common.type = model->mType;
+                    event.common.model = model->mHandle;
+                    event.common.data_size = 0;
+                    sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
+                    if (eventMemory != 0) {
+                        events.add(eventMemory);
+                    }
+                } else if (model->mType == SOUND_MODEL_TYPE_GENERIC) {
+                    struct sound_trigger_generic_recognition_event event;
+                    memset(&event, 0, sizeof(struct sound_trigger_generic_recognition_event));
+                    event.common.status = RECOGNITION_STATUS_ABORT;
+                    event.common.type = model->mType;
+                    event.common.model = model->mHandle;
+                    event.common.data_size = 0;
+                    sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
+                    if (eventMemory != 0) {
+                        events.add(eventMemory);
+                    }
+                } else if (model->mType == SOUND_MODEL_TYPE_UNKNOWN) {
+                    struct sound_trigger_phrase_recognition_event event;
+                    memset(&event, 0, sizeof(struct sound_trigger_phrase_recognition_event));
+                    event.common.status = RECOGNITION_STATUS_ABORT;
+                    event.common.type = model->mType;
+                    event.common.model = model->mHandle;
+                    event.common.data_size = 0;
+                    sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&event.common);
+                    if (eventMemory != 0) {
+                        events.add(eventMemory);
+                    }
+                } else {
+                    goto exit;
                 }
             }
         }