Merge "Retry usb_device_claim_interface when it's connected to the kernel driver"
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 cd3b84c..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,
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 cce5a9a..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 {
 
@@ -149,7 +151,22 @@
         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 setVideoBufferMode(int32_t videoBufferMode)
@@ -348,6 +365,14 @@
             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;
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 78a1b58..a36d2f9 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -243,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
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 3e4df0f..83cf192 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -629,7 +629,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";
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index f7bf29c..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,
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/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/AudioTrack.h b/include/media/AudioTrack.h
index 38adb03..a4b8571 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -954,7 +954,6 @@
 
     mutable Mutex           mLock;
 
-    bool                    mIsTimed;
     int                     mPreviousPriority;          // before start()
     SchedPolicy             mPreviousSchedulingGroup;
     bool                    mAwaitBoost;    // thread should wait for priority boost before running
@@ -992,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/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/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/mediarecorder.h b/include/media/mediarecorder.h
index c375dff..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
 };
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/ACodec.h b/include/media/stagefright/ACodec.h
index 8b5b862..2a69685 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -68,15 +68,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);
     };
@@ -170,6 +172,7 @@
         unsigned mDequeuedAt;
 
         sp<ABuffer> mData;
+        sp<RefBase> mMemRef;
         sp<GraphicBuffer> mGraphicBuffer;
         int mFenceFd;
         FrameRenderTracker::Info *mRenderInfo;
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 769adf8..3d00d30 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -61,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
@@ -81,6 +83,7 @@
                                           int32_t cameraId,
                                           const String16& clientName,
                                           uid_t clientUid,
+                                          pid_t clientPid,
                                           Size videoSize,
                                           int32_t frameRate,
                                           const sp<IGraphicBufferProducer>& surface,
@@ -198,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);
@@ -258,12 +261,12 @@
     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.
@@ -274,7 +277,8 @@
                                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,
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 bb36052..542db71 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -72,6 +72,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/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 93ffa93..fd9c3cd 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -248,6 +248,7 @@
     struct BufferInfo {
         uint32_t mBufferID;
         sp<ABuffer> mData;
+        sp<RefBase> mMemRef;
         sp<ABuffer> mEncryptedData;
         sp<IMemory> mSharedEncryptedBuffer;
         sp<AMessage> mNotify;
@@ -348,8 +349,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/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/MetaData.h b/include/media/stagefright/MetaData.h
index 59686ed..91341b8 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -182,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 {
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index 1ba9545..b8bb824 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -114,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/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 034cb35..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,7 +176,6 @@
 media_status_t AMediaCodec_releaseOutputBufferAtTime(
         AMediaCodec *mData, size_t idx, int64_t timestampNs);
 
-
 typedef enum {
     AMEDIACODECRYPTOINFO_MODE_CLEAR = 0,
     AMEDIACODECRYPTOINFO_MODE_AES_CTR = 1
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/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk
index 82415d5..4e4b094 100644
--- a/media/libeffects/preprocessing/Android.mk
+++ b/media/libeffects/preprocessing/Android.mk
@@ -12,7 +12,7 @@
 
 LOCAL_C_INCLUDES += \
     external/webrtc \
-    external/webrtc/webrtc/modules/interface \
+    external/webrtc/webrtc/modules/include \
     external/webrtc/webrtc/modules/audio_processing/include \
     $(call include-path-for, audio-effects)
 
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index fe41946..f48bac1 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -89,6 +89,7 @@
     preproc_session_t *session;     // session the effect is on
     const preproc_ops_t *ops;       // effect ops table
     preproc_fx_handle_t engine;     // handle on webRTC engine
+    uint32_t type;                  // subtype of effect
 #ifdef DUAL_MIC_TEST
     bool aux_channels_on;           // support auxiliary channels
     size_t cur_channel_config;      // current auciliary channel configuration
@@ -559,6 +560,21 @@
     ALOGV("NsInit");
     webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
     ns->set_level(kNsDefaultLevel);
+    webrtc::Config config;
+    std::vector<webrtc::Point> geometry;
+    // TODO(aluebs): Make the geometry settable.
+    geometry.push_back(webrtc::Point(-0.03f, 0.f, 0.f));
+    geometry.push_back(webrtc::Point(-0.01f, 0.f, 0.f));
+    geometry.push_back(webrtc::Point(0.01f, 0.f, 0.f));
+    geometry.push_back(webrtc::Point(0.03f, 0.f, 0.f));
+    // The geometry needs to be set with Beamforming enabled.
+    config.Set<webrtc::Beamforming>(
+            new webrtc::Beamforming(true, geometry));
+    effect->session->apm->SetExtraOptions(config);
+    config.Set<webrtc::Beamforming>(
+            new webrtc::Beamforming(false, geometry));
+    effect->session->apm->SetExtraOptions(config);
+    effect->type = NS_TYPE_SINGLE_CHANNEL;
     return 0;
 }
 
@@ -584,11 +600,35 @@
     return status;
 }
 
-int NsSetParameter (preproc_effect_t *effect __unused,
-                    void *pParam __unused,
-                    void *pValue __unused)
+int NsSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
 {
     int status = 0;
+    webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
+    uint32_t param = *(uint32_t *)pParam;
+    uint32_t value = *(uint32_t *)pValue;
+    switch(param) {
+        case NS_PARAM_LEVEL:
+            ns->set_level((webrtc::NoiseSuppression::Level)value);
+            ALOGV("NsSetParameter() level %d", value);
+            break;
+        case NS_PARAM_TYPE:
+        {
+            webrtc::Config config;
+            std::vector<webrtc::Point> geometry;
+            bool is_beamforming_enabled =
+                    value == NS_TYPE_MULTI_CHANNEL && ns->is_enabled();
+            config.Set<webrtc::Beamforming>(
+                    new webrtc::Beamforming(is_beamforming_enabled, geometry));
+            effect->session->apm->SetExtraOptions(config);
+            effect->type = value;
+            ALOGV("NsSetParameter() type %d", value);
+            break;
+        }
+        default:
+            ALOGW("NsSetParameter() unknown param %08x value %08x", param, value);
+            status = -EINVAL;
+    }
+
     return status;
 }
 
@@ -597,6 +637,12 @@
     webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
     ALOGV("NsEnable ns %p", ns);
     ns->Enable(true);
+    if (effect->type == NS_TYPE_MULTI_CHANNEL) {
+        webrtc::Config config;
+        std::vector<webrtc::Point> geometry;
+        config.Set<webrtc::Beamforming>(new webrtc::Beamforming(true, geometry));
+        effect->session->apm->SetExtraOptions(config);
+    }
 }
 
 void NsDisable(preproc_effect_t *effect)
@@ -604,6 +650,10 @@
     ALOGV("NsDisable");
     webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
     ns->Enable(false);
+    webrtc::Config config;
+    std::vector<webrtc::Point> geometry;
+    config.Set<webrtc::Beamforming>(new webrtc::Beamforming(false, geometry));
+    effect->session->apm->SetExtraOptions(config);
 }
 
 static const preproc_ops_t sNsOps = {
@@ -884,8 +934,8 @@
 int Session_SetConfig(preproc_session_t *session, effect_config_t *config)
 {
     uint32_t sr;
-    uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
-    uint32_t outCnl = audio_channel_count_from_out_mask(config->outputCfg.channels);
+    uint32_t inCnl = audio_channel_count_from_in_mask(config->inputCfg.channels);
+    uint32_t outCnl = audio_channel_count_from_in_mask(config->outputCfg.channels);
 
     if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
         config->inputCfg.format != config->outputCfg.format ||
@@ -897,17 +947,6 @@
          config->inputCfg.samplingRate, config->inputCfg.channels);
     int status;
 
-    // if at least one process is enabled, do not accept configuration changes
-    if (session->enabledMsk) {
-        if (session->samplingRate != config->inputCfg.samplingRate ||
-                session->inChannelCount != inCnl ||
-                session->outChannelCount != outCnl) {
-            return -ENOSYS;
-        } else {
-            return 0;
-        }
-    }
-
     // AEC implementation is limited to 16kHz
     if (config->inputCfg.samplingRate >= 32000 && !(session->createdMsk & (1 << PREPROC_AEC))) {
         session->apmSamplingRate = 32000;
@@ -919,10 +958,10 @@
     }
 
     const webrtc::ProcessingConfig processing_config = {
-      {{static_cast<int>(session->apmSamplingRate), static_cast<int>(inCnl)},
-       {static_cast<int>(session->apmSamplingRate), static_cast<int>(outCnl)},
-       {static_cast<int>(session->apmSamplingRate), static_cast<int>(inCnl)},
-       {static_cast<int>(session->apmSamplingRate), static_cast<int>(inCnl)}}};
+      {{static_cast<int>(session->apmSamplingRate), inCnl},
+       {static_cast<int>(session->apmSamplingRate), outCnl},
+       {static_cast<int>(session->apmSamplingRate), inCnl},
+       {static_cast<int>(session->apmSamplingRate), inCnl}}};
     status = session->apm->Initialize(processing_config);
     if (status < 0) {
         return -EINVAL;
@@ -1040,14 +1079,10 @@
     }
     uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
     const webrtc::ProcessingConfig processing_config = {
-       {{static_cast<int>(session->apmSamplingRate),
-         static_cast<int>(session->inChannelCount)},
-        {static_cast<int>(session->apmSamplingRate),
-         static_cast<int>(session->outChannelCount)},
-        {static_cast<int>(session->apmSamplingRate),
-         static_cast<int>(inCnl)},
-        {static_cast<int>(session->apmSamplingRate),
-         static_cast<int>(inCnl)}}};
+       {{static_cast<int>(session->apmSamplingRate), session->inChannelCount},
+        {static_cast<int>(session->apmSamplingRate), session->outChannelCount},
+        {static_cast<int>(session->apmSamplingRate), inCnl},
+        {static_cast<int>(session->apmSamplingRate), inCnl}}};
     int status = session->apm->Initialize(processing_config);
     if (status < 0) {
         return -EINVAL;
@@ -1298,8 +1333,7 @@
             }
             session->framesIn = 0;
         }
-        session->procFrame->samples_per_channel_ =
-                session->apmFrameCount * session->inChannelCount;
+        session->procFrame->samples_per_channel_ = session->apmFrameCount;
 
         effect->session->apm->ProcessStream(session->procFrame);
 
@@ -1826,8 +1860,7 @@
             }
             session->framesRev = 0;
         }
-        session->revFrame->samples_per_channel_ =
-                session->apmFrameCount * session->inChannelCount;
+        session->revFrame->samples_per_channel_ = session->apmFrameCount;
         effect->session->apm->AnalyzeReverseStream(session->revFrame);
         return 0;
     } else {
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index a13d53a..e17e47e 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),
@@ -750,7 +747,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) {
@@ -777,10 +774,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
@@ -800,10 +793,6 @@
 
 uint32_t AudioTrack::getOriginalSampleRate() const
 {
-    if (mIsTimed) {
-        return 0;
-    }
-
     return mOriginalSampleRate;
 }
 
@@ -813,7 +802,7 @@
     if (isAudioPlaybackRateEqual(playbackRate, mPlaybackRate)) {
         return NO_ERROR;
     }
-    if (mIsTimed || isOffloadedOrDirect_l()) {
+    if (isOffloadedOrDirect_l()) {
         return INVALID_OPERATION;
     }
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
@@ -877,7 +866,7 @@
         return NO_INIT;
     }
     // Reject if timed track or compressed audio.
-    if (mIsTimed || !audio_is_linear_pcm(mFormat)) {
+    if (!audio_is_linear_pcm(mFormat)) {
         return INVALID_OPERATION;
     }
     // TODO also need to inform the server side (through mAudioTrack) that
@@ -888,7 +877,7 @@
 
 status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
 {
-    if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) {
+    if (mSharedBuffer == 0 || isOffloadedOrDirect()) {
         return INVALID_OPERATION;
     }
 
@@ -991,7 +980,7 @@
 
 status_t AudioTrack::setPosition(uint32_t position)
 {
-    if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) {
+    if (mSharedBuffer == 0 || isOffloadedOrDirect()) {
         return INVALID_OPERATION;
     }
     if (position > mFrameCount) {
@@ -1056,7 +1045,7 @@
 
 status_t AudioTrack::getBufferPosition(uint32_t *position)
 {
-    if (mSharedBuffer == 0 || mIsTimed) {
+    if (mSharedBuffer == 0) {
         return INVALID_OPERATION;
     }
     if (position == NULL) {
@@ -1070,7 +1059,7 @@
 
 status_t AudioTrack::reload()
 {
-    if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) {
+    if (mSharedBuffer == 0 || isOffloadedOrDirect()) {
         return INVALID_OPERATION;
     }
 
@@ -1199,8 +1188,7 @@
         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.
+    // 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:
@@ -1284,9 +1272,6 @@
     }
 
     IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
-    if (mIsTimed) {
-        trackFlags |= IAudioFlinger::TRACK_TIMED;
-    }
 
     pid_t tid = -1;
     if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
@@ -1626,7 +1611,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;
     }
 
@@ -1676,73 +1661,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.
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 2742db0..d75ad87 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -179,7 +179,7 @@
             avail = 0;
         } else if (avail > 0) {
             // 'avail' may be non-contiguous, so return only the first contiguous chunk
-            ssize_t part1;
+            size_t part1;
             if (mIsOut) {
                 rear &= mFrameCountP2 - 1;
                 part1 = mFrameCountP2 - rear;
@@ -187,13 +187,13 @@
                 front &= mFrameCountP2 - 1;
                 part1 = mFrameCountP2 - front;
             }
-            if (part1 > avail) {
+            if (part1 > (size_t)avail) {
                 part1 = avail;
             }
-            if (part1 > (ssize_t) buffer->mFrameCount) {
+            if (part1 > buffer->mFrameCount) {
                 part1 = buffer->mFrameCount;
             }
-            buffer->mFrameCount = (size_t) part1;
+            buffer->mFrameCount = part1;
             buffer->mRaw = part1 > 0 ?
                     &((char *) mBuffers)[(mIsOut ? rear : front) * mFrameSize] : NULL;
             buffer->mNonContig = avail - part1;
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/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/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/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 73d07a0..533b6e0 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -782,8 +782,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;
 
@@ -1226,6 +1227,7 @@
             (mVideoEncoder == VIDEO_ENCODER_H263 ? MEDIA_MIMETYPE_VIDEO_H263 :
              mVideoEncoder == VIDEO_ENCODER_MPEG_4_SP ? MEDIA_MIMETYPE_VIDEO_MPEG4 :
              mVideoEncoder == VIDEO_ENCODER_VP8 ? MEDIA_MIMETYPE_VIDEO_VP8 :
+             mVideoEncoder == VIDEO_ENCODER_HEVC ? MEDIA_MIMETYPE_VIDEO_HEVC :
              mVideoEncoder == VIDEO_ENCODER_H264 ? MEDIA_MIMETYPE_VIDEO_AVC : ""),
             false /* decoder */, true /* hwCodec */, &codecs);
 
@@ -1450,13 +1452,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);
     }
@@ -1515,6 +1517,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;
@@ -1792,6 +1798,7 @@
         err = mWriter->stop();
         mWriter.clear();
     }
+    mTotalPausedDurationUs = 0;
 
     mGraphicBufferProducer.clear();
     mPersistentSurface.clear();
@@ -1873,7 +1880,6 @@
 
     mOutputFd = -1;
     mPauseStartTimeUs = 0;
-    mTotalPausedDurationUs = 0;
 
     return OK;
 }
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index a799e9d..761e987 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -80,6 +80,7 @@
     sp<IMediaRecorderClient> mListener;
     String16 mClientName;
     uid_t mClientUid;
+    pid_t mClientPid;
     sp<MediaWriter> mWriter;
     int mOutputFd;
     sp<AudioSource> mAudioSourceNode;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 9a0db30..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(
@@ -338,6 +343,10 @@
     return mIsStreaming;
 }
 
+void NuPlayer::GenericSource::setOffloadAudio(bool offload) {
+    mBufferingMonitor->setOffloadAudio(offload);
+}
+
 NuPlayer::GenericSource::~GenericSource() {
     if (mLooper != NULL) {
         mLooper->unregisterHandler(id());
@@ -466,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();
     }
@@ -492,7 +509,7 @@
         }
         mBitrate = -1;
 
-        cancelPollBuffering();
+        mBufferingMonitor->cancelPollBuffering();
     }
     notifyPrepared(err);
 }
@@ -571,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:
@@ -834,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;
       }
 
@@ -1045,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) {
@@ -1091,6 +926,7 @@
     CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
     if (audio) {
         mAudioLastDequeueTimeUs = timeUs;
+        mBufferingMonitor->updateDequeuedBufferTime(timeUs);
     } else {
         mVideoLastDequeueTimeUs = timeUs;
     }
@@ -1377,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) {
@@ -1403,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;
 }
@@ -1484,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;
     }
@@ -1585,8 +1431,10 @@
             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);
@@ -1630,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 2db5557..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();
 
@@ -111,6 +113,83 @@
         sp<AnotherPacketSource> mPackets;
     };
 
+    // 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;
@@ -147,17 +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();
 
@@ -212,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/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index ce68bd4..cede584 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1564,10 +1564,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 {
@@ -2138,11 +2142,7 @@
                 mPausedForBuffering = true;
                 onPause();
             }
-            // fall-thru
-        }
 
-        case Source::kWhatBufferingStart:
-        {
             notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_START, 0);
             break;
         }
@@ -2160,11 +2160,7 @@
                     onResume();
                 }
             }
-            // fall-thru
-        }
 
-        case Source::kWhatBufferingEnd:
-        {
             notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_END, 0);
             break;
         }
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 65e3a6e..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;
@@ -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;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 11a6a9f..0176eafa 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -46,8 +46,6 @@
         kWhatFlagsChanged,
         kWhatVideoSizeChanged,
         kWhatBufferingUpdate,
-        kWhatBufferingStart,
-        kWhatBufferingEnd,
         kWhatPauseOnBufferingStart,
         kWhatResumeOnBufferingEnd,
         kWhatCacheStats,
@@ -122,6 +120,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 c861fd1..2ecab6d 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -725,7 +725,7 @@
         mBuffering = true;
 
         sp<AMessage> notify = dupNotify();
-        notify->setInt32("what", kWhatBufferingStart);
+        notify->setInt32("what", kWhatPauseOnBufferingStart);
         notify->post();
     }
 }
@@ -741,7 +741,7 @@
         mBuffering = false;
 
         sp<AMessage> notify = dupNotify();
-        notify->setInt32("what", kWhatBufferingEnd);
+        notify->setInt32("what", kWhatResumeOnBufferingEnd);
         notify->post();
     }
 
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 04c42c9..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?
@@ -73,7 +73,7 @@
     }
     {
         // read from source
-        ssize_t actual = mSource->read(mAllocated, buffer->frameCount, pts);
+        ssize_t actual = mSource->read(mAllocated, buffer->frameCount);
         if (actual > 0) {
             ALOG_ASSERT((size_t) actual <= buffer->frameCount);
             mOffset = 0;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index cb5cfe3..82ac72c 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -853,6 +853,7 @@
                     if (type == kMetadataBufferTypeANWBuffer) {
                         ((VideoNativeMetadata *)mem->pointer())->nFenceFd = -1;
                     }
+                    info.mMemRef = mem;
                 }
 
                 mBuffers[portIndex].push(info);
@@ -873,8 +874,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);
@@ -1134,7 +1134,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)",
@@ -1570,6 +1570,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,
@@ -2845,6 +2847,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(
@@ -3530,8 +3533,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));
@@ -3844,7 +3847,7 @@
         fmt != OMX_COLOR_FormatYUV420PackedPlanar &&
         fmt != OMX_COLOR_FormatYUV420SemiPlanar &&
         fmt != OMX_COLOR_FormatYUV420PackedSemiPlanar &&
-        fmt != HAL_PIXEL_FORMAT_YV12) {
+        fmt != (OMX_COLOR_FORMATTYPE)HAL_PIXEL_FORMAT_YV12) {
         ALOGW("do not know color format 0x%x = %d", fmt, fmt);
         return false;
     }
@@ -4504,9 +4507,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() {
@@ -4521,6 +4525,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)
@@ -5898,6 +5906,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);
     }
 }
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 9a4a350..14a0c66 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -24,6 +24,7 @@
         FLACExtractor.cpp                 \
         FrameRenderTracker.cpp            \
         HTTPBase.cpp                      \
+        HevcUtils.cpp                     \
         JPEGSource.cpp                    \
         MP3Extractor.cpp                  \
         MPEG2TSWriter.cpp                 \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 98936ad..f535e5c 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1274,7 +1274,7 @@
         // then performs a color conversion and copy to get the data
         // into the ANativeBuffer.
         sp<AMessage> format;
-        convertMetaDataToMessage(meta, &format);
+        CHECK(OK == convertMetaDataToMessage(meta, &format));
         mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, format);
     }
 }
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index 4c0a578..e6303ba 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -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 dab623b..d302f82 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -142,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
@@ -153,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;
 }
@@ -170,6 +171,7 @@
     int32_t cameraId,
     const String16& clientName,
     uid_t clientUid,
+    pid_t clientPid,
     Size videoSize,
     int32_t frameRate,
     const sp<IGraphicBufferProducer>& surface,
@@ -193,7 +195,7 @@
     mVideoSize.height = -1;
 
     mInitCheck = init(camera, proxy, cameraId,
-                    clientName, clientUid,
+                    clientName, clientUid, clientPid,
                     videoSize, frameRate,
                     storeMetaDataInVideoBuffers);
     if (mInitCheck != OK) releaseCamera();
@@ -205,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 {
@@ -492,6 +494,7 @@
         int32_t cameraId,
         const String16& clientName,
         uid_t clientUid,
+        pid_t clientPid,
         Size videoSize,
         int32_t frameRate,
         bool storeMetaDataInVideoBuffers) {
@@ -499,7 +502,7 @@
     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);
@@ -583,6 +586,7 @@
         int32_t cameraId,
         const String16& clientName,
         uid_t clientUid,
+        pid_t clientPid,
         Size videoSize,
         int32_t frameRate,
         bool storeMetaDataInVideoBuffers) {
@@ -590,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;
     }
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/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/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index ea4a7ac..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,6 +70,18 @@
 #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
 
@@ -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);
@@ -234,6 +247,7 @@
     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);
@@ -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/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 1211aef..1ffd333 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1334,6 +1334,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());
@@ -1906,7 +1907,7 @@
             mCodec->initiateShutdown(
                     msg->what() == kWhatStop /* keepComponentAllocated */);
 
-            returnBuffersToCodec();
+            returnBuffersToCodec(reclaimed);
 
             if (mSoftRenderer != NULL && (mFlags & kFlagPushBlankBuffersOnShutdown)) {
                 pushBlankBuffersToNativeWindow(mSurface.get());
@@ -2309,12 +2310,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);
 
@@ -2326,7 +2327,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 */
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 99e58f1..fe66a58 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -86,6 +86,7 @@
     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;
@@ -122,6 +123,9 @@
 void RemoteDataSource::close() {
     mSource = NULL;
 }
+uint32_t RemoteDataSource::getFlags() {
+    return mSource->flags();
+}
 
 // static
 sp<IMediaExtractor> MediaExtractor::Create(
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 67d9921..8809640 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -449,6 +449,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);
 
@@ -478,21 +531,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/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 41fbf75..ee1f927 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1307,6 +1307,8 @@
         compressionFormat = OMX_VIDEO_CodingVP9;
     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG2, mime)) {
         compressionFormat = OMX_VIDEO_CodingMPEG2;
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, mime)) {
+        compressionFormat = OMX_VIDEO_CodingDolbyVision;
     } else {
         ALOGE("Not a supported video mime type: %s", mime);
         CHECK(!"Should not be here. Not a supported video mime type.");
@@ -1505,6 +1507,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,
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 2a8b635..dcc29fe 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -22,6 +22,7 @@
 #include <sys/stat.h>
 
 #include "include/ESDS.h"
+#include "include/HevcUtils.h"
 
 #include <arpa/inet.h>
 #include <cutils/properties.h>
@@ -100,7 +101,9 @@
     }
 
     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);
@@ -122,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);
@@ -155,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);
@@ -379,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;
@@ -461,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;
@@ -575,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)) {
@@ -693,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);
         }
     }
 
diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk
index 4d12f82..77a7b1e 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/Android.mk
@@ -102,7 +102,7 @@
 
 LOCAL_CFLAGS += -Werror
 LOCAL_CLANG := true
-#LOCAL_SANITIZE := signed-integer-overflow
+LOCAL_SANITIZE := signed-integer-overflow
 
 include $(BUILD_STATIC_LIBRARY)
 
@@ -120,7 +120,7 @@
 
 LOCAL_CFLAGS += -Werror
 LOCAL_CLANG := true
-#LOCAL_SANITIZE := signed-integer-overflow
+LOCAL_SANITIZE := signed-integer-overflow
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_amrwbenc
diff --git a/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c b/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c
index b9a9e26..e3b2f6c 100644
--- a/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c
+++ b/media/libstagefright/codecs/amrwbenc/src/c4t64fx.c
@@ -1014,8 +1014,8 @@
             {
                 ps2 = add1(ps1, dn[y]);
 
-                alp2 = alp1 + ((*p1++)<<13);
-                alp2 = alp2 + ((*p2++)<<14);
+                alp2 = L_add(alp1, ((*p1++)<<13));
+                alp2 = L_add(alp2, ((*p2++)<<14));
                 alp_16 = extract_h(alp2);
                 sq = vo_mult(ps2, ps2);
                 s = vo_L_mult(alpk, sq) - ((sqk * alp_16)<<1);
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/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/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/matroska/Android.mk b/media/libstagefright/matroska/Android.mk
index 193408c..b0cbf08 100644
--- a/media/libstagefright/matroska/Android.mk
+++ b/media/libstagefright/matroska/Android.mk
@@ -7,6 +7,7 @@
 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
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 82b471f..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();
@@ -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 120ef82..a1d6b00 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.h
+++ b/media/libstagefright/matroska/MatroskaExtractor.h
@@ -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/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 c967463..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;
@@ -1130,6 +1132,10 @@
             brokenLink = (data[offset + 7] & 0x20) != 0;
         }
 
+        if (mFormat != NULL && currentStartCode == 0xb2) {
+            userDataPositions.add(offset);
+        }
+
         if (mFormat != NULL && currentStartCode == 0x00) {
             // Picture start
 
@@ -1163,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/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/WebmWriter.cpp b/media/libstagefright/webm/WebmWriter.cpp
index 7f6ba01..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
@@ -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/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 7e3041b..e006e89 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -40,7 +40,6 @@
     ALOGI("ServiceManager: %p", sm.get());
     MediaPlayerService::instantiate();
     ResourceManagerService::instantiate();
-    CameraService::instantiate();
     registerExtensions();
     ProcessState::self()->startThreadPool();
     IPCThreadState::self()->joinThreadPool();
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 5bbd747..7d7ea13 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -784,7 +784,33 @@
         ALOGE("Failed to send a read request.");
         return false;
     }
-    return readData(callback, NULL /* expected size */, writtenSize, clientData);
+    // 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) {
diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h
index edc608f..ce60811 100644
--- a/media/mtp/MtpDevice.h
+++ b/media/mtp/MtpDevice.h
@@ -118,6 +118,12 @@
                                               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.
diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk
index 8f795cd..6546f14 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")))'
 
@@ -46,6 +49,8 @@
     libutils \
     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 8e36065..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) {
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 87f9aaa..6e3eb83 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -41,7 +41,6 @@
     libaudioresampler \
     libaudiospdif \
     libaudioutils \
-    libcommon_time_client \
     libcutils \
     libutils \
     liblog \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index d2786b9..f4bd1c4 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -56,8 +56,6 @@
 
 #include <powermanager/PowerManager.h>
 
-#include <common_time/cc_helper.h>
-
 #include <media/IMediaLogService.h>
 
 #include <media/nbaio/Pipe.h>
@@ -1359,8 +1357,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
@@ -1382,31 +1379,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,
@@ -2979,8 +2951,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 2571e67..62a3115 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>
@@ -414,18 +412,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 ---
@@ -496,12 +488,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/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/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 3f99b43..cc9acff 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -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;
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 7bc6f0c..1450ca1 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -83,8 +83,7 @@
                         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
@@ -158,92 +157,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 +216,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..e2014b7 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -61,8 +61,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
@@ -99,8 +98,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/Threads.cpp b/services/audioflinger/Threads.cpp
index 0458554..8ae798c 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -53,9 +53,6 @@
 
 #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"
@@ -1666,13 +1663,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
@@ -1716,11 +1709,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;
@@ -1819,17 +1812,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);
@@ -3640,22 +3626,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
@@ -5369,7 +5341,7 @@
 {
     // mix buffers...
     if (outputsReady(outputTracks)) {
-        mAudioMixer->process(AudioBufferProvider::kInvalidPTS);
+        mAudioMixer->process();
     } else {
         if (mMixerBufferValid) {
             memset(mMixerBuffer, 0, mMixerBufferSize);
@@ -5909,7 +5881,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;
@@ -6531,7 +6503,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) {
@@ -6632,7 +6604,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 8eed50d..fa047fa 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1109,7 +1109,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;
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 c753afd..5830f75 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"
@@ -242,7 +239,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
@@ -308,43 +305,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);
 }
@@ -590,7 +550,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;
@@ -1119,526 +1079,6 @@
 }
 // ----------------------------------------------------------------------------
 
-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;
-        }
-    } else {
-        LOG_ALWAYS_FATAL("TimedTrack::releaseBuffer of non-silence buffer with no"
-                  " buffers in the timed buffer queue");
-    }
-
-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(
             PlaybackThread *playbackThread,
             DuplicatingThread *sourceThread,
@@ -1855,7 +1295,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;
@@ -1866,7 +1306,7 @@
     if (buf.mFrameCount == 0) {
         return WOULD_BLOCK;
     }
-    status = Track::getNextBuffer(buffer, pts);
+    status = Track::getNextBuffer(buffer);
     return status;
 }
 
@@ -2005,8 +1445,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;
@@ -2146,7 +1585,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;
@@ -2158,7 +1597,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 0f3f138..8218edd 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -24,7 +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 \
+    $(TOPDIR)frameworks/av/services/audiopolicy/utilities
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
@@ -56,8 +56,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= \
-    managerdefault/AudioPolicyManager.cpp \
+LOCAL_SRC_FILES:= managerdefault/AudioPolicyManager.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
@@ -75,8 +74,7 @@
     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
 
@@ -84,7 +82,7 @@
 
 LOCAL_SHARED_LIBRARIES += libaudiopolicyenginedefault
 
-endif
+endif # ifeq ($(USE_CONFIGURABLE_AUDIO_POLICY), 1)
 
 LOCAL_C_INCLUDES += \
     $(TOPDIR)frameworks/av/services/audiopolicy/common/include \
@@ -122,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 dd3f144..75e0530 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -67,6 +67,14 @@
         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
+   };
+
+   typedef uint32_t concurrency_type__mask_t;
+
 public:
     virtual ~AudioPolicyInterface() {}
     //
@@ -140,7 +148,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;
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 34984f9..e3ee4e5 100755
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -30,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)
 
 
 /**
@@ -88,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 429f20a..5c81410 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -5,7 +5,6 @@
 LOCAL_SRC_FILES:= \
     src/DeviceDescriptor.cpp \
     src/AudioGain.cpp \
-    src/StreamDescriptor.cpp \
     src/HwModule.cpp \
     src/IOProfile.cpp \
     src/AudioPort.cpp \
@@ -20,6 +19,7 @@
     src/SoundTriggerSession.cpp \
     src/SessionRoute.cpp \
     src/AudioSourceDescriptor.cpp \
+    src/VolumeCurve.cpp \
     src/TypeConverter.cpp \
     src/AudioSession.cpp
 
@@ -35,9 +35,10 @@
     $(TOPDIR)frameworks/av/services/audiopolicy/utilities \
 
 ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
+
 LOCAL_SRC_FILES += src/Serializer.cpp
 
-LOCAL_STATIC_LIBRARIES := libxml2
+LOCAL_STATIC_LIBRARIES += libxml2
 
 LOCAL_SHARED_LIBRARIES += libicuuc
 
@@ -46,7 +47,12 @@
     $(TOPDIR)external/icu/icu4c/source/common
 
 else
-LOCAL_SRC_FILES += src/ConfigParsingUtils.cpp
+
+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 := \
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 77c0d07..049079e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -63,7 +63,8 @@
                              const sp<AudioSession>& audioSession);
     status_t removeAudioSession(audio_session_t session);
     sp<AudioSession> getAudioSession(audio_session_t session) const;
-    AudioSessionCollection getActiveAudioSessions() const;
+    AudioSessionCollection getAudioSessions(bool activeOnly) const;
+    audio_source_t getHighestPrioritySource(bool activeOnly) const;
 
 private:
     audio_port_handle_t           mId;
@@ -93,7 +94,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/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 6959420..f2756b5 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -28,7 +28,6 @@
 #include <AudioPolicyMix.h>
 #include <EffectDescriptor.h>
 #include <SoundTriggerSession.h>
-#include <StreamDescriptor.h>
 #include <SessionRoute.h>
 
 namespace android {
@@ -40,14 +39,23 @@
                       DeviceVector &availableOutputDevices,
                       DeviceVector &availableInputDevices,
                       sp<DeviceDescriptor> &defaultOutputDevices,
-                      bool &isSpeakerDrcEnabled)
+                      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;
@@ -131,6 +139,7 @@
     DeviceVector &mAvailableOutputDevices;
     DeviceVector &mAvailableInputDevices;
     sp<DeviceDescriptor> &mDefaultOutputDevices;
+    VolumeCurvesCollection *mVolumeCurves;
     bool &mIsSpeakerDrcEnabled;
 };
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 32cb600..0da3aea 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -71,7 +71,6 @@
     virtual void toAudioPort(struct audio_port *port) const;
 
     virtual void importAudioPort(const sp<AudioPort> port);
-    void clearCapabilities() { mProfiles.clearProfiles(); }
 
     void addAudioProfile(const sp<AudioProfile> &profile) { mProfiles.add(profile); }
 
@@ -160,6 +159,10 @@
     virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
                                    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
index 9780dc6..404e27d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
@@ -258,7 +258,6 @@
         if (dynamicFormatProfile == 0) {
             return;
         }
-        clearProfiles();
         for (size_t i = 0; i < formats.size(); i++) {
             sp<AudioProfile> profile = new AudioProfile(formats[i],
                                                         dynamicFormatProfile->getChannels(),
@@ -270,6 +269,33 @@
         }
     }
 
+    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++) {
@@ -308,33 +334,6 @@
         }
     }
 
-    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:
     sp<AudioProfile> getProfileFor(audio_format_t format) const
     {
         for (size_t i = 0; i < size(); i++) {
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
index 576822c..87c4c9a 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
@@ -87,6 +87,7 @@
     AudioSessionCollection getActiveSessions() 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;
 };
diff --git a/services/audiopolicy/enginedefault/src/Gains.h b/services/audiopolicy/common/managerdefinitions/include/Gains.h
similarity index 88%
rename from services/audiopolicy/enginedefault/src/Gains.h
rename to services/audiopolicy/common/managerdefinitions/include/Gains.h
index 4bd5edd..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(device_category deviceCategory,
-                                const StreamDescriptor& streamDesc,
-                                int indexInUi);
-
-    static float volIndexToDb(device_category deviceCategory,
-                              const StreamDescriptor& streamDesc,
+    static float volIndexToDb(const VolumeCurvePoint *point, int indexMin, int indexMax,
                               int indexInUi);
 
     // default volume curve
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
index b152dd5..078b582 100644
--- a/services/audiopolicy/common/managerdefinitions/include/Serializer.h
+++ b/services/audiopolicy/common/managerdefinitions/include/Serializer.h
@@ -198,11 +198,12 @@
     {
         static const char stream[];
         static const char deviceCategory[];
+        static const char reference[];
     };
 
     typedef VolumeCurve Element;
     typedef sp<VolumeCurve> PtrElement;
-    typedef VolumeCurveCollection Collection;
+    typedef VolumeCurvesCollection Collection;
     typedef void *PtrSerializingCtx;
 
     static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
diff --git a/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
index fbc942c..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>
@@ -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,
-                             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,
                                                 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/VolumeCurve.h b/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
index cccf1c8..009a26f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
+++ b/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
@@ -16,12 +16,13 @@
 
 #pragma once
 
-#include <Volume.h>
+#include "IVolumeCurvesCollection.h"
+#include <policy.h>
 #include <hardware/audio.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
-#include <utils/Errors.h>
-#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
 #include <system/audio.h>
 #include <cutils/config_utils.h>
 #include <string>
@@ -29,26 +30,194 @@
 
 namespace android {
 
-typedef std::pair<uint32_t, uint32_t> CurvePoint;
-typedef Vector<CurvePoint> CurvePoints;
+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:
-    void setStreamType(audio_stream_type_t streamType) { mStreamType = streamType; }
+    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 setDeviceCategory(device_category devCat) { mDeviceCategory = devCat; }
-    device_category getDeviceCategory() const { return mDeviceCategory; }
+    void add(const CurvePoint &point) { mCurvePoints.add(point); }
 
-    void setCurvePoints(const CurvePoints &points) { mCurvePoints = points; }
+    float volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const;
+
+    void dump(int fd) const;
 
 private:
-    CurvePoints mCurvePoints;
+    SortedVector<CurvePoint> mCurvePoints;
     device_category mDeviceCategory;
     audio_stream_type_t mStreamType;
 };
 
-typedef Vector<sp<VolumeCurve> > VolumeCurveCollection;
+// 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/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 9b6469c..6281715 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -132,6 +132,12 @@
     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
@@ -143,9 +149,13 @@
     return mSessions.valueFor(session);
 }
 
-AudioSessionCollection AudioInputDescriptor::getActiveAudioSessions() const
+AudioSessionCollection AudioInputDescriptor::getAudioSessions(bool activeOnly) const
 {
-    return mSessions.getActiveSessions();
+    if (activeOnly) {
+        return mSessions.getActiveSessions();
+    } else {
+        return mSessions;
+    }
 }
 
 status_t AudioInputDescriptor::addAudioSession(audio_session_t session,
@@ -216,17 +226,19 @@
     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>  inputDescriptor = valueAt(i);
         if ((inputDescriptor->isActive())
                 && (!ignoreVirtualInputs ||
                     !is_virtual_input_device(inputDescriptor->mDevice))) {
-            return keyAt(i);
+            activeInputs.add(inputDescriptor);
         }
     }
-    return 0;
+    return activeInputs;
 }
 
 audio_devices_t AudioInputCollection::getSupportedDevices(audio_io_handle_t handle) const
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 5d0f03f..f5927ab 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -81,7 +81,7 @@
         return sharesHwModuleWith(outputDesc->subOutput1()) ||
                     sharesHwModuleWith(outputDesc->subOutput2());
     } else {
-        return (getModuleHandle() == outputDesc->getModuleHandle());
+        return hasSameHwModuleAs(outputDesc);
     }
 }
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
index 597c029..a08ce02 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
@@ -18,6 +18,7 @@
 //#define LOG_NDEBUG 0
 
 #include <AudioPolicyInterface.h>
+#include "policy.h"
 #include "AudioSession.h"
 #include "AudioGain.h"
 #include "TypeConverter.h"
@@ -207,6 +208,24 @@
     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
 {
diff --git a/services/audiopolicy/enginedefault/src/Gains.cpp b/services/audiopolicy/common/managerdefinitions/src/Gains.cpp
similarity index 91%
rename from services/audiopolicy/enginedefault/src/Gains.cpp
rename to services/audiopolicy/common/managerdefinitions/src/Gains.cpp
index 0aace36..e3fc9a8 100644
--- a/services/audiopolicy/enginedefault/src/Gains.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Gains.cpp
@@ -197,17 +197,11 @@
 };
 
 //static
-float Gains::volIndexToDb(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(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 5bfe957..dd2a60a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -312,6 +312,8 @@
         }
         deviceList = hwModule->getDeclaredDevices().getDevicesFromType(device);
         if (!deviceList.isEmpty()) {
+            deviceList.itemAt(0)->setName(String8(device_name));
+            deviceList.itemAt(0)->mAddress = address;
             return deviceList.itemAt(0);
         }
     }
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 77824df..3e5bb7d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -47,6 +47,31 @@
 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,
@@ -60,13 +85,14 @@
             root = root->next;
             continue;
         }
-        if (!xmlStrcmp(root->name, (const xmlChar *)Trait::collectionTag)) {
-            root = root->xmlChildrenNode;
+        const xmlNode *child = root;
+        if (!xmlStrcmp(child->name, (const xmlChar *)Trait::collectionTag)) {
+            child = child->xmlChildrenNode;
         }
-        while (root != NULL) {
-            if (!xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
+        while (child != NULL) {
+            if (!xmlStrcmp(child->name, (const xmlChar *)Trait::tag)) {
                 typename Trait::PtrElement element;
-                status_t status = Trait::deserialize(doc, root, element, serializingContext);
+                status_t status = Trait::deserialize(doc, child, element, serializingContext);
                 if (status != NO_ERROR) {
                     return status;
                 }
@@ -75,12 +101,14 @@
                           Trait::collectionTag);
                 }
             }
-            root = root->next;
+            child = child->next;
         }
-        return NO_ERROR;
+        if (!xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
+            return NO_ERROR;
+        }
+        root = root->next;
     }
-    ALOGV("%s: No %s collection found", __FUNCTION__, Trait::collectionTag);
-    return BAD_VALUE;
+    return NO_ERROR;
 }
 
 const char *const AudioGainTraits::tag = "gain";
@@ -487,7 +515,7 @@
 
 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*/)
@@ -513,8 +541,20 @@
               deviceCategoryLiteral.c_str());
         return BAD_VALUE;
     }
-    CurvePoints points;
-    const xmlNode *child = root->xmlChildrenNode;
+
+    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);;
@@ -529,15 +569,11 @@
                       (const char*)pointDefinition);
                 return BAD_VALUE;
             }
-            points.add(std::make_pair(point[0], point[1]));
+            element->add(CurvePoint(point[0], point[1]));
             xmlFree(pointDefinition);
         }
         child = child->next;
     }
-    element = new Element();
-    element->setDeviceCategory(deviceCategory);
-    element->setStreamType(streamType);
-    element->setCurvePoints(points);
     return NO_ERROR;
 }
 
@@ -592,7 +628,8 @@
 
     // deserialize volume section
     VolumeTraits::Collection volumes;
-    deserializeCollection<VolumeTraits>(doc, cur, volumes, NULL);
+    deserializeCollection<VolumeTraits>(doc, cur, volumes, &config);
+    config.setVolumes(volumes);
 
     // Global Configuration
     GlobalConfigTraits::deserialize(cur, config);
diff --git a/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
index 12c7930..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>
 
@@ -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
index 74d8809..58eaf79 100644
--- a/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
@@ -219,7 +219,7 @@
     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)
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_PATCH),
 };
 
 template<>
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/audio_policy_configuration.xml b/services/audiopolicy/config/audio_policy_configuration.xml
index dccc3a8..7af2f81 100644
--- a/services/audiopolicy/config/audio_policy_configuration.xml
+++ b/services/audiopolicy/config/audio_policy_configuration.xml
@@ -206,28 +206,11 @@
     </modules>
     <!-- End of Modules section -->
 
-    <!-- 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_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER">
-            <point>0,-9600</point>
-            <point>100,0</point>
-        </volume>
-        <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_EARPIECE">
-            <point>0,-9800</point>
-            <point>50,-1000</point>
-            <point>100,0</point>
-        </volume>
-    </volumes>
+    <!-- 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/engine/interface/AudioPolicyManagerInterface.h b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
index 3a3bdbf..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(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 06d00ca..e6b5f85 100755
--- a/services/audiopolicy/engineconfigurable/Android.mk
+++ b/services/audiopolicy/engineconfigurable/Android.mk
@@ -42,10 +42,7 @@
     libmedia_helper \
     libaudiopolicypfwwrapper \
     libaudiopolicycomponents \
-
-ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
-LOCAL_STATIC_LIBRARIES += libxml2
-endif
+    libxml2
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
diff --git a/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h b/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
index 43d441e..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,
-                                           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 55da35e..e15e418 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Android.mk
@@ -61,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
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/PolicyConfigurableDomains.xml b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/PolicyConfigurableDomains.xml
index 8cb0723..4ac466e 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/PolicyConfigurableDomains.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/PolicyConfigurableDomains.xml
@@ -9508,1544 +9508,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 +9575,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/volumes.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/example/Settings/volumes.pfw
index 1049564..7ac7d5f 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..cf7df60 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 ####################-->
 
@@ -142,10 +140,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..f08d45f 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>
 
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/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/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/VolumeProfile.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.cpp
deleted file mode 100755
index 1469c3f..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 >= DEVICE_CATEGORY_CNT) {
-        mCategory = DEVICE_CATEGORY_SPEAKER;
-    } else {
-        mCategory = static_cast<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 3c2d9bc..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;
-    device_category mCategory;
-
-    static const uint32_t gFractional = 8; /**< Beware to align with the structure. */
-};
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index 074af50..7d585c0 100755
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -115,18 +115,6 @@
     return (mApmObserver != NULL)? NO_ERROR : NO_INIT;
 }
 
-bool Engine::setVolumeProfileForStream(const audio_stream_type_t &streamType,
-                                       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 +176,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 +199,6 @@
     return element->template set<Property>(property) == NO_ERROR;
 }
 
-float Engine::volIndexToDb(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);
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.h b/services/audiopolicy/engineconfigurable/src/Engine.h
index 8a15e5e..bc5e035 100755
--- a/services/audiopolicy/engineconfigurable/src/Engine.h
+++ b/services/audiopolicy/engineconfigurable/src/Engine.h
@@ -88,20 +88,6 @@
         {
             return mPolicyEngine->setDeviceConnectionState(devDesc, state);
         }
-        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(device_category deviceCategory,
-                                   audio_stream_type_t stream,
-                                   int indexInUi)
-        {
-            return mPolicyEngine->volIndexToDb(deviceCategory, stream, indexInUi);
-        }
 
     private:
         Engine *mPolicyEngine;
@@ -141,11 +127,7 @@
                                                                                            stream);
         }
         virtual bool setVolumeProfileForStream(const audio_stream_type_t &stream,
-                                               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)
         {
@@ -181,9 +163,6 @@
     audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const;
     status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
                                       audio_policy_dev_state_t state);
-    float volIndexToDb(device_category category, audio_stream_type_t stream, int indexInUi);
-    status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax);
-
     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 3bd5220..0ed364f 100755
--- a/services/audiopolicy/engineconfigurable/src/Stream.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Stream.cpp
@@ -62,91 +62,22 @@
     return mApplicableStrategy;
 }
 
-status_t Element<audio_stream_type_t>::setVolumeProfile(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 =%zu", __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 =%zu 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(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 b103f89..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<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(device_category category, const VolumeCurvePoints &points);
-
-    float volIndexToDb(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/enginedefault/Android.mk b/services/audiopolicy/enginedefault/Android.mk
index b3b3dde..bb12714 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 \
@@ -38,11 +36,7 @@
 LOCAL_STATIC_LIBRARIES := \
     libmedia_helper \
     libaudiopolicycomponents \
-
-ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
-LOCAL_STATIC_LIBRARIES += libxml2
-endif #ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
-
+    libxml2
 
 LOCAL_SHARED_LIBRARIES += \
     libcutils \
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index b0df018..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,56 +62,6 @@
     return (mApmObserver != NULL) ?  NO_ERROR : NO_INIT;
 }
 
-float Engine::volIndexToDb(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 < DEVICE_CATEGORY_CNT; j++) {
-            streams.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) {
-        streams.setVolumeCurvePoint(AUDIO_STREAM_SYSTEM, DEVICE_CATEGORY_SPEAKER,
-                Gains::sDefaultSystemVolumeCurveDrc);
-        streams.setVolumeCurvePoint(AUDIO_STREAM_RING, DEVICE_CATEGORY_SPEAKER,
-                Gains::sSpeakerSonificationVolumeCurveDrc);
-        streams.setVolumeCurvePoint(AUDIO_STREAM_ALARM, DEVICE_CATEGORY_SPEAKER,
-                Gains::sSpeakerSonificationVolumeCurveDrc);
-        streams.setVolumeCurvePoint(AUDIO_STREAM_NOTIFICATION, DEVICE_CATEGORY_SPEAKER,
-                Gains::sSpeakerSonificationVolumeCurveDrc);
-        streams.setVolumeCurvePoint(AUDIO_STREAM_MUSIC, DEVICE_CATEGORY_SPEAKER,
-                Gains::sSpeakerMediaVolumeCurveDrc);
-        streams.setVolumeCurvePoint(AUDIO_STREAM_ACCESSIBILITY, DEVICE_CATEGORY_SPEAKER,
-                Gains::sSpeakerMediaVolumeCurveDrc);
-    }
-}
-
-
 status_t Engine::setPhoneState(audio_mode_t state)
 {
     ALOGV("setPhoneState() state %d", state);
@@ -130,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 < DEVICE_CATEGORY_CNT; j++) {
-            streams.setVolumeCurvePoint(AUDIO_STREAM_DTMF, static_cast<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 < DEVICE_CATEGORY_CNT; j++) {
-            streams.setVolumeCurvePoint(AUDIO_STREAM_DTMF, static_cast<device_category>(j),
-                                         Gains::sVolumeProfiles[AUDIO_STREAM_DTMF][j]);
-        }
+        mApmObserver->getVolumeCurves().restoreOriginVolumeCurve(AUDIO_STREAM_DTMF);
     }
     return NO_ERROR;
 }
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 697f19b..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(device_category deviceCategory,
-                                   audio_stream_type_t stream, int indexInUi)
-        {
-            return mPolicyEngine->volIndexToDb(deviceCategory, stream, indexInUi);
-        }
     private:
         Engine *mPolicyEngine;
     } mManagerInterface;
@@ -140,11 +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(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 2aed7b1..d1d5df6 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -39,11 +39,11 @@
 #include <media/AudioPolicyHelper.h>
 #include <soundtrigger/SoundTrigger.h>
 #include "AudioPolicyManager.h"
-#ifdef USE_XML_AUDIO_POLICY_CONF
-#include <Serializer.h>
-#else
+#ifndef USE_XML_AUDIO_POLICY_CONF
 #include <ConfigParsingUtils.h>
+#include <StreamDescriptor.h>
 #endif
+#include <Serializer.h>
 #include "TypeConverter.h"
 #include <policy.h>
 
@@ -420,15 +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()) {
-                //FIXME: consider all active sessions
-                AudioSessionCollection activeSessions = activeDesc->getActiveAudioSessions();
-                audio_session_t activeSession = activeSessions.keyAt(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);
+                }
             }
         }
 
@@ -594,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->getSupportedDevices().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);
         }
     }
 }
@@ -1159,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);
 
@@ -1334,6 +1337,7 @@
 
     *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("");
@@ -1471,14 +1475,22 @@
                                                               isSoundTrigger,
                                                               policyMix, mpClientInterface);
 
-// TODO enable input reuse
-#if 0
+
     // 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 same sound trigger attribute
-        if (profile == desc->mProfile &&
-            isSoundTrigger == desc->isSoundTrigger()) {
+        // 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) {
@@ -1488,16 +1500,33 @@
                 } else {
                     ALOGW("getInputForDevice() record with different attributes"
                           " exists for session %d", session);
-                    return input;
+                    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);
             }
-            ALOGV("getInputForDevice() reusing input %d", mInputs.keyAt(i));
-            return mInputs.keyAt(i);
         }
     }
-#endif
 
     audio_config_t config = AUDIO_CONFIG_INITIALIZER;
     config.sample_rate = profileSamplingRate;
@@ -1540,10 +1569,50 @@
     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);
@@ -1557,81 +1626,62 @@
         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->inputSource() == AUDIO_SOURCE_HOTWORD) &&
-                    !activeDesc->hasPreemptedSession(session)) {
-                ALOGW("startInput(%d) preempting low-priority input %d", input, activeInput);
-                //FIXME: consider all active sessions
-                AudioSessionCollection activeSessions = activeDesc->getActiveAudioSessions();
-                audio_session_t activeSession = activeSessions.keyAt(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->isActive() || 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->isActive()) {
+            // 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", audioSession->inputSource());
 
-    audioSession->changeActiveCount(1);
     return NO_ERROR;
 }
 
@@ -1662,36 +1712,41 @@
     // Routing?
     mInputRoutes.decRouteActivity(session);
 
-    if (!inputDesc->isActive()) {
-        // 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;
 }
@@ -1766,10 +1821,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);
     }
 }
 
@@ -1778,8 +1832,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)) {
@@ -1787,7 +1841,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);
@@ -1795,30 +1849,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;
@@ -1851,7 +1905,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;
 }
@@ -2106,7 +2160,7 @@
     mHwModules.dump(fd);
     mOutputs.dump(fd);
     mInputs.dump(fd);
-    mStreams.dump(fd);
+    mVolumeCurves->dump(fd);
     mEffects.dump(fd);
     mAudioPatches.dump(fd);
 
@@ -2454,7 +2508,7 @@
                 // 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()) ||
+                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) {
@@ -2554,7 +2608,7 @@
                 return BAD_VALUE;
             }
             setInputDevice(inputDesc->mIoHandle,
-                           getNewInputDevice(inputDesc->mIoHandle),
+                           getNewInputDevice(inputDesc),
                            true,
                            NULL);
         } else if (patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) {
@@ -2991,7 +3045,6 @@
 #endif //AUDIO_POLICY_TEST
     mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
     mA2dpSuspended(false),
-    mSpeakerDrcEnabled(false),
     mAudioPortGeneration(1),
     mBeaconMuteRefCount(0),
     mBeaconPlayingRefCount(0),
@@ -2999,6 +3052,35 @@
     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__);
@@ -3014,27 +3096,7 @@
     status_t status = mEngine->initCheck();
     ALOG_ASSERT(status == NO_ERROR, "Policy engine not initialized(err=%d)", status);
 
-    mUidCached = getuid();
-    mpClientInterface = clientInterface;
-
-    AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
-                             mDefaultOutputDevice, mSpeakerDrcEnabled);
-
-#ifdef USE_XML_AUDIO_POLICY_CONF
-    PolicySerializer serializer;
-    if (serializer.deserialize(AUDIO_POLICY_XML_CONFIG_FILE, config) != NO_ERROR) {
-#else
-    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();
-    }
     // 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;
@@ -3465,7 +3527,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) {
@@ -3710,7 +3772,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) {
@@ -4172,9 +4234,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) {
@@ -4186,7 +4248,12 @@
         }
     }
 
-    audio_devices_t device = getDeviceAndMixForInputSource(inputDesc->inputSource());
+    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;
 }
@@ -4220,7 +4287,6 @@
         devices |= AUDIO_DEVICE_OUT_SPEAKER;
         devices &= ~AUDIO_DEVICE_OUT_SPEAKER_SAFE;
     }
-
     return devices;
 }
 
@@ -4526,7 +4592,6 @@
                     patchDesc->mPatch = patch;
                 }
                 patchDesc->mAfPatchHandle = afPatchHandle;
-                patchDesc->mUid = mUidCached;
                 if (patchHandle) {
                     *patchHandle = patchDesc->mHandle;
                 }
@@ -4631,7 +4696,6 @@
                     patchDesc->mPatch = patch;
                 }
                 patchDesc->mAfPatchHandle = afPatchHandle;
-                patchDesc->mUid = mUidCached;
                 if (patchHandle) {
                     *patchHandle = patchDesc->mHandle;
                 }
@@ -4731,11 +4795,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
@@ -4751,7 +4814,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
@@ -4760,8 +4823,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) {
@@ -4813,7 +4877,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;
         }
@@ -4839,7 +4903,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,
@@ -4871,7 +4935,6 @@
                                            int delayMs,
                                            audio_devices_t device)
 {
-    const StreamDescriptor& streamDesc = mStreams.valueFor(stream);
     if (device == AUDIO_DEVICE_NONE) {
         device = outputDesc->device();
     }
@@ -4881,7 +4944,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);
@@ -4896,7 +4959,7 @@
         }
         if (--outputDesc->mMuteCount[stream] == 0) {
             checkAndSetVolume(stream,
-                              streamDesc.getVolumeIndex(device),
+                              mVolumeCurves->getVolumeIndex(stream, device),
                               outputDesc,
                               device,
                               delayMs);
@@ -5129,8 +5192,10 @@
     }
     const FormatVector &supportedFormats = profiles.getSupportedFormats();
 
-    for(size_t formatIndex = 0; formatIndex < supportedFormats.size(); formatIndex++) {
+    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);
 
@@ -5141,7 +5206,7 @@
             ALOGV("%s: supported sampling rates %s", __FUNCTION__, reply.string());
             value = strpbrk((char *)reply.string(), "=");
             if (value != NULL) {
-                profiles.setSampleRatesFor(samplingRatesFromString(value + 1), format);
+                samplingRates = samplingRatesFromString(value + 1);
             }
         }
         if (profiles.hasDynamicChannelsFor(format)) {
@@ -5151,9 +5216,10 @@
             ALOGV("%s: supported channel masks %s", __FUNCTION__, reply.string());
             value = strpbrk((char *)reply.string(), "=");
             if (value != NULL) {
-                profiles.setChannelsFor(channelMasksFromString(value + 1), format);
+                channelMasks = channelMasksFromString(value + 1);
             }
         }
+        profiles.addProfileFromHal(new AudioProfile(format, channelMasks, samplingRates));
     }
 }
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 37faac2..1b1a9b4 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -33,7 +33,6 @@
 #include <AudioGain.h>
 #include <AudioPort.h>
 #include <AudioPatch.h>
-#include <ConfigParsingUtils.h>
 #include <DeviceDescriptor.h>
 #include <IOProfile.h>
 #include <HwModule.h>
@@ -42,8 +41,8 @@
 #include <AudioPolicyMix.h>
 #include <EffectDescriptor.h>
 #include <SoundTriggerSession.h>
-#include <StreamDescriptor.h>
 #include <SessionRoute.h>
+#include <VolumeCurve.h>
 
 namespace android {
 
@@ -140,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,
@@ -235,10 +235,6 @@
         virtual status_t setMasterMono(bool mono);
         virtual status_t getMasterMono(bool *mono);
 
-        // Audio policy configuration file parsing (audio_policy.conf)
-        // TODO candidates to be moved to ConfigParsingUtils
-                void defaultAudioPolicyConfig(void);
-
         // return the strategy corresponding to a given stream type
         routing_strategy getStrategy(audio_stream_type_t stream) const;
 
@@ -272,10 +268,7 @@
         {
             return mAvailableInputDevices;
         }
-        virtual StreamDescriptorCollection &getStreamDescriptors()
-        {
-            return mStreams;
-        }
+        virtual IVolumeCurvesCollection &getVolumeCurves() { return *mVolumeCurves; }
         virtual const sp<DeviceDescriptor> &getDefaultOutputDevice() const
         {
             return mDefaultOutputDevice;
@@ -413,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()
         {
@@ -513,6 +506,8 @@
 
         void clearAudioSources(uid_t uid);
 
+        bool isConcurentCaptureAllowed(const sp<AudioInputDescriptor>& inputDesc,
+                const sp<AudioSession>& audioSession);
 
         uid_t mUidCached;
         AudioPolicyClientInterface *mpClientInterface;  // audio policy client interface
@@ -531,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
@@ -539,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;
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index f6f8276..eed545e 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
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index 3dec437..58ea24c 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:
 
@@ -178,17 +179,17 @@
                          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 c7486a5..e08c952 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -349,8 +349,27 @@
         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) {
+        // enforce permission (if any) required for each type of concurrency
+        switch (concurrency) {
+        case AudioPolicyInterface::API_INPUT_CONCURRENCY_NONE:
+            break;
+        case AudioPolicyInterface::API_INPUT_CONCURRENCY_CALL:
+            //TODO: check incall capture permission
+            break;
+        case AudioPolicyInterface::API_INPUT_CONCURRENCY_CAPTURE:
+            //TODO: check concurrent capture permission
+            break;
+       default:
+            LOG_ALWAYS_FATAL("startInput() encountered an invalid input type %d",
+                    (int)concurrency);
+        }
+    }
+
+    return status;
 }
 
 status_t AudioPolicyService::stopInput(audio_io_handle_t input,
@@ -378,7 +397,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);
         }
@@ -551,7 +570,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)
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
index 08b2a3b..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);
         }
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 9ba8f3f..d416353 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -46,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/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 4be2c92..f0bcc0b 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>
@@ -56,6 +57,10 @@
 #include "api2/CameraDeviceClient.h"
 #include "utils/CameraTraces.h"
 
+namespace {
+    const char* kPermissionServiceName = "permission";
+}; // namespace anonymous
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -779,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;
     }
@@ -852,22 +857,52 @@
     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();
+    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;
+
     if (!mModule) {
         ALOGE("CameraService::connect X (PID %d) rejected (camera HAL module not loaded)",
                 callingPid);
@@ -1140,6 +1175,7 @@
         int cameraId,
         const String16& clientPackageName,
         int clientUid,
+        int clientPid,
         /*out*/
         sp<ICamera>& device) {
 
@@ -1148,7 +1184,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),
@@ -1189,7 +1225,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),
@@ -1214,8 +1250,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),
@@ -1781,21 +1817,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
@@ -1920,6 +1941,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() {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 5877c65..66de77f 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -116,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);
 
@@ -244,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
@@ -488,7 +488,8 @@
     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 validateConnectLocked(const String8& cameraId, /*inout*/int& clientUid,
+            /*inout*/int& clientPid) const;
 
     // Handle active client evictions, and update service state.
     // Only call with with mServiceLock held.
@@ -501,8 +502,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;
@@ -801,12 +803,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(),
@@ -826,7 +827,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 c17fc65..5ac5743 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -371,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;
 
@@ -1233,6 +1233,7 @@
 }
 
 void Camera2Client::releaseRecordingFrame(const sp<IMemory>& mem) {
+    (void)mem;
     ATRACE_CALL();
     ALOGW("%s: Not supported in buffer queue mode.", __FUNCTION__);
 }
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index cba4590..6aeab98 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -234,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;
@@ -1001,6 +1001,7 @@
 }
 
 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;
 }
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index bd9fea3..6b60307 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -456,11 +456,12 @@
         return BAD_VALUE;
     }
 
-    int streamId = -1;
+    // TODO: Hookup the stream set id with upper layer.
+    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);
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 d1c79d0..f33d1ba 100644
--- a/services/camera/libcameraservice/common/CameraModule.cpp
+++ b/services/camera/libcameraservice/common/CameraModule.cpp
@@ -130,6 +130,7 @@
         // 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;
@@ -151,6 +152,13 @@
                 // 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) {
@@ -161,6 +169,19 @@
                 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
diff --git a/services/camera/libcameraservice/device3/Camera3BufferManager.cpp b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
new file mode 100644
index 0000000..6d79167
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.cpp
@@ -0,0 +1,404 @@
+/*
+ * 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 watermark should be the max of buffer count of each stream inside a stream set.
+    if (streamInfo.totalBufferCount > currentStreamSet.allocatedBufferWaterMark) {
+       currentStreamSet.allocatedBufferWaterMark = 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.allocatedBufferWaterMark = 0;
+    for (size_t i = 0; i < infoMap.size(); i++) {
+        if (infoMap[i].totalBufferCount > currentSet.allocatedBufferWaterMark) {
+            currentSet.allocatedBufferWaterMark = infoMap[i].totalBufferCount;
+        }
+    }
+
+    // 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);
+    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: allocate a new graphic buffer %p with handle %p",
+                    __FUNCTION__, buffer.graphicBuffer.get(), buffer.graphicBuffer->handle);
+            if (res != OK) {
+                ALOGE("%s: graphic buffer allocation failed: (error %d %s) ",
+                        __FUNCTION__, res, strerror(-res));
+                return res;
+            }
+        }
+
+        // Increase the hand-out buffer count for tracking purpose.
+        BufferCountMap& handOutBufferCounts = streamSet.handoutBufferCountMap;
+        size_t& bufferCount = handOutBufferCounts.editValueFor(streamId);
+        bufferCount++;
+
+        *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) {
+                    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) {
+                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 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].allocatedBufferWaterMark;
+    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;
+}
+
+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..0b4f55c
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3BufferManager.h
@@ -0,0 +1,288 @@
+/*
+ * 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.
+         */
+        size_t allocatedBufferWaterMark;
+        /**
+         * 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;
+        }
+    };
+
+    /**
+     * 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);
+};
+
+} // 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 6c07aef..ea1e5f6 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -167,6 +167,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,
@@ -293,6 +296,7 @@
 
         mRequestThread.clear();
         mStatusTracker.clear();
+        mBufferManager.clear();
 
         hal3Device = mHal3Device;
     }
@@ -502,6 +506,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");
@@ -926,7 +934,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);
@@ -963,6 +971,11 @@
     assert(mStatus != STATUS_ACTIVE);
 
     sp<Camera3OutputStream> newStream;
+    // Overwrite stream set id to invalid for HAL3.1 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) {
@@ -979,7 +992,7 @@
             }
         }
         newStream = new Camera3OutputStream(mNextStreamId, consumer,
-                width, height, blobBufferSize, format, dataSpace, rotation);
+                width, height, blobBufferSize, format, dataSpace, rotation, streamSetId);
     } else if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
         ssize_t rawOpaqueBufferSize = getRawOpaqueBufferSize(width, height);
         if (rawOpaqueBufferSize <= 0) {
@@ -987,13 +1000,22 @@
             return BAD_VALUE;
         }
         newStream = new Camera3OutputStream(mNextStreamId, consumer,
-                width, height, rawOpaqueBufferSize, format, dataSpace, rotation);
+                width, height, rawOpaqueBufferSize, format, dataSpace, rotation, streamSetId);
     } else {
         newStream = new Camera3OutputStream(mNextStreamId, consumer,
-                width, height, format, dataSpace, rotation);
+                width, height, format, dataSpace, rotation, streamSetId);
     }
     newStream->setStatusTracker(mStatusTracker);
 
+    /**
+     * Camera3 Buffer manager is only supported by HAL3.2 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.
+     */
+    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);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 7e20b0d..f70a153 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -29,6 +29,7 @@
 
 #include "common/CameraDeviceBase.h"
 #include "device3/StatusTracker.h"
+#include "device3/Camera3BufferManager.h"
 
 /**
  * Function pointer types with C calling convention to
@@ -97,7 +98,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);
@@ -721,6 +723,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 7b298e6..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),
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 a5aa1fa..4e79029 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -34,28 +34,36 @@
 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, 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),
+        mTimestampBuffer(true),
+        mUseBufferManager(false) {
 
     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, 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),
+        mTimestampBuffer(true),
+        mUseBufferManager(false) {
 
     if (format != HAL_PIXEL_FORMAT_BLOB && format != HAL_PIXEL_FORMAT_RAW_OPAQUE) {
         ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__,
@@ -67,17 +75,28 @@
         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),
+        mUseBufferManager(false) {
+
+    if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
+        mBufferReleasedListener = new BufferReleasedListener(this);
+    }
 
     // Subclasses expected to initialize mConsumer themselves
 }
@@ -96,28 +115,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 +220,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,11 +235,17 @@
             mTraceFirstBuffer = false;
         }
 
-        res = native_window_set_buffers_timestamp(mConsumer.get(), timestamp);
-        if (res != OK) {
-            ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
-                  __FUNCTION__, mId, strerror(-res), res);
-            return res;
+        /* Certain consumers (such as AudioSource or HardwareComposer) use
+         * MONOTONIC time, causing time misalignment if camera timestamp is
+         * in BOOTTIME. Avoid setting timestamp, and let BufferQueue generate it
+         * instead. */
+        if (mTimestampBuffer) {
+            res = native_window_set_buffers_timestamp(mConsumer.get(), timestamp);
+            if (res != OK) {
+                ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
+                      __FUNCTION__, mId, strerror(-res), res);
+                return res;
+            }
         }
 
         res = currentConsumer->queueBuffer(currentConsumer.get(),
@@ -270,9 +318,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 +398,7 @@
     mHandoutTotalBufferCount = 0;
     mFrameCount = 0;
     mLastTimestamp = 0;
+    mTimestampBuffer = !(isConsumedByHWComposer() | isVideoStream());
 
     res = native_window_set_buffer_count(mConsumer.get(),
             mTotalBufferCount);
@@ -366,6 +415,30 @@
                 __FUNCTION__, mTransform, strerror(-res), res);
     }
 
+    /**
+     * Camera3 Buffer manager is only supported by HAL3.2 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.
+     */
+    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 +449,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 +471,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 +527,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..c2c3452 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,
+            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,
+            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,25 @@
     // Name of Surface consumer
     String8           mConsumerName;
 
+    // Whether to timestamp the output buffer
+    bool mTimestampBuffer;
+
+    /**
+     * 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;
     /**
      * Internal Camera3Stream interface
      */
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 141f6c3..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;
@@ -77,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.h b/services/camera/libcameraservice/gui/RingBufferConsumer.h
index 243ea31..28dc5d5 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.h
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.h
@@ -189,4 +189,4 @@
 
 } // namespace android
 
-#endif // ANDROID_GUI_CPUCONSUMER_H
+#endif // ANDROID_GUI_RINGBUFFERCONSUMER_H
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 9de6fe2..b3500f6 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -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,34 @@
             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 {
+                    goto exit;
                 }
             }
         }