am 10ef7f75: am b0924c63: am 7af634e1: am 8ec119d2: am d138024f: am b32957db: am a9d7c917: am a99d3d83: am 738a753a: SampleTable: fix integer overflow checks.

* commit '10ef7f7514bdf6d9c38c93d9bb0194c0920d152f':
  SampleTable: fix integer overflow checks.
diff --git a/camera/Android.mk b/camera/Android.mk
index fa518ff..5cedab0 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -8,6 +8,7 @@
 	Camera.cpp \
 	CameraMetadata.cpp \
 	CameraParameters.cpp \
+	CameraParameters2.cpp \
 	ICamera.cpp \
 	ICameraClient.cpp \
 	ICameraService.cpp \
@@ -16,6 +17,9 @@
 	ICameraRecordingProxyListener.cpp \
 	IProCameraUser.cpp \
 	IProCameraCallbacks.cpp \
+	camera2/ICameraDeviceUser.cpp \
+	camera2/ICameraDeviceCallbacks.cpp \
+	camera2/CaptureRequest.cpp \
 	ProCamera.cpp \
 	CameraBase.cpp \
 
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index 1b136de..22199fa 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -39,6 +39,9 @@
 {
 }
 
+CameraTraits<Camera>::TCamConnectService CameraTraits<Camera>::fnConnectService =
+        &ICameraService::connect;
+
 // construct a camera client from an existing camera remote
 sp<Camera> Camera::create(const sp<ICamera>& camera)
 {
@@ -97,13 +100,13 @@
 }
 
 // pass the buffered IGraphicBufferProducer to the camera service
-status_t Camera::setPreviewTexture(const sp<IGraphicBufferProducer>& bufferProducer)
+status_t Camera::setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer)
 {
-    ALOGV("setPreviewTexture(%p)", bufferProducer.get());
+    ALOGV("setPreviewTarget(%p)", bufferProducer.get());
     sp <ICamera> c = mCamera;
     if (c == 0) return NO_INIT;
     ALOGD_IF(bufferProducer == 0, "app passed NULL surface");
-    return c->setPreviewTexture(bufferProducer);
+    return c->setPreviewTarget(bufferProducer);
 }
 
 // start preview mode
@@ -124,7 +127,7 @@
     return c->storeMetaDataInBuffers(enabled);
 }
 
-// start recording mode, must call setPreviewDisplay first
+// start recording mode, must call setPreviewTarget first
 status_t Camera::startRecording()
 {
     ALOGV("startRecording");
@@ -255,6 +258,14 @@
     mCamera->setPreviewCallbackFlag(flag);
 }
 
+status_t Camera::setPreviewCallbackTarget(
+        const sp<IGraphicBufferProducer>& callbackProducer)
+{
+    sp <ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->setPreviewCallbackTarget(callbackProducer);
+}
+
 // callback from camera service
 void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
 {
diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp
index c25c5fd..55376b0 100644
--- a/camera/CameraBase.cpp
+++ b/camera/CameraBase.cpp
@@ -92,20 +92,25 @@
 
 template <typename TCam, typename TCamTraits>
 sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
-                                         const String16& clientPackageName,
+                                               const String16& clientPackageName,
                                                int clientUid)
 {
     ALOGV("%s: connect", __FUNCTION__);
     sp<TCam> c = new TCam(cameraId);
     sp<TCamCallbacks> cl = c;
+    status_t status = NO_ERROR;
     const sp<ICameraService>& cs = getCameraService();
+
     if (cs != 0) {
-        c->mCamera = cs->connect(cl, cameraId, clientPackageName, clientUid);
+        TCamConnectService fnConnectService = TCamTraits::fnConnectService;
+        status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
+                                             /*out*/ c->mCamera);
     }
-    if (c->mCamera != 0) {
+    if (status == OK && c->mCamera != 0) {
         c->mCamera->asBinder()->linkToDeath(c);
         c->mStatus = NO_ERROR;
     } else {
+        ALOGW("An error occurred while connecting to camera: %d", cameraId);
         c.clear();
     }
     return c;
diff --git a/camera/CameraMetadata.cpp b/camera/CameraMetadata.cpp
index a8f9eff..7765914 100644
--- a/camera/CameraMetadata.cpp
+++ b/camera/CameraMetadata.cpp
@@ -21,9 +21,13 @@
 #include <utils/Errors.h>
 
 #include <camera/CameraMetadata.h>
+#include <binder/Parcel.h>
 
 namespace android {
 
+typedef Parcel::WritableBlob WritableBlob;
+typedef Parcel::ReadableBlob ReadableBlob;
+
 CameraMetadata::CameraMetadata() :
         mBuffer(NULL), mLocked(false) {
 }
@@ -129,11 +133,19 @@
 }
 
 status_t CameraMetadata::append(const CameraMetadata &other) {
+    return append(other.mBuffer);
+}
+
+status_t CameraMetadata::append(const camera_metadata_t* other) {
     if (mLocked) {
         ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
         return INVALID_OPERATION;
     }
-    return append_camera_metadata(mBuffer, other.mBuffer);
+    size_t extraEntries = get_camera_metadata_entry_count(other);
+    size_t extraData = get_camera_metadata_data_count(other);
+    resizeIfNeeded(extraEntries, extraData);
+
+    return append_camera_metadata(mBuffer, other);
 }
 
 size_t CameraMetadata::entryCount() const {
@@ -408,4 +420,175 @@
     return OK;
 }
 
+status_t CameraMetadata::readFromParcel(const Parcel& data,
+                                        camera_metadata_t** out) {
+
+    status_t err = OK;
+
+    camera_metadata_t* metadata = NULL;
+
+    if (out) {
+        *out = NULL;
+    }
+
+    // arg0 = metadataSize (int32)
+    int32_t metadataSizeTmp = -1;
+    if ((err = data.readInt32(&metadataSizeTmp)) != OK) {
+        ALOGE("%s: Failed to read metadata size (error %d %s)",
+              __FUNCTION__, err, strerror(-err));
+        return err;
+    }
+    const size_t metadataSize = static_cast<size_t>(metadataSizeTmp);
+
+    if (metadataSize == 0) {
+        ALOGV("%s: Read 0-sized metadata", __FUNCTION__);
+        return OK;
+    }
+
+    // NOTE: this doesn't make sense to me. shouldnt the blob
+    // know how big it is? why do we have to specify the size
+    // to Parcel::readBlob ?
+
+    ReadableBlob blob;
+    // arg1 = metadata (blob)
+    do {
+        if ((err = data.readBlob(metadataSize, &blob)) != OK) {
+            ALOGE("%s: Failed to read metadata blob (sized %d). Possible "
+                  " serialization bug. Error %d %s",
+                  __FUNCTION__, metadataSize, err, strerror(-err));
+            break;
+        }
+        const camera_metadata_t* tmp =
+                       reinterpret_cast<const camera_metadata_t*>(blob.data());
+
+        metadata = allocate_copy_camera_metadata_checked(tmp, metadataSize);
+        if (metadata == NULL) {
+            // We consider that allocation only fails if the validation
+            // also failed, therefore the readFromParcel was a failure.
+            err = BAD_VALUE;
+        }
+    } while(0);
+    blob.release();
+
+    if (out) {
+        ALOGV("%s: Set out metadata to %p", __FUNCTION__, metadata);
+        *out = metadata;
+    } else if (metadata != NULL) {
+        ALOGV("%s: Freed camera metadata at %p", __FUNCTION__, metadata);
+        free_camera_metadata(metadata);
+    }
+
+    return err;
+}
+
+status_t CameraMetadata::writeToParcel(Parcel& data,
+                                       const camera_metadata_t* metadata) {
+    status_t res = OK;
+
+    // arg0 = metadataSize (int32)
+
+    if (metadata == NULL) {
+        return data.writeInt32(0);
+    }
+
+    const size_t metadataSize = get_camera_metadata_compact_size(metadata);
+    res = data.writeInt32(static_cast<int32_t>(metadataSize));
+    if (res != OK) {
+        return res;
+    }
+
+    // arg1 = metadata (blob)
+    WritableBlob blob;
+    do {
+        res = data.writeBlob(metadataSize, &blob);
+        if (res != OK) {
+            break;
+        }
+        copy_camera_metadata(blob.data(), metadataSize, metadata);
+
+        IF_ALOGV() {
+            if (validate_camera_metadata_structure(
+                        (const camera_metadata_t*)blob.data(),
+                        &metadataSize) != OK) {
+                ALOGV("%s: Failed to validate metadata %p after writing blob",
+                       __FUNCTION__, blob.data());
+            } else {
+                ALOGV("%s: Metadata written to blob. Validation success",
+                        __FUNCTION__);
+            }
+        }
+
+        // Not too big of a problem since receiving side does hard validation
+        // Don't check the size since the compact size could be larger
+        if (validate_camera_metadata_structure(metadata, /*size*/NULL) != OK) {
+            ALOGW("%s: Failed to validate metadata %p before writing blob",
+                   __FUNCTION__, metadata);
+        }
+
+    } while(false);
+    blob.release();
+
+    return res;
+}
+
+status_t CameraMetadata::readFromParcel(Parcel *parcel) {
+
+    ALOGV("%s: parcel = %p", __FUNCTION__, parcel);
+
+    status_t res = OK;
+
+    if (parcel == NULL) {
+        ALOGE("%s: parcel is null", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    camera_metadata *buffer = NULL;
+    // TODO: reading should return a status code, in case validation fails
+    res = CameraMetadata::readFromParcel(*parcel, &buffer);
+
+    if (res != NO_ERROR) {
+        ALOGE("%s: Failed to read from parcel. Metadata is unchanged.",
+              __FUNCTION__);
+        return res;
+    }
+
+    clear();
+    mBuffer = buffer;
+
+    return OK;
+}
+
+status_t CameraMetadata::writeToParcel(Parcel *parcel) const {
+
+    ALOGV("%s: parcel = %p", __FUNCTION__, parcel);
+
+    if (parcel == NULL) {
+        ALOGE("%s: parcel is null", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    return CameraMetadata::writeToParcel(*parcel, mBuffer);
+}
+
+void CameraMetadata::swap(CameraMetadata& other) {
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return;
+    } else if (other.mLocked) {
+        ALOGE("%s: Other CameraMetadata is locked", __FUNCTION__);
+        return;
+    }
+
+    camera_metadata* thisBuf = mBuffer;
+    camera_metadata* otherBuf = other.mBuffer;
+
+    other.mBuffer = thisBuf;
+    mBuffer = otherBuf;
+}
+
 }; // namespace android
diff --git a/camera/CameraParameters2.cpp b/camera/CameraParameters2.cpp
new file mode 100644
index 0000000..eac79e1
--- /dev/null
+++ b/camera/CameraParameters2.cpp
@@ -0,0 +1,381 @@
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "CameraParams2"
+// #define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <camera/CameraParameters2.h>
+
+namespace android {
+
+CameraParameters2::CameraParameters2()
+                : mMap()
+{
+}
+
+CameraParameters2::~CameraParameters2()
+{
+}
+
+String8 CameraParameters2::flatten() const
+{
+    String8 flattened("");
+    size_t size = mMap.size();
+
+    for (size_t i = 0; i < size; i++) {
+        String8 k, v;
+        k = mMap.keyAt(i);
+        v = mMap.valueAt(i);
+
+        flattened += k;
+        flattened += "=";
+        flattened += v;
+        if (i != size-1)
+            flattened += ";";
+    }
+
+    ALOGV("%s: Flattened params = %s", __FUNCTION__, flattened.string());
+
+    return flattened;
+}
+
+void CameraParameters2::unflatten(const String8 &params)
+{
+    const char *a = params.string();
+    const char *b;
+
+    mMap.clear();
+
+    for (;;) {
+        // Find the bounds of the key name.
+        b = strchr(a, '=');
+        if (b == 0)
+            break;
+
+        // Create the key string.
+        String8 k(a, (size_t)(b-a));
+
+        // Find the value.
+        a = b+1;
+        b = strchr(a, ';');
+        if (b == 0) {
+            // If there's no semicolon, this is the last item.
+            String8 v(a);
+            mMap.add(k, v);
+            break;
+        }
+
+        String8 v(a, (size_t)(b-a));
+        mMap.add(k, v);
+        a = b+1;
+    }
+}
+
+
+void CameraParameters2::set(const char *key, const char *value)
+{
+    // XXX i think i can do this with strspn()
+    if (strchr(key, '=') || strchr(key, ';')) {
+        //XXX ALOGE("Key \"%s\"contains invalid character (= or ;)", key);
+        return;
+    }
+
+    if (strchr(value, '=') || strchr(value, ';')) {
+        //XXX ALOGE("Value \"%s\"contains invalid character (= or ;)", value);
+        return;
+    }
+
+    // Replacing a value updates the key's order to be the new largest order
+    ssize_t res = mMap.replaceValueFor(String8(key), String8(value));
+    LOG_ALWAYS_FATAL_IF(res < 0, "replaceValueFor(%s,%s) failed", key, value);
+}
+
+void CameraParameters2::set(const char *key, int value)
+{
+    char str[16];
+    sprintf(str, "%d", value);
+    set(key, str);
+}
+
+void CameraParameters2::setFloat(const char *key, float value)
+{
+    char str[16];  // 14 should be enough. We overestimate to be safe.
+    snprintf(str, sizeof(str), "%g", value);
+    set(key, str);
+}
+
+const char *CameraParameters2::get(const char *key) const
+{
+    ssize_t idx = mMap.indexOfKey(String8(key));
+    if (idx < 0) {
+        return NULL;
+    } else {
+        return mMap.valueAt(idx).string();
+    }
+}
+
+int CameraParameters2::getInt(const char *key) const
+{
+    const char *v = get(key);
+    if (v == 0)
+        return -1;
+    return strtol(v, 0, 0);
+}
+
+float CameraParameters2::getFloat(const char *key) const
+{
+    const char *v = get(key);
+    if (v == 0) return -1;
+    return strtof(v, 0);
+}
+
+status_t CameraParameters2::compareSetOrder(const char *key1, const char *key2,
+        int *order) const {
+    if (key1 == NULL) {
+        ALOGE("%s: key1 must not be NULL", __FUNCTION__);
+        return BAD_VALUE;
+    } else if (key2 == NULL) {
+        ALOGE("%s: key2 must not be NULL", __FUNCTION__);
+        return BAD_VALUE;
+    } else if (order == NULL) {
+        ALOGE("%s: order must not be NULL", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    ssize_t index1 = mMap.indexOfKey(String8(key1));
+    ssize_t index2 = mMap.indexOfKey(String8(key2));
+    if (index1 < 0) {
+        ALOGW("%s: Key1 (%s) was not set", __FUNCTION__, key1);
+        return NAME_NOT_FOUND;
+    } else if (index2 < 0) {
+        ALOGW("%s: Key2 (%s) was not set", __FUNCTION__, key2);
+        return NAME_NOT_FOUND;
+    }
+
+    *order = (index1 == index2) ? 0  :
+             (index1 < index2)  ? -1 :
+             1;
+
+    return OK;
+}
+
+void CameraParameters2::remove(const char *key)
+{
+    mMap.removeItem(String8(key));
+}
+
+// Parse string like "640x480" or "10000,20000"
+static int parse_pair(const char *str, int *first, int *second, char delim,
+                      char **endptr = NULL)
+{
+    // Find the first integer.
+    char *end;
+    int w = (int)strtol(str, &end, 10);
+    // If a delimeter does not immediately follow, give up.
+    if (*end != delim) {
+        ALOGE("Cannot find delimeter (%c) in str=%s", delim, str);
+        return -1;
+    }
+
+    // Find the second integer, immediately after the delimeter.
+    int h = (int)strtol(end+1, &end, 10);
+
+    *first = w;
+    *second = h;
+
+    if (endptr) {
+        *endptr = end;
+    }
+
+    return 0;
+}
+
+static void parseSizesList(const char *sizesStr, Vector<Size> &sizes)
+{
+    if (sizesStr == 0) {
+        return;
+    }
+
+    char *sizeStartPtr = (char *)sizesStr;
+
+    while (true) {
+        int width, height;
+        int success = parse_pair(sizeStartPtr, &width, &height, 'x',
+                                 &sizeStartPtr);
+        if (success == -1 || (*sizeStartPtr != ',' && *sizeStartPtr != '\0')) {
+            ALOGE("Picture sizes string \"%s\" contains invalid character.", sizesStr);
+            return;
+        }
+        sizes.push(Size(width, height));
+
+        if (*sizeStartPtr == '\0') {
+            return;
+        }
+        sizeStartPtr++;
+    }
+}
+
+void CameraParameters2::setPreviewSize(int width, int height)
+{
+    char str[32];
+    sprintf(str, "%dx%d", width, height);
+    set(CameraParameters::KEY_PREVIEW_SIZE, str);
+}
+
+void CameraParameters2::getPreviewSize(int *width, int *height) const
+{
+    *width = *height = -1;
+    // Get the current string, if it doesn't exist, leave the -1x-1
+    const char *p = get(CameraParameters::KEY_PREVIEW_SIZE);
+    if (p == 0)  return;
+    parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters2::getPreferredPreviewSizeForVideo(int *width, int *height) const
+{
+    *width = *height = -1;
+    const char *p = get(CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO);
+    if (p == 0)  return;
+    parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters2::getSupportedPreviewSizes(Vector<Size> &sizes) const
+{
+    const char *previewSizesStr = get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES);
+    parseSizesList(previewSizesStr, sizes);
+}
+
+void CameraParameters2::setVideoSize(int width, int height)
+{
+    char str[32];
+    sprintf(str, "%dx%d", width, height);
+    set(CameraParameters::KEY_VIDEO_SIZE, str);
+}
+
+void CameraParameters2::getVideoSize(int *width, int *height) const
+{
+    *width = *height = -1;
+    const char *p = get(CameraParameters::KEY_VIDEO_SIZE);
+    if (p == 0) return;
+    parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters2::getSupportedVideoSizes(Vector<Size> &sizes) const
+{
+    const char *videoSizesStr = get(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES);
+    parseSizesList(videoSizesStr, sizes);
+}
+
+void CameraParameters2::setPreviewFrameRate(int fps)
+{
+    set(CameraParameters::KEY_PREVIEW_FRAME_RATE, fps);
+}
+
+int CameraParameters2::getPreviewFrameRate() const
+{
+    return getInt(CameraParameters::KEY_PREVIEW_FRAME_RATE);
+}
+
+void CameraParameters2::getPreviewFpsRange(int *min_fps, int *max_fps) const
+{
+    *min_fps = *max_fps = -1;
+    const char *p = get(CameraParameters::KEY_PREVIEW_FPS_RANGE);
+    if (p == 0) return;
+    parse_pair(p, min_fps, max_fps, ',');
+}
+
+void CameraParameters2::setPreviewFpsRange(int min_fps, int max_fps)
+{
+    String8 str = String8::format("%d,%d", min_fps, max_fps);
+    set(CameraParameters::KEY_PREVIEW_FPS_RANGE, str.string());
+}
+
+void CameraParameters2::setPreviewFormat(const char *format)
+{
+    set(CameraParameters::KEY_PREVIEW_FORMAT, format);
+}
+
+const char *CameraParameters2::getPreviewFormat() const
+{
+    return get(CameraParameters::KEY_PREVIEW_FORMAT);
+}
+
+void CameraParameters2::setPictureSize(int width, int height)
+{
+    char str[32];
+    sprintf(str, "%dx%d", width, height);
+    set(CameraParameters::KEY_PICTURE_SIZE, str);
+}
+
+void CameraParameters2::getPictureSize(int *width, int *height) const
+{
+    *width = *height = -1;
+    // Get the current string, if it doesn't exist, leave the -1x-1
+    const char *p = get(CameraParameters::KEY_PICTURE_SIZE);
+    if (p == 0) return;
+    parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters2::getSupportedPictureSizes(Vector<Size> &sizes) const
+{
+    const char *pictureSizesStr = get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES);
+    parseSizesList(pictureSizesStr, sizes);
+}
+
+void CameraParameters2::setPictureFormat(const char *format)
+{
+    set(CameraParameters::KEY_PICTURE_FORMAT, format);
+}
+
+const char *CameraParameters2::getPictureFormat() const
+{
+    return get(CameraParameters::KEY_PICTURE_FORMAT);
+}
+
+void CameraParameters2::dump() const
+{
+    ALOGD("dump: mMap.size = %d", mMap.size());
+    for (size_t i = 0; i < mMap.size(); i++) {
+        String8 k, v;
+        k = mMap.keyAt(i);
+        v = mMap.valueAt(i);
+        ALOGD("%s: %s\n", k.string(), v.string());
+    }
+}
+
+status_t CameraParameters2::dump(int fd, const Vector<String16>& args) const
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, 255, "CameraParameters2::dump: mMap.size = %zu\n", mMap.size());
+    result.append(buffer);
+    for (size_t i = 0; i < mMap.size(); i++) {
+        String8 k, v;
+        k = mMap.keyAt(i);
+        v = mMap.valueAt(i);
+        snprintf(buffer, 255, "\t%s: %s\n", k.string(), v.string());
+        result.append(buffer);
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/camera/ICamera.cpp b/camera/ICamera.cpp
index 8900867..8c6e1f7 100644
--- a/camera/ICamera.cpp
+++ b/camera/ICamera.cpp
@@ -29,8 +29,9 @@
 
 enum {
     DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
-    SET_PREVIEW_TEXTURE,
+    SET_PREVIEW_TARGET,
     SET_PREVIEW_CALLBACK_FLAG,
+    SET_PREVIEW_CALLBACK_TARGET,
     START_PREVIEW,
     STOP_PREVIEW,
     AUTO_FOCUS,
@@ -65,17 +66,18 @@
         Parcel data, reply;
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
         remote()->transact(DISCONNECT, data, &reply);
+        reply.readExceptionCode();
     }
 
     // pass the buffered IGraphicBufferProducer to the camera service
-    status_t setPreviewTexture(const sp<IGraphicBufferProducer>& bufferProducer)
+    status_t setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer)
     {
-        ALOGV("setPreviewTexture");
+        ALOGV("setPreviewTarget");
         Parcel data, reply;
         data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
         sp<IBinder> b(bufferProducer->asBinder());
         data.writeStrongBinder(b);
-        remote()->transact(SET_PREVIEW_TEXTURE, data, &reply);
+        remote()->transact(SET_PREVIEW_TARGET, data, &reply);
         return reply.readInt32();
     }
 
@@ -90,7 +92,19 @@
         remote()->transact(SET_PREVIEW_CALLBACK_FLAG, data, &reply);
     }
 
-    // start preview mode, must call setPreviewDisplay first
+    status_t setPreviewCallbackTarget(
+            const sp<IGraphicBufferProducer>& callbackProducer)
+    {
+        ALOGV("setPreviewCallbackTarget");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        sp<IBinder> b(callbackProducer->asBinder());
+        data.writeStrongBinder(b);
+        remote()->transact(SET_PREVIEW_CALLBACK_TARGET, data, &reply);
+        return reply.readInt32();
+    }
+
+    // start preview mode, must call setPreviewTarget first
     status_t startPreview()
     {
         ALOGV("startPreview");
@@ -100,7 +114,7 @@
         return reply.readInt32();
     }
 
-    // start recording mode, must call setPreviewDisplay first
+    // start recording mode, must call setPreviewTarget first
     status_t startRecording()
     {
         ALOGV("startRecording");
@@ -268,14 +282,15 @@
             ALOGV("DISCONNECT");
             CHECK_INTERFACE(ICamera, data, reply);
             disconnect();
+            reply->writeNoException();
             return NO_ERROR;
         } break;
-        case SET_PREVIEW_TEXTURE: {
-            ALOGV("SET_PREVIEW_TEXTURE");
+        case SET_PREVIEW_TARGET: {
+            ALOGV("SET_PREVIEW_TARGET");
             CHECK_INTERFACE(ICamera, data, reply);
             sp<IGraphicBufferProducer> st =
                 interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
-            reply->writeInt32(setPreviewTexture(st));
+            reply->writeInt32(setPreviewTarget(st));
             return NO_ERROR;
         } break;
         case SET_PREVIEW_CALLBACK_FLAG: {
@@ -285,6 +300,14 @@
             setPreviewCallbackFlag(callback_flag);
             return NO_ERROR;
         } break;
+        case SET_PREVIEW_CALLBACK_TARGET: {
+            ALOGV("SET_PREVIEW_CALLBACK_TARGET");
+            CHECK_INTERFACE(ICamera, data, reply);
+            sp<IGraphicBufferProducer> cp =
+                interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
+            reply->writeInt32(setPreviewCallbackTarget(cp));
+            return NO_ERROR;
+        }
         case START_PREVIEW: {
             ALOGV("START_PREVIEW");
             CHECK_INTERFACE(ICamera, data, reply);
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index 134f7f0..5fc89fb 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -15,6 +15,9 @@
 ** limitations under the License.
 */
 
+#define LOG_TAG "BpCameraService"
+#include <utils/Log.h>
+
 #include <stdint.h>
 #include <sys/types.h>
 
@@ -28,9 +31,59 @@
 #include <camera/IProCameraCallbacks.h>
 #include <camera/ICamera.h>
 #include <camera/ICameraClient.h>
+#include <camera/camera2/ICameraDeviceUser.h>
+#include <camera/camera2/ICameraDeviceCallbacks.h>
+#include <camera/CameraMetadata.h>
 
 namespace android {
 
+namespace {
+
+enum {
+    EX_SECURITY = -1,
+    EX_BAD_PARCELABLE = -2,
+    EX_ILLEGAL_ARGUMENT = -3,
+    EX_NULL_POINTER = -4,
+    EX_ILLEGAL_STATE = -5,
+    EX_HAS_REPLY_HEADER = -128,  // special; see below
+};
+
+static bool readExceptionCode(Parcel& reply) {
+    int32_t exceptionCode = reply.readExceptionCode();
+
+    if (exceptionCode != 0) {
+        const char* errorMsg;
+        switch(exceptionCode) {
+            case EX_SECURITY:
+                errorMsg = "Security";
+                break;
+            case EX_BAD_PARCELABLE:
+                errorMsg = "BadParcelable";
+                break;
+            case EX_NULL_POINTER:
+                errorMsg = "NullPointer";
+                break;
+            case EX_ILLEGAL_STATE:
+                errorMsg = "IllegalState";
+                break;
+            // Binder should be handling this code inside Parcel::readException
+            // but lets have a to-string here anyway just in case.
+            case EX_HAS_REPLY_HEADER:
+                errorMsg = "HasReplyHeader";
+                break;
+            default:
+                errorMsg = "Unknown";
+        }
+
+        ALOGE("Binder transmission error %s (%d)", errorMsg, exceptionCode);
+        return true;
+    }
+
+    return false;
+}
+
+};
+
 class BpCameraService: public BpInterface<ICameraService>
 {
 public:
@@ -45,6 +98,8 @@
         Parcel data, reply;
         data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
         remote()->transact(BnCameraService::GET_NUMBER_OF_CAMERAS, data, &reply);
+
+        if (readExceptionCode(reply)) return 0;
         return reply.readInt32();
     }
 
@@ -55,14 +110,44 @@
         data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
         data.writeInt32(cameraId);
         remote()->transact(BnCameraService::GET_CAMERA_INFO, data, &reply);
-        cameraInfo->facing = reply.readInt32();
-        cameraInfo->orientation = reply.readInt32();
-        return reply.readInt32();
+
+        if (readExceptionCode(reply)) return -EPROTO;
+        status_t result = reply.readInt32();
+        if (reply.readInt32() != 0) {
+            cameraInfo->facing = reply.readInt32();
+            cameraInfo->orientation = reply.readInt32();
+        }
+        return result;
     }
 
-    // connect to camera service
-    virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId,
-                                const String16 &clientPackageName, int clientUid)
+    // get camera characteristics (static metadata)
+    virtual status_t getCameraCharacteristics(int cameraId,
+                                              CameraMetadata* cameraInfo) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
+        data.writeInt32(cameraId);
+        remote()->transact(BnCameraService::GET_CAMERA_CHARACTERISTICS, data, &reply);
+
+        if (readExceptionCode(reply)) return -EPROTO;
+        status_t result = reply.readInt32();
+
+        CameraMetadata out;
+        if (reply.readInt32() != 0) {
+            out.readFromParcel(&reply);
+        }
+
+        if (cameraInfo != NULL) {
+            cameraInfo->swap(out);
+        }
+
+        return result;
+    }
+
+    // connect to camera service (android.hardware.Camera)
+    virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
+                             const String16 &clientPackageName, int clientUid,
+                             /*out*/
+                             sp<ICamera>& device)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
@@ -71,12 +156,20 @@
         data.writeString16(clientPackageName);
         data.writeInt32(clientUid);
         remote()->transact(BnCameraService::CONNECT, data, &reply);
-        return interface_cast<ICamera>(reply.readStrongBinder());
+
+        if (readExceptionCode(reply)) return -EPROTO;
+        status_t status = reply.readInt32();
+        if (reply.readInt32() != 0) {
+            device = interface_cast<ICamera>(reply.readStrongBinder());
+        }
+        return status;
     }
 
     // connect to camera service (pro client)
-    virtual sp<IProCameraUser> connect(const sp<IProCameraCallbacks>& cameraCb, int cameraId,
-                                       const String16 &clientPackageName, int clientUid)
+    virtual status_t connectPro(const sp<IProCameraCallbacks>& cameraCb, int cameraId,
+                                const String16 &clientPackageName, int clientUid,
+                                /*out*/
+                                sp<IProCameraUser>& device)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
@@ -85,7 +178,38 @@
         data.writeString16(clientPackageName);
         data.writeInt32(clientUid);
         remote()->transact(BnCameraService::CONNECT_PRO, data, &reply);
-        return interface_cast<IProCameraUser>(reply.readStrongBinder());
+
+        if (readExceptionCode(reply)) return -EPROTO;
+        status_t status = reply.readInt32();
+        if (reply.readInt32() != 0) {
+            device = interface_cast<IProCameraUser>(reply.readStrongBinder());
+        }
+        return status;
+    }
+
+    // connect to camera service (android.hardware.camera2.CameraDevice)
+    virtual status_t connectDevice(
+            const sp<ICameraDeviceCallbacks>& cameraCb,
+            int cameraId,
+            const String16& clientPackageName,
+            int clientUid,
+            /*out*/
+            sp<ICameraDeviceUser>& device)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
+        data.writeStrongBinder(cameraCb->asBinder());
+        data.writeInt32(cameraId);
+        data.writeString16(clientPackageName);
+        data.writeInt32(clientUid);
+        remote()->transact(BnCameraService::CONNECT_DEVICE, data, &reply);
+
+        if (readExceptionCode(reply)) return -EPROTO;
+        status_t status = reply.readInt32();
+        if (reply.readInt32() != 0) {
+            device = interface_cast<ICameraDeviceUser>(reply.readStrongBinder());
+        }
+        return status;
     }
 
     virtual status_t addListener(const sp<ICameraServiceListener>& listener)
@@ -94,6 +218,8 @@
         data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
         data.writeStrongBinder(listener->asBinder());
         remote()->transact(BnCameraService::ADD_LISTENER, data, &reply);
+
+        if (readExceptionCode(reply)) return -EPROTO;
         return reply.readInt32();
     }
 
@@ -103,6 +229,8 @@
         data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
         data.writeStrongBinder(listener->asBinder());
         remote()->transact(BnCameraService::REMOVE_LISTENER, data, &reply);
+
+        if (readExceptionCode(reply)) return -EPROTO;
         return reply.readInt32();
     }
 };
@@ -117,17 +245,34 @@
     switch(code) {
         case GET_NUMBER_OF_CAMERAS: {
             CHECK_INTERFACE(ICameraService, data, reply);
+            reply->writeNoException();
             reply->writeInt32(getNumberOfCameras());
             return NO_ERROR;
         } break;
         case GET_CAMERA_INFO: {
             CHECK_INTERFACE(ICameraService, data, reply);
-            CameraInfo cameraInfo;
+            CameraInfo cameraInfo = CameraInfo();
             memset(&cameraInfo, 0, sizeof(cameraInfo));
             status_t result = getCameraInfo(data.readInt32(), &cameraInfo);
+            reply->writeNoException();
+            reply->writeInt32(result);
+
+            // Fake a parcelable object here
+            reply->writeInt32(1); // means the parcelable is included
             reply->writeInt32(cameraInfo.facing);
             reply->writeInt32(cameraInfo.orientation);
+            return NO_ERROR;
+        } break;
+        case GET_CAMERA_CHARACTERISTICS: {
+            CHECK_INTERFACE(ICameraService, data, reply);
+            CameraMetadata info;
+            status_t result = getCameraCharacteristics(data.readInt32(), &info);
+            reply->writeNoException();
             reply->writeInt32(result);
+
+            // out-variables are after exception and return value
+            reply->writeInt32(1); // means the parcelable is included
+            info.writeToParcel(reply);
             return NO_ERROR;
         } break;
         case CONNECT: {
@@ -137,26 +282,64 @@
             int32_t cameraId = data.readInt32();
             const String16 clientName = data.readString16();
             int32_t clientUid = data.readInt32();
-            sp<ICamera> camera = connect(cameraClient, cameraId,
-                    clientName, clientUid);
-            reply->writeStrongBinder(camera->asBinder());
+            sp<ICamera> camera;
+            status_t status = connect(cameraClient, cameraId,
+                    clientName, clientUid, /*out*/ camera);
+            reply->writeNoException();
+            reply->writeInt32(status);
+            if (camera != NULL) {
+                reply->writeInt32(1);
+                reply->writeStrongBinder(camera->asBinder());
+            } else {
+                reply->writeInt32(0);
+            }
             return NO_ERROR;
         } break;
         case CONNECT_PRO: {
             CHECK_INTERFACE(ICameraService, data, reply);
-            sp<IProCameraCallbacks> cameraClient = interface_cast<IProCameraCallbacks>(data.readStrongBinder());
+            sp<IProCameraCallbacks> cameraClient =
+                interface_cast<IProCameraCallbacks>(data.readStrongBinder());
             int32_t cameraId = data.readInt32();
             const String16 clientName = data.readString16();
             int32_t clientUid = data.readInt32();
-            sp<IProCameraUser> camera = connect(cameraClient, cameraId,
-                                                clientName, clientUid);
-            reply->writeStrongBinder(camera->asBinder());
+            sp<IProCameraUser> camera;
+            status_t status = connectPro(cameraClient, cameraId,
+                    clientName, clientUid, /*out*/ camera);
+            reply->writeNoException();
+            reply->writeInt32(status);
+            if (camera != NULL) {
+                reply->writeInt32(1);
+                reply->writeStrongBinder(camera->asBinder());
+            } else {
+                reply->writeInt32(0);
+            }
+            return NO_ERROR;
+        } break;
+        case CONNECT_DEVICE: {
+            CHECK_INTERFACE(ICameraService, data, reply);
+            sp<ICameraDeviceCallbacks> cameraClient =
+                interface_cast<ICameraDeviceCallbacks>(data.readStrongBinder());
+            int32_t cameraId = data.readInt32();
+            const String16 clientName = data.readString16();
+            int32_t clientUid = data.readInt32();
+            sp<ICameraDeviceUser> camera;
+            status_t status = connectDevice(cameraClient, cameraId,
+                    clientName, clientUid, /*out*/ camera);
+            reply->writeNoException();
+            reply->writeInt32(status);
+            if (camera != NULL) {
+                reply->writeInt32(1);
+                reply->writeStrongBinder(camera->asBinder());
+            } else {
+                reply->writeInt32(0);
+            }
             return NO_ERROR;
         } break;
         case ADD_LISTENER: {
             CHECK_INTERFACE(ICameraService, data, reply);
             sp<ICameraServiceListener> listener =
                 interface_cast<ICameraServiceListener>(data.readStrongBinder());
+            reply->writeNoException();
             reply->writeInt32(addListener(listener));
             return NO_ERROR;
         } break;
@@ -164,6 +347,7 @@
             CHECK_INTERFACE(ICameraService, data, reply);
             sp<ICameraServiceListener> listener =
                 interface_cast<ICameraServiceListener>(data.readStrongBinder());
+            reply->writeNoException();
             reply->writeInt32(removeListener(listener));
             return NO_ERROR;
         } break;
diff --git a/camera/ICameraServiceListener.cpp b/camera/ICameraServiceListener.cpp
index 640ee35..b2f1729 100644
--- a/camera/ICameraServiceListener.cpp
+++ b/camera/ICameraServiceListener.cpp
@@ -54,6 +54,8 @@
                            data,
                            &reply,
                            IBinder::FLAG_ONEWAY);
+
+        reply.readExceptionCode();
     }
 };
 
@@ -73,6 +75,7 @@
             int32_t cameraId = data.readInt32();
 
             onStatusChanged(status, cameraId);
+            reply->writeNoException();
 
             return NO_ERROR;
         } break;
diff --git a/camera/IProCameraCallbacks.cpp b/camera/IProCameraCallbacks.cpp
index b9cd14d..bd3d420 100644
--- a/camera/IProCameraCallbacks.cpp
+++ b/camera/IProCameraCallbacks.cpp
@@ -28,7 +28,7 @@
 
 #include <camera/IProCameraCallbacks.h>
 
-#include <system/camera_metadata.h>
+#include "camera/CameraMetadata.h"
 
 namespace android {
 
@@ -38,9 +38,6 @@
     RESULT_RECEIVED,
 };
 
-void readMetadata(const Parcel& data, camera_metadata_t** out);
-void writeMetadata(Parcel& data, camera_metadata_t* metadata);
-
 class BpProCameraCallbacks: public BpInterface<IProCameraCallbacks>
 {
 public:
@@ -70,12 +67,12 @@
                            IBinder::FLAG_ONEWAY);
     }
 
-    void onResultReceived(int32_t frameId, camera_metadata* result) {
+    void onResultReceived(int32_t requestId, camera_metadata* result) {
         ALOGV("onResultReceived");
         Parcel data, reply;
         data.writeInterfaceToken(IProCameraCallbacks::getInterfaceDescriptor());
-        data.writeInt32(frameId);
-        writeMetadata(data, result);
+        data.writeInt32(requestId);
+        CameraMetadata::writeToParcel(data, result);
         remote()->transact(RESULT_RECEIVED, data, &reply, IBinder::FLAG_ONEWAY);
     }
 };
@@ -110,10 +107,10 @@
         case RESULT_RECEIVED: {
             ALOGV("RESULT_RECEIVED");
             CHECK_INTERFACE(IProCameraCallbacks, data, reply);
-            int32_t frameId = data.readInt32();
+            int32_t requestId = data.readInt32();
             camera_metadata_t *result = NULL;
-            readMetadata(data, &result);
-            onResultReceived(frameId, result);
+            CameraMetadata::readFromParcel(data, &result);
+            onResultReceived(requestId, result);
             return NO_ERROR;
             break;
         }
diff --git a/camera/IProCameraUser.cpp b/camera/IProCameraUser.cpp
index 4c4dec3..8f22124 100644
--- a/camera/IProCameraUser.cpp
+++ b/camera/IProCameraUser.cpp
@@ -15,7 +15,7 @@
 ** limitations under the License.
 */
 
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 #define LOG_TAG "IProCameraUser"
 #include <utils/Log.h>
 #include <stdint.h>
@@ -24,13 +24,10 @@
 #include <camera/IProCameraUser.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/Surface.h>
-#include <system/camera_metadata.h>
+#include "camera/CameraMetadata.h"
 
 namespace android {
 
-typedef Parcel::WritableBlob WritableBlob;
-typedef Parcel::ReadableBlob ReadableBlob;
-
 enum {
     DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
     CONNECT,
@@ -46,107 +43,6 @@
     GET_CAMERA_INFO,
 };
 
-/**
-  * Caller becomes the owner of the new metadata
-  * 'const Parcel' doesnt prevent us from calling the read functions.
-  *  which is interesting since it changes the internal state
-  *
-  * NULL can be returned when no metadata was sent, OR if there was an issue
-  * unpacking the serialized data (i.e. bad parcel or invalid structure).
-  */
-void readMetadata(const Parcel& data, camera_metadata_t** out) {
-
-    status_t err = OK;
-
-    camera_metadata_t* metadata = NULL;
-
-    if (out) {
-        *out = NULL;
-    }
-
-    // arg0 = metadataSize (int32)
-    int32_t metadataSizeTmp = -1;
-    if ((err = data.readInt32(&metadataSizeTmp)) != OK) {
-        ALOGE("%s: Failed to read metadata size (error %d %s)",
-              __FUNCTION__, err, strerror(-err));
-        return;
-    }
-    const size_t metadataSize = static_cast<size_t>(metadataSizeTmp);
-
-    if (metadataSize == 0) {
-        return;
-    }
-
-    // NOTE: this doesn't make sense to me. shouldnt the blob
-    // know how big it is? why do we have to specify the size
-    // to Parcel::readBlob ?
-
-    ReadableBlob blob;
-    // arg1 = metadata (blob)
-    do {
-        if ((err = data.readBlob(metadataSize, &blob)) != OK) {
-            ALOGE("%s: Failed to read metadata blob (sized %d). Possible "
-                  " serialization bug. Error %d %s",
-                  __FUNCTION__, metadataSize, err, strerror(-err));
-            break;
-        }
-        const camera_metadata_t* tmp =
-                       reinterpret_cast<const camera_metadata_t*>(blob.data());
-
-        metadata = allocate_copy_camera_metadata_checked(tmp, metadataSize);
-    } while(0);
-    blob.release();
-
-    if (out) {
-        *out = metadata;
-    } else if (metadata != NULL) {
-        free_camera_metadata(metadata);
-    }
-}
-
-/**
-  * Caller retains ownership of metadata
-  * - Write 2 (int32 + blob) args in the current position
-  */
-void writeMetadata(Parcel& data, camera_metadata_t* metadata) {
-    // arg0 = metadataSize (int32)
-
-    if (metadata == NULL) {
-        data.writeInt32(0);
-        return;
-    }
-
-    const size_t metadataSize = get_camera_metadata_compact_size(metadata);
-    data.writeInt32(static_cast<int32_t>(metadataSize));
-
-    // arg1 = metadata (blob)
-    WritableBlob blob;
-    {
-        data.writeBlob(metadataSize, &blob);
-        copy_camera_metadata(blob.data(), metadataSize, metadata);
-
-        IF_ALOGV() {
-            if (validate_camera_metadata_structure(
-                        (const camera_metadata_t*)blob.data(),
-                        &metadataSize) != OK) {
-                ALOGV("%s: Failed to validate metadata %p after writing blob",
-                       __FUNCTION__, blob.data());
-            } else {
-                ALOGV("%s: Metadata written to blob. Validation success",
-                        __FUNCTION__);
-            }
-        }
-
-        // Not too big of a problem since receiving side does hard validation
-        if (validate_camera_metadata_structure(metadata, &metadataSize) != OK) {
-            ALOGW("%s: Failed to validate metadata %p before writing blob",
-                   __FUNCTION__, metadata);
-        }
-
-    }
-    blob.release();
-}
-
 class BpProCameraUser: public BpInterface<IProCameraUser>
 {
 public:
@@ -162,6 +58,7 @@
         Parcel data, reply;
         data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor());
         remote()->transact(DISCONNECT, data, &reply);
+        reply.readExceptionCode();
     }
 
     virtual status_t connect(const sp<IProCameraCallbacks>& cameraClient)
@@ -213,7 +110,7 @@
         data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor());
 
         // arg0+arg1
-        writeMetadata(data, metadata);
+        CameraMetadata::writeToParcel(data, metadata);
 
         // arg2 = streaming (bool)
         data.writeInt32(streaming);
@@ -274,7 +171,7 @@
         data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor());
         data.writeInt32(templateId);
         remote()->transact(CREATE_DEFAULT_REQUEST, data, &reply);
-        readMetadata(reply, /*out*/request);
+        CameraMetadata::readFromParcel(reply, /*out*/request);
         return reply.readInt32();
     }
 
@@ -285,7 +182,7 @@
         data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor());
         data.writeInt32(cameraId);
         remote()->transact(GET_CAMERA_INFO, data, &reply);
-        readMetadata(reply, /*out*/info);
+        CameraMetadata::readFromParcel(reply, /*out*/info);
         return reply.readInt32();
     }
 
@@ -307,6 +204,7 @@
             ALOGV("DISCONNECT");
             CHECK_INTERFACE(IProCameraUser, data, reply);
             disconnect();
+            reply->writeNoException();
             return NO_ERROR;
         } break;
         case CONNECT: {
@@ -341,7 +239,7 @@
         case SUBMIT_REQUEST: {
             CHECK_INTERFACE(IProCameraUser, data, reply);
             camera_metadata_t* metadata;
-            readMetadata(data, /*out*/&metadata);
+            CameraMetadata::readFromParcel(data, /*out*/&metadata);
 
             // arg2 = streaming (bool)
             bool streaming = data.readInt32();
@@ -393,7 +291,7 @@
             status_t ret;
             ret = createDefaultRequest(templateId, &request);
 
-            writeMetadata(*reply, request);
+            CameraMetadata::writeToParcel(*reply, request);
             reply->writeInt32(ret);
 
             free_camera_metadata(request);
@@ -409,7 +307,7 @@
             status_t ret;
             ret = getCameraInfo(cameraId, &info);
 
-            writeMetadata(*reply, info);
+            CameraMetadata::writeToParcel(*reply, info);
             reply->writeInt32(ret);
 
             free_camera_metadata(info);
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index fec5461..ba5a48c 100644
--- a/camera/ProCamera.cpp
+++ b/camera/ProCamera.cpp
@@ -26,7 +26,6 @@
 #include <binder/IMemory.h>
 
 #include <camera/ProCamera.h>
-#include <camera/ICameraService.h>
 #include <camera/IProCameraUser.h>
 #include <camera/IProCameraCallbacks.h>
 
@@ -47,6 +46,9 @@
 {
 }
 
+CameraTraits<ProCamera>::TCamConnectService CameraTraits<ProCamera>::fnConnectService =
+        &ICameraService::connectPro;
+
 ProCamera::~ProCamera()
 {
 
@@ -88,8 +90,8 @@
     }
 }
 
-void ProCamera::onResultReceived(int32_t frameId, camera_metadata* result) {
-    ALOGV("%s: frameId = %d, result = %p", __FUNCTION__, frameId, result);
+void ProCamera::onResultReceived(int32_t requestId, camera_metadata* result) {
+    ALOGV("%s: requestId = %d, result = %p", __FUNCTION__, requestId, result);
 
     sp<ProCameraListener> listener;
     {
@@ -110,7 +112,7 @@
     result = tmp.release();
 
     if (listener != NULL) {
-        listener->onResultReceived(frameId, result);
+        listener->onResultReceived(requestId, result);
     } else {
         free_camera_metadata(result);
     }
@@ -247,11 +249,11 @@
     sp <IProCameraUser> c = mCamera;
     if (c == 0) return NO_INIT;
 
-    sp<CpuConsumer> cc = new CpuConsumer(heapCount, synchronousMode);
+    sp<BufferQueue> bq = new BufferQueue();
+    sp<CpuConsumer> cc = new CpuConsumer(bq, heapCount/*, synchronousMode*/);
     cc->setName(String8("ProCamera::mCpuConsumer"));
 
-    sp<Surface> stc = new Surface(
-        cc->getProducerInterface());
+    sp<Surface> stc = new Surface(bq);
 
     status_t s = createStream(width, height, format,
                               stc->getIGraphicBufferProducer(),
diff --git a/camera/camera2/CaptureRequest.cpp b/camera/camera2/CaptureRequest.cpp
new file mode 100644
index 0000000..57e5319
--- /dev/null
+++ b/camera/camera2/CaptureRequest.cpp
@@ -0,0 +1,124 @@
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "CameraRequest"
+#include <utils/Log.h>
+
+#include <camera/camera2/CaptureRequest.h>
+
+#include <binder/Parcel.h>
+#include <gui/Surface.h>
+
+namespace android {
+
+status_t CaptureRequest::readFromParcel(Parcel* parcel) {
+    if (parcel == NULL) {
+        ALOGE("%s: Null parcel", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    mMetadata.clear();
+    mSurfaceList.clear();
+
+    status_t err;
+
+    if ((err = mMetadata.readFromParcel(parcel)) != OK) {
+        ALOGE("%s: Failed to read metadata from parcel", __FUNCTION__);
+        return err;
+    }
+    ALOGV("%s: Read metadata from parcel", __FUNCTION__);
+
+    int32_t size;
+    if ((err = parcel->readInt32(&size)) != OK) {
+        ALOGE("%s: Failed to read surface list size from parcel", __FUNCTION__);
+        return err;
+    }
+    ALOGV("%s: Read surface list size = %d", __FUNCTION__, size);
+
+    // Do not distinguish null arrays from 0-sized arrays.
+    for (int i = 0; i < size; ++i) {
+        // Parcel.writeParcelableArray
+        size_t len;
+        const char16_t* className = parcel->readString16Inplace(&len);
+        ALOGV("%s: Read surface class = %s", __FUNCTION__,
+              className != NULL ? String8(className).string() : "<null>");
+
+        if (className == NULL) {
+            continue;
+        }
+
+        // Surface.writeToParcel
+        String16 name = parcel->readString16();
+        ALOGV("%s: Read surface name = %s",
+              __FUNCTION__, String8(name).string());
+        sp<IBinder> binder(parcel->readStrongBinder());
+        ALOGV("%s: Read surface binder = %p",
+              __FUNCTION__, binder.get());
+
+        sp<Surface> surface;
+
+        if (binder != NULL) {
+            sp<IGraphicBufferProducer> gbp =
+                    interface_cast<IGraphicBufferProducer>(binder);
+            surface = new Surface(gbp);
+        }
+
+        mSurfaceList.push_back(surface);
+    }
+
+    return OK;
+}
+
+status_t CaptureRequest::writeToParcel(Parcel* parcel) const {
+    if (parcel == NULL) {
+        ALOGE("%s: Null parcel", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    status_t err;
+
+    if ((err = mMetadata.writeToParcel(parcel)) != OK) {
+        return err;
+    }
+
+    int32_t size = static_cast<int32_t>(mSurfaceList.size());
+
+    // Send 0-sized arrays when it's empty. Do not send null arrays.
+    parcel->writeInt32(size);
+
+    for (int32_t i = 0; i < size; ++i) {
+        sp<Surface> surface = mSurfaceList[i];
+
+        sp<IBinder> binder;
+        if (surface != 0) {
+            binder = surface->getIGraphicBufferProducer()->asBinder();
+        }
+
+        // not sure if readParcelableArray does this, hard to tell from source
+        parcel->writeString16(String16("android.view.Surface"));
+
+        // Surface.writeToParcel
+        parcel->writeString16(String16("unknown_name"));
+        // Surface.nativeWriteToParcel
+        parcel->writeStrongBinder(binder);
+    }
+
+    return OK;
+}
+
+}; // namespace android
diff --git a/camera/camera2/ICameraDeviceCallbacks.cpp b/camera/camera2/ICameraDeviceCallbacks.cpp
new file mode 100644
index 0000000..613358a
--- /dev/null
+++ b/camera/camera2/ICameraDeviceCallbacks.cpp
@@ -0,0 +1,148 @@
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ICameraDeviceCallbacks"
+#include <utils/Log.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
+#include <utils/Mutex.h>
+
+#include <camera/camera2/ICameraDeviceCallbacks.h>
+#include "camera/CameraMetadata.h"
+
+namespace android {
+
+enum {
+    CAMERA_ERROR = IBinder::FIRST_CALL_TRANSACTION,
+    CAMERA_IDLE,
+    CAPTURE_STARTED,
+    RESULT_RECEIVED,
+};
+
+class BpCameraDeviceCallbacks: public BpInterface<ICameraDeviceCallbacks>
+{
+public:
+    BpCameraDeviceCallbacks(const sp<IBinder>& impl)
+        : BpInterface<ICameraDeviceCallbacks>(impl)
+    {
+    }
+
+    void onDeviceError(CameraErrorCode errorCode)
+    {
+        ALOGV("onDeviceError");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor());
+        data.writeInt32(static_cast<int32_t>(errorCode));
+        remote()->transact(CAMERA_ERROR, data, &reply, IBinder::FLAG_ONEWAY);
+        data.writeNoException();
+    }
+
+    void onDeviceIdle()
+    {
+        ALOGV("onDeviceIdle");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor());
+        remote()->transact(CAMERA_IDLE, data, &reply, IBinder::FLAG_ONEWAY);
+        data.writeNoException();
+    }
+
+    void onCaptureStarted(int32_t requestId, int64_t timestamp)
+    {
+        ALOGV("onCaptureStarted");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor());
+        data.writeInt32(requestId);
+        data.writeInt64(timestamp);
+        remote()->transact(CAPTURE_STARTED, data, &reply, IBinder::FLAG_ONEWAY);
+        data.writeNoException();
+    }
+
+
+    void onResultReceived(int32_t requestId, const CameraMetadata& result) {
+        ALOGV("onResultReceived");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor());
+        data.writeInt32(requestId);
+        data.writeInt32(1); // to mark presence of metadata object
+        result.writeToParcel(&data);
+        remote()->transact(RESULT_RECEIVED, data, &reply, IBinder::FLAG_ONEWAY);
+        data.writeNoException();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(CameraDeviceCallbacks,
+                         "android.hardware.camera2.ICameraDeviceCallbacks");
+
+// ----------------------------------------------------------------------
+
+status_t BnCameraDeviceCallbacks::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    ALOGV("onTransact - code = %d", code);
+    switch(code) {
+        case CAMERA_ERROR: {
+            ALOGV("onDeviceError");
+            CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply);
+            CameraErrorCode errorCode =
+                    static_cast<CameraErrorCode>(data.readInt32());
+            onDeviceError(errorCode);
+            data.readExceptionCode();
+            return NO_ERROR;
+        } break;
+        case CAMERA_IDLE: {
+            ALOGV("onDeviceIdle");
+            CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply);
+            onDeviceIdle();
+            data.readExceptionCode();
+            return NO_ERROR;
+        } break;
+        case CAPTURE_STARTED: {
+            ALOGV("onCaptureStarted");
+            CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply);
+            int32_t requestId = data.readInt32();
+            int64_t timestamp = data.readInt64();
+            onCaptureStarted(requestId, timestamp);
+            data.readExceptionCode();
+            return NO_ERROR;
+        } break;
+        case RESULT_RECEIVED: {
+            ALOGV("onResultReceived");
+            CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply);
+            int32_t requestId = data.readInt32();
+            CameraMetadata result;
+            if (data.readInt32() != 0) {
+                result.readFromParcel(const_cast<Parcel*>(&data));
+            } else {
+                ALOGW("No metadata object is present in result");
+            }
+            onResultReceived(requestId, result);
+            data.readExceptionCode();
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/camera/camera2/ICameraDeviceUser.cpp b/camera/camera2/ICameraDeviceUser.cpp
new file mode 100644
index 0000000..1e5822f
--- /dev/null
+++ b/camera/camera2/ICameraDeviceUser.cpp
@@ -0,0 +1,352 @@
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "ICameraDeviceUser"
+#include <utils/Log.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/Parcel.h>
+#include <camera/camera2/ICameraDeviceUser.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
+#include <camera/CameraMetadata.h>
+#include <camera/camera2/CaptureRequest.h>
+
+namespace android {
+
+typedef Parcel::WritableBlob WritableBlob;
+typedef Parcel::ReadableBlob ReadableBlob;
+
+enum {
+    DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
+    SUBMIT_REQUEST,
+    CANCEL_REQUEST,
+    DELETE_STREAM,
+    CREATE_STREAM,
+    CREATE_DEFAULT_REQUEST,
+    GET_CAMERA_INFO,
+    WAIT_UNTIL_IDLE,
+    FLUSH
+};
+
+namespace {
+    // Read empty strings without printing a false error message.
+    String16 readMaybeEmptyString16(const Parcel& parcel) {
+        size_t len;
+        const char16_t* str = parcel.readString16Inplace(&len);
+        if (str != NULL) {
+            return String16(str, len);
+        } else {
+            return String16();
+        }
+    }
+};
+
+class BpCameraDeviceUser : public BpInterface<ICameraDeviceUser>
+{
+public:
+    BpCameraDeviceUser(const sp<IBinder>& impl)
+        : BpInterface<ICameraDeviceUser>(impl)
+    {
+    }
+
+    // disconnect from camera service
+    void disconnect()
+    {
+        ALOGV("disconnect");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        remote()->transact(DISCONNECT, data, &reply);
+        reply.readExceptionCode();
+    }
+
+    virtual int submitRequest(sp<CaptureRequest> request, bool streaming)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+
+        // arg0 = CaptureRequest
+        if (request != 0) {
+            data.writeInt32(1);
+            request->writeToParcel(&data);
+        } else {
+            data.writeInt32(0);
+        }
+
+        // arg1 = streaming (bool)
+        data.writeInt32(streaming);
+
+        remote()->transact(SUBMIT_REQUEST, data, &reply);
+
+        reply.readExceptionCode();
+        return reply.readInt32();
+    }
+
+    virtual status_t cancelRequest(int requestId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        data.writeInt32(requestId);
+
+        remote()->transact(CANCEL_REQUEST, data, &reply);
+
+        reply.readExceptionCode();
+        return reply.readInt32();
+    }
+
+    virtual status_t deleteStream(int streamId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        data.writeInt32(streamId);
+
+        remote()->transact(DELETE_STREAM, data, &reply);
+
+        reply.readExceptionCode();
+        return reply.readInt32();
+    }
+
+    virtual status_t createStream(int width, int height, int format,
+                          const sp<IGraphicBufferProducer>& bufferProducer)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        data.writeInt32(width);
+        data.writeInt32(height);
+        data.writeInt32(format);
+
+        data.writeInt32(1); // marker that bufferProducer is not null
+        data.writeString16(String16("unknown_name")); // name of surface
+        sp<IBinder> b(bufferProducer->asBinder());
+        data.writeStrongBinder(b);
+
+        remote()->transact(CREATE_STREAM, data, &reply);
+
+        reply.readExceptionCode();
+        return reply.readInt32();
+    }
+
+    // Create a request object from a template.
+    virtual status_t createDefaultRequest(int templateId,
+                                          /*out*/
+                                          CameraMetadata* request)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        data.writeInt32(templateId);
+        remote()->transact(CREATE_DEFAULT_REQUEST, data, &reply);
+
+        reply.readExceptionCode();
+        status_t result = reply.readInt32();
+
+        CameraMetadata out;
+        if (reply.readInt32() != 0) {
+            out.readFromParcel(&reply);
+        }
+
+        if (request != NULL) {
+            request->swap(out);
+        }
+        return result;
+    }
+
+
+    virtual status_t getCameraInfo(CameraMetadata* info)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        remote()->transact(GET_CAMERA_INFO, data, &reply);
+
+        reply.readExceptionCode();
+        status_t result = reply.readInt32();
+
+        CameraMetadata out;
+        if (reply.readInt32() != 0) {
+            out.readFromParcel(&reply);
+        }
+
+        if (info != NULL) {
+            info->swap(out);
+        }
+
+        return result;
+    }
+
+    virtual status_t waitUntilIdle()
+    {
+        ALOGV("waitUntilIdle");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        remote()->transact(WAIT_UNTIL_IDLE, data, &reply);
+        reply.readExceptionCode();
+        return reply.readInt32();
+    }
+
+    virtual status_t flush()
+    {
+        ALOGV("flush");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor());
+        remote()->transact(FLUSH, data, &reply);
+        reply.readExceptionCode();
+        return reply.readInt32();
+    }
+
+private:
+
+
+};
+
+IMPLEMENT_META_INTERFACE(CameraDeviceUser,
+                         "android.hardware.camera2.ICameraDeviceUser");
+
+// ----------------------------------------------------------------------
+
+status_t BnCameraDeviceUser::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case DISCONNECT: {
+            ALOGV("DISCONNECT");
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+            disconnect();
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
+        case SUBMIT_REQUEST: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+
+            // arg0 = request
+            sp<CaptureRequest> request;
+            if (data.readInt32() != 0) {
+                request = new CaptureRequest();
+                request->readFromParcel(const_cast<Parcel*>(&data));
+            }
+
+            // arg1 = streaming (bool)
+            bool streaming = data.readInt32();
+
+            // return code: requestId (int32)
+            reply->writeNoException();
+            reply->writeInt32(submitRequest(request, streaming));
+
+            return NO_ERROR;
+        } break;
+        case CANCEL_REQUEST: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+            int requestId = data.readInt32();
+            reply->writeNoException();
+            reply->writeInt32(cancelRequest(requestId));
+            return NO_ERROR;
+        } break;
+        case DELETE_STREAM: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+            int streamId = data.readInt32();
+            reply->writeNoException();
+            reply->writeInt32(deleteStream(streamId));
+            return NO_ERROR;
+        } break;
+        case CREATE_STREAM: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+            int width, height, format;
+
+            width = data.readInt32();
+            ALOGV("%s: CREATE_STREAM: width = %d", __FUNCTION__, width);
+            height = data.readInt32();
+            ALOGV("%s: CREATE_STREAM: height = %d", __FUNCTION__, height);
+            format = data.readInt32();
+            ALOGV("%s: CREATE_STREAM: format = %d", __FUNCTION__, format);
+
+            sp<IGraphicBufferProducer> bp;
+            if (data.readInt32() != 0) {
+                String16 name = readMaybeEmptyString16(data);
+                bp = interface_cast<IGraphicBufferProducer>(
+                        data.readStrongBinder());
+
+                ALOGV("%s: CREATE_STREAM: bp = %p, name = %s", __FUNCTION__,
+                      bp.get(), String8(name).string());
+            } else {
+                ALOGV("%s: CREATE_STREAM: bp = unset, name = unset",
+                      __FUNCTION__);
+            }
+
+            status_t ret;
+            ret = createStream(width, height, format, bp);
+
+            reply->writeNoException();
+            ALOGV("%s: CREATE_STREAM: write noException", __FUNCTION__);
+            reply->writeInt32(ret);
+            ALOGV("%s: CREATE_STREAM: write ret = %d", __FUNCTION__, ret);
+
+            return NO_ERROR;
+        } break;
+
+        case CREATE_DEFAULT_REQUEST: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+
+            int templateId = data.readInt32();
+
+            CameraMetadata request;
+            status_t ret;
+            ret = createDefaultRequest(templateId, &request);
+
+            reply->writeNoException();
+            reply->writeInt32(ret);
+
+            // out-variables are after exception and return value
+            reply->writeInt32(1); // to mark presence of metadata object
+            request.writeToParcel(const_cast<Parcel*>(reply));
+
+            return NO_ERROR;
+        } break;
+        case GET_CAMERA_INFO: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+
+            CameraMetadata info;
+            status_t ret;
+            ret = getCameraInfo(&info);
+
+            reply->writeNoException();
+            reply->writeInt32(ret);
+
+            // out-variables are after exception and return value
+            reply->writeInt32(1); // to mark presence of metadata object
+            info.writeToParcel(reply);
+
+            return NO_ERROR;
+        } break;
+        case WAIT_UNTIL_IDLE: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+            reply->writeNoException();
+            reply->writeInt32(waitUntilIdle());
+            return NO_ERROR;
+        } break;
+        case FLUSH: {
+            CHECK_INTERFACE(ICameraDeviceUser, data, reply);
+            reply->writeNoException();
+            reply->writeInt32(flush());
+            return NO_ERROR;
+        }
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp
index f203949..1f5867a 100644
--- a/camera/tests/ProCameraTests.cpp
+++ b/camera/tests/ProCameraTests.cpp
@@ -271,7 +271,6 @@
             CpuConsumer::LockedBuffer buf;
             status_t ret;
 
-            EXPECT_OK(ret);
             if (OK == (ret = consumer->lockNextBuffer(&buf))) {
 
                 dout << "Frame received on streamId = " << streamId <<
@@ -285,9 +284,9 @@
         }
     }
 
-    virtual void onResultReceived(int32_t frameId,
+    virtual void onResultReceived(int32_t requestId,
                                   camera_metadata* request) {
-        dout << "Result received frameId = " << frameId
+        dout << "Result received requestId = " << requestId
              << ", requestPtr = " << (void*)request << std::endl;
         QueueEvent(RESULT_RECEIVED);
         free_camera_metadata(request);
@@ -482,7 +481,7 @@
      * Creating a streaming request for these output streams from a template,
      *  and submit it
      */
-    void createSubmitRequestForStreams(uint8_t* streamIds, size_t count, int requestCount=-1) {
+    void createSubmitRequestForStreams(int32_t* streamIds, size_t count, int requestCount=-1) {
 
         ASSERT_NE((void*)NULL, streamIds);
         ASSERT_LT(0u, count);
@@ -629,7 +628,7 @@
 
             EXPECT_OK(mCamera->exclusiveTryLock());
 
-            uint8_t streams[] = { depthStreamId };
+            int32_t streams[] = { depthStreamId };
             ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(
                                                  streams,
                                                  /*count*/1));
@@ -706,7 +705,7 @@
     // set the output streams to just this stream ID
 
     // wow what a verbose API.
-    uint8_t allStreams[] = { streamId, depthStreamId };
+    int32_t allStreams[] = { streamId, depthStreamId };
     // IMPORTANT. bad things will happen if its not a uint8.
     size_t streamCount = sizeof(allStreams) / sizeof(allStreams[0]);
     camera_metadata_entry_t entry;
@@ -735,7 +734,7 @@
 
     free_camera_metadata(request);
 
-    for (int i = 0; i < streamCount; ++i) {
+    for (size_t i = 0; i < streamCount; ++i) {
         EXPECT_OK(mCamera->deleteStream(allStreams[i]));
     }
     EXPECT_OK(mCamera->exclusiveUnlock());
@@ -777,7 +776,7 @@
 
     // set the output streams to just this stream ID
 
-    uint8_t allStreams[] = { streamId };
+    int32_t allStreams[] = { streamId };
     camera_metadata_entry_t entry;
     uint32_t tag = static_cast<uint32_t>(ANDROID_REQUEST_OUTPUT_STREAMS);
     int find = find_camera_metadata_entry(request, tag, &entry);
@@ -848,7 +847,7 @@
     // set the output streams to just this stream ID
 
     // wow what a verbose API.
-    uint8_t allStreams[] = { streamId, depthStreamId };
+    int32_t allStreams[] = { streamId, depthStreamId };
     size_t streamCount = 2;
     camera_metadata_entry_t entry;
     uint32_t tag = static_cast<uint32_t>(ANDROID_REQUEST_OUTPUT_STREAMS);
@@ -923,7 +922,7 @@
 
     // set the output streams to just this stream ID
 
-    uint8_t allStreams[] = { streamId };
+    int32_t allStreams[] = { streamId };
     size_t streamCount = 1;
     camera_metadata_entry_t entry;
     uint32_t tag = static_cast<uint32_t>(ANDROID_REQUEST_OUTPUT_STREAMS);
@@ -974,7 +973,7 @@
 
     EXPECT_OK(mCamera->exclusiveTryLock());
 
-    uint8_t streams[] = { streamId };
+    int32_t streams[] = { streamId };
     ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/1));
 
     // Consume a couple of results
@@ -1002,7 +1001,7 @@
 
     EXPECT_OK(mCamera->exclusiveTryLock());
 
-    uint8_t streams[] = { streamId };
+    int32_t streams[] = { streamId };
     ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/1,
                                             /*requests*/TEST_CPU_FRAME_COUNT));
 
@@ -1049,7 +1048,7 @@
 
     EXPECT_OK(mCamera->exclusiveTryLock());
 
-    uint8_t streams[] = { streamId, depthStreamId };
+    int32_t streams[] = { streamId, depthStreamId };
     ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/2,
                                                     /*requests*/REQUEST_COUNT));
 
@@ -1128,7 +1127,7 @@
 
     EXPECT_OK(mCamera->exclusiveTryLock());
 
-    uint8_t streams[] = { streamId };
+    int32_t streams[] = { streamId };
     ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/1,
                                                      /*requests*/NUM_REQUESTS));
 
@@ -1172,7 +1171,6 @@
     }
 
     const int NUM_REQUESTS = 20 * TEST_CPU_FRAME_COUNT;
-    const int CONSECUTIVE_FAILS_ASSUME_TIME_OUT = 5;
 
     int streamId = -1;
     sp<CpuConsumer> consumer;
@@ -1183,7 +1181,7 @@
 
     EXPECT_OK(mCamera->exclusiveTryLock());
 
-    uint8_t streams[] = { streamId };
+    int32_t streams[] = { streamId };
     ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/1,
                                                      /*requests*/NUM_REQUESTS));
 
@@ -1278,4 +1276,3 @@
 }
 }
 }
-
diff --git a/cmds/screenrecord/Android.mk b/cmds/screenrecord/Android.mk
new file mode 100644
index 0000000..b4a5947
--- /dev/null
+++ b/cmds/screenrecord/Android.mk
@@ -0,0 +1,38 @@
+# Copyright 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+	screenrecord.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+	libstagefright libmedia libutils libbinder libstagefright_foundation \
+	libjpeg libgui libcutils liblog
+
+LOCAL_C_INCLUDES := \
+	frameworks/av/media/libstagefright \
+	frameworks/av/media/libstagefright/include \
+	$(TOP)/frameworks/native/include/media/openmax \
+	external/jpeg
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE:= screenrecord
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
new file mode 100644
index 0000000..49999b5
--- /dev/null
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -0,0 +1,739 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ScreenRecord"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <utils/Errors.h>
+#include <utils/Thread.h>
+#include <utils/Timers.h>
+
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/ISurfaceComposer.h>
+#include <ui/DisplayInfo.h>
+#include <media/openmax/OMX_IVCommon.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaMuxer.h>
+#include <media/ICrypto.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <getopt.h>
+#include <sys/wait.h>
+
+using namespace android;
+
+static const uint32_t kMinBitRate = 100000;         // 0.1Mbps
+static const uint32_t kMaxBitRate = 100 * 1000000;  // 100Mbps
+static const uint32_t kMaxTimeLimitSec = 180;       // 3 minutes
+static const uint32_t kFallbackWidth = 1280;        // 720p
+static const uint32_t kFallbackHeight = 720;
+
+// Command-line parameters.
+static bool gVerbose = false;               // chatty on stdout
+static bool gRotate = false;                // rotate 90 degrees
+static bool gSizeSpecified = false;         // was size explicitly requested?
+static uint32_t gVideoWidth = 0;            // default width+height
+static uint32_t gVideoHeight = 0;
+static uint32_t gBitRate = 4000000;         // 4Mbps
+static uint32_t gTimeLimitSec = kMaxTimeLimitSec;
+
+// Set by signal handler to stop recording.
+static bool gStopRequested;
+
+// Previous signal handler state, restored after first hit.
+static struct sigaction gOrigSigactionINT;
+static struct sigaction gOrigSigactionHUP;
+
+
+/*
+ * Catch keyboard interrupt signals.  On receipt, the "stop requested"
+ * flag is raised, and the original handler is restored (so that, if
+ * we get stuck finishing, a second Ctrl-C will kill the process).
+ */
+static void signalCatcher(int signum)
+{
+    gStopRequested = true;
+    switch (signum) {
+    case SIGINT:
+    case SIGHUP:
+        sigaction(SIGINT, &gOrigSigactionINT, NULL);
+        sigaction(SIGHUP, &gOrigSigactionHUP, NULL);
+        break;
+    default:
+        abort();
+        break;
+    }
+}
+
+/*
+ * Configures signal handlers.  The previous handlers are saved.
+ *
+ * If the command is run from an interactive adb shell, we get SIGINT
+ * when Ctrl-C is hit.  If we're run from the host, the local adb process
+ * gets the signal, and we get a SIGHUP when the terminal disconnects.
+ */
+static status_t configureSignals()
+{
+    struct sigaction act;
+    memset(&act, 0, sizeof(act));
+    act.sa_handler = signalCatcher;
+    if (sigaction(SIGINT, &act, &gOrigSigactionINT) != 0) {
+        status_t err = -errno;
+        fprintf(stderr, "Unable to configure SIGINT handler: %s\n",
+                strerror(errno));
+        return err;
+    }
+    if (sigaction(SIGHUP, &act, &gOrigSigactionHUP) != 0) {
+        status_t err = -errno;
+        fprintf(stderr, "Unable to configure SIGHUP handler: %s\n",
+                strerror(errno));
+        return err;
+    }
+    return NO_ERROR;
+}
+
+/*
+ * Returns "true" if the device is rotated 90 degrees.
+ */
+static bool isDeviceRotated(int orientation) {
+    return orientation != DISPLAY_ORIENTATION_0 &&
+            orientation != DISPLAY_ORIENTATION_180;
+}
+
+/*
+ * Configures and starts the MediaCodec encoder.  Obtains an input surface
+ * from the codec.
+ */
+static status_t prepareEncoder(float displayFps, sp<MediaCodec>* pCodec,
+        sp<IGraphicBufferProducer>* pBufferProducer) {
+    status_t err;
+
+    if (gVerbose) {
+        printf("Configuring recorder for %dx%d video at %.2fMbps\n",
+                gVideoWidth, gVideoHeight, gBitRate / 1000000.0);
+    }
+
+    sp<AMessage> format = new AMessage;
+    format->setInt32("width", gVideoWidth);
+    format->setInt32("height", gVideoHeight);
+    format->setString("mime", "video/avc");
+    format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
+    format->setInt32("bitrate", gBitRate);
+    format->setFloat("frame-rate", displayFps);
+    format->setInt32("i-frame-interval", 10);
+
+    sp<ALooper> looper = new ALooper;
+    looper->setName("screenrecord_looper");
+    looper->start();
+    ALOGV("Creating codec");
+    sp<MediaCodec> codec = MediaCodec::CreateByType(looper, "video/avc", true);
+    if (codec == NULL) {
+        fprintf(stderr, "ERROR: unable to create video/avc codec instance\n");
+        return UNKNOWN_ERROR;
+    }
+    err = codec->configure(format, NULL, NULL,
+            MediaCodec::CONFIGURE_FLAG_ENCODE);
+    if (err != NO_ERROR) {
+        codec->release();
+        codec.clear();
+
+        fprintf(stderr, "ERROR: unable to configure codec (err=%d)\n", err);
+        return err;
+    }
+
+    ALOGV("Creating buffer producer");
+    sp<IGraphicBufferProducer> bufferProducer;
+    err = codec->createInputSurface(&bufferProducer);
+    if (err != NO_ERROR) {
+        codec->release();
+        codec.clear();
+
+        fprintf(stderr,
+            "ERROR: unable to create encoder input surface (err=%d)\n", err);
+        return err;
+    }
+
+    ALOGV("Starting codec");
+    err = codec->start();
+    if (err != NO_ERROR) {
+        codec->release();
+        codec.clear();
+
+        fprintf(stderr, "ERROR: unable to start codec (err=%d)\n", err);
+        return err;
+    }
+
+    ALOGV("Codec prepared");
+    *pCodec = codec;
+    *pBufferProducer = bufferProducer;
+    return 0;
+}
+
+/*
+ * Configures the virtual display.  When this completes, virtual display
+ * frames will start being sent to the encoder's surface.
+ */
+static status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo,
+        const sp<IGraphicBufferProducer>& bufferProducer,
+        sp<IBinder>* pDisplayHandle) {
+    status_t err;
+
+    // Set the region of the layer stack we're interested in, which in our
+    // case is "all of it".  If the app is rotated (so that the width of the
+    // app is based on the height of the display), reverse width/height.
+    bool deviceRotated = isDeviceRotated(mainDpyInfo.orientation);
+    uint32_t sourceWidth, sourceHeight;
+    if (!deviceRotated) {
+        sourceWidth = mainDpyInfo.w;
+        sourceHeight = mainDpyInfo.h;
+    } else {
+        ALOGV("using rotated width/height");
+        sourceHeight = mainDpyInfo.w;
+        sourceWidth = mainDpyInfo.h;
+    }
+    Rect layerStackRect(sourceWidth, sourceHeight);
+
+    // We need to preserve the aspect ratio of the display.
+    float displayAspect = (float) sourceHeight / (float) sourceWidth;
+
+
+    // Set the way we map the output onto the display surface (which will
+    // be e.g. 1280x720 for a 720p video).  The rect is interpreted
+    // post-rotation, so if the display is rotated 90 degrees we need to
+    // "pre-rotate" it by flipping width/height, so that the orientation
+    // adjustment changes it back.
+    //
+    // We might want to encode a portrait display as landscape to use more
+    // of the screen real estate.  (If players respect a 90-degree rotation
+    // hint, we can essentially get a 720x1280 video instead of 1280x720.)
+    // In that case, we swap the configured video width/height and then
+    // supply a rotation value to the display projection.
+    uint32_t videoWidth, videoHeight;
+    uint32_t outWidth, outHeight;
+    if (!gRotate) {
+        videoWidth = gVideoWidth;
+        videoHeight = gVideoHeight;
+    } else {
+        videoWidth = gVideoHeight;
+        videoHeight = gVideoWidth;
+    }
+    if (videoHeight > (uint32_t)(videoWidth * displayAspect)) {
+        // limited by narrow width; reduce height
+        outWidth = videoWidth;
+        outHeight = (uint32_t)(videoWidth * displayAspect);
+    } else {
+        // limited by short height; restrict width
+        outHeight = videoHeight;
+        outWidth = (uint32_t)(videoHeight / displayAspect);
+    }
+    uint32_t offX, offY;
+    offX = (videoWidth - outWidth) / 2;
+    offY = (videoHeight - outHeight) / 2;
+    Rect displayRect(offX, offY, offX + outWidth, offY + outHeight);
+
+    if (gVerbose) {
+        if (gRotate) {
+            printf("Rotated content area is %ux%u at offset x=%d y=%d\n",
+                    outHeight, outWidth, offY, offX);
+        } else {
+            printf("Content area is %ux%u at offset x=%d y=%d\n",
+                    outWidth, outHeight, offX, offY);
+        }
+    }
+
+
+    sp<IBinder> dpy = SurfaceComposerClient::createDisplay(
+            String8("ScreenRecorder"), false /* secure */);
+
+    SurfaceComposerClient::openGlobalTransaction();
+    SurfaceComposerClient::setDisplaySurface(dpy, bufferProducer);
+    SurfaceComposerClient::setDisplayProjection(dpy,
+            gRotate ? DISPLAY_ORIENTATION_90 : DISPLAY_ORIENTATION_0,
+            layerStackRect, displayRect);
+    SurfaceComposerClient::setDisplayLayerStack(dpy, 0);    // default stack
+    SurfaceComposerClient::closeGlobalTransaction();
+
+    *pDisplayHandle = dpy;
+
+    return NO_ERROR;
+}
+
+/*
+ * Runs the MediaCodec encoder, sending the output to the MediaMuxer.  The
+ * input frames are coming from the virtual display as fast as SurfaceFlinger
+ * wants to send them.
+ *
+ * The muxer must *not* have been started before calling.
+ */
+static status_t runEncoder(const sp<MediaCodec>& encoder,
+        const sp<MediaMuxer>& muxer) {
+    static int kTimeout = 250000;   // be responsive on signal
+    status_t err;
+    ssize_t trackIdx = -1;
+    uint32_t debugNumFrames = 0;
+    int64_t startWhenNsec = systemTime(CLOCK_MONOTONIC);
+    int64_t endWhenNsec = startWhenNsec + seconds_to_nanoseconds(gTimeLimitSec);
+
+    Vector<sp<ABuffer> > buffers;
+    err = encoder->getOutputBuffers(&buffers);
+    if (err != NO_ERROR) {
+        fprintf(stderr, "Unable to get output buffers (err=%d)\n", err);
+        return err;
+    }
+
+    // This is set by the signal handler.
+    gStopRequested = false;
+
+    // Run until we're signaled.
+    while (!gStopRequested) {
+        size_t bufIndex, offset, size;
+        int64_t ptsUsec;
+        uint32_t flags;
+
+        if (systemTime(CLOCK_MONOTONIC) > endWhenNsec) {
+            if (gVerbose) {
+                printf("Time limit reached\n");
+            }
+            break;
+        }
+
+        ALOGV("Calling dequeueOutputBuffer");
+        err = encoder->dequeueOutputBuffer(&bufIndex, &offset, &size, &ptsUsec,
+                &flags, kTimeout);
+        ALOGV("dequeueOutputBuffer returned %d", err);
+        switch (err) {
+        case NO_ERROR:
+            // got a buffer
+            if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) != 0) {
+                // ignore this -- we passed the CSD into MediaMuxer when
+                // we got the format change notification
+                ALOGV("Got codec config buffer (%u bytes); ignoring", size);
+                size = 0;
+            }
+            if (size != 0) {
+                ALOGV("Got data in buffer %d, size=%d, pts=%lld",
+                        bufIndex, size, ptsUsec);
+                CHECK(trackIdx != -1);
+
+                // If the virtual display isn't providing us with timestamps,
+                // use the current time.
+                if (ptsUsec == 0) {
+                    ptsUsec = systemTime(SYSTEM_TIME_MONOTONIC) / 1000;
+                }
+
+                // The MediaMuxer docs are unclear, but it appears that we
+                // need to pass either the full set of BufferInfo flags, or
+                // (flags & BUFFER_FLAG_SYNCFRAME).
+                err = muxer->writeSampleData(buffers[bufIndex], trackIdx,
+                        ptsUsec, flags);
+                if (err != NO_ERROR) {
+                    fprintf(stderr, "Failed writing data to muxer (err=%d)\n",
+                            err);
+                    return err;
+                }
+                debugNumFrames++;
+            }
+            err = encoder->releaseOutputBuffer(bufIndex);
+            if (err != NO_ERROR) {
+                fprintf(stderr, "Unable to release output buffer (err=%d)\n",
+                        err);
+                return err;
+            }
+            if ((flags & MediaCodec::BUFFER_FLAG_EOS) != 0) {
+                // Not expecting EOS from SurfaceFlinger.  Go with it.
+                ALOGD("Received end-of-stream");
+                gStopRequested = false;
+            }
+            break;
+        case -EAGAIN:                       // INFO_TRY_AGAIN_LATER
+            ALOGV("Got -EAGAIN, looping");
+            break;
+        case INFO_FORMAT_CHANGED:           // INFO_OUTPUT_FORMAT_CHANGED
+            {
+                // format includes CSD, which we must provide to muxer
+                ALOGV("Encoder format changed");
+                sp<AMessage> newFormat;
+                encoder->getOutputFormat(&newFormat);
+                trackIdx = muxer->addTrack(newFormat);
+                ALOGV("Starting muxer");
+                err = muxer->start();
+                if (err != NO_ERROR) {
+                    fprintf(stderr, "Unable to start muxer (err=%d)\n", err);
+                    return err;
+                }
+            }
+            break;
+        case INFO_OUTPUT_BUFFERS_CHANGED:   // INFO_OUTPUT_BUFFERS_CHANGED
+            // not expected for an encoder; handle it anyway
+            ALOGV("Encoder buffers changed");
+            err = encoder->getOutputBuffers(&buffers);
+            if (err != NO_ERROR) {
+                fprintf(stderr,
+                        "Unable to get new output buffers (err=%d)\n", err);
+                return err;
+            }
+            break;
+        case INVALID_OPERATION:
+            fprintf(stderr, "Request for encoder buffer failed\n");
+            return err;
+        default:
+            fprintf(stderr,
+                    "Got weird result %d from dequeueOutputBuffer\n", err);
+            return err;
+        }
+    }
+
+    ALOGV("Encoder stopping (req=%d)", gStopRequested);
+    if (gVerbose) {
+        printf("Encoder stopping; recorded %u frames in %lld seconds\n",
+                debugNumFrames,
+                nanoseconds_to_seconds(systemTime(CLOCK_MONOTONIC) - startWhenNsec));
+    }
+    return NO_ERROR;
+}
+
+/*
+ * Main "do work" method.
+ *
+ * Configures codec, muxer, and virtual display, then starts moving bits
+ * around.
+ */
+static status_t recordScreen(const char* fileName) {
+    status_t err;
+
+    // Configure signal handler.
+    err = configureSignals();
+    if (err != NO_ERROR) return err;
+
+    // Start Binder thread pool.  MediaCodec needs to be able to receive
+    // messages from mediaserver.
+    sp<ProcessState> self = ProcessState::self();
+    self->startThreadPool();
+
+    // Get main display parameters.
+    sp<IBinder> mainDpy = SurfaceComposerClient::getBuiltInDisplay(
+            ISurfaceComposer::eDisplayIdMain);
+    DisplayInfo mainDpyInfo;
+    err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
+    if (err != NO_ERROR) {
+        fprintf(stderr, "ERROR: unable to get display characteristics\n");
+        return err;
+    }
+    if (gVerbose) {
+        printf("Main display is %dx%d @%.2ffps (orientation=%u)\n",
+                mainDpyInfo.w, mainDpyInfo.h, mainDpyInfo.fps,
+                mainDpyInfo.orientation);
+    }
+
+    bool rotated = isDeviceRotated(mainDpyInfo.orientation);
+    if (gVideoWidth == 0) {
+        gVideoWidth = rotated ? mainDpyInfo.h : mainDpyInfo.w;
+    }
+    if (gVideoHeight == 0) {
+        gVideoHeight = rotated ? mainDpyInfo.w : mainDpyInfo.h;
+    }
+
+    // Configure and start the encoder.
+    sp<MediaCodec> encoder;
+    sp<IGraphicBufferProducer> bufferProducer;
+    err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer);
+
+    if (err != NO_ERROR && !gSizeSpecified) {
+        // fallback is defined for landscape; swap if we're in portrait
+        bool needSwap = gVideoWidth < gVideoHeight;
+        uint32_t newWidth = needSwap ? kFallbackHeight : kFallbackWidth;
+        uint32_t newHeight = needSwap ? kFallbackWidth : kFallbackHeight;
+        if (gVideoWidth != newWidth && gVideoHeight != newHeight) {
+            ALOGV("Retrying with 720p");
+            fprintf(stderr, "WARNING: failed at %dx%d, retrying at %dx%d\n",
+                    gVideoWidth, gVideoHeight, newWidth, newHeight);
+            gVideoWidth = newWidth;
+            gVideoHeight = newHeight;
+            err = prepareEncoder(mainDpyInfo.fps, &encoder, &bufferProducer);
+        }
+    }
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    // Configure virtual display.
+    sp<IBinder> dpy;
+    err = prepareVirtualDisplay(mainDpyInfo, bufferProducer, &dpy);
+    if (err != NO_ERROR) {
+        encoder->release();
+        encoder.clear();
+
+        return err;
+    }
+
+    // Configure, but do not start, muxer.
+    sp<MediaMuxer> muxer = new MediaMuxer(fileName,
+            MediaMuxer::OUTPUT_FORMAT_MPEG_4);
+    if (gRotate) {
+        muxer->setOrientationHint(90);
+    }
+
+    // Main encoder loop.
+    err = runEncoder(encoder, muxer);
+    if (err != NO_ERROR) {
+        encoder->release();
+        encoder.clear();
+
+        return err;
+    }
+
+    if (gVerbose) {
+        printf("Stopping encoder and muxer\n");
+    }
+
+    // Shut everything down, starting with the producer side.
+    bufferProducer = NULL;
+    SurfaceComposerClient::destroyDisplay(dpy);
+
+    encoder->stop();
+    muxer->stop();
+    encoder->release();
+
+    return 0;
+}
+
+/*
+ * Sends a broadcast to the media scanner to tell it about the new video.
+ *
+ * This is optional, but nice to have.
+ */
+static status_t notifyMediaScanner(const char* fileName) {
+    pid_t pid = fork();
+    if (pid < 0) {
+        int err = errno;
+        ALOGW("fork() failed: %s", strerror(err));
+        return -err;
+    } else if (pid > 0) {
+        // parent; wait for the child, mostly to make the verbose-mode output
+        // look right, but also to check for and log failures
+        int status;
+        pid_t actualPid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
+        if (actualPid != pid) {
+            ALOGW("waitpid() returned %d (errno=%d)", actualPid, errno);
+        } else if (status != 0) {
+            ALOGW("'am broadcast' exited with status=%d", status);
+        } else {
+            ALOGV("'am broadcast' exited successfully");
+        }
+    } else {
+        const char* kCommand = "/system/bin/am";
+
+        // child; we're single-threaded, so okay to alloc
+        String8 fileUrl("file://");
+        fileUrl.append(fileName);
+        const char* const argv[] = {
+                kCommand,
+                "broadcast",
+                "-a",
+                "android.intent.action.MEDIA_SCANNER_SCAN_FILE",
+                "-d",
+                fileUrl.string(),
+                NULL
+        };
+        if (gVerbose) {
+            printf("Executing:");
+            for (int i = 0; argv[i] != NULL; i++) {
+                printf(" %s", argv[i]);
+            }
+            putchar('\n');
+        } else {
+            // non-verbose, suppress 'am' output
+            ALOGV("closing stdout/stderr in child");
+            int fd = open("/dev/null", O_WRONLY);
+            if (fd >= 0) {
+                dup2(fd, STDOUT_FILENO);
+                dup2(fd, STDERR_FILENO);
+                close(fd);
+            }
+        }
+        execv(kCommand, const_cast<char* const*>(argv));
+        ALOGE("execv(%s) failed: %s\n", kCommand, strerror(errno));
+        exit(1);
+    }
+    return NO_ERROR;
+}
+
+/*
+ * Parses a string of the form "1280x720".
+ *
+ * Returns true on success.
+ */
+static bool parseWidthHeight(const char* widthHeight, uint32_t* pWidth,
+        uint32_t* pHeight) {
+    long width, height;
+    char* end;
+
+    // Must specify base 10, or "0x0" gets parsed differently.
+    width = strtol(widthHeight, &end, 10);
+    if (end == widthHeight || *end != 'x' || *(end+1) == '\0') {
+        // invalid chars in width, or missing 'x', or missing height
+        return false;
+    }
+    height = strtol(end + 1, &end, 10);
+    if (*end != '\0') {
+        // invalid chars in height
+        return false;
+    }
+
+    *pWidth = width;
+    *pHeight = height;
+    return true;
+}
+
+/*
+ * Dumps usage on stderr.
+ */
+static void usage() {
+    fprintf(stderr,
+        "Usage: screenrecord [options] <filename>\n"
+        "\n"
+        "Records the device's display to a .mp4 file.\n"
+        "\n"
+        "Options:\n"
+        "--size WIDTHxHEIGHT\n"
+        "    Set the video size, e.g. \"1280x720\".  Default is the device's main\n"
+        "    display resolution (if supported), 1280x720 if not.  For best results,\n"
+        "    use a size supported by the AVC encoder.\n"
+        "--bit-rate RATE\n"
+        "    Set the video bit rate, in megabits per second.  Default %dMbps.\n"
+        "--time-limit TIME\n"
+        "    Set the maximum recording time, in seconds.  Default / maximum is %d.\n"
+        "--rotate\n"
+        "    Rotate the output 90 degrees.\n"
+        "--verbose\n"
+        "    Display interesting information on stdout.\n"
+        "--help\n"
+        "    Show this message.\n"
+        "\n"
+        "Recording continues until Ctrl-C is hit or the time limit is reached.\n"
+        "\n",
+        gBitRate / 1000000, gTimeLimitSec
+        );
+}
+
+/*
+ * Parses args and kicks things off.
+ */
+int main(int argc, char* const argv[]) {
+    static const struct option longOptions[] = {
+        { "help",       no_argument,        NULL, 'h' },
+        { "verbose",    no_argument,        NULL, 'v' },
+        { "size",       required_argument,  NULL, 's' },
+        { "bit-rate",   required_argument,  NULL, 'b' },
+        { "time-limit", required_argument,  NULL, 't' },
+        { "rotate",     no_argument,        NULL, 'r' },
+        { NULL,         0,                  NULL, 0 }
+    };
+
+    while (true) {
+        int optionIndex = 0;
+        int ic = getopt_long(argc, argv, "", longOptions, &optionIndex);
+        if (ic == -1) {
+            break;
+        }
+
+        switch (ic) {
+        case 'h':
+            usage();
+            return 0;
+        case 'v':
+            gVerbose = true;
+            break;
+        case 's':
+            if (!parseWidthHeight(optarg, &gVideoWidth, &gVideoHeight)) {
+                fprintf(stderr, "Invalid size '%s', must be width x height\n",
+                        optarg);
+                return 2;
+            }
+            if (gVideoWidth == 0 || gVideoHeight == 0) {
+                fprintf(stderr,
+                    "Invalid size %ux%u, width and height may not be zero\n",
+                    gVideoWidth, gVideoHeight);
+                return 2;
+            }
+            gSizeSpecified = true;
+            break;
+        case 'b':
+            gBitRate = atoi(optarg);
+            if (gBitRate < kMinBitRate || gBitRate > kMaxBitRate) {
+                fprintf(stderr,
+                        "Bit rate %dbps outside acceptable range [%d,%d]\n",
+                        gBitRate, kMinBitRate, kMaxBitRate);
+                return 2;
+            }
+            break;
+        case 't':
+            gTimeLimitSec = atoi(optarg);
+            if (gTimeLimitSec == 0 || gTimeLimitSec > kMaxTimeLimitSec) {
+                fprintf(stderr,
+                        "Time limit %ds outside acceptable range [1,%d]\n",
+                        gTimeLimitSec, kMaxTimeLimitSec);
+                return 2;
+            }
+            break;
+        case 'r':
+            gRotate = true;
+            break;
+        default:
+            if (ic != '?') {
+                fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
+            }
+            return 2;
+        }
+    }
+
+    if (optind != argc - 1) {
+        fprintf(stderr, "Must specify output file (see --help).\n");
+        return 2;
+    }
+
+    // MediaMuxer tries to create the file in the constructor, but we don't
+    // learn about the failure until muxer.start(), which returns a generic
+    // error code without logging anything.  We attempt to create the file
+    // now for better diagnostics.
+    const char* fileName = argv[optind];
+    int fd = open(fileName, O_CREAT | O_RDWR, 0644);
+    if (fd < 0) {
+        fprintf(stderr, "Unable to open '%s': %s\n", fileName, strerror(errno));
+        return 1;
+    }
+    close(fd);
+
+    status_t err = recordScreen(fileName);
+    if (err == NO_ERROR) {
+        // Try to notify the media scanner.  Not fatal if this fails.
+        notifyMediaScanner(fileName);
+    }
+    ALOGD(err == NO_ERROR ? "success" : "failed");
+    return (int) err;
+}
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 3844487..561ce02 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -19,7 +19,7 @@
 
 LOCAL_CFLAGS += -Wno-multichar
 
-LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_MODULE:= stagefright
 
@@ -42,7 +42,7 @@
 
 LOCAL_CFLAGS += -Wno-multichar
 
-LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_MODULE:= record
 
@@ -65,7 +65,7 @@
 
 LOCAL_CFLAGS += -Wno-multichar
 
-LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_MODULE:= recordvideo
 
@@ -89,7 +89,7 @@
 
 LOCAL_CFLAGS += -Wno-multichar
 
-LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_MODULE:= audioloop
 
@@ -112,7 +112,7 @@
 
 LOCAL_CFLAGS += -Wno-multichar
 
-LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_MODULE:= stream
 
@@ -135,7 +135,7 @@
 
 LOCAL_CFLAGS += -Wno-multichar
 
-LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_MODULE:= sf2
 
@@ -159,7 +159,7 @@
 
 LOCAL_CFLAGS += -Wno-multichar
 
-LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_MODULE:= codec
 
@@ -182,7 +182,7 @@
 
 LOCAL_CFLAGS += -Wno-multichar
 
-LOCAL_MODULE_TAGS := debug
+LOCAL_MODULE_TAGS := optional
 
 LOCAL_MODULE:= muxer
 
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 115b07c..030bf1b 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -30,8 +30,6 @@
 #include <binder/ProcessState.h>
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include "include/LiveSession.h"
 #include "include/NuCachedSource2.h"
 #include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/DataSource.h>
@@ -53,6 +51,7 @@
 
 #include <fcntl.h>
 
+#include <gui/GLConsumer.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 
@@ -618,7 +617,7 @@
         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_VPX
+        MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9
     };
 
     const char *codecType = queryDecoders? "decoder" : "encoder";
@@ -678,7 +677,6 @@
     gDisplayHistogram = false;
 
     sp<ALooper> looper;
-    sp<LiveSession> liveSession;
 
     int res;
     while ((res = getopt(argc, argv, "han:lm:b:ptsrow:kxSTd:D:")) >= 0) {
@@ -940,8 +938,9 @@
         } else {
             CHECK(useSurfaceTexAlloc);
 
-            sp<GLConsumer> texture = new GLConsumer(0 /* tex */);
-            gSurface = new Surface(texture->getBufferQueue());
+            sp<BufferQueue> bq = new BufferQueue();
+            sp<GLConsumer> texture = new GLConsumer(bq, 0 /* tex */);
+            gSurface = new Surface(bq);
         }
 
         CHECK_EQ((status_t)OK,
@@ -961,9 +960,7 @@
 
         sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
 
-        if (strncasecmp(filename, "sine:", 5)
-                && strncasecmp(filename, "httplive://", 11)
-                && dataSource == NULL) {
+        if (strncasecmp(filename, "sine:", 5) && dataSource == NULL) {
             fprintf(stderr, "Unable to create data source.\n");
             return 1;
         }
@@ -995,44 +992,21 @@
                 mediaSources.push(mediaSource);
             }
         } else {
-            sp<MediaExtractor> extractor;
+            sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
 
-            if (!strncasecmp("httplive://", filename, 11)) {
-                String8 uri("http://");
-                uri.append(filename + 11);
+            if (extractor == NULL) {
+                fprintf(stderr, "could not create extractor.\n");
+                return -1;
+            }
 
-                if (looper == NULL) {
-                    looper = new ALooper;
-                    looper->start();
-                }
-                liveSession = new LiveSession(NULL /* notify */);
-                looper->registerHandler(liveSession);
+            sp<MetaData> meta = extractor->getMetaData();
 
-                liveSession->connect(uri.string());
-                dataSource = liveSession->getDataSource();
+            if (meta != NULL) {
+                const char *mime;
+                CHECK(meta->findCString(kKeyMIMEType, &mime));
 
-                extractor =
-                    MediaExtractor::Create(
-                            dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
-
-                syncInfoPresent = false;
-            } else {
-                extractor = MediaExtractor::Create(dataSource);
-
-                if (extractor == NULL) {
-                    fprintf(stderr, "could not create extractor.\n");
-                    return -1;
-                }
-
-                sp<MetaData> meta = extractor->getMetaData();
-
-                if (meta != NULL) {
-                    const char *mime;
-                    CHECK(meta->findCString(kKeyMIMEType, &mime));
-
-                    if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
-                        syncInfoPresent = false;
-                    }
+                if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
+                    syncInfoPresent = false;
                 }
             }
 
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
index 06fc29d..f2cadf7 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
@@ -48,6 +48,14 @@
         return (!memcmp(uuid, mock_uuid, sizeof(uuid)));
     }
 
+    bool MockDrmFactory::isContentTypeSupported(const String8 &mimeType)
+    {
+        if (mimeType != "video/mp4") {
+            return false;
+        }
+        return true;
+    }
+
     status_t MockDrmFactory::createDrmPlugin(const uint8_t uuid[16], DrmPlugin **plugin)
     {
         *plugin = new MockDrmPlugin();
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
index ca9eac7..2297f9b 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
@@ -32,6 +32,7 @@
         virtual ~MockDrmFactory() {}
 
         bool isCryptoSchemeSupported(const uint8_t uuid[16]);
+        bool isContentTypeSupported(const String8 &mimeType);
         status_t createDrmPlugin(const uint8_t uuid[16], DrmPlugin **plugin);
     };
 
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 37626a4..79682b8 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -51,8 +51,14 @@
     typedef CameraListener        TCamListener;
     typedef ICamera               TCamUser;
     typedef ICameraClient         TCamCallbacks;
+    typedef status_t (ICameraService::*TCamConnectService)(const sp<ICameraClient>&,
+                                                           int, const String16&, int,
+                                                           /*out*/
+                                                           sp<ICamera>&);
+    static TCamConnectService     fnConnectService;
 };
 
+
 class Camera :
     public CameraBase<Camera>,
     public BnCameraClient
@@ -75,9 +81,9 @@
             status_t    unlock();
 
             // pass the buffered IGraphicBufferProducer to the camera service
-            status_t    setPreviewTexture(const sp<IGraphicBufferProducer>& bufferProducer);
+            status_t    setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer);
 
-            // start preview mode, must call setPreviewDisplay first
+            // start preview mode, must call setPreviewTarget first
             status_t    startPreview();
 
             // stop preview mode
@@ -86,7 +92,7 @@
             // get preview state
             bool        previewEnabled();
 
-            // start recording mode, must call setPreviewDisplay first
+            // start recording mode, must call setPreviewTarget first
             status_t    startRecording();
 
             // stop recording mode
@@ -121,7 +127,15 @@
 
             void        setListener(const sp<CameraListener>& listener);
             void        setRecordingProxyListener(const sp<ICameraRecordingProxyListener>& listener);
+
+            // Configure preview callbacks to app. Only one of the older
+            // callbacks or the callback surface can be active at the same time;
+            // enabling one will disable the other if active. Flags can be
+            // disabled by calling it with CAMERA_FRAME_CALLBACK_FLAG_NOOP, and
+            // Target by calling it with a NULL interface.
             void        setPreviewCallbackFlags(int preview_callback_flag);
+            status_t    setPreviewCallbackTarget(
+                    const sp<IGraphicBufferProducer>& callbackProducer);
 
             sp<ICameraRecordingProxy> getRecordingProxy();
 
diff --git a/include/camera/CameraBase.h b/include/camera/CameraBase.h
index 9b08c0f..1b93157 100644
--- a/include/camera/CameraBase.h
+++ b/include/camera/CameraBase.h
@@ -54,9 +54,10 @@
 class CameraBase : public IBinder::DeathRecipient
 {
 public:
-    typedef typename TCamTraits::TCamListener    TCamListener;
-    typedef typename TCamTraits::TCamUser        TCamUser;
-    typedef typename TCamTraits::TCamCallbacks   TCamCallbacks;
+    typedef typename TCamTraits::TCamListener       TCamListener;
+    typedef typename TCamTraits::TCamUser           TCamUser;
+    typedef typename TCamTraits::TCamCallbacks      TCamCallbacks;
+    typedef typename TCamTraits::TCamConnectService TCamConnectService;
 
     static sp<TCam>      connect(int cameraId,
                                  const String16& clientPackageName,
diff --git a/include/camera/CameraMetadata.h b/include/camera/CameraMetadata.h
index 8eeb2e7..1254d3c 100644
--- a/include/camera/CameraMetadata.h
+++ b/include/camera/CameraMetadata.h
@@ -22,6 +22,7 @@
 #include <utils/Vector.h>
 
 namespace android {
+class Parcel;
 
 /**
  * A convenience wrapper around the C-based camera_metadata_t library.
@@ -98,6 +99,11 @@
     status_t append(const CameraMetadata &other);
 
     /**
+     * Append metadata from a raw camera_metadata buffer
+     */
+    status_t append(const camera_metadata* other);
+
+    /**
      * Number of metadata entries.
      */
     size_t entryCount() const;
@@ -159,6 +165,12 @@
     status_t erase(uint32_t tag);
 
     /**
+     * Swap the underlying camera metadata between this and the other
+     * metadata object.
+     */
+    void swap(CameraMetadata &other);
+
+    /**
      * Dump contents into FD for debugging. The verbosity levels are
      * 0: Tag entry information only, no data values
      * 1: Level 0 plus at most 16 data values per entry
@@ -169,6 +181,31 @@
      */
     void dump(int fd, int verbosity = 1, int indentation = 0) const;
 
+    /**
+     * Serialization over Binder
+     */
+
+    // Metadata object is unchanged when reading from parcel fails.
+    status_t readFromParcel(Parcel *parcel);
+    status_t writeToParcel(Parcel *parcel) const;
+
+    /**
+      * Caller becomes the owner of the new metadata
+      * 'const Parcel' doesnt prevent us from calling the read functions.
+      *  which is interesting since it changes the internal state
+      *
+      * NULL can be returned when no metadata was sent, OR if there was an issue
+      * unpacking the serialized data (i.e. bad parcel or invalid structure).
+      */
+    static status_t readFromParcel(const Parcel &parcel,
+                                   camera_metadata_t** out);
+    /**
+      * Caller retains ownership of metadata
+      * - Write 2 (int32 + blob) args in the current position
+      */
+    static status_t writeToParcel(Parcel &parcel,
+                                  const camera_metadata_t* metadata);
+
   private:
     camera_metadata_t *mBuffer;
     bool               mLocked;
diff --git a/include/camera/CameraParameters2.h b/include/camera/CameraParameters2.h
new file mode 100644
index 0000000..88ad812
--- /dev/null
+++ b/include/camera/CameraParameters2.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_PARAMETERS2_H
+#define ANDROID_HARDWARE_CAMERA_PARAMETERS2_H
+
+#include <utils/Vector.h>
+#include <utils/String8.h>
+#include "CameraParameters.h"
+
+namespace android {
+
+/**
+ * A copy of CameraParameters plus ABI-breaking changes. Needed
+ * because some camera HALs directly link to CameraParameters and cannot
+ * tolerate an ABI change.
+ */
+class CameraParameters2
+{
+public:
+    CameraParameters2();
+    CameraParameters2(const String8 &params) { unflatten(params); }
+    ~CameraParameters2();
+
+    String8 flatten() const;
+    void unflatten(const String8 &params);
+
+    void set(const char *key, const char *value);
+    void set(const char *key, int value);
+    void setFloat(const char *key, float value);
+    // Look up string value by key.
+    // -- The string remains valid until the next set/remove of the same key,
+    //    or until the map gets cleared.
+    const char *get(const char *key) const;
+    int getInt(const char *key) const;
+    float getFloat(const char *key) const;
+
+    // Compare the order that key1 was set vs the order that key2 was set.
+    //
+    // Sets the order parameter to an integer less than, equal to, or greater
+    // than zero if key1's set order was respectively, to be less than, to
+    // match, or to be greater than key2's set order.
+    //
+    // Error codes:
+    //  * NAME_NOT_FOUND - if either key has not been set previously
+    //  * BAD_VALUE - if any of the parameters are NULL
+    status_t compareSetOrder(const char *key1, const char *key2,
+            /*out*/
+            int *order) const;
+
+    void remove(const char *key);
+
+    void setPreviewSize(int width, int height);
+    void getPreviewSize(int *width, int *height) const;
+    void getSupportedPreviewSizes(Vector<Size> &sizes) const;
+
+    // Set the dimensions in pixels to the given width and height
+    // for video frames. The given width and height must be one
+    // of the supported dimensions returned from
+    // getSupportedVideoSizes(). Must not be called if
+    // getSupportedVideoSizes() returns an empty Vector of Size.
+    void setVideoSize(int width, int height);
+    // Retrieve the current dimensions (width and height)
+    // in pixels for video frames, which must be one of the
+    // supported dimensions returned from getSupportedVideoSizes().
+    // Must not be called if getSupportedVideoSizes() returns an
+    // empty Vector of Size.
+    void getVideoSize(int *width, int *height) const;
+    // Retrieve a Vector of supported dimensions (width and height)
+    // in pixels for video frames. If sizes returned from the method
+    // is empty, the camera does not support calls to setVideoSize()
+    // or getVideoSize(). In adddition, it also indicates that
+    // the camera only has a single output, and does not have
+    // separate output for video frames and preview frame.
+    void getSupportedVideoSizes(Vector<Size> &sizes) const;
+    // Retrieve the preferred preview size (width and height) in pixels
+    // for video recording. The given width and height must be one of
+    // supported preview sizes returned from getSupportedPreviewSizes().
+    // Must not be called if getSupportedVideoSizes() returns an empty
+    // Vector of Size. If getSupportedVideoSizes() returns an empty
+    // Vector of Size, the width and height returned from this method
+    // is invalid, and is "-1x-1".
+    void getPreferredPreviewSizeForVideo(int *width, int *height) const;
+
+    void setPreviewFrameRate(int fps);
+    int getPreviewFrameRate() const;
+    void getPreviewFpsRange(int *min_fps, int *max_fps) const;
+    void setPreviewFpsRange(int min_fps, int max_fps);
+    void setPreviewFormat(const char *format);
+    const char *getPreviewFormat() const;
+    void setPictureSize(int width, int height);
+    void getPictureSize(int *width, int *height) const;
+    void getSupportedPictureSizes(Vector<Size> &sizes) const;
+    void setPictureFormat(const char *format);
+    const char *getPictureFormat() const;
+
+    void dump() const;
+    status_t dump(int fd, const Vector<String16>& args) const;
+
+private:
+
+    // Quick and dirty map that maintains insertion order
+    template <typename KeyT, typename ValueT>
+    struct OrderedKeyedVector {
+
+        ssize_t add(const KeyT& key, const ValueT& value) {
+            return mList.add(Pair(key, value));
+        }
+
+        size_t size() const {
+            return mList.size();
+        }
+
+        const KeyT& keyAt(size_t idx) const {
+            return mList[idx].mKey;
+        }
+
+        const ValueT& valueAt(size_t idx) const {
+            return mList[idx].mValue;
+        }
+
+        const ValueT& valueFor(const KeyT& key) const {
+            ssize_t i = indexOfKey(key);
+            LOG_ALWAYS_FATAL_IF(i<0, "%s: key not found", __PRETTY_FUNCTION__);
+
+            return valueAt(i);
+        }
+
+        ssize_t indexOfKey(const KeyT& key) const {
+                size_t vectorIdx = 0;
+                for (; vectorIdx < mList.size(); ++vectorIdx) {
+                    if (mList[vectorIdx].mKey == key) {
+                        return (ssize_t) vectorIdx;
+                    }
+                }
+
+                return NAME_NOT_FOUND;
+        }
+
+        ssize_t removeItem(const KeyT& key) {
+            size_t vectorIdx = (size_t) indexOfKey(key);
+
+            if (vectorIdx < 0) {
+                return vectorIdx;
+            }
+
+            return mList.removeAt(vectorIdx);
+        }
+
+        void clear() {
+            mList.clear();
+        }
+
+        // Same as removing and re-adding. The key's index changes to max.
+        ssize_t replaceValueFor(const KeyT& key, const ValueT& value) {
+            removeItem(key);
+            return add(key, value);
+        }
+
+    private:
+
+        struct Pair {
+            Pair() : mKey(), mValue() {}
+            Pair(const KeyT& key, const ValueT& value) :
+                    mKey(key),
+                    mValue(value) {}
+            KeyT   mKey;
+            ValueT mValue;
+        };
+
+        Vector<Pair> mList;
+    };
+
+    /**
+     * Order matters: Keys that are set() later are stored later in the map.
+     *
+     * If two keys have meaning that conflict, then the later-set key
+     * wins.
+     *
+     * For example, preview FPS and preview FPS range conflict since only
+     * we only want to use the FPS range if that's the last thing that was set.
+     * So in that case, only use preview FPS range if it was set later than
+     * the preview FPS.
+     */
+    OrderedKeyedVector<String8,String8>    mMap;
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/camera/ICamera.h b/include/camera/ICamera.h
index 2236c1f..b025735 100644
--- a/include/camera/ICamera.h
+++ b/include/camera/ICamera.h
@@ -32,6 +32,9 @@
 
 class ICamera: public IInterface
 {
+    /**
+     * Keep up-to-date with ICamera.aidl in frameworks/base
+     */
 public:
     DECLARE_META_INTERFACE(Camera);
 
@@ -47,14 +50,21 @@
     virtual status_t        unlock() = 0;
 
     // pass the buffered IGraphicBufferProducer to the camera service
-    virtual status_t        setPreviewTexture(
+    virtual status_t        setPreviewTarget(
             const sp<IGraphicBufferProducer>& bufferProducer) = 0;
 
     // set the preview callback flag to affect how the received frames from
-    // preview are handled.
+    // preview are handled. Enabling preview callback flags disables any active
+    // preview callback surface set by setPreviewCallbackTarget().
     virtual void            setPreviewCallbackFlag(int flag) = 0;
+    // set a buffer interface to use for client-received preview frames instead
+    // of preview callback buffers. Passing a valid interface here disables any
+    // active preview callbacks set by setPreviewCallbackFlag(). Passing NULL
+    // disables the use of the callback target.
+    virtual status_t        setPreviewCallbackTarget(
+            const sp<IGraphicBufferProducer>& callbackProducer) = 0;
 
-    // start preview mode, must call setPreviewDisplay first
+    // start preview mode, must call setPreviewTarget first
     virtual status_t        startPreview() = 0;
 
     // stop preview mode
diff --git a/include/camera/ICameraClient.h b/include/camera/ICameraClient.h
index b30aa7a..1584dba 100644
--- a/include/camera/ICameraClient.h
+++ b/include/camera/ICameraClient.h
@@ -28,6 +28,9 @@
 
 class ICameraClient: public IInterface
 {
+    /**
+     * Keep up-to-date with ICameraClient.aidl in frameworks/base
+     */
 public:
     DECLARE_META_INTERFACE(CameraClient);
 
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index aaf6eb3..f342122 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -28,17 +28,25 @@
 class IProCameraUser;
 class IProCameraCallbacks;
 class ICameraServiceListener;
+class ICameraDeviceUser;
+class ICameraDeviceCallbacks;
+class CameraMetadata;
 
 class ICameraService : public IInterface
 {
 public:
+    /**
+     * Keep up-to-date with ICameraService.aidl in frameworks/base
+     */
     enum {
         GET_NUMBER_OF_CAMERAS = IBinder::FIRST_CALL_TRANSACTION,
         GET_CAMERA_INFO,
         CONNECT,
         CONNECT_PRO,
+        CONNECT_DEVICE,
         ADD_LISTENER,
         REMOVE_LISTENER,
+        GET_CAMERA_CHARACTERISTICS,
     };
 
     enum {
@@ -52,6 +60,9 @@
     virtual status_t getCameraInfo(int cameraId,
                                           struct CameraInfo* cameraInfo) = 0;
 
+    virtual status_t getCameraCharacteristics(int cameraId,
+                                              CameraMetadata* cameraInfo) = 0;
+
     // Returns 'OK' if operation succeeded
     // - Errors: ALREADY_EXISTS if the listener was already added
     virtual status_t addListener(const sp<ICameraServiceListener>& listener)
@@ -65,15 +76,27 @@
      * clientUid == USE_CALLING_UID, then the calling UID is used instead. Only
      * trusted callers can set a clientUid other than USE_CALLING_UID.
      */
-    virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient,
+    virtual status_t connect(const sp<ICameraClient>& cameraClient,
             int cameraId,
             const String16& clientPackageName,
-            int clientUid) = 0;
+            int clientUid,
+            /*out*/
+            sp<ICamera>& device) = 0;
 
-    virtual sp<IProCameraUser> connect(const sp<IProCameraCallbacks>& cameraCb,
+    virtual status_t connectPro(const sp<IProCameraCallbacks>& cameraCb,
             int cameraId,
             const String16& clientPackageName,
-            int clientUid) = 0;
+            int clientUid,
+            /*out*/
+            sp<IProCameraUser>& device) = 0;
+
+    virtual status_t connectDevice(
+            const sp<ICameraDeviceCallbacks>& cameraCb,
+            int cameraId,
+            const String16& clientPackageName,
+            int clientUid,
+            /*out*/
+            sp<ICameraDeviceUser>& device) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/camera/ICameraServiceListener.h b/include/camera/ICameraServiceListener.h
index f2a11c2..0a0e43a 100644
--- a/include/camera/ICameraServiceListener.h
+++ b/include/camera/ICameraServiceListener.h
@@ -26,6 +26,9 @@
 
 class ICameraServiceListener : public IInterface
 {
+    /**
+     * Keep up-to-date with ICameraServiceListener.aidl in frameworks/base
+     */
 public:
 
     /**
diff --git a/include/camera/IProCameraCallbacks.h b/include/camera/IProCameraCallbacks.h
index 563ec17..e8abb89 100644
--- a/include/camera/IProCameraCallbacks.h
+++ b/include/camera/IProCameraCallbacks.h
@@ -30,6 +30,9 @@
 
 class IProCameraCallbacks : public IInterface
 {
+    /**
+     * Keep up-to-date with IProCameraCallbacks.aidl in frameworks/base
+     */
 public:
     DECLARE_META_INTERFACE(ProCameraCallbacks);
 
@@ -48,7 +51,7 @@
     /** Missing by design: implementation is client-side in ProCamera.cpp **/
     // virtual void onBufferReceived(int streamId,
     //                               const CpuConsumer::LockedBufer& buf);
-    virtual void            onResultReceived(int32_t frameId,
+    virtual void            onResultReceived(int32_t requestId,
                                              camera_metadata* result) = 0;
 };
 
diff --git a/include/camera/IProCameraUser.h b/include/camera/IProCameraUser.h
index 45b818c..2ccc4d2 100644
--- a/include/camera/IProCameraUser.h
+++ b/include/camera/IProCameraUser.h
@@ -34,6 +34,9 @@
 
 class IProCameraUser: public IInterface
 {
+    /**
+     * Keep up-to-date with IProCameraUser.aidl in frameworks/base
+     */
 public:
     DECLARE_META_INTERFACE(ProCameraUser);
 
diff --git a/include/camera/ProCamera.h b/include/camera/ProCamera.h
index 3d1652f..83a3028 100644
--- a/include/camera/ProCamera.h
+++ b/include/camera/ProCamera.h
@@ -25,6 +25,7 @@
 #include <camera/IProCameraUser.h>
 #include <camera/Camera.h>
 #include <camera/CameraMetadata.h>
+#include <camera/ICameraService.h>
 #include <gui/CpuConsumer.h>
 
 #include <gui/Surface.h>
@@ -87,8 +88,14 @@
     typedef ProCameraListener     TCamListener;
     typedef IProCameraUser        TCamUser;
     typedef IProCameraCallbacks   TCamCallbacks;
+    typedef status_t (ICameraService::*TCamConnectService)(const sp<IProCameraCallbacks>&,
+                                                           int, const String16&, int,
+                                                           /*out*/
+                                                           sp<IProCameraUser>&);
+    static TCamConnectService     fnConnectService;
 };
 
+
 class ProCamera :
     public CameraBase<ProCamera>,
     public BnProCameraCallbacks
@@ -245,7 +252,7 @@
     virtual void        onLockStatusChanged(
                                 IProCameraCallbacks::LockStatus newLockStatus);
 
-    virtual void        onResultReceived(int32_t frameId,
+    virtual void        onResultReceived(int32_t requestId,
                                          camera_metadata* result);
 private:
     ProCamera(int cameraId);
diff --git a/include/camera/camera2/CaptureRequest.h b/include/camera/camera2/CaptureRequest.h
new file mode 100644
index 0000000..e56d61f
--- /dev/null
+++ b/include/camera/camera2/CaptureRequest.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_PHOTOGRAPHY_CAPTUREREQUEST_H
+#define ANDROID_HARDWARE_PHOTOGRAPHY_CAPTUREREQUEST_H
+
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+#include <camera/CameraMetadata.h>
+
+namespace android {
+
+class Surface;
+
+struct CaptureRequest : public virtual RefBase {
+public:
+
+    CameraMetadata          mMetadata;
+    Vector<sp<Surface> >    mSurfaceList;
+
+    /**
+     * Keep impl up-to-date with CaptureRequest.java in frameworks/base
+     */
+    status_t                readFromParcel(Parcel* parcel);
+    status_t                writeToParcel(Parcel* parcel) const;
+};
+}; // namespace android
+
+#endif
diff --git a/include/camera/camera2/ICameraDeviceCallbacks.h b/include/camera/camera2/ICameraDeviceCallbacks.h
new file mode 100644
index 0000000..8dac4f2
--- /dev/null
+++ b/include/camera/camera2/ICameraDeviceCallbacks.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_PHOTOGRAPHY_CALLBACKS_H
+#define ANDROID_HARDWARE_PHOTOGRAPHY_CALLBACKS_H
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/IMemory.h>
+#include <utils/Timers.h>
+#include <system/camera.h>
+
+namespace android {
+class CameraMetadata;
+
+class ICameraDeviceCallbacks : public IInterface
+{
+    /**
+     * Keep up-to-date with ICameraDeviceCallbacks.aidl in frameworks/base
+     */
+public:
+    DECLARE_META_INTERFACE(CameraDeviceCallbacks);
+
+    /**
+     * Error codes for CAMERA_MSG_ERROR
+     */
+    enum CameraErrorCode {
+        ERROR_CAMERA_DISCONNECTED = 0,
+        ERROR_CAMERA_DEVICE = 1,
+        ERROR_CAMERA_SERVICE = 2
+    };
+
+    // One way
+    virtual void            onDeviceError(CameraErrorCode errorCode) = 0;
+
+    // One way
+    virtual void            onDeviceIdle() = 0;
+
+    // One way
+    virtual void            onCaptureStarted(int32_t requestId,
+                                             int64_t timestamp) = 0;
+
+    // One way
+    virtual void            onResultReceived(int32_t requestId,
+                                             const CameraMetadata& result) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnCameraDeviceCallbacks : public BnInterface<ICameraDeviceCallbacks>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/camera/camera2/ICameraDeviceUser.h b/include/camera/camera2/ICameraDeviceUser.h
new file mode 100644
index 0000000..f71f302
--- /dev/null
+++ b/include/camera/camera2/ICameraDeviceUser.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_PHOTOGRAPHY_ICAMERADEVICEUSER_H
+#define ANDROID_HARDWARE_PHOTOGRAPHY_ICAMERADEVICEUSER_H
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+struct camera_metadata;
+
+namespace android {
+
+class ICameraDeviceUserClient;
+class IGraphicBufferProducer;
+class Surface;
+class CaptureRequest;
+class CameraMetadata;
+
+class ICameraDeviceUser : public IInterface
+{
+    /**
+     * Keep up-to-date with ICameraDeviceUser.aidl in frameworks/base
+     */
+public:
+    DECLARE_META_INTERFACE(CameraDeviceUser);
+
+    virtual void            disconnect() = 0;
+
+    /**
+     * Request Handling
+     **/
+
+    virtual int             submitRequest(sp<CaptureRequest> request,
+                                          bool streaming = false) = 0;
+    virtual status_t        cancelRequest(int requestId) = 0;
+
+    virtual status_t        deleteStream(int streamId) = 0;
+    virtual status_t        createStream(
+            int width, int height, int format,
+            const sp<IGraphicBufferProducer>& bufferProducer) = 0;
+
+    // Create a request object from a template.
+    virtual status_t        createDefaultRequest(int templateId,
+                                                 /*out*/
+                                                 CameraMetadata* request) = 0;
+    // Get static camera metadata
+    virtual status_t        getCameraInfo(/*out*/
+                                          CameraMetadata* info) = 0;
+
+    // Wait until all the submitted requests have finished processing
+    virtual status_t        waitUntilIdle() =  0;
+
+    // Flush all pending and in-progress work as quickly as possible.
+    virtual status_t        flush() = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnCameraDeviceUser: public BnInterface<ICameraDeviceUser>
+{
+public:
+    virtual status_t    onTransact( uint32_t code,
+                                    const Parcel& data,
+                                    Parcel* reply,
+                                    uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif
diff --git a/include/cpustats/CentralTendencyStatistics.h b/include/cpustats/CentralTendencyStatistics.h
new file mode 100644
index 0000000..21b6981
--- /dev/null
+++ b/include/cpustats/CentralTendencyStatistics.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 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 _CENTRAL_TENDENCY_STATISTICS_H
+#define _CENTRAL_TENDENCY_STATISTICS_H
+
+#include <math.h>
+
+// Not multithread safe
+class CentralTendencyStatistics {
+
+public:
+
+    CentralTendencyStatistics() :
+            mMean(NAN), mMedian(NAN), mMinimum(INFINITY), mMaximum(-INFINITY), mN(0), mM2(0),
+            mVariance(NAN), mVarianceKnownForN(0), mStddev(NAN), mStddevKnownForN(0) { }
+
+    ~CentralTendencyStatistics() { }
+
+    // add x to the set of samples
+    void sample(double x);
+
+    // return the arithmetic mean of all samples so far
+    double mean() const { return mMean; }
+
+    // return the minimum of all samples so far
+    double minimum() const { return mMinimum; }
+
+    // return the maximum of all samples so far
+    double maximum() const { return mMaximum; }
+
+    // return the variance of all samples so far
+    double variance() const;
+
+    // return the standard deviation of all samples so far
+    double stddev() const;
+
+    // return the number of samples added so far
+    unsigned n() const { return mN; }
+
+    // reset the set of samples to be empty
+    void reset();
+
+private:
+    double mMean;
+    double mMedian;
+    double mMinimum;
+    double mMaximum;
+    unsigned mN;    // number of samples so far
+    double mM2;
+
+    // cached variance, and n at time of caching
+    mutable double mVariance;
+    mutable unsigned mVarianceKnownForN;
+
+    // cached standard deviation, and n at time of caching
+    mutable double mStddev;
+    mutable unsigned mStddevKnownForN;
+
+};
+
+#endif // _CENTRAL_TENDENCY_STATISTICS_H
diff --git a/include/cpustats/README.txt b/include/cpustats/README.txt
new file mode 100644
index 0000000..14439f0
--- /dev/null
+++ b/include/cpustats/README.txt
@@ -0,0 +1,6 @@
+This is a static library of CPU usage statistics, originally written
+for audio but most are not actually specific to audio.
+
+Requirements to be here:
+ * should be related to CPU usage statistics
+ * should be portable to host; avoid Android OS dependencies without a conditional
diff --git a/include/cpustats/ThreadCpuUsage.h b/include/cpustats/ThreadCpuUsage.h
new file mode 100644
index 0000000..9756844
--- /dev/null
+++ b/include/cpustats/ThreadCpuUsage.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2011 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 _THREAD_CPU_USAGE_H
+#define _THREAD_CPU_USAGE_H
+
+#include <fcntl.h>
+#include <pthread.h>
+
+namespace android {
+
+// Track CPU usage for the current thread.
+// Units are in per-thread CPU ns, as reported by
+// clock_gettime(CLOCK_THREAD_CPUTIME_ID).  Simple usage: for cyclic
+// threads where you want to measure the execution time of the whole
+// cycle, just call sampleAndEnable() at the start of each cycle.
+// For acyclic threads, or for cyclic threads where you want to measure/track
+// only part of each cycle, call enable(), disable(), and/or setEnabled()
+// to demarcate the region(s) of interest, and then call sample() periodically.
+// This class is not thread-safe for concurrent calls from multiple threads;
+// the methods of this class may only be called by the current thread
+// which constructed the object.
+
+class ThreadCpuUsage
+{
+
+public:
+    ThreadCpuUsage() :
+        mIsEnabled(false),
+        mWasEverEnabled(false),
+        mAccumulator(0),
+        // mPreviousTs
+        // mMonotonicTs
+        mMonotonicKnown(false)
+        {
+            (void) pthread_once(&sOnceControl, &init);
+            for (int i = 0; i < sKernelMax; ++i) {
+                mCurrentkHz[i] = (uint32_t) ~0;   // unknown
+            }
+        }
+
+    ~ThreadCpuUsage() { }
+
+    // Return whether currently tracking CPU usage by current thread
+    bool isEnabled() const  { return mIsEnabled; }
+
+    // Enable tracking of CPU usage by current thread;
+    // any CPU used from this point forward will be tracked.
+    // Returns the previous enabled status.
+    bool enable()       { return setEnabled(true); }
+
+    // Disable tracking of CPU usage by current thread;
+    // any CPU used from this point forward will be ignored.
+    // Returns the previous enabled status.
+    bool disable()      { return setEnabled(false); }
+
+    // Set the enabled status and return the previous enabled status.
+    // This method is intended to be used for safe nested enable/disabling.
+    bool setEnabled(bool isEnabled);
+
+    // Add a sample point, and also enable tracking if needed.
+    // If tracking has never been enabled, then this call enables tracking but
+    // does _not_ add a sample -- it is not possible to add a sample the
+    // first time because there is no previous point to subtract from.
+    // Otherwise, if tracking is enabled,
+    // then adds a sample for tracked CPU ns since the previous
+    // sample, or since the first call to sampleAndEnable(), enable(), or
+    // setEnabled(true).  If there was a previous sample but tracking is
+    // now disabled, then adds a sample for the tracked CPU ns accumulated
+    // up until the most recent disable(), resets this accumulator, and then
+    // enables tracking.  Calling this method rather than enable() followed
+    // by sample() avoids a race condition for the first sample.
+    // Returns true if the sample 'ns' is valid, or false if invalid.
+    // Note that 'ns' is an output parameter passed by reference.
+    // The caller does not need to initialize this variable.
+    // The units are CPU nanoseconds consumed by current thread.
+    bool sampleAndEnable(double& ns);
+
+    // Add a sample point, but do not
+    // change the tracking enabled status.  If tracking has either never been
+    // enabled, or has never been enabled since the last sample, then log a warning
+    // and don't add sample.  Otherwise, adds a sample for tracked CPU ns since
+    // the previous sample or since the first call to sampleAndEnable(),
+    // enable(), or setEnabled(true) if no previous sample.
+    // Returns true if the sample is valid, or false if invalid.
+    // Note that 'ns' is an output parameter passed by reference.
+    // The caller does not need to initialize this variable.
+    // The units are CPU nanoseconds consumed by current thread.
+    bool sample(double& ns);
+
+    // Return the elapsed delta wall clock ns since initial enable or reset,
+    // as reported by clock_gettime(CLOCK_MONOTONIC).
+    long long elapsed() const;
+
+    // Reset elapsed wall clock.  Has no effect on tracking or accumulator.
+    void resetElapsed();
+
+    // Return current clock frequency for specified CPU, in kHz.
+    // You can get your CPU number using sched_getcpu(2).  Note that, unless CPU affinity
+    // has been configured appropriately, the CPU number can change.
+    // Also note that, unless the CPU governor has been configured appropriately,
+    // the CPU frequency can change.  And even if the CPU frequency is locked down
+    // to a particular value, that the frequency might still be adjusted
+    // to prevent thermal overload.  Therefore you should poll for your thread's
+    // current CPU number and clock frequency periodically.
+    uint32_t getCpukHz(int cpuNum);
+
+private:
+    bool mIsEnabled;                // whether tracking is currently enabled
+    bool mWasEverEnabled;           // whether tracking was ever enabled
+    long long mAccumulator;         // accumulated thread CPU time since last sample, in ns
+    struct timespec mPreviousTs;    // most recent thread CPU time, valid only if mIsEnabled is true
+    struct timespec mMonotonicTs;   // most recent monotonic time
+    bool mMonotonicKnown;           // whether mMonotonicTs has been set
+
+    static const int MAX_CPU = 8;
+    static int sScalingFds[MAX_CPU];// file descriptor per CPU for reading scaling_cur_freq
+    uint32_t mCurrentkHz[MAX_CPU];  // current CPU frequency in kHz, not static to avoid a race
+    static pthread_once_t sOnceControl;
+    static int sKernelMax;          // like MAX_CPU, but determined at runtime == cpu/kernel_max + 1
+    static void init();             // called once at first ThreadCpuUsage construction
+    static pthread_mutex_t sMutex;  // protects sScalingFds[] after initialization
+};
+
+}   // namespace android
+
+#endif //  _THREAD_CPU_USAGE_H
diff --git a/include/media/AudioBufferProvider.h b/include/media/AudioBufferProvider.h
index 43e4de7..ef392f0 100644
--- a/include/media/AudioBufferProvider.h
+++ b/include/media/AudioBufferProvider.h
@@ -26,6 +26,8 @@
 {
 public:
 
+    // FIXME merge with AudioTrackShared::Buffer, AudioTrack::Buffer, and AudioRecord::Buffer
+    //       and rename getNextBuffer() to obtainBuffer()
     struct Buffer {
         Buffer() : raw(NULL), frameCount(0) { }
         union {
@@ -44,6 +46,19 @@
     // 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
+    //  buffer->frameCount  maximum number of desired frames
+    // On successful return:
+    //  status              NO_ERROR
+    //  buffer->raw         non-NULL pointer to buffer->frameCount contiguous available frames
+    //  buffer->frameCount  number of contiguous available frames at buffer->raw,
+    //                      0 < buffer->frameCount <= entry value
+    // On error return:
+    //  status              != NO_ERROR
+    //  buffer->raw         NULL
+    //  buffer->frameCount  0
     virtual status_t getNextBuffer(Buffer* buffer, int64_t pts = kInvalidPTS) = 0;
 
     virtual void releaseBuffer(Buffer* buffer) = 0;
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 38c6548..052064d 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -14,31 +14,27 @@
  * limitations under the License.
  */
 
-#ifndef AUDIORECORD_H_
-#define AUDIORECORD_H_
+#ifndef ANDROID_AUDIORECORD_H
+#define ANDROID_AUDIORECORD_H
 
-#include <binder/IMemory.h>
 #include <cutils/sched_policy.h>
 #include <media/AudioSystem.h>
 #include <media/IAudioRecord.h>
-#include <system/audio.h>
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
 #include <utils/threads.h>
 
 namespace android {
 
+// ----------------------------------------------------------------------------
+
 class audio_track_cblk_t;
 class AudioRecordClientProxy;
 
 // ----------------------------------------------------------------------------
 
-class AudioRecord : virtual public RefBase
+class AudioRecord : public RefBase
 {
 public:
 
-    static const int DEFAULT_SAMPLE_RATE = 8000;
-
     /* Events used by AudioRecord callback function (callback_t).
      * Keep in sync with frameworks/base/media/java/android/media/AudioRecord.java NATIVE_EVENT_*.
      */
@@ -49,6 +45,8 @@
                                     // (See setMarkerPosition()).
         EVENT_NEW_POS = 3,          // Record head is at a new position
                                     // (See setPositionUpdatePeriod()).
+        EVENT_NEW_IAUDIORECORD = 4, // IAudioRecord was re-created, either due to re-routing and
+                                    // voluntary invalidation by mediaserver, or mediaserver crash.
     };
 
     /* Client should declare Buffer on the stack and pass address to obtainBuffer()
@@ -58,11 +56,17 @@
     class Buffer
     {
     public:
+        // FIXME use m prefix
         size_t      frameCount;     // number of sample frames corresponding to size;
                                     // on input it is the number of frames available,
                                     // on output is the number of frames actually drained
+                                    // (currently ignored, but will make the primary field in future)
 
-        size_t      size;           // total size in bytes == frameCount * frameSize
+        size_t      size;           // input/output in bytes == frameCount * frameSize
+                                    // FIXME this is redundant with respect to frameCount,
+                                    // and TRANSFER_OBTAIN mode is broken for 8-bit data
+                                    // since we don't define the frame format
+
         union {
             void*       raw;
             short*      i16;        // signed 16-bit
@@ -84,6 +88,7 @@
      *          - EVENT_OVERRUN: unused.
      *          - EVENT_MARKER: pointer to const uint32_t containing the marker position in frames.
      *          - EVENT_NEW_POS: pointer to const uint32_t containing the new position in frames.
+     *          - EVENT_NEW_IAUDIORECORD: unused.
      */
 
     typedef void (*callback_t)(int event, void* user, void *info);
@@ -101,94 +106,112 @@
                                       audio_format_t format,
                                       audio_channel_mask_t channelMask);
 
+    /* How data is transferred from AudioRecord
+     */
+    enum transfer_type {
+        TRANSFER_DEFAULT,   // not specified explicitly; determine from other parameters
+        TRANSFER_CALLBACK,  // callback EVENT_MORE_DATA
+        TRANSFER_OBTAIN,    // FIXME deprecated: call obtainBuffer() and releaseBuffer()
+        TRANSFER_SYNC,      // synchronous read()
+    };
+
     /* Constructs an uninitialized AudioRecord. No connection with
-     * AudioFlinger takes place.
+     * AudioFlinger takes place.  Use set() after this.
      */
                         AudioRecord();
 
     /* Creates an AudioRecord object and registers it with AudioFlinger.
      * Once created, the track needs to be started before it can be used.
-     * Unspecified values are set to the audio hardware's current
-     * values.
+     * Unspecified values are set to appropriate default values.
      *
      * Parameters:
      *
-     * inputSource:        Select the audio input to record to (e.g. AUDIO_SOURCE_DEFAULT).
-     * sampleRate:         Track sampling rate in Hz.
+     * inputSource:        Select the audio input to record from (e.g. AUDIO_SOURCE_DEFAULT).
+     * sampleRate:         Data sink sampling rate in Hz.
      * format:             Audio format (e.g AUDIO_FORMAT_PCM_16_BIT for signed
      *                     16 bits per sample).
-     * channelMask:        Channel mask.
+     * channelMask:        Channel mask, such that audio_is_input_channel(channelMask) is true.
      * frameCount:         Minimum size of track PCM buffer in frames. This defines the
      *                     application's contribution to the
      *                     latency of the track.  The actual size selected by the AudioRecord could
      *                     be larger if the requested size is not compatible with current audio HAL
      *                     latency.  Zero means to use a default value.
      * cbf:                Callback function. If not null, this function is called periodically
-     *                     to consume new PCM data.
+     *                     to consume new PCM data and inform of marker, position updates, etc.
      * user:               Context for use by the callback receiver.
      * notificationFrames: The callback function is called each time notificationFrames PCM
      *                     frames are ready in record track output buffer.
      * sessionId:          Not yet supported.
+     * transferType:       How data is transferred from AudioRecord.
+     * flags:              See comments on audio_input_flags_t in <system/audio.h>
+     * threadCanCallJava:  Not present in parameter list, and so is fixed at false.
      */
 
                         AudioRecord(audio_source_t inputSource,
-                                    uint32_t sampleRate = 0,
-                                    audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                    audio_channel_mask_t channelMask = AUDIO_CHANNEL_IN_MONO,
+                                    uint32_t sampleRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t channelMask,
                                     int frameCount      = 0,
                                     callback_t cbf = NULL,
                                     void* user = NULL,
                                     int notificationFrames = 0,
-                                    int sessionId = 0);
-
+                                    int sessionId = 0,
+                                    transfer_type transferType = TRANSFER_DEFAULT,
+                                    audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE);
 
     /* Terminates the AudioRecord and unregisters it from AudioFlinger.
      * Also destroys all resources associated with the AudioRecord.
      */
-                        ~AudioRecord();
+protected:
+                        virtual ~AudioRecord();
+public:
 
-
-    /* Initialize an uninitialized AudioRecord.
+    /* Initialize an AudioRecord that was created using the AudioRecord() constructor.
+     * Don't call set() more than once, or after an AudioRecord() constructor that takes parameters.
      * Returned status (from utils/Errors.h) can be:
      *  - NO_ERROR: successful intialization
-     *  - INVALID_OPERATION: AudioRecord is already intitialized or record device is already in use
+     *  - INVALID_OPERATION: AudioRecord is already initialized or record device is already in use
      *  - BAD_VALUE: invalid parameter (channels, format, sampleRate...)
      *  - NO_INIT: audio server or audio hardware not initialized
      *  - PERMISSION_DENIED: recording is not allowed for the requesting process
+     *
+     * Parameters not listed in the AudioRecord constructors above:
+     *
+     * threadCanCallJava:  Whether callbacks are made from an attached thread and thus can call JNI.
      */
-            status_t    set(audio_source_t inputSource = AUDIO_SOURCE_DEFAULT,
-                            uint32_t sampleRate = 0,
-                            audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                            audio_channel_mask_t channelMask = AUDIO_CHANNEL_IN_MONO,
+            status_t    set(audio_source_t inputSource,
+                            uint32_t sampleRate,
+                            audio_format_t format,
+                            audio_channel_mask_t channelMask,
                             int frameCount      = 0,
                             callback_t cbf = NULL,
                             void* user = NULL,
                             int notificationFrames = 0,
                             bool threadCanCallJava = false,
-                            int sessionId = 0);
-
+                            int sessionId = 0,
+                            transfer_type transferType = TRANSFER_DEFAULT,
+                            audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE);
 
     /* Result of constructing the AudioRecord. This must be checked
      * before using any AudioRecord API (except for set()), because using
      * an uninitialized AudioRecord produces undefined results.
      * See set() method above for possible return codes.
      */
-            status_t    initCheck() const;
+            status_t    initCheck() const   { return mStatus; }
 
     /* Returns this track's estimated latency in milliseconds.
      * This includes the latency due to AudioRecord buffer size,
      * and audio hardware driver.
      */
-            uint32_t     latency() const;
+            uint32_t    latency() const     { return mLatency; }
 
    /* getters, see constructor and set() */
 
-            audio_format_t format() const;
-            uint32_t    channelCount() const;
-            size_t      frameCount() const;
-            size_t      frameSize() const { return mFrameSize; }
-            audio_source_t inputSource() const;
-
+            audio_format_t format() const   { return mFormat; }
+            uint32_t    channelCount() const    { return mChannelCount; }
+            size_t      frameCount() const  { return mFrameCount; }
+            size_t      frameSize() const   { return mFrameSize; }
+            audio_source_t inputSource() const  { return mInputSource; }
 
     /* After it's created the track is not active. Call start() to
      * make it active. If set, the callback will start being called.
@@ -198,26 +221,29 @@
             status_t    start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE,
                               int triggerSession = 0);
 
-    /* Stop a track. If set, the callback will cease being called and
-     * obtainBuffer returns STOPPED. Note that obtainBuffer() still works
-     * and will drain buffers until the pool is exhausted.
+    /* Stop a track. If set, the callback will cease being called.  Note that obtainBuffer() still
+     * works and will drain buffers until the pool is exhausted, and then will return WOULD_BLOCK.
      */
             void        stop();
             bool        stopped() const;
 
-    /* Get sample rate for this record track in Hz.
+    /* Return the sink sample rate for this record track in Hz.
+     * Unlike AudioTrack, the sample rate is const after initialization, so doesn't need a lock.
      */
-            uint32_t    getSampleRate() const;
+            uint32_t    getSampleRate() const   { return mSampleRate; }
 
     /* Sets marker position. When record reaches the number of frames specified,
      * a callback with event type EVENT_MARKER is called. Calling setMarkerPosition
      * with marker == 0 cancels marker notification callback.
+     * To set a marker at a position which would compute as 0,
+     * a workaround is to the set the marker at a nearby position such as ~0 or 1.
      * If the AudioRecord has been opened with no callback function associated,
      * the operation will fail.
      *
      * Parameters:
      *
-     * marker:   marker position expressed in frames.
+     * marker:   marker position expressed in wrapping (overflow) frame units,
+     *           like the return value of getPosition().
      *
      * Returned status (from utils/Errors.h) can be:
      *  - NO_ERROR: successful operation
@@ -226,13 +252,13 @@
             status_t    setMarkerPosition(uint32_t marker);
             status_t    getMarkerPosition(uint32_t *marker) const;
 
-
     /* Sets position update period. Every time the number of frames specified has been recorded,
      * a callback with event type EVENT_NEW_POS is called.
      * Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification
      * callback.
      * If the AudioRecord has been opened with no callback function associated,
      * the operation will fail.
+     * Extremely small values may be rounded up to a value the implementation can support.
      *
      * Parameters:
      *
@@ -245,13 +271,13 @@
             status_t    setPositionUpdatePeriod(uint32_t updatePeriod);
             status_t    getPositionUpdatePeriod(uint32_t *updatePeriod) const;
 
-
-    /* Gets record head position. The position is the total number of frames
-     * recorded since record start.
+    /* Return the total number of frames recorded since recording started.
+     * The counter will wrap (overflow) periodically, e.g. every ~27 hours at 44.1 kHz.
+     * It is reset to zero by stop().
      *
      * Parameters:
      *
-     *  position:  Address where to return record head position within AudioRecord buffer.
+     *  position:  Address where to return record head position.
      *
      * Returned status (from utils/Errors.h) can be:
      *  - NO_ERROR: successful operation
@@ -276,38 +302,74 @@
      *
      * Returned value:
      *  AudioRecord session ID.
+     *
+     * No lock needed because session ID doesn't change after first set().
      */
-            int    getSessionId() const;
+            int    getSessionId() const { return mSessionId; }
 
-    /* Obtains a buffer of "frameCount" frames. The buffer must be
-     * drained entirely, and then released with releaseBuffer().
-     * If the track is stopped, obtainBuffer() returns
-     * STOPPED instead of NO_ERROR as long as there are buffers available,
-     * at which point NO_MORE_BUFFERS is returned.
+    /* Obtains a buffer of up to "audioBuffer->frameCount" full frames.
+     * After draining these frames of data, the caller should release them with releaseBuffer().
+     * If the track buffer is not empty, obtainBuffer() returns as many contiguous
+     * full frames as are available immediately.
+     * If the track buffer is empty and track is stopped, obtainBuffer() returns WOULD_BLOCK
+     * regardless of the value of waitCount.
+     * If the track buffer is empty and track is not stopped, obtainBuffer() blocks with a
+     * maximum timeout based on waitCount; see chart below.
      * Buffers will be returned until the pool
      * is exhausted, at which point obtainBuffer() will either block
-     * or return WOULD_BLOCK depending on the value of the "blocking"
+     * or return WOULD_BLOCK depending on the value of the "waitCount"
      * parameter.
      *
+     * obtainBuffer() and releaseBuffer() are deprecated for direct use by applications,
+     * which should use read() or callback EVENT_MORE_DATA instead.
+     *
      * Interpretation of waitCount:
      *  +n  limits wait time to n * WAIT_PERIOD_MS,
      *  -1  causes an (almost) infinite wait time,
      *   0  non-blocking.
+     *
+     * Buffer fields
+     * On entry:
+     *  frameCount  number of frames requested
+     * After error return:
+     *  frameCount  0
+     *  size        0
+     *  raw         undefined
+     * After successful return:
+     *  frameCount  actual number of frames available, <= number requested
+     *  size        actual number of bytes available
+     *  raw         pointer to the buffer
      */
 
-        enum {
-            NO_MORE_BUFFERS = 0x80000001,   // same name in AudioFlinger.h, ok to be different value
-            STOPPED = 1
-        };
+    /* FIXME Deprecated public API for TRANSFER_OBTAIN mode */
+            status_t    obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
+                                __attribute__((__deprecated__));
 
-            status_t    obtainBuffer(Buffer* audioBuffer, int32_t waitCount);
+private:
+    /* If nonContig is non-NULL, it is an output parameter that will be set to the number of
+     * additional non-contiguous frames that are available immediately.
+     * FIXME We could pass an array of Buffers instead of only one Buffer to obtainBuffer(),
+     * in case the requested amount of frames is in two or more non-contiguous regions.
+     * FIXME requested and elapsed are both relative times.  Consider changing to absolute time.
+     */
+            status_t    obtainBuffer(Buffer* audioBuffer, const struct timespec *requested,
+                                     struct timespec *elapsed = NULL, size_t *nonContig = NULL);
+public:
 
-    /* Release an emptied buffer of "frameCount" frames for AudioFlinger to re-fill. */
+    /* Release an emptied buffer of "audioBuffer->frameCount" frames for AudioFlinger to re-fill. */
+    // FIXME make private when obtainBuffer() for TRANSFER_OBTAIN is removed
             void        releaseBuffer(Buffer* audioBuffer);
 
-
     /* As a convenience we provide a read() interface to the audio buffer.
-     * This is implemented on top of obtainBuffer/releaseBuffer.
+     * Input parameter 'size' is in byte units.
+     * This is implemented on top of obtainBuffer/releaseBuffer. For best
+     * performance use callbacks. Returns actual number of bytes read >= 0,
+     * or one of the following negative status codes:
+     *      INVALID_OPERATION   AudioRecord is configured for streaming mode
+     *      BAD_VALUE           size is invalid
+     *      WOULD_BLOCK         when obtainBuffer() returns same, or
+     *                          AudioRecord was stopped during the read
+     *      or any other error code returned by IAudioRecord::start() or restoreRecord_l().
      */
             ssize_t     read(void* buffer, size_t size);
 
@@ -338,66 +400,113 @@
                 void        resume();   // allow thread to execute, if not requested to exit
 
     private:
+                void        pauseInternal(nsecs_t ns = 0LL);
+                                        // like pause(), but only used internally within thread
+
         friend class AudioRecord;
         virtual bool        threadLoop();
-        AudioRecord& mReceiver;
+        AudioRecord&        mReceiver;
         virtual ~AudioRecordThread();
         Mutex               mMyLock;    // Thread::mLock is private
         Condition           mMyCond;    // Thread::mThreadExitedCondition is private
-        bool                mPaused;    // whether thread is currently paused
+        bool                mPaused;    // whether thread is requested to pause at next loop entry
+        bool                mPausedInt; // whether thread internally requests pause
+        nsecs_t             mPausedNs;  // if mPausedInt then associated timeout, otherwise ignored
     };
 
             // body of AudioRecordThread::threadLoop()
-            bool processAudioBuffer(const sp<AudioRecordThread>& thread);
+            // returns the maximum amount of time before we would like to run again, where:
+            //      0           immediately
+            //      > 0         no later than this many nanoseconds from now
+            //      NS_WHENEVER still active but no particular deadline
+            //      NS_INACTIVE inactive so don't run again until re-started
+            //      NS_NEVER    never again
+            static const nsecs_t NS_WHENEVER = -1, NS_INACTIVE = -2, NS_NEVER = -3;
+            nsecs_t processAudioBuffer(const sp<AudioRecordThread>& thread);
 
-            status_t openRecord_l(uint32_t sampleRate,
-                                audio_format_t format,
-                                size_t frameCount,
-                                audio_io_handle_t input);
-            audio_io_handle_t getInput_l();
-            status_t restoreRecord_l(audio_track_cblk_t*& cblk);
+            // caller must hold lock on mLock for all _l methods
+            status_t openRecord_l(size_t epoch);
+
+            // FIXME enum is faster than strcmp() for parameter 'from'
+            status_t restoreRecord_l(const char *from);
 
     sp<AudioRecordThread>   mAudioRecordThread;
     mutable Mutex           mLock;
 
-    bool                    mActive;            // protected by mLock
+    // Current client state:  false = stopped, true = active.  Protected by mLock.  If more states
+    // are added, consider changing this to enum State { ... } mState as in AudioTrack.
+    bool                    mActive;
 
     // for client callback handler
     callback_t              mCbf;               // callback handler for events, or NULL
     void*                   mUserData;
 
     // for notification APIs
-    uint32_t                mNotificationFrames;
-    uint32_t                mRemainingFrames;
-    uint32_t                mMarkerPosition;    // in frames
+    uint32_t                mNotificationFramesReq; // requested number of frames between each
+                                                    // notification callback
+    uint32_t                mNotificationFramesAct; // actual number of frames between each
+                                                    // notification callback
+    bool                    mRefreshRemaining;  // processAudioBuffer() should refresh next 2
+
+    // These are private to processAudioBuffer(), and are not protected by a lock
+    uint32_t                mRemainingFrames;       // number of frames to request in obtainBuffer()
+    bool                    mRetryOnPartialBuffer;  // sleep and retry after partial obtainBuffer()
+    int                     mObservedSequence;      // last observed value of mSequence
+
+    uint32_t                mMarkerPosition;    // in wrapping (overflow) frame units
     bool                    mMarkerReached;
     uint32_t                mNewPosition;       // in frames
-    uint32_t                mUpdatePeriod;      // in ms
+    uint32_t                mUpdatePeriod;      // in frames, zero means no EVENT_NEW_POS
+
+    status_t                mStatus;
 
     // constant after constructor or set()
     uint32_t                mSampleRate;
     size_t                  mFrameCount;
     audio_format_t          mFormat;
-    uint8_t                 mChannelCount;
+    uint32_t                mChannelCount;
     size_t                  mFrameSize;         // app-level frame size == AudioFlinger frame size
     audio_source_t          mInputSource;
-    status_t                mStatus;
-    uint32_t                mLatency;
+    uint32_t                mLatency;           // in ms
     audio_channel_mask_t    mChannelMask;
-    audio_io_handle_t       mInput;                     // returned by AudioSystem::getInput()
+    audio_input_flags_t     mFlags;
     int                     mSessionId;
+    transfer_type           mTransfer;
+
+    audio_io_handle_t       mInput;             // returned by AudioSystem::getInput()
 
     // may be changed if IAudioRecord object is re-created
     sp<IAudioRecord>        mAudioRecord;
     sp<IMemory>             mCblkMemory;
-    audio_track_cblk_t*     mCblk;
-    void*                   mBuffers;           // starting address of buffers in shared memory
+    audio_track_cblk_t*     mCblk;              // re-load after mLock.unlock()
 
-    int                     mPreviousPriority;          // before start()
+    int                     mPreviousPriority;  // before start()
     SchedPolicy             mPreviousSchedulingGroup;
-    AudioRecordClientProxy* mProxy;
+    bool                    mAwaitBoost;    // thread should wait for priority boost before running
+
+    // The proxy should only be referenced while a lock is held because the proxy isn't
+    // multi-thread safe.
+    // An exception is that a blocking ClientProxy::obtainBuffer() may be called without a lock,
+    // provided that the caller also holds an extra reference to the proxy and shared memory to keep
+    // them around in case they are replaced during the obtainBuffer().
+    sp<AudioRecordClientProxy> mProxy;
+
+    bool                    mInOverrun;         // whether recorder is currently in overrun state
+
+private:
+    class DeathNotifier : public IBinder::DeathRecipient {
+    public:
+        DeathNotifier(AudioRecord* audioRecord) : mAudioRecord(audioRecord) { }
+    protected:
+        virtual void        binderDied(const wp<IBinder>& who);
+    private:
+        const wp<AudioRecord> mAudioRecord;
+    };
+
+    sp<DeathNotifier>       mDeathNotifier;
+    uint32_t                mSequence;              // incremented for each new IAudioRecord attempt
 };
 
 }; // namespace android
 
-#endif /*AUDIORECORD_H_*/
+#endif // ANDROID_AUDIORECORD_H
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index b11c812..225ef76 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -17,20 +17,18 @@
 #ifndef ANDROID_AUDIOSYSTEM_H_
 #define ANDROID_AUDIOSYSTEM_H_
 
-#include <utils/RefBase.h>
-#include <utils/threads.h>
-#include <media/IAudioFlinger.h>
-
+#include <hardware/audio_effect.h>
+#include <media/IAudioFlingerClient.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
-
-/* XXX: Should be include by all the users instead */
-#include <media/AudioParameter.h>
+#include <utils/Errors.h>
+#include <utils/Mutex.h>
 
 namespace android {
 
 typedef void (*audio_error_callback)(status_t err);
 
+class IAudioFlinger;
 class IAudioPolicyService;
 class String8;
 
@@ -128,8 +126,10 @@
     // - BAD_VALUE: invalid parameter
     // NOTE: this feature is not supported on all hardware platforms and it is
     // necessary to check returned status before using the returned values.
-    static status_t getRenderPosition(size_t *halFrames, size_t *dspFrames,
-            audio_stream_type_t stream = AUDIO_STREAM_DEFAULT);
+    static status_t getRenderPosition(audio_io_handle_t output,
+                                      size_t *halFrames,
+                                      size_t *dspFrames,
+                                      audio_stream_type_t stream = AUDIO_STREAM_DEFAULT);
 
     // return the number of input frames lost by HAL implementation, or 0 if the handle is invalid
     static size_t getInputFramesLost(audio_io_handle_t ioHandle);
@@ -155,11 +155,11 @@
     class OutputDescriptor {
     public:
         OutputDescriptor()
-        : samplingRate(0), format(AUDIO_FORMAT_DEFAULT), channels(0), frameCount(0), latency(0)  {}
+        : samplingRate(0), format(AUDIO_FORMAT_DEFAULT), channelMask(0), frameCount(0), latency(0)  {}
 
         uint32_t samplingRate;
-        int32_t format;
-        int32_t channels;
+        audio_format_t format;
+        audio_channel_mask_t channelMask;
         size_t frameCount;
         uint32_t latency;
     };
@@ -197,7 +197,8 @@
                                         uint32_t samplingRate = 0,
                                         audio_format_t format = AUDIO_FORMAT_DEFAULT,
                                         audio_channel_mask_t channelMask = AUDIO_CHANNEL_OUT_STEREO,
-                                        audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE);
+                                        audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+                                        const audio_offload_info_t *offloadInfo = NULL);
     static status_t startOutput(audio_io_handle_t output,
                                 audio_stream_type_t stream,
                                 int session = 0);
@@ -245,6 +246,15 @@
     static uint32_t getPrimaryOutputSamplingRate();
     static size_t getPrimaryOutputFrameCount();
 
+    static status_t setLowRamDevice(bool isLowRamDevice);
+
+    // Check if hw offload is possible for given format, stream type, sample rate,
+    // bit rate, duration, video and streaming or offload property is enabled
+    static bool isOffloadSupported(const audio_offload_info_t& info);
+
+    // check presence of audio flinger service.
+    // returns NO_ERROR if binding to service succeeds, DEAD_OBJECT otherwise
+    static status_t checkAudioFlinger();
     // ----------------------------------------------------------------------------
 
 private:
diff --git a/include/media/AudioTimestamp.h b/include/media/AudioTimestamp.h
new file mode 100644
index 0000000..c29c7e5
--- /dev/null
+++ b/include/media/AudioTimestamp.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_TIMESTAMP_H
+#define ANDROID_AUDIO_TIMESTAMP_H
+
+#include <time.h>
+
+class AudioTimestamp {
+public:
+    AudioTimestamp() : mPosition(0) {
+        mTime.tv_sec = 0;
+        mTime.tv_nsec = 0;
+    }
+    // FIXME change type to match android.media.AudioTrack
+    uint32_t        mPosition; // a frame position in AudioTrack::getPosition() units
+    struct timespec mTime;     // corresponding CLOCK_MONOTONIC when frame is expected to present
+};
+
+#endif  // ANDROID_AUDIO_TIMESTAMP_H
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 64f82bb..4736369 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -17,18 +17,10 @@
 #ifndef ANDROID_AUDIOTRACK_H
 #define ANDROID_AUDIOTRACK_H
 
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <media/IAudioFlinger.h>
-#include <media/IAudioTrack.h>
-#include <media/AudioSystem.h>
-
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <binder/IInterface.h>
-#include <binder/IMemory.h>
 #include <cutils/sched_policy.h>
+#include <media/AudioSystem.h>
+#include <media/AudioTimestamp.h>
+#include <media/IAudioTrack.h>
 #include <utils/threads.h>
 
 namespace android {
@@ -37,10 +29,11 @@
 
 class audio_track_cblk_t;
 class AudioTrackClientProxy;
+class StaticAudioTrackClientProxy;
 
 // ----------------------------------------------------------------------------
 
-class AudioTrack : virtual public RefBase
+class AudioTrack : public RefBase
 {
 public:
     enum channel_index {
@@ -49,7 +42,7 @@
         RIGHT  = 1
     };
 
-    /* Events used by AudioTrack callback function (audio_track_cblk_t).
+    /* Events used by AudioTrack callback function (callback_t).
      * Keep in sync with frameworks/base/media/java/android/media/AudioTrack.java NATIVE_EVENT_*.
      */
     enum event_type {
@@ -64,7 +57,15 @@
                                     // (See setMarkerPosition()).
         EVENT_NEW_POS = 4,          // Playback head is at a new position
                                     // (See setPositionUpdatePeriod()).
-        EVENT_BUFFER_END = 5        // Playback head is at the end of the buffer.
+        EVENT_BUFFER_END = 5,       // Playback head is at the end of the buffer.
+                                    // Not currently used by android.media.AudioTrack.
+        EVENT_NEW_IAUDIOTRACK = 6,  // IAudioTrack was re-created, either due to re-routing and
+                                    // voluntary invalidation by mediaserver, or mediaserver crash.
+        EVENT_STREAM_END = 7,       // Sent after all the buffers queued in AF and HW are played
+                                    // back (after stop is called)
+        EVENT_NEW_TIMESTAMP = 8,    // Delivered periodically and when there's a significant change
+                                    // in the mapping from frame position to presentation time.
+                                    // See AudioTimestamp for the information included with event.
     };
 
     /* Client should declare Buffer on the stack and pass address to obtainBuffer()
@@ -74,19 +75,25 @@
     class Buffer
     {
     public:
+        // FIXME use m prefix
         size_t      frameCount;   // number of sample frames corresponding to size;
                                   // on input it is the number of frames desired,
                                   // on output is the number of frames actually filled
+                                  // (currently ignored, but will make the primary field in future)
 
-        size_t      size;         // input/output in byte units
+        size_t      size;         // input/output in bytes == frameCount * frameSize
+                                  // on output is the number of bytes actually filled
+                                  // FIXME this is redundant with respect to frameCount,
+                                  // and TRANSFER_OBTAIN mode is broken for 8-bit data
+                                  // since we don't define the frame format
+
         union {
             void*       raw;
-            short*      i16;    // signed 16-bit
-            int8_t*     i8;     // unsigned 8-bit, offset by 0x80
+            short*      i16;      // signed 16-bit
+            int8_t*     i8;       // unsigned 8-bit, offset by 0x80
         };
     };
 
-
     /* As a convenience, if a callback is supplied, a handler thread
      * is automatically created with the appropriate priority. This thread
      * invokes the callback when a new buffer becomes available or various conditions occur.
@@ -100,9 +107,12 @@
      *            written.
      *          - EVENT_UNDERRUN: unused.
      *          - EVENT_LOOP_END: pointer to an int indicating the number of loops remaining.
-     *          - EVENT_MARKER: pointer to an uint32_t containing the marker position in frames.
-     *          - EVENT_NEW_POS: pointer to an uint32_t containing the new position in frames.
+     *          - EVENT_MARKER: pointer to const uint32_t containing the marker position in frames.
+     *          - EVENT_NEW_POS: pointer to const uint32_t containing the new position in frames.
      *          - EVENT_BUFFER_END: unused.
+     *          - EVENT_NEW_IAUDIOTRACK: unused.
+     *          - EVENT_STREAM_END: unused.
+     *          - EVENT_NEW_TIMESTAMP: pointer to const AudioTimestamp.
      */
 
     typedef void (*callback_t)(int event, void* user, void *info);
@@ -112,11 +122,22 @@
      * Returned status (from utils/Errors.h) can be:
      *  - NO_ERROR: successful operation
      *  - NO_INIT: audio server or audio hardware not initialized
+     *  - BAD_VALUE: unsupported configuration
      */
 
-     static status_t getMinFrameCount(size_t* frameCount,
-                                      audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT,
-                                      uint32_t sampleRate = 0);
+    static status_t getMinFrameCount(size_t* frameCount,
+                                     audio_stream_type_t streamType,
+                                     uint32_t sampleRate);
+
+    /* How data is transferred to AudioTrack
+     */
+    enum transfer_type {
+        TRANSFER_DEFAULT,   // not specified explicitly; determine from the other parameters
+        TRANSFER_CALLBACK,  // callback EVENT_MORE_DATA
+        TRANSFER_OBTAIN,    // FIXME deprecated: call obtainBuffer() and releaseBuffer()
+        TRANSFER_SYNC,      // synchronous write()
+        TRANSFER_SHARED,    // shared memory
+    };
 
     /* Constructs an uninitialized AudioTrack. No connection with
      * AudioFlinger takes place.  Use set() after this.
@@ -128,13 +149,13 @@
      * Unspecified values are set to appropriate default values.
      * With this constructor, the track is configured for streaming mode.
      * Data to be rendered is supplied by write() or by the callback EVENT_MORE_DATA.
-     * Intermixing a combination of write() and non-ignored EVENT_MORE_DATA is deprecated.
+     * Intermixing a combination of write() and non-ignored EVENT_MORE_DATA is not allowed.
      *
      * Parameters:
      *
      * streamType:         Select the type of audio stream this track is attached to
      *                     (e.g. AUDIO_STREAM_MUSIC).
-     * sampleRate:         Track sampling rate in Hz.
+     * sampleRate:         Data source sampling rate in Hz.
      * format:             Audio format (e.g AUDIO_FORMAT_PCM_16_BIT for signed
      *                     16 bits per sample).
      * channelMask:        Channel mask.
@@ -149,21 +170,25 @@
      * user:               Context for use by the callback receiver.
      * notificationFrames: The callback function is called each time notificationFrames PCM
      *                     frames have been consumed from track input buffer.
+     *                     This is expressed in units of frames at the initial source sample rate.
      * sessionId:          Specific session ID, or zero to use default.
-     * threadCanCallJava:  Whether callbacks are made from an attached thread and thus can call JNI.
-     *                     If not present in parameter list, then fixed at false.
+     * transferType:       How data is transferred to AudioTrack.
+     * threadCanCallJava:  Not present in parameter list, and so is fixed at false.
      */
 
                         AudioTrack( audio_stream_type_t streamType,
-                                    uint32_t sampleRate  = 0,
-                                    audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                    audio_channel_mask_t channelMask = 0,
+                                    uint32_t sampleRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t,
                                     int frameCount       = 0,
                                     audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                                     callback_t cbf       = NULL,
                                     void* user           = NULL,
                                     int notificationFrames = 0,
-                                    int sessionId        = 0);
+                                    int sessionId        = 0,
+                                    transfer_type transferType = TRANSFER_DEFAULT,
+                                    const audio_offload_info_t *offloadInfo = NULL,
+                                    int uid = -1);
 
     /* Creates an audio track and registers it with AudioFlinger.
      * With this constructor, the track is configured for static buffer mode.
@@ -174,38 +199,48 @@
      * The write() method is not supported in this case.
      * It is recommended to pass a callback function to be notified of playback end by an
      * EVENT_UNDERRUN event.
-     * FIXME EVENT_MORE_DATA still occurs; it must be ignored.
      */
 
                         AudioTrack( audio_stream_type_t streamType,
-                                    uint32_t sampleRate = 0,
-                                    audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                    audio_channel_mask_t channelMask = 0,
-                                    const sp<IMemory>& sharedBuffer = 0,
+                                    uint32_t sampleRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t channelMask,
+                                    const sp<IMemory>& sharedBuffer,
                                     audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                                     callback_t cbf      = NULL,
                                     void* user          = NULL,
                                     int notificationFrames = 0,
-                                    int sessionId       = 0);
+                                    int sessionId       = 0,
+                                    transfer_type transferType = TRANSFER_DEFAULT,
+                                    const audio_offload_info_t *offloadInfo = NULL,
+                                    int uid = -1);
 
     /* Terminates the AudioTrack and unregisters it from AudioFlinger.
      * Also destroys all resources associated with the AudioTrack.
      */
-                        ~AudioTrack();
+protected:
+                        virtual ~AudioTrack();
+public:
 
-    /* Initialize an uninitialized AudioTrack.
+    /* Initialize an AudioTrack that was created using the AudioTrack() constructor.
+     * Don't call set() more than once, or after the AudioTrack() constructors that take parameters.
      * Returned status (from utils/Errors.h) can be:
      *  - NO_ERROR: successful initialization
      *  - INVALID_OPERATION: AudioTrack is already initialized
      *  - BAD_VALUE: invalid parameter (channelMask, format, sampleRate...)
      *  - NO_INIT: audio server or audio hardware not initialized
+     * If status is not equal to NO_ERROR, don't call any other APIs on this AudioTrack.
      * If sharedBuffer is non-0, the frameCount parameter is ignored and
      * replaced by the shared buffer's total allocated size in frame units.
+     *
+     * Parameters not listed in the AudioTrack constructors above:
+     *
+     * threadCanCallJava:  Whether callbacks are made from an attached thread and thus can call JNI.
      */
-            status_t    set(audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT,
-                            uint32_t sampleRate = 0,
-                            audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                            audio_channel_mask_t channelMask = 0,
+            status_t    set(audio_stream_type_t streamType,
+                            uint32_t sampleRate,
+                            audio_format_t format,
+                            audio_channel_mask_t channelMask,
                             int frameCount      = 0,
                             audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                             callback_t cbf      = NULL,
@@ -213,9 +248,12 @@
                             int notificationFrames = 0,
                             const sp<IMemory>& sharedBuffer = 0,
                             bool threadCanCallJava = false,
-                            int sessionId       = 0);
+                            int sessionId       = 0,
+                            transfer_type transferType = TRANSFER_DEFAULT,
+                            const audio_offload_info_t *offloadInfo = NULL,
+                            int uid = -1);
 
-    /* Result of constructing the AudioTrack. This must be checked
+    /* Result of constructing the AudioTrack. This must be checked for successful initialization
      * before using any AudioTrack API (except for set()), because using
      * an uninitialized AudioTrack produces undefined results.
      * See set() method above for possible return codes.
@@ -233,15 +271,16 @@
             audio_stream_type_t streamType() const { return mStreamType; }
             audio_format_t format() const   { return mFormat; }
 
-    /* Return frame size in bytes, which for linear PCM is channelCount * (bit depth per channel / 8).
+    /* Return frame size in bytes, which for linear PCM is
+     * channelCount * (bit depth per channel / 8).
      * channelCount is determined from channelMask, and bit depth comes from format.
      * For non-linear formats, the frame size is typically 1 byte.
      */
-            uint32_t    channelCount() const { return mChannelCount; }
-
-            uint32_t    frameCount() const  { return mFrameCount; }
             size_t      frameSize() const   { return mFrameSize; }
 
+            uint32_t    channelCount() const { return mChannelCount; }
+            uint32_t    frameCount() const  { return mFrameCount; }
+
     /* Return the static buffer specified in constructor or set(), or 0 for streaming mode */
             sp<IMemory> sharedBuffer() const { return mSharedBuffer; }
 
@@ -249,14 +288,13 @@
      * make it active. If set, the callback will start being called.
      * If the track was previously paused, volume is ramped up over the first mix buffer.
      */
-            void        start();
+            status_t        start();
 
     /* Stop a track.
      * In static buffer mode, the track is stopped immediately.
-     * In streaming mode, the callback will cease being called and
-     * obtainBuffer returns STOPPED. Note that obtainBuffer() still works
-     * and will fill up buffers until the pool is exhausted.
-     * The stop does not occur immediately: any data remaining in the buffer
+     * In streaming mode, the callback will cease being called.  Note that obtainBuffer() still
+     * works and will fill up buffers until the pool is exhausted, and then will return WOULD_BLOCK.
+     * In streaming mode the stop does not occur immediately: any data remaining in the buffer
      * is first drained, mixed, and output, and only then is the track marked as stopped.
      */
             void        stop();
@@ -270,7 +308,7 @@
             void        flush();
 
     /* Pause a track. After pause, the callback will cease being called and
-     * obtainBuffer returns STOPPED. Note that obtainBuffer() still works
+     * obtainBuffer returns WOULD_BLOCK. Note that obtainBuffer() still works
      * and will fill up buffers until the pool is exhausted.
      * Volume is ramped down over the next mix buffer following the pause request,
      * and then the track is marked as paused.  It can be resumed with ramp up by start().
@@ -294,11 +332,11 @@
             status_t    setAuxEffectSendLevel(float level);
             void        getAuxEffectSendLevel(float* level) const;
 
-    /* Set sample rate for this track in Hz, mostly used for games' sound effects
+    /* Set source sample rate for this track in Hz, mostly used for games' sound effects
      */
             status_t    setSampleRate(uint32_t sampleRate);
 
-    /* Return current sample rate in Hz, or 0 if unknown */
+    /* Return current source sample rate in Hz, or 0 if unknown */
             uint32_t    getSampleRate() const;
 
     /* Enables looping and sets the start and end points of looping.
@@ -306,20 +344,24 @@
      *
      * Parameters:
      *
-     * loopStart:   loop start expressed as the number of PCM frames played since AudioTrack start.
-     * loopEnd:     loop end expressed as the number of PCM frames played since AudioTrack start.
+     * loopStart:   loop start in frames relative to start of buffer.
+     * loopEnd:     loop end in frames relative to start of buffer.
      * loopCount:   number of loops to execute. Calling setLoop() with loopCount == 0 cancels any
-     *              pending or active loop. loopCount = -1 means infinite looping.
+     *              pending or active loop. loopCount == -1 means infinite looping.
      *
      * For proper operation the following condition must be respected:
-     *          (loopEnd-loopStart) <= framecount()
+     *      loopCount != 0 implies 0 <= loopStart < loopEnd <= frameCount().
+     *
+     * If the loop period (loopEnd - loopStart) is too small for the implementation to support,
+     * setLoop() will return BAD_VALUE.  loopCount must be >= -1.
+     *
      */
             status_t    setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount);
 
     /* Sets marker position. When playback reaches the number of frames specified, a callback with
      * event type EVENT_MARKER is called. Calling setMarkerPosition with marker == 0 cancels marker
      * notification callback.  To set a marker at a position which would compute as 0,
-     * a workaround is to the set the marker at a nearby position such as -1 or 1.
+     * a workaround is to the set the marker at a nearby position such as ~0 or 1.
      * If the AudioTrack has been opened with no callback function associated, the operation will
      * fail.
      *
@@ -354,18 +396,14 @@
             status_t    setPositionUpdatePeriod(uint32_t updatePeriod);
             status_t    getPositionUpdatePeriod(uint32_t *updatePeriod) const;
 
-    /* Sets playback head position within AudioTrack buffer. The new position is specified
-     * in number of frames.
-     * This method must be called with the AudioTrack in paused or stopped state.
-     * Note that the actual position set is <position> modulo the AudioTrack buffer size in frames.
-     * Therefore using this method makes sense only when playing a "static" audio buffer
-     * as opposed to streaming.
-     * The getPosition() method on the other hand returns the total number of frames played since
-     * playback start.
+    /* Sets playback head position.
+     * Only supported for static buffer mode.
      *
      * Parameters:
      *
-     * position:  New playback head position within AudioTrack buffer.
+     * position:  New playback head position in frames relative to start of buffer.
+     *            0 <= position <= frameCount().  Note that end of buffer is permitted,
+     *            but will result in an immediate underrun if started.
      *
      * Returned status (from utils/Errors.h) can be:
      *  - NO_ERROR: successful operation
@@ -378,8 +416,22 @@
     /* Return the total number of frames played since playback start.
      * The counter will wrap (overflow) periodically, e.g. every ~27 hours at 44.1 kHz.
      * It is reset to zero by flush(), reload(), and stop().
+     *
+     * Parameters:
+     *
+     *  position:  Address where to return play head position.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - BAD_VALUE:  position is NULL
      */
-            status_t    getPosition(uint32_t *position);
+            status_t    getPosition(uint32_t *position) const;
+
+    /* For static buffer mode only, this returns the current playback position in frames
+     * relative to start of buffer.  It is analogous to the position units used by
+     * setLoop() and setPosition().  After underrun, the position will be at end of buffer.
+     */
+            status_t    getBufferPosition(uint32_t *position);
 
     /* Forces AudioTrack buffer full condition. When playing a static buffer, this method avoids
      * rewriting the buffer before restarting playback after a stop.
@@ -426,15 +478,19 @@
      */
             status_t    attachAuxEffect(int effectId);
 
-    /* Obtains a buffer of "frameCount" frames. The buffer must be
-     * filled entirely, and then released with releaseBuffer().
-     * If the track is stopped, obtainBuffer() returns
-     * STOPPED instead of NO_ERROR as long as there are buffers available,
-     * at which point NO_MORE_BUFFERS is returned.
+    /* Obtains a buffer of up to "audioBuffer->frameCount" empty slots for frames.
+     * After filling these slots with data, the caller should release them with releaseBuffer().
+     * If the track buffer is not full, obtainBuffer() returns as many contiguous
+     * [empty slots for] frames as are available immediately.
+     * If the track buffer is full and track is stopped, obtainBuffer() returns WOULD_BLOCK
+     * regardless of the value of waitCount.
+     * If the track buffer is full and track is not stopped, obtainBuffer() blocks with a
+     * maximum timeout based on waitCount; see chart below.
      * Buffers will be returned until the pool
      * is exhausted, at which point obtainBuffer() will either block
-     * or return WOULD_BLOCK depending on the value of the "blocking"
+     * or return WOULD_BLOCK depending on the value of the "waitCount"
      * parameter.
+     * Each sample is 16-bit signed PCM.
      *
      * obtainBuffer() and releaseBuffer() are deprecated for direct use by applications,
      * which should use write() or callback EVENT_MORE_DATA instead.
@@ -457,33 +513,76 @@
      *  raw         pointer to the buffer
      */
 
-        enum {
-            NO_MORE_BUFFERS = 0x80000001,   // same name in AudioFlinger.h, ok to be different value
-            STOPPED = 1
-        };
+    /* FIXME Deprecated public API for TRANSFER_OBTAIN mode */
+            status_t    obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
+                                __attribute__((__deprecated__));
 
-            status_t    obtainBuffer(Buffer* audioBuffer, int32_t waitCount);
+private:
+    /* If nonContig is non-NULL, it is an output parameter that will be set to the number of
+     * additional non-contiguous frames that are available immediately.
+     * FIXME We could pass an array of Buffers instead of only one Buffer to obtainBuffer(),
+     * in case the requested amount of frames is in two or more non-contiguous regions.
+     * FIXME requested and elapsed are both relative times.  Consider changing to absolute time.
+     */
+            status_t    obtainBuffer(Buffer* audioBuffer, const struct timespec *requested,
+                                     struct timespec *elapsed = NULL, size_t *nonContig = NULL);
+public:
 
-    /* Release a filled buffer of "frameCount" frames for AudioFlinger to process. */
+//EL_FIXME to be reconciled with new obtainBuffer() return codes and control block proxy
+//            enum {
+//            NO_MORE_BUFFERS = 0x80000001,   // same name in AudioFlinger.h, ok to be different value
+//            TEAR_DOWN       = 0x80000002,
+//            STOPPED = 1,
+//            STREAM_END_WAIT,
+//            STREAM_END
+//        };
+
+    /* Release a filled buffer of "audioBuffer->frameCount" frames for AudioFlinger to process. */
+    // FIXME make private when obtainBuffer() for TRANSFER_OBTAIN is removed
             void        releaseBuffer(Buffer* audioBuffer);
 
     /* As a convenience we provide a write() interface to the audio buffer.
+     * Input parameter 'size' is in byte units.
      * This is implemented on top of obtainBuffer/releaseBuffer. For best
      * performance use callbacks. Returns actual number of bytes written >= 0,
      * or one of the following negative status codes:
-     *      INVALID_OPERATION   AudioTrack is configured for shared buffer mode
+     *      INVALID_OPERATION   AudioTrack is configured for static buffer or streaming mode
      *      BAD_VALUE           size is invalid
-     *      STOPPED             AudioTrack was stopped during the write
-     *      NO_MORE_BUFFERS     when obtainBuffer() returns same
+     *      WOULD_BLOCK         when obtainBuffer() returns same, or
+     *                          AudioTrack was stopped during the write
      *      or any other error code returned by IAudioTrack::start() or restoreTrack_l().
-     * Not supported for static buffer mode.
      */
             ssize_t     write(const void* buffer, size_t size);
 
     /*
      * Dumps the state of an audio track.
      */
-            status_t dump(int fd, const Vector<String16>& args) const;
+            status_t    dump(int fd, const Vector<String16>& args) const;
+
+    /*
+     * Return the total number of frames which AudioFlinger desired but were unavailable,
+     * and thus which resulted in an underrun.  Reset to zero by stop().
+     */
+            uint32_t    getUnderrunFrames() const;
+
+    /* Get the flags */
+            audio_output_flags_t getFlags() const { return mFlags; }
+
+    /* Set parameters - only possible when using direct output */
+            status_t    setParameters(const String8& keyValuePairs);
+
+    /* Get parameters */
+            String8     getParameters(const String8& keys);
+
+    /* Poll for a timestamp on demand.
+     * Use if EVENT_NEW_TIMESTAMP is not delivered often enough for your needs,
+     * or if you need to get the most recent timestamp outside of the event callback handler.
+     * Caution: calling this method too often may be inefficient;
+     * if you need a high resolution mapping between frame position and presentation time,
+     * consider implementing that at application level, based on the low resolution timestamps.
+     * Returns NO_ERROR if timestamp is valid.
+     */
+            status_t    getTimestamp(AudioTimestamp& timestamp);
 
 protected:
     /* copying audio tracks is not allowed */
@@ -504,102 +603,159 @@
                 void        resume();   // allow thread to execute, if not requested to exit
 
     private:
+                void        pauseInternal(nsecs_t ns = 0LL);
+                                        // like pause(), but only used internally within thread
+
         friend class AudioTrack;
         virtual bool        threadLoop();
-        AudioTrack& mReceiver;
-        ~AudioTrackThread();
+        AudioTrack&         mReceiver;
+        virtual ~AudioTrackThread();
         Mutex               mMyLock;    // Thread::mLock is private
         Condition           mMyCond;    // Thread::mThreadExitedCondition is private
-        bool                mPaused;    // whether thread is currently paused
+        bool                mPaused;    // whether thread is requested to pause at next loop entry
+        bool                mPausedInt; // whether thread internally requests pause
+        nsecs_t             mPausedNs;  // if mPausedInt then associated timeout, otherwise ignored
+        bool                mIgnoreNextPausedInt;   // whether to ignore next mPausedInt request
     };
 
             // body of AudioTrackThread::threadLoop()
-            bool processAudioBuffer(const sp<AudioTrackThread>& thread);
+            // returns the maximum amount of time before we would like to run again, where:
+            //      0           immediately
+            //      > 0         no later than this many nanoseconds from now
+            //      NS_WHENEVER still active but no particular deadline
+            //      NS_INACTIVE inactive so don't run again until re-started
+            //      NS_NEVER    never again
+            static const nsecs_t NS_WHENEVER = -1, NS_INACTIVE = -2, NS_NEVER = -3;
+            nsecs_t processAudioBuffer(const sp<AudioTrackThread>& thread);
+            status_t processStreamEnd(int32_t waitCount);
+
 
             // caller must hold lock on mLock for all _l methods
+
             status_t createTrack_l(audio_stream_type_t streamType,
                                  uint32_t sampleRate,
                                  audio_format_t format,
                                  size_t frameCount,
                                  audio_output_flags_t flags,
                                  const sp<IMemory>& sharedBuffer,
-                                 audio_io_handle_t output);
+                                 audio_io_handle_t output,
+                                 size_t epoch);
 
-            // can only be called when !mActive
+            // can only be called when mState != STATE_ACTIVE
             void flush_l();
 
-            status_t setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount);
+            void setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount);
             audio_io_handle_t getOutput_l();
-            status_t restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart);
-            bool stopped_l() const { return !mActive; }
 
+            // FIXME enum is faster than strcmp() for parameter 'from'
+            status_t restoreTrack_l(const char *from);
+
+            bool     isOffloaded() const
+                { return (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0; }
+
+    // Next 3 fields may be changed if IAudioTrack is re-created, but always != 0
     sp<IAudioTrack>         mAudioTrack;
     sp<IMemory>             mCblkMemory;
-    sp<AudioTrackThread>    mAudioTrackThread;
+    audio_track_cblk_t*     mCblk;                  // re-load after mLock.unlock()
 
+    sp<AudioTrackThread>    mAudioTrackThread;
     float                   mVolume[2];
     float                   mSendLevel;
-    uint32_t                mSampleRate;
+    mutable uint32_t        mSampleRate;            // mutable because getSampleRate() can update it.
     size_t                  mFrameCount;            // corresponds to current IAudioTrack
     size_t                  mReqFrameCount;         // frame count to request the next time a new
                                                     // IAudioTrack is needed
 
-    audio_track_cblk_t*     mCblk;                  // re-load after mLock.unlock()
 
-            // Starting address of buffers in shared memory.  If there is a shared buffer, mBuffers
-            // is the value of pointer() for the shared buffer, otherwise mBuffers points
-            // immediately after the control block.  This address is for the mapping within client
-            // address space.  AudioFlinger::TrackBase::mBuffer is for the server address space.
-    void*                   mBuffers;
-
+    // constant after constructor or set()
     audio_format_t          mFormat;                // as requested by client, not forced to 16-bit
     audio_stream_type_t     mStreamType;
     uint32_t                mChannelCount;
     audio_channel_mask_t    mChannelMask;
+    transfer_type           mTransfer;
 
-                // mFrameSize is equal to mFrameSizeAF for non-PCM or 16-bit PCM data.
-                // For 8-bit PCM data, mFrameSizeAF is
-                // twice as large because data is expanded to 16-bit before being stored in buffer.
+    // mFrameSize is equal to mFrameSizeAF for non-PCM or 16-bit PCM data.  For 8-bit PCM data, it's
+    // twice as large as mFrameSize because data is expanded to 16-bit before it's stored in buffer.
     size_t                  mFrameSize;             // app-level frame size
     size_t                  mFrameSizeAF;           // AudioFlinger frame size
 
     status_t                mStatus;
-    uint32_t                mLatency;
 
-    bool                    mActive;                // protected by mLock
+    // can change dynamically when IAudioTrack invalidated
+    uint32_t                mLatency;               // in ms
 
+    // Indicates the current track state.  Protected by mLock.
+    enum State {
+        STATE_ACTIVE,
+        STATE_STOPPED,
+        STATE_PAUSED,
+        STATE_PAUSED_STOPPING,
+        STATE_FLUSHED,
+        STATE_STOPPING,
+    }                       mState;
+
+    // for client callback handler
     callback_t              mCbf;                   // callback handler for events, or NULL
-    void*                   mUserData;              // for client callback handler
+    void*                   mUserData;
 
     // for notification APIs
     uint32_t                mNotificationFramesReq; // requested number of frames between each
-                                                    // notification callback
+                                                    // notification callback,
+                                                    // at initial source sample rate
     uint32_t                mNotificationFramesAct; // actual number of frames between each
-                                                    // notification callback
+                                                    // notification callback,
+                                                    // at initial source sample rate
+    bool                    mRefreshRemaining;      // processAudioBuffer() should refresh next 2
+
+    // These are private to processAudioBuffer(), and are not protected by a lock
+    uint32_t                mRemainingFrames;       // number of frames to request in obtainBuffer()
+    bool                    mRetryOnPartialBuffer;  // sleep and retry after partial obtainBuffer()
+    uint32_t                mObservedSequence;      // last observed value of mSequence
+
     sp<IMemory>             mSharedBuffer;
-    int                     mLoopCount;
-    uint32_t                mRemainingFrames;
+    uint32_t                mLoopPeriod;            // in frames, zero means looping is disabled
     uint32_t                mMarkerPosition;        // in wrapping (overflow) frame units
     bool                    mMarkerReached;
     uint32_t                mNewPosition;           // in frames
-    uint32_t                mUpdatePeriod;          // in frames
+    uint32_t                mUpdatePeriod;          // in frames, zero means no EVENT_NEW_POS
 
-    bool                    mFlushed; // FIXME will be made obsolete by making flush() synchronous
     audio_output_flags_t    mFlags;
     int                     mSessionId;
     int                     mAuxEffectId;
 
-    // When locking both mLock and mCblk->lock, must lock in this order to avoid deadlock:
-    //      1. mLock
-    //      2. mCblk->lock
-    // It is OK to lock only mCblk->lock.
     mutable Mutex           mLock;
 
     bool                    mIsTimed;
     int                     mPreviousPriority;          // before start()
     SchedPolicy             mPreviousSchedulingGroup;
-    AudioTrackClientProxy*  mProxy;
     bool                    mAwaitBoost;    // thread should wait for priority boost before running
+
+    // The proxy should only be referenced while a lock is held because the proxy isn't
+    // multi-thread safe, especially the SingleStateQueue part of the proxy.
+    // An exception is that a blocking ClientProxy::obtainBuffer() may be called without a lock,
+    // provided that the caller also holds an extra reference to the proxy and shared memory to keep
+    // them around in case they are replaced during the obtainBuffer().
+    sp<StaticAudioTrackClientProxy> mStaticProxy;   // for type safety only
+    sp<AudioTrackClientProxy>       mProxy;         // primary owner of the memory
+
+    bool                    mInUnderrun;            // whether track is currently in underrun state
+    String8                 mName;                  // server's name for this IAudioTrack
+    uint32_t                mPausedPosition;
+
+private:
+    class DeathNotifier : public IBinder::DeathRecipient {
+    public:
+        DeathNotifier(AudioTrack* audioTrack) : mAudioTrack(audioTrack) { }
+    protected:
+        virtual void        binderDied(const wp<IBinder>& who);
+    private:
+        const wp<AudioTrack> mAudioTrack;
+    };
+
+    sp<DeathNotifier>       mDeathNotifier;
+    uint32_t                mSequence;              // incremented for each new IAudioTrack attempt
+    audio_io_handle_t       mOutput;                // cached output io handle
+    int                     mClientUid;
 };
 
 class TimedAudioTrack : public AudioTrack
diff --git a/include/media/ExtendedAudioBufferProvider.h b/include/media/ExtendedAudioBufferProvider.h
index 00c4444..2539ed3 100644
--- a/include/media/ExtendedAudioBufferProvider.h
+++ b/include/media/ExtendedAudioBufferProvider.h
@@ -18,12 +18,20 @@
 #define ANDROID_EXTENDED_AUDIO_BUFFER_PROVIDER_H
 
 #include <media/AudioBufferProvider.h>
+#include <media/AudioTimestamp.h>
 
 namespace android {
 
 class ExtendedAudioBufferProvider : public AudioBufferProvider {
 public:
     virtual size_t  framesReady() const = 0;  // see description at AudioFlinger.h
+
+    // Return the total number of frames that have been obtained and released
+    virtual size_t  framesReleased() const { return 0; }
+
+    // Invoked by buffer consumer when a new timestamp is available.
+    // Default implementation ignores the timestamp.
+    virtual void    onTimestamp(const AudioTimestamp& timestamp) { }
 };
 
 }   // namespace android
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 9c3067e..899d79f 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -49,9 +49,13 @@
         TRACK_DEFAULT = 0,  // client requests a default AudioTrack
         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
     };
     typedef uint32_t track_flags_t;
 
+    // invariant on exit for all APIs that return an sp<>:
+    //   (return value != 0) == (*status == NO_ERROR)
+
     /* create an audio track and registers it with AudioFlinger.
      * return null if the track cannot be created.
      */
@@ -66,6 +70,11 @@
                                 audio_io_handle_t output,
                                 pid_t tid,  // -1 means unused, otherwise must be valid non-0
                                 int *sessionId,
+                                // input: ignored
+                                // output: server's description of IAudioTrack for display in logs.
+                                // Don't attempt to parse, as the format could change.
+                                String8& name,
+                                int clientUid,
                                 status_t *status) = 0;
 
     virtual sp<IAudioRecord> openRecord(
@@ -74,7 +83,7 @@
                                 audio_format_t format,
                                 audio_channel_mask_t channelMask,
                                 size_t frameCount,
-                                track_flags_t flags,
+                                track_flags_t *flags,
                                 pid_t tid,  // -1 means unused, otherwise must be valid non-0
                                 int *sessionId,
                                 status_t *status) = 0;
@@ -124,7 +133,9 @@
     virtual     String8     getParameters(audio_io_handle_t ioHandle, const String8& keys)
                                     const = 0;
 
-    // register a current process for audio output change notifications
+    // Register an object to receive audio input/output change and track notifications.
+    // For a given calling pid, AudioFlinger disregards any registrations after the first.
+    // Thus the IAudioFlingerClient must be a singleton per process.
     virtual void registerClient(const sp<IAudioFlingerClient>& client) = 0;
 
     // retrieve the audio recording buffer size
@@ -137,7 +148,8 @@
                                          audio_format_t *pFormat,
                                          audio_channel_mask_t *pChannelMask,
                                          uint32_t *pLatencyMs,
-                                         audio_output_flags_t flags) = 0;
+                                         audio_output_flags_t flags,
+                                         const audio_offload_info_t *offloadInfo = NULL) = 0;
     virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
                                     audio_io_handle_t output2) = 0;
     virtual status_t closeOutput(audio_io_handle_t output) = 0;
@@ -193,6 +205,10 @@
     virtual uint32_t getPrimaryOutputSamplingRate() = 0;
     virtual size_t getPrimaryOutputFrameCount() = 0;
 
+    // Intended for AudioService to inform AudioFlinger of device's low RAM attribute,
+    // and should be called at most once.  For a definition of what "low RAM" means, see
+    // android.app.ActivityManager.isLowRamDevice().
+    virtual status_t setLowRamDevice(bool isLowRamDevice) = 0;
 };
 
 
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index b5ad4ef..09b9ea6 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -53,7 +53,8 @@
                                         uint32_t samplingRate = 0,
                                         audio_format_t format = AUDIO_FORMAT_DEFAULT,
                                         audio_channel_mask_t channelMask = 0,
-                                        audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE) = 0;
+                                        audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+                                        const audio_offload_info_t *offloadInfo = NULL) = 0;
     virtual status_t startOutput(audio_io_handle_t output,
                                  audio_stream_type_t stream,
                                  int session = 0) = 0;
@@ -95,6 +96,9 @@
     virtual status_t queryDefaultPreProcessing(int audioSession,
                                               effect_descriptor_t *descriptors,
                                               uint32_t *count) = 0;
+   // Check if offload is possible for given format, stream type, sample rate,
+    // bit rate, duration, video and streaming or offload property is enabled
+    virtual bool isOffloadSupported(const audio_offload_info_t& info) = 0;
 };
 
 
diff --git a/include/media/IAudioRecord.h b/include/media/IAudioRecord.h
index d6e3141..eccc2ca 100644
--- a/include/media/IAudioRecord.h
+++ b/include/media/IAudioRecord.h
@@ -34,6 +34,9 @@
 public:
     DECLARE_META_INTERFACE(AudioRecord);
 
+    /* get this tracks control block */
+    virtual sp<IMemory> getCblk() const = 0;
+
     /* After it's created the track is not active. Call start() to
      * make it active.
      */
@@ -44,9 +47,6 @@
      * will be processed, unless flush() is called.
      */
     virtual void        stop() = 0;
-
-    /* get this tracks control block */
-    virtual sp<IMemory> getCblk() const = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index 144be0e..5c8a484 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -25,6 +25,8 @@
 #include <binder/IInterface.h>
 #include <binder/IMemory.h>
 #include <utils/LinearTransform.h>
+#include <utils/String8.h>
+#include <media/AudioTimestamp.h>
 
 namespace android {
 
@@ -82,6 +84,15 @@
        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;
+
+    /* Return NO_ERROR if timestamp is valid */
+    virtual status_t    getTimestamp(AudioTimestamp& timestamp) = 0;
+
+    /* Signal the playback thread for a change in control block */
+    virtual void        signal() = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/IDrm.h b/include/media/IDrm.h
index d630c40..5ef26af 100644
--- a/include/media/IDrm.h
+++ b/include/media/IDrm.h
@@ -32,7 +32,7 @@
 
     virtual status_t initCheck() const = 0;
 
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) = 0;
+    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) = 0;
 
     virtual status_t createPlugin(const uint8_t uuid[16]) = 0;
 
diff --git a/include/media/IHDCP.h b/include/media/IHDCP.h
index 6d27b18..352561e 100644
--- a/include/media/IHDCP.h
+++ b/include/media/IHDCP.h
@@ -17,6 +17,7 @@
 #include <binder/IInterface.h>
 #include <media/hardware/HDCPAPI.h>
 #include <media/stagefright/foundation/ABase.h>
+#include <ui/GraphicBuffer.h>
 
 namespace android {
 
@@ -45,6 +46,17 @@
     // Request to shutdown the active HDCP session.
     virtual status_t shutdownAsync() = 0;
 
+    // Returns the capability bitmask of this HDCP session.
+    // Possible return values (please refer to HDCAPAPI.h):
+    //   HDCP_CAPS_ENCRYPT: mandatory, meaning the HDCP module can encrypt
+    //   from an input byte-array buffer to an output byte-array buffer
+    //   HDCP_CAPS_ENCRYPT_NATIVE: the HDCP module supports encryption from
+    //   a native buffer to an output byte-array buffer. The format of the
+    //   input native buffer is specific to vendor's encoder implementation.
+    //   It is the same format as that used by the encoder when
+    //   "storeMetaDataInBuffers" extension is enabled on its output port.
+    virtual uint32_t getCaps() = 0;
+
     // ENCRYPTION only:
     // Encrypt data according to the HDCP spec. "size" bytes of data are
     // available at "inData" (virtual address), "size" may not be a multiple
@@ -59,6 +71,20 @@
             const void *inData, size_t size, uint32_t streamCTR,
             uint64_t *outInputCTR, void *outData) = 0;
 
+    // Encrypt data according to the HDCP spec. "size" bytes of data starting
+    // at location "offset" are available in "buffer" (buffer handle). "size"
+    // may not be a multiple of 128 bits (16 bytes). An equal number of
+    // encrypted bytes should be written to the buffer at "outData" (virtual
+    // address). This operation is to be synchronous, i.e. this call does not
+    // return until outData contains size bytes of encrypted data.
+    // streamCTR will be assigned by the caller (to 0 for the first PES stream,
+    // 1 for the second and so on)
+    // inputCTR _will_be_maintained_by_the_callee_ for each PES stream.
+    virtual status_t encryptNative(
+            const sp<GraphicBuffer> &graphicBuffer,
+            size_t offset, size_t size, uint32_t streamCTR,
+            uint64_t *outInputCTR, void *outData) = 0;
+
     // DECRYPTION only:
     // Decrypt data according to the HDCP spec.
     // "size" bytes of encrypted data are available at "inData"
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index fef7af2..2998b37 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -49,8 +49,12 @@
     virtual sp<IMediaMetadataRetriever> createMetadataRetriever() = 0;
     virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client, int audioSessionId = 0) = 0;
 
-    virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat) = 0;
-    virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat) = 0;
+    virtual status_t         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels,
+                                    audio_format_t* pFormat,
+                                    const sp<IMemoryHeap>& heap, size_t *pSize) = 0;
+    virtual status_t         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate,
+                                    int* pNumChannels, audio_format_t* pFormat,
+                                    const sp<IMemoryHeap>& heap, size_t *pSize) = 0;
     virtual sp<IOMX>            getOMX() = 0;
     virtual sp<ICrypto>         makeCrypto() = 0;
     virtual sp<IDrm>            makeDrm() = 0;
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 0b1d1e4..6643736 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -83,6 +83,10 @@
     virtual status_t storeMetaDataInBuffers(
             node_id node, OMX_U32 port_index, OMX_BOOL enable) = 0;
 
+    virtual status_t prepareForAdaptivePlayback(
+            node_id node, OMX_U32 portIndex, OMX_BOOL enable,
+            OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) = 0;
+
     virtual status_t enableGraphicBuffers(
             node_id node, OMX_U32 port_index, OMX_BOOL enable) = 0;
 
@@ -97,6 +101,10 @@
             node_id node, OMX_U32 port_index,
             const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) = 0;
 
+    virtual status_t updateGraphicBufferInMeta(
+            node_id node, OMX_U32 port_index,
+            const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) = 0;
+
     virtual status_t createInputSurface(
             node_id node, OMX_U32 port_index,
             sp<IGraphicBufferProducer> *bufferProducer) = 0;
@@ -130,6 +138,18 @@
             node_id node,
             const char *parameter_name,
             OMX_INDEXTYPE *index) = 0;
+
+    enum InternalOptionType {
+        INTERNAL_OPTION_SUSPEND,  // data is a bool
+        INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY,  // data is an int64_t
+        INTERNAL_OPTION_MAX_TIMESTAMP_GAP, // data is int64_t
+    };
+    virtual status_t setInternalOption(
+            node_id node,
+            OMX_U32 port_index,
+            InternalOptionType type,
+            const void *data,
+            size_t size) = 0;
 };
 
 struct omx_message {
diff --git a/include/media/IRemoteDisplayClient.h b/include/media/IRemoteDisplayClient.h
index 7b0fa9e..0e6d55d 100644
--- a/include/media/IRemoteDisplayClient.h
+++ b/include/media/IRemoteDisplayClient.h
@@ -49,7 +49,7 @@
     // Provides a surface texture that the client should use to stream buffers to
     // the remote display.
     virtual void onDisplayConnected(const sp<IGraphicBufferProducer>& bufferProducer,
-            uint32_t width, uint32_t height, uint32_t flags) = 0; // one-way
+            uint32_t width, uint32_t height, uint32_t flags, uint32_t session) = 0; // one-way
 
     // Indicates that the remote display has been disconnected normally.
     // This method should only be called once the client has called 'dispose()'
diff --git a/include/media/JetPlayer.h b/include/media/JetPlayer.h
index 0616bf0..388f767 100644
--- a/include/media/JetPlayer.h
+++ b/include/media/JetPlayer.h
@@ -88,7 +88,7 @@
     EAS_DATA_HANDLE     mEasData;
     EAS_FILE_LOCATOR    mEasJetFileLoc;
     EAS_PCM*            mAudioBuffer;// EAS renders the MIDI data into this buffer,
-    AudioTrack*         mAudioTrack; // and we play it in this audio track
+    sp<AudioTrack>      mAudioTrack; // and we play it in this audio track
     int                 mTrackBufferSize;
     S_JET_STATUS        mJetStatus;
     S_JET_STATUS        mPreviousJetStatus;
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 9a75f81..26d8729 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -74,9 +74,18 @@
     // AudioSink: abstraction layer for audio output
     class AudioSink : public RefBase {
     public:
+        enum cb_event_t {
+            CB_EVENT_FILL_BUFFER,   // Request to write more data to buffer.
+            CB_EVENT_STREAM_END,    // Sent after all the buffers queued in AF and HW are played
+                                    // back (after stop is called)
+            CB_EVENT_TEAR_DOWN      // The AudioTrack was invalidated due to use case change:
+                                    // Need to re-evaluate offloading options
+        };
+
         // Callback returns the number of bytes actually written to the buffer.
         typedef size_t (*AudioCallback)(
-                AudioSink *audioSink, void *buffer, size_t size, void *cookie);
+                AudioSink *audioSink, void *buffer, size_t size, void *cookie,
+                        cb_event_t event);
 
         virtual             ~AudioSink() {}
         virtual bool        ready() const = 0; // audio output is open and ready
@@ -90,6 +99,8 @@
         virtual status_t    getPosition(uint32_t *position) const = 0;
         virtual status_t    getFramesWritten(uint32_t *frameswritten) const = 0;
         virtual int         getSessionId() const = 0;
+        virtual audio_stream_type_t getAudioStreamType() const = 0;
+        virtual uint32_t    getSampleRate() const = 0;
 
         // If no callback is specified, use the "write" API below to submit
         // audio data.
@@ -99,9 +110,10 @@
                 int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT,
                 AudioCallback cb = NULL,
                 void *cookie = NULL,
-                audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE) = 0;
+                audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+                const audio_offload_info_t *offloadInfo = NULL) = 0;
 
-        virtual void        start() = 0;
+        virtual status_t    start() = 0;
         virtual ssize_t     write(const void* buffer, size_t size) = 0;
         virtual void        stop() = 0;
         virtual void        flush() = 0;
@@ -110,6 +122,9 @@
 
         virtual status_t    setPlaybackRatePermille(int32_t rate) { return INVALID_OPERATION; }
         virtual bool        needsTrailingPadding() { return true; }
+
+        virtual status_t    setParameters(const String8& keyValuePairs) { return NO_ERROR; };
+        virtual String8     getParameters(const String8& keys) { return String8::empty(); };
     };
 
                         MediaPlayerBase() : mCookie(0), mNotify(0) {}
diff --git a/include/media/SoundPool.h b/include/media/SoundPool.h
index 7bf3069..2dd78cc 100644
--- a/include/media/SoundPool.h
+++ b/include/media/SoundPool.h
@@ -22,6 +22,8 @@
 #include <utils/Vector.h>
 #include <utils/KeyedVector.h>
 #include <media/AudioTrack.h>
+#include <binder/MemoryHeapBase.h>
+#include <binder/MemoryBase.h>
 
 namespace android {
 
@@ -85,6 +87,7 @@
     int64_t             mLength;
     char*               mUrl;
     sp<IMemory>         mData;
+    sp<MemoryHeapBase>  mHeap;
 };
 
 // stores pending events for stolen channels
@@ -118,7 +121,7 @@
 class SoundChannel : public SoundEvent {
 public:
     enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING };
-    SoundChannel() : mAudioTrack(NULL), mState(IDLE), mNumChannels(1),
+    SoundChannel() : mState(IDLE), mNumChannels(1),
             mPos(0), mToggle(0), mAutoPaused(false) {}
     ~SoundChannel();
     void init(SoundPool* soundPool);
@@ -148,7 +151,7 @@
     bool doStop_l();
 
     SoundPool*          mSoundPool;
-    AudioTrack*         mAudioTrack;
+    sp<AudioTrack>      mAudioTrack;
     SoundEvent          mNextEvent;
     Mutex               mLock;
     int                 mState;
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index 2183fbe..98c4332 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -160,7 +160,7 @@
     bool isInited() { return (mState == TONE_IDLE)?false:true;}
 
     // returns the audio session this ToneGenerator belongs to or 0 if an error occured.
-    int getSessionId() { return (mpAudioTrack == NULL) ? 0 : mpAudioTrack->getSessionId(); }
+    int getSessionId() { return (mpAudioTrack == 0) ? 0 : mpAudioTrack->getSessionId(); }
 
 private:
 
@@ -264,7 +264,7 @@
     unsigned short mLoopCounter; // Current tone loopback count
 
     uint32_t mSamplingRate;  // AudioFlinger Sampling rate
-    AudioTrack *mpAudioTrack;  // Pointer to audio track used for playback
+    sp<AudioTrack> mpAudioTrack;  // Pointer to audio track used for playback
     Mutex mLock;  // Mutex to control concurent access to ToneGenerator object from audio callback and application API
     Mutex mCbkCondLock; // Mutex associated to mWaitCbkCond
     Condition mWaitCbkCond; // condition enabling interface to wait for audio callback completion after a change is requested
diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
index aa58905..6167dd6 100644
--- a/include/media/Visualizer.h
+++ b/include/media/Visualizer.h
@@ -19,7 +19,7 @@
 
 #include <media/AudioEffect.h>
 #include <audio_effects/effect_visualizer.h>
-#include <string.h>
+#include <utils/Thread.h>
 
 /**
  * The Visualizer class enables application to retrieve part of the currently playing audio for
@@ -114,6 +114,14 @@
     status_t setScalingMode(uint32_t mode);
     uint32_t getScalingMode() { return mScalingMode; }
 
+    // set which measurements are done on the audio buffers processed by the effect.
+    // valid measurements (mask): MEASUREMENT_MODE_PEAK_RMS
+    status_t setMeasurementMode(uint32_t mode);
+    uint32_t getMeasurementMode() { return mMeasurementMode; }
+
+    // return a set of int32_t measurements
+    status_t getIntMeasurements(uint32_t type, uint32_t number, int32_t *measurements);
+
     // return a capture in PCM 8 bit unsigned format. The size of the capture is equal to
     // getCaptureSize()
     status_t getWaveForm(uint8_t *waveform);
@@ -156,6 +164,7 @@
     uint32_t mCaptureSize;
     uint32_t mSampleRate;
     uint32_t mScalingMode;
+    uint32_t mMeasurementMode;
     capture_cbk_t mCaptureCallBack;
     void *mCaptureCbkUser;
     sp<CaptureThread> mCaptureThread;
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 14381c7..4c05fc3 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -42,9 +42,14 @@
     MEDIA_BUFFERING_UPDATE  = 3,
     MEDIA_SEEK_COMPLETE     = 4,
     MEDIA_SET_VIDEO_SIZE    = 5,
+    MEDIA_STARTED           = 6,
+    MEDIA_PAUSED            = 7,
+    MEDIA_STOPPED           = 8,
+    MEDIA_SKIPPED           = 9,
     MEDIA_TIMED_TEXT        = 99,
     MEDIA_ERROR             = 100,
     MEDIA_INFO              = 200,
+    MEDIA_SUBTITLE_DATA     = 201,
 };
 
 // Generic error codes for the media player framework.  Errors are fatal, the
@@ -173,6 +178,7 @@
     MEDIA_TRACK_TYPE_VIDEO = 1,
     MEDIA_TRACK_TYPE_AUDIO = 2,
     MEDIA_TRACK_TYPE_TIMEDTEXT = 3,
+    MEDIA_TRACK_TYPE_SUBTITLE = 4,
 };
 
 // ----------------------------------------------------------------------------
@@ -218,8 +224,12 @@
             bool            isLooping();
             status_t        setVolume(float leftVolume, float rightVolume);
             void            notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
-    static  sp<IMemory>     decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat);
-    static  sp<IMemory>     decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat);
+    static  status_t        decode(const char* url, uint32_t *pSampleRate, int* pNumChannels,
+                                   audio_format_t* pFormat,
+                                   const sp<IMemoryHeap>& heap, size_t *pSize);
+    static  status_t        decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate,
+                                   int* pNumChannels, audio_format_t* pFormat,
+                                   const sp<IMemoryHeap>& heap, size_t *pSize);
             status_t        invoke(const Parcel& request, Parcel *reply);
             status_t        setMetadataFilter(const Parcel& filter);
             status_t        getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
diff --git a/include/media/nbaio/AudioStreamOutSink.h b/include/media/nbaio/AudioStreamOutSink.h
index 5976b18..7948d40 100644
--- a/include/media/nbaio/AudioStreamOutSink.h
+++ b/include/media/nbaio/AudioStreamOutSink.h
@@ -52,6 +52,8 @@
     // implementation of GNWT (if any)
     virtual status_t getNextWriteTimestamp(int64_t *timestamp);
 
+    virtual status_t getTimestamp(AudioTimestamp& timestamp);
+
     // NBAIO_Sink end
 
 #if 0   // until necessary
diff --git a/include/media/nbaio/MonoPipe.h b/include/media/nbaio/MonoPipe.h
index 5fcfe9e..d3802fe 100644
--- a/include/media/nbaio/MonoPipe.h
+++ b/include/media/nbaio/MonoPipe.h
@@ -20,9 +20,12 @@
 #include <time.h>
 #include <utils/LinearTransform.h>
 #include "NBAIO.h"
+#include <media/SingleStateQueue.h>
 
 namespace android {
 
+typedef SingleStateQueue<AudioTimestamp> AudioTimestampSingleStateQueue;
+
 // MonoPipe is similar to Pipe except:
 //  - supports only a single reader, called MonoPipeReader
 //  - write() cannot overrun; instead it will return a short actual count if insufficient space
@@ -88,6 +91,9 @@
             // Return true if the write side of a pipe is currently shutdown.
             bool    isShutdown();
 
+            // Return NO_ERROR if there is a timestamp available
+            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
@@ -127,6 +133,10 @@
     LinearTransform mSamplesToLocalTime;
 
     bool            mIsShutdown;    // whether shutdown(true) was called, no barriers are needed
+
+    AudioTimestampSingleStateQueue::Shared      mTimestampShared;
+    AudioTimestampSingleStateQueue::Mutator     mTimestampMutator;
+    AudioTimestampSingleStateQueue::Observer    mTimestampObserver;
 };
 
 }   // namespace android
diff --git a/include/media/nbaio/MonoPipeReader.h b/include/media/nbaio/MonoPipeReader.h
index 0e1c992..78fe867 100644
--- a/include/media/nbaio/MonoPipeReader.h
+++ b/include/media/nbaio/MonoPipeReader.h
@@ -49,6 +49,8 @@
 
     virtual ssize_t read(void *buffer, size_t count, int64_t readPTS);
 
+    virtual void    onTimestamp(const AudioTimestamp& timestamp);
+
     // NBAIO_Source end
 
 #if 0   // until necessary
diff --git a/include/media/nbaio/NBAIO.h b/include/media/nbaio/NBAIO.h
index f5d6eb5..1da0c73 100644
--- a/include/media/nbaio/NBAIO.h
+++ b/include/media/nbaio/NBAIO.h
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
+#include <media/AudioTimestamp.h>
 
 namespace android {
 
@@ -213,6 +214,11 @@
     //  <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.
+    virtual status_t getTimestamp(AudioTimestamp& timestamp) { return INVALID_OPERATION; }
+
 protected:
     NBAIO_Sink(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0) { }
     virtual ~NBAIO_Sink() { }
@@ -300,6 +306,10 @@
     virtual ssize_t readVia(readVia_t via, size_t total, void *user,
                             int64_t readPTS, size_t block = 0);
 
+    // Invoked asynchronously by corresponding sink when a new timestamp is available.
+    // Default implementation ignores the timestamp.
+    virtual void    onTimestamp(const AudioTimestamp& timestamp) { }
+
 protected:
     NBAIO_Source(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0) { }
     virtual ~NBAIO_Source() { }
diff --git a/include/media/nbaio/NBLog.h b/include/media/nbaio/NBLog.h
index 107ba66..6d59ea7 100644
--- a/include/media/nbaio/NBLog.h
+++ b/include/media/nbaio/NBLog.h
@@ -90,6 +90,8 @@
     virtual ~Timeline();
 #endif
 
+    // Input parameter 'size' is the desired size of the timeline in byte units.
+    // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
     static size_t sharedSize(size_t size);
 
 #if 0
@@ -110,8 +112,12 @@
 class Writer : public RefBase {
 public:
     Writer();                   // dummy nop implementation without shared memory
+
+    // Input parameter 'size' is the desired size of the timeline in byte units.
+    // The size of the shared memory must be at least Timeline::sharedSize(size).
     Writer(size_t size, void *shared);
     Writer(size_t size, const sp<IMemory>& iMemory);
+
     virtual ~Writer() { }
 
     virtual void    log(const char *string);
@@ -165,8 +171,12 @@
 
 class Reader : public RefBase {
 public:
+
+    // Input parameter 'size' is the desired size of the timeline in byte units.
+    // The size of the shared memory must be at least Timeline::sharedSize(size).
     Reader(size_t size, const void *shared);
     Reader(size_t size, const sp<IMemory>& iMemory);
+
     virtual ~Reader() { }
 
     void    dump(int fd, size_t indent = 0);
diff --git a/include/media/nbaio/SourceAudioBufferProvider.h b/include/media/nbaio/SourceAudioBufferProvider.h
index c08331b..cdfb6fe 100644
--- a/include/media/nbaio/SourceAudioBufferProvider.h
+++ b/include/media/nbaio/SourceAudioBufferProvider.h
@@ -36,6 +36,8 @@
 
     // ExtendedAudioBufferProvider interface
     virtual size_t   framesReady() const;
+    virtual size_t   framesReleased() const;
+    virtual void     onTimestamp(const AudioTimestamp& timestamp);
 
 private:
     const sp<NBAIO_Source> mSource;     // the wrapped source
@@ -45,6 +47,7 @@
     size_t              mOffset;    // frame offset within mAllocated of valid data
     size_t              mRemaining; // frame count within mAllocated of valid data
     size_t              mGetCount;  // buffer.frameCount of the most recent getNextBuffer
+    uint32_t            mFramesReleased;    // counter of the total number of frames released
 };
 
 }   // namespace android
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index df25d7b..bf3a998 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -67,6 +67,8 @@
 
     void signalRequestIDRFrame();
 
+    bool isConfiguredForAdaptivePlayback() { return mIsConfiguredForAdaptivePlayback; }
+
     struct PortDescription : public RefBase {
         size_t countBuffers();
         IOMX::buffer_id bufferIDAt(size_t index) const;
@@ -116,6 +118,7 @@
         kWhatStart                   = 'star',
         kWhatRequestIDRFrame         = 'ridr',
         kWhatSetParameters           = 'setP',
+        kWhatSubmitOutputMetaDataBufferIfEOS = 'subm',
     };
 
     enum {
@@ -124,7 +127,8 @@
     };
 
     enum {
-        kFlagIsSecure   = 1,
+        kFlagIsSecure                                 = 1,
+        kFlagPushBlankBuffersToNativeWindowOnShutdown = 2,
     };
 
     struct BufferInfo {
@@ -138,6 +142,7 @@
 
         IOMX::buffer_id mBufferID;
         Status mStatus;
+        unsigned mDequeuedAt;
 
         sp<ABuffer> mData;
         sp<GraphicBuffer> mGraphicBuffer;
@@ -182,8 +187,9 @@
 
     bool mSentFormat;
     bool mIsEncoder;
-
+    bool mUseMetadataOnEncoderOutput;
     bool mShutdownInProgress;
+    bool mIsConfiguredForAdaptivePlayback;
 
     // If "mKeepComponentAllocated" we only transition back to Loaded state
     // and do not release the component instance.
@@ -194,12 +200,24 @@
 
     bool mChannelMaskPresent;
     int32_t mChannelMask;
+    unsigned mDequeueCounter;
+    bool mStoreMetaDataInOutputBuffers;
+    int32_t mMetaDataBuffersToSubmit;
+
+    int64_t mRepeatFrameDelayUs;
+    int64_t mMaxPtsGapUs;
 
     status_t setCyclicIntraMacroblockRefresh(const sp<AMessage> &msg, int32_t mode);
     status_t allocateBuffersOnPort(OMX_U32 portIndex);
     status_t freeBuffersOnPort(OMX_U32 portIndex);
     status_t freeBuffer(OMX_U32 portIndex, size_t i);
 
+    status_t configureOutputBuffersFromNativeWindow(
+            OMX_U32 *nBufferCount, OMX_U32 *nBufferSize,
+            OMX_U32 *nMinUndequeuedBuffers);
+    status_t allocateOutputMetaDataBuffers();
+    status_t submitOutputMetaDataBuffer();
+    void signalSubmitOutputMetaDataBufferIfEOS_workaround();
     status_t allocateOutputBuffersFromNativeWindow();
     status_t cancelBufferToNativeWindow(BufferInfo *info);
     status_t freeOutputBuffersNotOwnedByComponent();
@@ -252,6 +270,7 @@
     status_t setupMPEG4EncoderParameters(const sp<AMessage> &msg);
     status_t setupH263EncoderParameters(const sp<AMessage> &msg);
     status_t setupAVCEncoderParameters(const sp<AMessage> &msg);
+    status_t setupVPXEncoderParameters(const sp<AMessage> &msg);
 
     status_t verifySupportForProfileAndLevel(int32_t profile, int32_t level);
 
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 1dc408f..14afb85 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -36,8 +36,16 @@
         SEEK_COMPLETE
     };
 
+    enum {
+        ALLOW_DEEP_BUFFERING = 0x01,
+        USE_OFFLOAD = 0x02,
+        HAS_VIDEO   = 0x1000,
+        IS_STREAMING = 0x2000
+
+    };
+
     AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink,
-                bool allowDeepBuffering = false,
+                uint32_t flags = 0,
                 AwesomePlayer *audioObserver = NULL);
 
     virtual ~AudioPlayer();
@@ -51,7 +59,7 @@
     status_t start(bool sourceAlreadyStarted = false);
 
     void pause(bool playPendingSamples = false);
-    void resume();
+    status_t resume();
 
     // Returns the timestamp of the last buffer played (in us).
     int64_t getMediaTimeUs();
@@ -67,10 +75,12 @@
 
     status_t setPlaybackRatePermille(int32_t ratePermille);
 
+    void notifyAudioEOS();
+
 private:
     friend class VideoEditorAudioPlayer;
     sp<MediaSource> mSource;
-    AudioTrack *mAudioTrack;
+    sp<AudioTrack> mAudioTrack;
 
     MediaBuffer *mInputBuffer;
 
@@ -97,17 +107,20 @@
     MediaBuffer *mFirstBuffer;
 
     sp<MediaPlayerBase::AudioSink> mAudioSink;
-    bool mAllowDeepBuffering;       // allow audio deep audio buffers. Helps with low power audio
-                                    // playback but implies high latency
     AwesomePlayer *mObserver;
     int64_t mPinnedTimeUs;
 
+    bool mPlaying;
+    int64_t mStartPosUs;
+    const uint32_t mCreateFlags;
+
     static void AudioCallback(int event, void *user, void *info);
     void AudioCallback(int event, void *info);
 
     static size_t AudioSinkCallback(
             MediaPlayerBase::AudioSink *audioSink,
-            void *data, size_t size, void *me);
+            void *data, size_t size, void *me,
+            MediaPlayerBase::AudioSink::cb_event_t event);
 
     size_t fillBuffer(void *data, size_t size);
 
@@ -116,6 +129,10 @@
     void reset();
 
     uint32_t getNumFramesPendingPlayout() const;
+    int64_t getOutputPlayPositionUs_l();
+
+    bool allowDeepBuffering() const { return (mCreateFlags & ALLOW_DEEP_BUFFERING) != 0; }
+    bool useOffload() const { return (mCreateFlags & USE_OFFLOAD) != 0; }
 
     AudioPlayer(const AudioPlayer &);
     AudioPlayer &operator=(const AudioPlayer &);
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h
index 99f3c3b..4c9aaad 100644
--- a/include/media/stagefright/AudioSource.h
+++ b/include/media/stagefright/AudioSource.h
@@ -73,7 +73,7 @@
     Condition mFrameAvailableCondition;
     Condition mFrameEncodingCompletionCondition;
 
-    AudioRecord *mRecord;
+    sp<AudioRecord> mRecord;
     status_t mInitCheck;
     bool mStarted;
     int32_t mSampleRate;
diff --git a/include/media/stagefright/CameraSourceTimeLapse.h b/include/media/stagefright/CameraSourceTimeLapse.h
index 6b7a63c..34213be 100644
--- a/include/media/stagefright/CameraSourceTimeLapse.h
+++ b/include/media/stagefright/CameraSourceTimeLapse.h
@@ -41,7 +41,8 @@
         Size videoSize,
         int32_t videoFrameRate,
         const sp<IGraphicBufferProducer>& surface,
-        int64_t timeBetweenTimeLapseFrameCaptureUs);
+        int64_t timeBetweenTimeLapseFrameCaptureUs,
+        bool storeMetaDataInVideoBuffers = true);
 
     virtual ~CameraSourceTimeLapse();
 
@@ -116,7 +117,8 @@
         Size videoSize,
         int32_t videoFrameRate,
         const sp<IGraphicBufferProducer>& surface,
-        int64_t timeBetweenTimeLapseFrameCaptureUs);
+        int64_t timeBetweenTimeLapseFrameCaptureUs,
+        bool storeMetaDataInVideoBuffers = true);
 
     // Wrapper over CameraSource::signalBufferReturned() to implement quick stop.
     // It only handles the case when mLastReadBufferCopy is signalled. Otherwise
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index 742bc0e..157b1aa 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -80,7 +80,6 @@
             const sp<DataSource> &source, String8 *mimeType,
             float *confidence, sp<AMessage> *meta);
 
-    static void RegisterSniffer(SnifferFunc func);
     static void RegisterDefaultSniffers();
 
     // for DRM
@@ -101,6 +100,9 @@
 private:
     static Mutex gSnifferMutex;
     static List<SnifferFunc> gSniffers;
+    static bool gSniffersRegistered;
+
+    static void RegisterSniffer_l(SnifferFunc func);
 
     DataSource(const DataSource &);
     DataSource &operator=(const DataSource &);
diff --git a/include/media/stagefright/MediaCodecList.h b/include/media/stagefright/MediaCodecList.h
index dfb845b..590623b 100644
--- a/include/media/stagefright/MediaCodecList.h
+++ b/include/media/stagefright/MediaCodecList.h
@@ -50,7 +50,8 @@
     status_t getCodecCapabilities(
             size_t index, const char *type,
             Vector<ProfileLevel> *profileLevels,
-            Vector<uint32_t> *colorFormats) const;
+            Vector<uint32_t> *colorFormats,
+            uint32_t *flags) const;
 
 private:
     enum Section {
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 81de6e4..85693d4 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -22,7 +22,8 @@
 
 extern const char *MEDIA_MIMETYPE_IMAGE_JPEG;
 
-extern const char *MEDIA_MIMETYPE_VIDEO_VPX;
+extern const char *MEDIA_MIMETYPE_VIDEO_VP8;
+extern const char *MEDIA_MIMETYPE_VIDEO_VP9;
 extern const char *MEDIA_MIMETYPE_VIDEO_AVC;
 extern const char *MEDIA_MIMETYPE_VIDEO_MPEG4;
 extern const char *MEDIA_MIMETYPE_VIDEO_H263;
diff --git a/include/media/stagefright/MediaErrors.h b/include/media/stagefright/MediaErrors.h
index ee5e4e2..686f286 100644
--- a/include/media/stagefright/MediaErrors.h
+++ b/include/media/stagefright/MediaErrors.h
@@ -56,14 +56,11 @@
     ERROR_DRM_TAMPER_DETECTED               = DRM_ERROR_BASE - 7,
     ERROR_DRM_NOT_PROVISIONED               = DRM_ERROR_BASE - 8,
     ERROR_DRM_DEVICE_REVOKED                = DRM_ERROR_BASE - 9,
+    ERROR_DRM_RESOURCE_BUSY                 = DRM_ERROR_BASE - 10,
 
     ERROR_DRM_VENDOR_MAX                    = DRM_ERROR_BASE - 500,
     ERROR_DRM_VENDOR_MIN                    = DRM_ERROR_BASE - 999,
 
-    // Deprecated
-    ERROR_DRM_WV_VENDOR_MAX                 = ERROR_DRM_VENDOR_MAX,
-    ERROR_DRM_WV_VENDOR_MIN                 = ERROR_DRM_VENDOR_MIN,
-
     // Heartbeat Error Codes
     HEARTBEAT_ERROR_BASE = -3000,
     ERROR_HEARTBEAT_TERMINATE_REQUESTED                     = HEARTBEAT_ERROR_BASE,
diff --git a/include/media/stagefright/MediaMuxer.h b/include/media/stagefright/MediaMuxer.h
index c1fdbad..ff6a66e 100644
--- a/include/media/stagefright/MediaMuxer.h
+++ b/include/media/stagefright/MediaMuxer.h
@@ -79,6 +79,16 @@
     status_t setOrientationHint(int degrees);
 
     /**
+     * Set the location.
+     * @param latitude The latitude in degree x 1000. Its value must be in the range
+     * [-900000, 900000].
+     * @param longitude The longitude in degree x 1000. Its value must be in the range
+     * [-1800000, 1800000].
+     * @return OK if no error.
+     */
+    status_t setLocation(int latitude, int longitude);
+
+    /**
      * Stop muxing.
      * This method is a blocking call. Depending on how
      * much data is bufferred internally, the time needed for stopping
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index de3fc36..3a87474 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -134,6 +134,7 @@
     kKeyRequiresSecureBuffers = 'secu',  // bool (int32_t)
 
     kKeyIsADTS            = 'adts',  // bool (int32_t)
+    kKeyAACAOT            = 'aaot',  // int32_t
 
     // If a MediaBuffer's data represents (at least partially) encrypted
     // data, the following fields aid in decryption.
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 583c3b3..daaf20f 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -361,9 +361,14 @@
 };
 
 struct CodecCapabilities {
+    enum {
+        kFlagSupportsAdaptivePlayback = 1 << 0,
+    };
+
     String8 mComponentName;
     Vector<CodecProfileLevel> mProfileLevels;
     Vector<OMX_U32> mColorFormats;
+    uint32_t mFlags;
 };
 
 // Return a vector of componentNames with supported profile/level pairs
diff --git a/include/media/stagefright/SurfaceMediaSource.h b/include/media/stagefright/SurfaceMediaSource.h
index 5f21da9..db5f947 100644
--- a/include/media/stagefright/SurfaceMediaSource.h
+++ b/include/media/stagefright/SurfaceMediaSource.h
@@ -56,7 +56,7 @@
 
 class SurfaceMediaSource : public MediaSource,
                                 public MediaBufferObserver,
-                                protected BufferQueue::ConsumerListener {
+                                protected ConsumerListener {
 public:
     enum { MIN_UNDEQUEUED_BUFFERS = 4};
 
@@ -146,9 +146,13 @@
     // this consumer
     sp<BufferQueue> mBufferQueue;
 
-    // mBufferSlot caches GraphicBuffers from the buffer queue
-    sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
+    struct SlotData {
+        sp<GraphicBuffer> mGraphicBuffer;
+        uint64_t mFrameNumber;
+    };
 
+    // mSlots caches GraphicBuffers and frameNumbers from the buffer queue
+    SlotData mSlots[BufferQueue::NUM_BUFFER_SLOTS];
 
     // The permenent width and height of SMS buffers
     int mWidth;
diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h
index 73940d3..bbad271 100644
--- a/include/media/stagefright/Utils.h
+++ b/include/media/stagefright/Utils.h
@@ -22,6 +22,8 @@
 #include <stdint.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
+#include <system/audio.h>
+#include <media/MediaPlayerInterface.h>
 
 namespace android {
 
@@ -48,6 +50,16 @@
 
 AString MakeUserAgent();
 
+// Convert a MIME type to a AudioSystem::audio_format
+status_t mapMimeToAudioFormat(audio_format_t& format, const char* mime);
+
+// Send information from MetaData to the HAL via AudioSink
+status_t sendMetaDataToHal(sp<MediaPlayerBase::AudioSink>& sink, const sp<MetaData>& meta);
+
+// Check whether the stream defined by meta can be offloaded to hardware
+bool canOffloadStream(const sp<MetaData>& meta, bool hasVideo,
+                      bool isStreaming, audio_stream_type_t streamType);
+
 }  // namespace android
 
 #endif  // UTILS_H_
diff --git a/include/media/stagefright/foundation/ALooperRoster.h b/include/media/stagefright/foundation/ALooperRoster.h
index 2e5fd73..940fc55 100644
--- a/include/media/stagefright/foundation/ALooperRoster.h
+++ b/include/media/stagefright/foundation/ALooperRoster.h
@@ -30,6 +30,7 @@
             const sp<ALooper> looper, const sp<AHandler> &handler);
 
     void unregisterHandler(ALooper::handler_id handlerID);
+    void unregisterStaleHandlers();
 
     status_t postMessage(const sp<AMessage> &msg, int64_t delayUs = 0);
     void deliverMessage(const sp<AMessage> &msg);
diff --git a/media/libstagefright/wifi-display/ANetworkSession.h b/include/media/stagefright/foundation/ANetworkSession.h
similarity index 97%
rename from media/libstagefright/wifi-display/ANetworkSession.h
rename to include/media/stagefright/foundation/ANetworkSession.h
index 7c62b29..fd3ebaa 100644
--- a/media/libstagefright/wifi-display/ANetworkSession.h
+++ b/include/media/stagefright/foundation/ANetworkSession.h
@@ -77,6 +77,8 @@
             int32_t sessionID, const void *data, ssize_t size = -1,
             bool timeValid = false, int64_t timeUs = -1ll);
 
+    status_t switchToWebSocketMode(int32_t sessionID);
+
     enum NotificationReason {
         kWhatError,
         kWhatConnected,
@@ -84,6 +86,7 @@
         kWhatData,
         kWhatDatagram,
         kWhatBinaryData,
+        kWhatWebSocketMessage,
         kWhatNetworkStall,
     };
 
diff --git a/include/media/stagefright/foundation/AUtils.h b/include/media/stagefright/foundation/AUtils.h
new file mode 100644
index 0000000..60cb41d
--- /dev/null
+++ b/include/media/stagefright/foundation/AUtils.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef A_UTILS_H_
+
+#define A_UTILS_H_
+
+/* ============================ math templates ============================ */
+
+template<class T>
+void ENSURE_UNSIGNED_TYPE() {
+    T TYPE_MUST_BE_UNSIGNED[(T)-1 < 0 ? -1 : 0];
+}
+
+// needle is in range [hayStart, hayStart + haySize)
+template<class T, class U>
+inline static bool isInRange(const T &hayStart, const U &haySize, const T &needle) {
+    ENSURE_UNSIGNED_TYPE<U>();
+    return (T)(hayStart + haySize) >= hayStart && needle >= hayStart && (U)(needle - hayStart) < haySize;
+}
+
+// [needleStart, needleStart + needleSize) is in range [hayStart, hayStart + haySize)
+template<class T, class U>
+inline static bool isInRange(
+        const T &hayStart, const U &haySize, const T &needleStart, const U &needleSize) {
+    ENSURE_UNSIGNED_TYPE<U>();
+    return isInRange(hayStart, haySize, needleStart)
+            && (T)(needleStart + needleSize) >= needleStart
+            && (U)(needleStart + needleSize - hayStart) <= haySize;
+}
+
+#endif  // A_UTILS_H_
diff --git a/media/libstagefright/wifi-display/ParsedMessage.h b/include/media/stagefright/foundation/ParsedMessage.h
similarity index 96%
rename from media/libstagefright/wifi-display/ParsedMessage.h
rename to include/media/stagefright/foundation/ParsedMessage.h
index e9a1859..9d43a93 100644
--- a/media/libstagefright/wifi-display/ParsedMessage.h
+++ b/include/media/stagefright/foundation/ParsedMessage.h
@@ -32,7 +32,7 @@
 
     const char *getContent() const;
 
-    void getRequestField(size_t index, AString *field) const;
+    bool getRequestField(size_t index, AString *field) const;
     bool getStatusCode(int32_t *statusCode) const;
 
     AString debugString() const;
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 41e20f8..7fd9379 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -22,32 +22,51 @@
 
 #include <utils/threads.h>
 #include <utils/Log.h>
+#include <utils/RefBase.h>
+#include <media/nbaio/roundup.h>
+#include <media/SingleStateQueue.h>
+#include <private/media/StaticAudioTrackState.h>
 
 namespace android {
 
 // ----------------------------------------------------------------------------
 
-// Maximum cumulated timeout milliseconds before restarting audioflinger thread
-#define MAX_STARTUP_TIMEOUT_MS  3000    // Longer timeout period at startup to cope with A2DP
-                                        // init time
-#define MAX_RUN_TIMEOUT_MS      1000
-#define WAIT_PERIOD_MS          10
-
-#define CBLK_UNDERRUN   0x01 // set: underrun (out) or overrrun (in), clear: no underrun or overrun
+// for audio_track_cblk_t::mFlags
+#define CBLK_UNDERRUN   0x01 // set by server immediately on output underrun, cleared by client
 #define CBLK_FORCEREADY 0x02 // set: track is considered ready immediately by AudioFlinger,
                              // clear: track is ready when buffer full
 #define CBLK_INVALID    0x04 // track buffer invalidated by AudioFlinger, need to re-create
-#define CBLK_DISABLED   0x08 // track disabled by AudioFlinger due to underrun, need to re-start
+#define CBLK_DISABLED   0x08 // output track disabled by AudioFlinger due to underrun,
+                             // need to re-start.  Unlike CBLK_UNDERRUN, this is not set
+                             // immediately, but only after a long string of underruns.
+// 0x10 unused
+#define CBLK_LOOP_CYCLE 0x20 // set by server each time a loop cycle other than final one completes
+#define CBLK_LOOP_FINAL 0x40 // set by server when the final loop cycle completes
+#define CBLK_BUFFER_END 0x80 // set by server when the position reaches end of buffer if not looping
+#define CBLK_OVERRUN   0x100 // set by server immediately on input overrun, cleared by client
+#define CBLK_INTERRUPT 0x200 // set by client on interrupt(), cleared by client in obtainBuffer()
+#define CBLK_STREAM_END_DONE 0x400 // set by server on render completion, cleared by client
+
+//EL_FIXME 20 seconds may not be enough and must be reconciled with new obtainBuffer implementation
+#define MAX_RUN_OFFLOADED_TIMEOUT_MS 20000 //assuming upto a maximum of 20 seconds of offloaded
 
 struct AudioTrackSharedStreaming {
     // similar to NBAIO MonoPipe
-    volatile int32_t mFront;
-    volatile int32_t mRear;
+    // in continuously incrementing frame units, take modulo buffer size, which must be a power of 2
+    volatile int32_t mFront;    // read by server
+    volatile int32_t mRear;     // write by client
+    volatile int32_t mFlush;    // incremented by client to indicate a request to flush;
+                                // server notices and discards all data between mFront and mRear
+    volatile uint32_t mUnderrunFrames;  // server increments for each unavailable but desired frame
 };
 
-// future
+typedef SingleStateQueue<StaticAudioTrackState> StaticAudioTrackSingleStateQueue;
+
 struct AudioTrackSharedStatic {
-    int mReserved;
+    StaticAudioTrackSingleStateQueue::Shared
+                    mSingleStateQueue;
+    size_t          mBufferPosition;    // updated asynchronously by server,
+                                        // "for entertainment purposes only"
 };
 
 // ----------------------------------------------------------------------------
@@ -55,65 +74,63 @@
 // Important: do not add any virtual methods, including ~
 struct audio_track_cblk_t
 {
+                // Since the control block is always located in shared memory, this constructor
+                // is only used for placement new().  It is never used for regular new() or stack.
+                            audio_track_cblk_t();
+                /*virtual*/ ~audio_track_cblk_t() { }
+
                 friend class Proxy;
+                friend class ClientProxy;
                 friend class AudioTrackClientProxy;
                 friend class AudioRecordClientProxy;
                 friend class ServerProxy;
+                friend class AudioTrackServerProxy;
+                friend class AudioRecordServerProxy;
 
     // The data members are grouped so that members accessed frequently and in the same context
     // are in the same line of data cache.
-                Mutex       lock;           // sizeof(int)
-                Condition   cv;             // sizeof(int)
 
-                // next 4 are offsets within "buffers"
-    volatile    uint32_t    user;
-    volatile    uint32_t    server;
-                uint32_t    userBase;
-                uint32_t    serverBase;
-
-                int         mPad1;          // unused, but preserves cache line alignment
+                uint32_t    mServer;    // Number of filled frames consumed by server (mIsOut),
+                                        // or filled frames provided by server (!mIsOut).
+                                        // It is updated asynchronously by server without a barrier.
+                                        // The value should be used "for entertainment purposes only",
+                                        // which means don't make important decisions based on it.
 
                 size_t      frameCount_;    // used during creation to pass actual track buffer size
                                             // from AudioFlinger to client, and not referenced again
-                                            // FIXME remove here and replace by createTrack() in/out parameter
+                                            // FIXME remove here and replace by createTrack() in/out
+                                            // parameter
                                             // renamed to "_" to detect incorrect use
 
-                // Cache line boundary (32 bytes)
+    volatile    int32_t     mFutex;     // event flag: down (P) by client,
+                                        // up (V) by server or binderDied() or interrupt()
+#define CBLK_FUTEX_WAKE 1               // if event flag bit is set, then a deferred wake is pending
 
-                uint32_t    loopStart;
-                uint32_t    loopEnd;        // read-only for server, read/write for client
-                int         loopCount;      // read/write for client
+private:
+
+                size_t      mMinimum;       // server wakes up client if available >= mMinimum
 
                 // Channel volumes are fixed point U4.12, so 0x1000 means 1.0.
                 // Left channel is in [0:15], right channel is in [16:31].
                 // Always read and write the combined pair atomically.
                 // For AudioTrack only, not used by AudioRecord.
-private:
                 uint32_t    mVolumeLR;
 
                 uint32_t    mSampleRate;    // AudioTrack only: client's requested sample rate in Hz
                                             // or 0 == default. Write-only client, read-only server.
 
-                uint8_t     mPad2;           // unused
-
-public:
-                // read-only for client, server writes once at initialization and is then read-only
-                uint8_t     mName;           // normal tracks: track name, fast tracks: track index
-
-                // used by client only
-                uint16_t    bufferTimeoutMs; // Maximum cumulated timeout before restarting
-                                             // audioflinger
-
-                uint16_t    waitTimeMs;      // Cumulated wait time, used by client only
-private:
                 // client write-only, server read-only
                 uint16_t    mSendLevel;      // Fixed point U4.12 so 0x1000 means 1.0
+
+                uint16_t    mPad2;           // unused
+
 public:
-    volatile    int32_t     flags;
+
+    volatile    int32_t     mFlags;         // combinations of CBLK_*
 
                 // Cache line boundary (32 bytes)
 
-#if 0
+public:
                 union {
                     AudioTrackSharedStreaming   mStreaming;
                     AudioTrackSharedStatic      mStatic;
@@ -121,25 +138,6 @@
                 } u;
 
                 // Cache line boundary (32 bytes)
-#endif
-
-                // Since the control block is always located in shared memory, this constructor
-                // is only used for placement new().  It is never used for regular new() or stack.
-                            audio_track_cblk_t();
-
-private:
-                // if there is a shared buffer, "buffers" is the value of pointer() for the shared
-                // buffer, otherwise "buffers" points immediately after the control block
-                void*       buffer(void *buffers, uint32_t frameSize, size_t offset) const;
-
-                bool        tryLock();
-
-                // isOut == true means AudioTrack, isOut == false means AudioRecord
-                bool        stepServer(size_t stepCount, size_t frameCount, bool isOut);
-                uint32_t    stepUser(size_t stepCount, size_t frameCount, bool isOut);
-                uint32_t    framesAvailable(size_t frameCount, bool isOut);
-                uint32_t    framesAvailable_l(size_t frameCount, bool isOut);
-                uint32_t    framesReady(bool isOut);
 };
 
 // ----------------------------------------------------------------------------
@@ -147,29 +145,32 @@
 // Proxy for shared memory control block, to isolate callers from needing to know the details.
 // There is exactly one ClientProxy and one ServerProxy per shared memory control block.
 // The proxies are located in normal memory, and are not multi-thread safe within a given side.
-class Proxy {
+class Proxy : public RefBase {
 protected:
-    Proxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize)
-        : mCblk(cblk), mBuffers(buffers), mFrameCount(frameCount), mFrameSize(frameSize) { }
+    Proxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize, bool isOut,
+            bool clientInServer);
     virtual ~Proxy() { }
 
 public:
-    void*   buffer(size_t offset) const {
-        return mCblk->buffer(mBuffers, mFrameSize, offset);
-    }
+    struct Buffer {
+        size_t  mFrameCount;            // number of frames available in this buffer
+        void*   mRaw;                   // pointer to first frame
+        size_t  mNonContig;             // number of additional non-contiguous frames available
+    };
 
 protected:
     // These refer to shared memory, and are virtual addresses with respect to the current process.
     // They may have different virtual addresses within the other process.
-    audio_track_cblk_t* const   mCblk;          // the control block
-    void* const                 mBuffers;       // starting address of buffers
+    audio_track_cblk_t* const   mCblk;  // the control block
+    void* const     mBuffers;           // starting address of buffers
 
-    const size_t                mFrameCount;    // not necessarily a power of 2
-    const size_t                mFrameSize;     // in bytes
-#if 0
-    const size_t                mFrameCountP2;  // mFrameCount rounded to power of 2, streaming mode
-#endif
-
+    const size_t    mFrameCount;        // not necessarily a power of 2
+    const size_t    mFrameSize;         // in bytes
+    const size_t    mFrameCountP2;      // mFrameCount rounded to power of 2, streaming mode
+    const bool      mIsOut;             // true for AudioTrack, false for AudioRecord
+    const bool      mClientInServer;    // true for OutputTrack, false for AudioTrack & AudioRecord
+    bool            mIsShutdown;        // latch set to true when shared memory corruption detected
+    size_t          mUnreleased;        // unreleased frames remaining from most recent obtainBuffer
 };
 
 // ----------------------------------------------------------------------------
@@ -177,9 +178,88 @@
 // Proxy seen by AudioTrack client and AudioRecord client
 class ClientProxy : public Proxy {
 protected:
-    ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize)
-        : Proxy(cblk, buffers, frameCount, frameSize) { }
+    ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize,
+            bool isOut, bool clientInServer);
     virtual ~ClientProxy() { }
+
+public:
+    static const struct timespec kForever;
+    static const struct timespec kNonBlocking;
+
+    // Obtain a buffer with filled frames (reading) or empty frames (writing).
+    // It is permitted to call obtainBuffer() multiple times in succession, without any intervening
+    // calls to releaseBuffer().  In that case, the final obtainBuffer() is the one that effectively
+    // sets or extends the unreleased frame count.
+    // On entry:
+    //  buffer->mFrameCount should be initialized to maximum number of desired frames,
+    //      which must be > 0.
+    //  buffer->mNonContig is unused.
+    //  buffer->mRaw is unused.
+    //  requested is the requested timeout in local monotonic delta time units:
+    //      NULL or &kNonBlocking means non-blocking (zero timeout).
+    //      &kForever means block forever (infinite timeout).
+    //      Other values mean a specific timeout in local monotonic delta time units.
+    //  elapsed is a pointer to a location that will hold the total local monotonic time that
+    //      elapsed while blocked, or NULL if not needed.
+    // On exit:
+    //  buffer->mFrameCount has the actual number of contiguous available frames,
+    //      which is always 0 when the return status != NO_ERROR.
+    //  buffer->mNonContig is the number of additional non-contiguous available frames.
+    //  buffer->mRaw is a pointer to the first available frame,
+    //      or NULL when buffer->mFrameCount == 0.
+    // The return status is one of:
+    //  NO_ERROR    Success, buffer->mFrameCount > 0.
+    //  WOULD_BLOCK Non-blocking mode and no frames are available.
+    //  TIMED_OUT   Timeout occurred before any frames became available.
+    //              This can happen even for infinite timeout, due to a spurious wakeup.
+    //              In this case, the caller should investigate and then re-try as appropriate.
+    //  DEAD_OBJECT Server has died or invalidated, caller should destroy this proxy and re-create.
+    //  -EINTR      Call has been interrupted.  Look around to see why, and then perhaps try again.
+    //  NO_INIT     Shared memory is corrupt.
+    // Assertion failure on entry, if buffer == NULL or buffer->mFrameCount == 0.
+    status_t    obtainBuffer(Buffer* buffer, const struct timespec *requested = NULL,
+            struct timespec *elapsed = NULL);
+
+    // Release (some of) the frames last obtained.
+    // On entry, buffer->mFrameCount should have the number of frames to release,
+    // which must (cumulatively) be <= the number of frames last obtained but not yet released.
+    // buffer->mRaw is ignored, but is normally same pointer returned by last obtainBuffer().
+    // It is permitted to call releaseBuffer() multiple times to release the frames in chunks.
+    // On exit:
+    //  buffer->mFrameCount is zero.
+    //  buffer->mRaw is NULL.
+    void        releaseBuffer(Buffer* buffer);
+
+    // Call after detecting server's death
+    void        binderDied();
+
+    // Call to force an obtainBuffer() to return quickly with -EINTR
+    void        interrupt();
+
+    size_t      getPosition() {
+        return mEpoch + mCblk->mServer;
+    }
+
+    void        setEpoch(size_t epoch) {
+        mEpoch = epoch;
+    }
+
+    void        setMinimum(size_t minimum) {
+        mCblk->mMinimum = minimum;
+    }
+
+    // Return the number of frames that would need to be obtained and released
+    // in order for the client to be aligned at start of buffer
+    virtual size_t  getMisalignment();
+
+    size_t      getEpoch() const {
+        return mEpoch;
+    }
+
+    size_t      getFramesFilled();
+
+private:
+    size_t      mEpoch;
 };
 
 // ----------------------------------------------------------------------------
@@ -187,8 +267,10 @@
 // Proxy used by AudioTrack client, which also includes AudioFlinger::PlaybackThread::OutputTrack
 class AudioTrackClientProxy : public ClientProxy {
 public:
-    AudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize)
-        : ClientProxy(cblk, buffers, frameCount, frameSize) { }
+    AudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
+            size_t frameSize, bool clientInServer = false)
+        : ClientProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/,
+          clientInServer) { }
     virtual ~AudioTrackClientProxy() { }
 
     // No barriers on the following operations, so the ordering of loads/stores
@@ -208,27 +290,42 @@
         mCblk->mSampleRate = sampleRate;
     }
 
-    // called by:
-    //   PlaybackThread::OutputTrack::write
-    //   AudioTrack::createTrack_l
-    //   AudioTrack::releaseBuffer
-    //   AudioTrack::reload
-    //   AudioTrack::restoreTrack_l (2 places)
-    size_t      stepUser(size_t stepCount) {
-        return mCblk->stepUser(stepCount, mFrameCount, true /*isOut*/);
+    virtual void flush();
+
+    virtual uint32_t    getUnderrunFrames() const {
+        return mCblk->u.mStreaming.mUnderrunFrames;
     }
 
-    // called by AudioTrack::obtainBuffer and AudioTrack::processBuffer
-    size_t      framesAvailable() {
-        return mCblk->framesAvailable(mFrameCount, true /*isOut*/);
+    bool        clearStreamEndDone();   // and return previous value
+
+    bool        getStreamEndDone() const;
+
+    status_t    waitStreamEndDone(const struct timespec *requested);
+};
+
+class StaticAudioTrackClientProxy : public AudioTrackClientProxy {
+public:
+    StaticAudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
+            size_t frameSize);
+    virtual ~StaticAudioTrackClientProxy() { }
+
+    virtual void    flush();
+
+#define MIN_LOOP    16  // minimum length of each loop iteration in frames
+            void    setLoop(size_t loopStart, size_t loopEnd, int loopCount);
+            size_t  getBufferPosition();
+
+    virtual size_t  getMisalignment() {
+        return 0;
     }
 
-    // called by AudioTrack::obtainBuffer and PlaybackThread::OutputTrack::obtainBuffer
-    // FIXME remove this API since it assumes a lock that should be invisible to caller
-    size_t      framesAvailable_l() {
-        return mCblk->framesAvailable_l(mFrameCount, true /*isOut*/);
+    virtual uint32_t    getUnderrunFrames() const {
+        return 0;
     }
 
+private:
+    StaticAudioTrackSingleStateQueue::Mutator   mMutator;
+    size_t          mBufferPosition;    // so that getBufferPosition() appears to be synchronous
 };
 
 // ----------------------------------------------------------------------------
@@ -236,60 +333,134 @@
 // Proxy used by AudioRecord client
 class AudioRecordClientProxy : public ClientProxy {
 public:
-    AudioRecordClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize)
-        : ClientProxy(cblk, buffers, frameCount, frameSize) { }
+    AudioRecordClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
+            size_t frameSize)
+        : ClientProxy(cblk, buffers, frameCount, frameSize,
+            false /*isOut*/, false /*clientInServer*/) { }
     ~AudioRecordClientProxy() { }
-
-    // called by AudioRecord::releaseBuffer
-    size_t      stepUser(size_t stepCount) {
-        return mCblk->stepUser(stepCount, mFrameCount, false /*isOut*/);
-    }
-
-    // called by AudioRecord::processBuffer
-    size_t      framesAvailable() {
-        return mCblk->framesAvailable(mFrameCount, false /*isOut*/);
-    }
-
-    // called by AudioRecord::obtainBuffer
-    size_t      framesReady() {
-        return mCblk->framesReady(false /*isOut*/);
-    }
-
 };
 
 // ----------------------------------------------------------------------------
 
 // Proxy used by AudioFlinger server
 class ServerProxy : public Proxy {
+protected:
+    ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize,
+            bool isOut, bool clientInServer);
 public:
-    ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize, bool isOut)
-        : Proxy(cblk, buffers, frameCount, frameSize), mIsOut(isOut) { }
     virtual ~ServerProxy() { }
 
-    // for AudioTrack and AudioRecord
-    bool        step(size_t stepCount) { return mCblk->stepServer(stepCount, mFrameCount, mIsOut); }
+    // Obtain a buffer with filled frames (writing) or empty frames (reading).
+    // It is permitted to call obtainBuffer() multiple times in succession, without any intervening
+    // calls to releaseBuffer().  In that case, the final obtainBuffer() is the one that effectively
+    // sets or extends the unreleased frame count.
+    // Always non-blocking.
+    // On entry:
+    //  buffer->mFrameCount should be initialized to maximum number of desired frames,
+    //      which must be > 0.
+    //  buffer->mNonContig is unused.
+    //  buffer->mRaw is unused.
+    //  ackFlush is true iff being called from Track::start to acknowledge a pending flush.
+    // On exit:
+    //  buffer->mFrameCount has the actual number of contiguous available frames,
+    //      which is always 0 when the return status != NO_ERROR.
+    //  buffer->mNonContig is the number of additional non-contiguous available frames.
+    //  buffer->mRaw is a pointer to the first available frame,
+    //      or NULL when buffer->mFrameCount == 0.
+    // The return status is one of:
+    //  NO_ERROR    Success, buffer->mFrameCount > 0.
+    //  WOULD_BLOCK No frames are available.
+    //  NO_INIT     Shared memory is corrupt.
+    virtual status_t    obtainBuffer(Buffer* buffer, bool ackFlush = false);
 
+    // Release (some of) the frames last obtained.
+    // On entry, buffer->mFrameCount should have the number of frames to release,
+    // which must (cumulatively) be <= the number of frames last obtained but not yet released.
+    // It is permitted to call releaseBuffer() multiple times to release the frames in chunks.
+    // buffer->mRaw is ignored, but is normally same pointer returned by last obtainBuffer().
+    // On exit:
+    //  buffer->mFrameCount is zero.
+    //  buffer->mRaw is NULL.
+    virtual void        releaseBuffer(Buffer* buffer);
+
+protected:
+    size_t      mAvailToClient; // estimated frames available to client prior to releaseBuffer()
+    int32_t     mFlush;         // our copy of cblk->u.mStreaming.mFlush, for streaming output only
+};
+
+// Proxy used by AudioFlinger for servicing AudioTrack
+class AudioTrackServerProxy : public ServerProxy {
+public:
+    AudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
+            size_t frameSize, bool clientInServer = false)
+        : ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer) { }
+protected:
+    virtual ~AudioTrackServerProxy() { }
+
+public:
     // return value of these methods must be validated by the caller
     uint32_t    getSampleRate() const { return mCblk->mSampleRate; }
     uint16_t    getSendLevel_U4_12() const { return mCblk->mSendLevel; }
     uint32_t    getVolumeLR() const { return mCblk->mVolumeLR; }
 
-    // for AudioTrack only
-    size_t      framesReady() {
-        ALOG_ASSERT(mIsOut);
-        return mCblk->framesReady(true);
-    }
+    // estimated total number of filled frames available to server to read,
+    // which may include non-contiguous frames
+    virtual size_t      framesReady();
 
-    // for AudioRecord only, called by RecordThread::RecordTrack::getNextBuffer
-    // FIXME remove this API since it assumes a lock that should be invisible to caller
-    size_t      framesAvailableIn_l() {
-        ALOG_ASSERT(!mIsOut);
-        return mCblk->framesAvailable_l(mFrameCount, false);
-    }
+    // Currently AudioFlinger will call framesReady() for a fast track from two threads:
+    // FastMixer thread, and normal mixer thread.  This is dangerous, as the proxy is intended
+    // to be called from at most one thread of server, and one thread of client.
+    // As a temporary workaround, this method informs the proxy implementation that it
+    // should avoid doing a state queue poll from within framesReady().
+    // FIXME Change AudioFlinger to not call framesReady() from normal mixer thread.
+    virtual void        framesReadyIsCalledByMultipleThreads() { }
+
+    bool     setStreamEndDone();    // and return previous value
+
+    // Add to the tally of underrun frames, and inform client of underrun
+    virtual void        tallyUnderrunFrames(uint32_t frameCount);
+
+    // Return the total number of frames which AudioFlinger desired but were unavailable,
+    // and thus which resulted in an underrun.
+    virtual uint32_t    getUnderrunFrames() const { return mCblk->u.mStreaming.mUnderrunFrames; }
+
+    // Return the total number of frames that AudioFlinger has obtained and released
+    virtual size_t      framesReleased() const { return mCblk->mServer; }
+};
+
+class StaticAudioTrackServerProxy : public AudioTrackServerProxy {
+public:
+    StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
+            size_t frameSize);
+protected:
+    virtual ~StaticAudioTrackServerProxy() { }
+
+public:
+    virtual size_t      framesReady();
+    virtual void        framesReadyIsCalledByMultipleThreads();
+    virtual status_t    obtainBuffer(Buffer* buffer, bool ackFlush);
+    virtual void        releaseBuffer(Buffer* buffer);
+    virtual void        tallyUnderrunFrames(uint32_t frameCount);
+    virtual uint32_t    getUnderrunFrames() const { return 0; }
 
 private:
-    const bool  mIsOut;     // true for AudioTrack, false for AudioRecord
+    ssize_t             pollPosition(); // poll for state queue update, and return current position
+    StaticAudioTrackSingleStateQueue::Observer  mObserver;
+    size_t              mPosition;  // server's current play position in frames, relative to 0
+    size_t              mEnd;       // cached value computed from mState, safe for asynchronous read
+    bool                mFramesReadyIsCalledByMultipleThreads;
+    StaticAudioTrackState   mState;
+};
 
+// Proxy used by AudioFlinger for servicing AudioRecord
+class AudioRecordServerProxy : public ServerProxy {
+public:
+    AudioRecordServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
+            size_t frameSize)
+        : ServerProxy(cblk, buffers, frameCount, frameSize, false /*isOut*/,
+            false /*clientInServer*/) { }
+protected:
+    virtual ~AudioRecordServerProxy() { }
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libvideoeditor/lvpp/NativeWindowRenderer.cpp b/libvideoeditor/lvpp/NativeWindowRenderer.cpp
index 702900b..8b362ef 100755
--- a/libvideoeditor/lvpp/NativeWindowRenderer.cpp
+++ b/libvideoeditor/lvpp/NativeWindowRenderer.cpp
@@ -568,8 +568,9 @@
 RenderInput::RenderInput(NativeWindowRenderer* renderer, GLuint textureId)
     : mRenderer(renderer)
     , mTextureId(textureId) {
-    mST = new GLConsumer(mTextureId);
-    mSTC = new Surface(mST->getBufferQueue());
+    sp<BufferQueue> bq = new BufferQueue();
+    mST = new GLConsumer(bq, mTextureId);
+    mSTC = new Surface(bq);
     native_window_connect(mSTC.get(), NATIVE_WINDOW_API_MEDIA);
 }
 
diff --git a/libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp b/libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp
index c111ba8..176f8e9 100755
--- a/libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp
+++ b/libvideoeditor/lvpp/VideoEditorAudioPlayer.cpp
@@ -35,8 +35,7 @@
 VideoEditorAudioPlayer::VideoEditorAudioPlayer(
         const sp<MediaPlayerBase::AudioSink> &audioSink,
         PreviewPlayer *observer)
-    : mAudioTrack(NULL),
-      mInputBuffer(NULL),
+    : mInputBuffer(NULL),
       mSampleRate(0),
       mLatencyUs(0),
       mFrameSize(0),
@@ -111,8 +110,7 @@
     } else {
         mAudioTrack->stop();
 
-        delete mAudioTrack;
-        mAudioTrack = NULL;
+        mAudioTrack.clear();
     }
 
     // Make sure to release any buffer we hold onto so that the
@@ -151,7 +149,7 @@
     mStarted = false;
 }
 
-void VideoEditorAudioPlayer::resume() {
+status_t VideoEditorAudioPlayer::resume() {
     ALOGV("resume");
 
     AudioMixSettings audioMixSettings;
@@ -182,6 +180,7 @@
     } else {
         mAudioTrack->start();
     }
+    return OK;
 }
 
 status_t VideoEditorAudioPlayer::seekTo(int64_t time_us) {
@@ -538,8 +537,7 @@
                 0, AUDIO_OUTPUT_FLAG_NONE, &AudioCallback, this, 0);
 
         if ((err = mAudioTrack->initCheck()) != OK) {
-            delete mAudioTrack;
-            mAudioTrack = NULL;
+            mAudioTrack.clear();
 
             if (mFirstBuffer != NULL) {
                 mFirstBuffer->release();
@@ -578,10 +576,15 @@
 
 size_t VideoEditorAudioPlayer::AudioSinkCallback(
         MediaPlayerBase::AudioSink *audioSink,
-        void *buffer, size_t size, void *cookie) {
+        void *buffer, size_t size, void *cookie,
+        MediaPlayerBase::AudioSink::cb_event_t event) {
     VideoEditorAudioPlayer *me = (VideoEditorAudioPlayer *)cookie;
 
-    return me->fillBuffer(buffer, size);
+    if (event == MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER ) {
+        return me->fillBuffer(buffer, size);
+    } else {
+        return 0;
+    }
 }
 
 
diff --git a/libvideoeditor/lvpp/VideoEditorAudioPlayer.h b/libvideoeditor/lvpp/VideoEditorAudioPlayer.h
index 626df39..2caf5e8 100755
--- a/libvideoeditor/lvpp/VideoEditorAudioPlayer.h
+++ b/libvideoeditor/lvpp/VideoEditorAudioPlayer.h
@@ -58,7 +58,7 @@
 
     status_t start(bool sourceAlreadyStarted = false);
     void pause(bool playPendingSamples = false);
-    void resume();
+    status_t resume();
     status_t seekTo(int64_t time_us);
     bool isSeeking();
     bool reachedEOS(status_t *finalStatus);
@@ -91,7 +91,7 @@
     int64_t mBGAudioStoryBoardCurrentMediaVolumeVal;
 
     sp<MediaSource> mSource;
-    AudioTrack *mAudioTrack;
+    sp<AudioTrack> mAudioTrack;
 
     MediaBuffer *mInputBuffer;
 
@@ -124,7 +124,8 @@
     size_t fillBuffer(void *data, size_t size);
     static size_t AudioSinkCallback(
             MediaPlayerBase::AudioSink *audioSink,
-            void *data, size_t size, void *me);
+            void *data, size_t size, void *me,
+            MediaPlayerBase::AudioSink::cb_event_t event);
 
     void reset();
     void clear();
diff --git a/libvideoeditor/lvpp/VideoEditorPlayer.cpp b/libvideoeditor/lvpp/VideoEditorPlayer.cpp
index 91a4415..8d656c4 100755
--- a/libvideoeditor/lvpp/VideoEditorPlayer.cpp
+++ b/libvideoeditor/lvpp/VideoEditorPlayer.cpp
@@ -310,7 +310,6 @@
 VideoEditorPlayer::VeAudioOutput::VeAudioOutput()
     : mCallback(NULL),
       mCallbackCookie(NULL) {
-    mTrack = 0;
     mStreamType = AUDIO_STREAM_MUSIC;
     mLeftVolume = 1.0;
     mRightVolume = 1.0;
@@ -392,7 +391,8 @@
 status_t VideoEditorPlayer::VeAudioOutput::open(
         uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
         audio_format_t format, int bufferCount,
-        AudioCallback cb, void *cookie, audio_output_flags_t flags) {
+        AudioCallback cb, void *cookie, audio_output_flags_t flags,
+        const audio_offload_info_t *offloadInfo) {
 
     mCallback = cb;
     mCallbackCookie = cookie;
@@ -405,7 +405,7 @@
 
     }
     ALOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount);
-    if (mTrack) close();
+    if (mTrack != 0) close();
     uint32_t afSampleRate;
     size_t afFrameCount;
     int frameCount;
@@ -434,7 +434,7 @@
         }
     }
 
-    AudioTrack *t;
+    sp<AudioTrack> t;
     if (mCallback != NULL) {
         t = new AudioTrack(
                 mStreamType,
@@ -457,7 +457,6 @@
 
     if ((t == 0) || (t->initCheck() != NO_ERROR)) {
         ALOGE("Unable to create audio track");
-        delete t;
         return NO_INIT;
     }
 
@@ -469,14 +468,18 @@
     return NO_ERROR;
 }
 
-void VideoEditorPlayer::VeAudioOutput::start() {
+status_t VideoEditorPlayer::VeAudioOutput::start() {
 
     ALOGV("start");
-    if (mTrack) {
+    if (mTrack != 0) {
         mTrack->setVolume(mLeftVolume, mRightVolume);
-        mTrack->start();
-        mTrack->getPosition(&mNumFramesWritten);
+        status_t status = mTrack->start();
+        if (status == NO_ERROR) {
+            mTrack->getPosition(&mNumFramesWritten);
+        }
+        return status;
     }
+    return NO_INIT;
 }
 
 void VideoEditorPlayer::VeAudioOutput::snoopWrite(
@@ -492,7 +495,7 @@
     LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
 
     //ALOGV("write(%p, %u)", buffer, size);
-    if (mTrack) {
+    if (mTrack != 0) {
         snoopWrite(buffer, size);
         ssize_t ret = mTrack->write(buffer, size);
         mNumFramesWritten += ret / 4; // assume 16 bit stereo
@@ -504,26 +507,25 @@
 void VideoEditorPlayer::VeAudioOutput::stop() {
 
     ALOGV("stop");
-    if (mTrack) mTrack->stop();
+    if (mTrack != 0) mTrack->stop();
 }
 
 void VideoEditorPlayer::VeAudioOutput::flush() {
 
     ALOGV("flush");
-    if (mTrack) mTrack->flush();
+    if (mTrack != 0) mTrack->flush();
 }
 
 void VideoEditorPlayer::VeAudioOutput::pause() {
 
     ALOGV("VeAudioOutput::pause");
-    if (mTrack) mTrack->pause();
+    if (mTrack != 0) mTrack->pause();
 }
 
 void VideoEditorPlayer::VeAudioOutput::close() {
 
     ALOGV("close");
-    delete mTrack;
-    mTrack = 0;
+    mTrack.clear();
 }
 
 void VideoEditorPlayer::VeAudioOutput::setVolume(float left, float right) {
@@ -531,7 +533,7 @@
     ALOGV("setVolume(%f, %f)", left, right);
     mLeftVolume = left;
     mRightVolume = right;
-    if (mTrack) {
+    if (mTrack != 0) {
         mTrack->setVolume(left, right);
     }
 }
@@ -548,7 +550,8 @@
     AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
 
     size_t actualSize = (*me->mCallback)(
-            me, buffer->raw, buffer->size, me->mCallbackCookie);
+            me, buffer->raw, buffer->size, me->mCallbackCookie,
+            MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER);
 
     buffer->size = actualSize;
 
@@ -582,4 +585,11 @@
     return mSessionId;
 }
 
+uint32_t VideoEditorPlayer::VeAudioOutput::getSampleRate() const {
+    if (mMsecsPerFrame == 0) {
+        return 0;
+    }
+    return (uint32_t)(1.e3 / mMsecsPerFrame);
+}
+
 }  // namespace android
diff --git a/libvideoeditor/lvpp/VideoEditorPlayer.h b/libvideoeditor/lvpp/VideoEditorPlayer.h
index 77194ab..b8c1254 100755
--- a/libvideoeditor/lvpp/VideoEditorPlayer.h
+++ b/libvideoeditor/lvpp/VideoEditorPlayer.h
@@ -48,19 +48,22 @@
         virtual status_t        getPosition(uint32_t *position) const;
         virtual status_t        getFramesWritten(uint32_t*) const;
         virtual int             getSessionId() const;
+        virtual uint32_t        getSampleRate() const;
 
         virtual status_t        open(
                 uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
                 audio_format_t format, int bufferCount,
-                AudioCallback cb, void *cookie, audio_output_flags_t flags);
+                AudioCallback cb, void *cookie, audio_output_flags_t flags,
+                const audio_offload_info_t *offloadInfo);
 
-        virtual void            start();
+        virtual status_t        start();
         virtual ssize_t         write(const void* buffer, size_t size);
         virtual void            stop();
         virtual void            flush();
         virtual void            pause();
         virtual void            close();
         void setAudioStreamType(audio_stream_type_t streamType) { mStreamType = streamType; }
+        virtual audio_stream_type_t getAudioStreamType() const { return mStreamType; }
                 void            setVolume(float left, float right);
         virtual status_t        dump(int fd,const Vector<String16>& args) const;
 
@@ -71,7 +74,7 @@
         static void             CallbackWrapper(
                 int event, void *me, void *info);
 
-        AudioTrack*             mTrack;
+        sp<AudioTrack>          mTrack;
         AudioCallback           mCallback;
         void *                  mCallbackCookie;
         audio_stream_type_t     mStreamType;
diff --git a/media/libcpustats/Android.mk b/media/libcpustats/Android.mk
new file mode 100644
index 0000000..b506353
--- /dev/null
+++ b/media/libcpustats/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES :=     \
+        CentralTendencyStatistics.cpp \
+        ThreadCpuUsage.cpp
+
+LOCAL_MODULE := libcpustats
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libcpustats/CentralTendencyStatistics.cpp b/media/libcpustats/CentralTendencyStatistics.cpp
new file mode 100644
index 0000000..42ab62b
--- /dev/null
+++ b/media/libcpustats/CentralTendencyStatistics.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2011 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 <stdlib.h>
+
+#include <cpustats/CentralTendencyStatistics.h>
+
+void CentralTendencyStatistics::sample(double x)
+{
+    // update min and max
+    if (x < mMinimum)
+        mMinimum = x;
+    if (x > mMaximum)
+        mMaximum = x;
+    // Knuth
+    if (mN == 0) {
+        mMean = 0;
+    }
+    ++mN;
+    double delta = x - mMean;
+    mMean += delta / mN;
+    mM2 += delta * (x - mMean);
+}
+
+void CentralTendencyStatistics::reset()
+{
+    mMean = NAN;
+    mMedian = NAN;
+    mMinimum = INFINITY;
+    mMaximum = -INFINITY;
+    mN = 0;
+    mM2 = 0;
+    mVariance = NAN;
+    mVarianceKnownForN = 0;
+    mStddev = NAN;
+    mStddevKnownForN = 0;
+}
+
+double CentralTendencyStatistics::variance() const
+{
+    double variance;
+    if (mVarianceKnownForN != mN) {
+        if (mN > 1) {
+            // double variance_n = M2/n;
+            variance = mM2 / (mN - 1);
+        } else {
+            variance = NAN;
+        }
+        mVariance = variance;
+        mVarianceKnownForN = mN;
+    } else {
+        variance = mVariance;
+    }
+    return variance;
+}
+
+double CentralTendencyStatistics::stddev() const
+{
+    double stddev;
+    if (mStddevKnownForN != mN) {
+        stddev = sqrt(variance());
+        mStddev = stddev;
+        mStddevKnownForN = mN;
+    } else {
+        stddev = mStddev;
+    }
+    return stddev;
+}
diff --git a/media/libcpustats/ThreadCpuUsage.cpp b/media/libcpustats/ThreadCpuUsage.cpp
new file mode 100644
index 0000000..637402a
--- /dev/null
+++ b/media/libcpustats/ThreadCpuUsage.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2011 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 "ThreadCpuUsage"
+//#define LOG_NDEBUG 0
+
+#include <errno.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <utils/Debug.h>
+#include <utils/Log.h>
+
+#include <cpustats/ThreadCpuUsage.h>
+
+namespace android {
+
+bool ThreadCpuUsage::setEnabled(bool isEnabled)
+{
+    bool wasEnabled = mIsEnabled;
+    // only do something if there is a change
+    if (isEnabled != wasEnabled) {
+        ALOGV("setEnabled(%d)", isEnabled);
+        int rc;
+        // enabling
+        if (isEnabled) {
+            rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &mPreviousTs);
+            if (rc) {
+                ALOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno);
+                isEnabled = false;
+            } else {
+                mWasEverEnabled = true;
+                // record wall clock time at first enable
+                if (!mMonotonicKnown) {
+                    rc = clock_gettime(CLOCK_MONOTONIC, &mMonotonicTs);
+                    if (rc) {
+                        ALOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno);
+                    } else {
+                        mMonotonicKnown = true;
+                    }
+                }
+            }
+        // disabling
+        } else {
+            struct timespec ts;
+            rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
+            if (rc) {
+                ALOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno);
+            } else {
+                long long delta = (ts.tv_sec - mPreviousTs.tv_sec) * 1000000000LL +
+                        (ts.tv_nsec - mPreviousTs.tv_nsec);
+                mAccumulator += delta;
+#if 0
+                mPreviousTs = ts;
+#endif
+            }
+        }
+        mIsEnabled = isEnabled;
+    }
+    return wasEnabled;
+}
+
+bool ThreadCpuUsage::sampleAndEnable(double& ns)
+{
+    bool ret;
+    bool wasEverEnabled = mWasEverEnabled;
+    if (enable()) {
+        // already enabled, so add a new sample relative to previous
+        return sample(ns);
+    } else if (wasEverEnabled) {
+        // was disabled, but add sample for accumulated time while enabled
+        ns = (double) mAccumulator;
+        mAccumulator = 0;
+        ALOGV("sampleAndEnable %.0f", ns);
+        return true;
+    } else {
+        // first time called
+        ns = 0.0;
+        ALOGV("sampleAndEnable false");
+        return false;
+    }
+}
+
+bool ThreadCpuUsage::sample(double &ns)
+{
+    if (mWasEverEnabled) {
+        if (mIsEnabled) {
+            struct timespec ts;
+            int rc;
+            rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
+            if (rc) {
+                ALOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno);
+                ns = 0.0;
+                return false;
+            } else {
+                long long delta = (ts.tv_sec - mPreviousTs.tv_sec) * 1000000000LL +
+                        (ts.tv_nsec - mPreviousTs.tv_nsec);
+                mAccumulator += delta;
+                mPreviousTs = ts;
+            }
+        } else {
+            mWasEverEnabled = false;
+        }
+        ns = (double) mAccumulator;
+        ALOGV("sample %.0f", ns);
+        mAccumulator = 0;
+        return true;
+    } else {
+        ALOGW("Can't add sample because measurements have never been enabled");
+        ns = 0.0;
+        return false;
+    }
+}
+
+long long ThreadCpuUsage::elapsed() const
+{
+    long long elapsed;
+    if (mMonotonicKnown) {
+        struct timespec ts;
+        int rc;
+        rc = clock_gettime(CLOCK_MONOTONIC, &ts);
+        if (rc) {
+            ALOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno);
+            elapsed = 0;
+        } else {
+            // mMonotonicTs is updated only at first enable and resetStatistics
+            elapsed = (ts.tv_sec - mMonotonicTs.tv_sec) * 1000000000LL +
+                    (ts.tv_nsec - mMonotonicTs.tv_nsec);
+        }
+    } else {
+        ALOGW("Can't compute elapsed time because measurements have never been enabled");
+        elapsed = 0;
+    }
+    ALOGV("elapsed %lld", elapsed);
+    return elapsed;
+}
+
+void ThreadCpuUsage::resetElapsed()
+{
+    ALOGV("resetElapsed");
+    if (mMonotonicKnown) {
+        int rc;
+        rc = clock_gettime(CLOCK_MONOTONIC, &mMonotonicTs);
+        if (rc) {
+            ALOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno);
+            mMonotonicKnown = false;
+        }
+    }
+}
+
+/*static*/
+int ThreadCpuUsage::sScalingFds[ThreadCpuUsage::MAX_CPU];
+pthread_once_t ThreadCpuUsage::sOnceControl = PTHREAD_ONCE_INIT;
+int ThreadCpuUsage::sKernelMax;
+pthread_mutex_t ThreadCpuUsage::sMutex = PTHREAD_MUTEX_INITIALIZER;
+
+/*static*/
+void ThreadCpuUsage::init()
+{
+    // read the number of CPUs
+    sKernelMax = 1;
+    int fd = open("/sys/devices/system/cpu/kernel_max", O_RDONLY);
+    if (fd >= 0) {
+#define KERNEL_MAX_SIZE 12
+        char kernelMax[KERNEL_MAX_SIZE];
+        ssize_t actual = read(fd, kernelMax, sizeof(kernelMax));
+        if (actual >= 2 && kernelMax[actual-1] == '\n') {
+            sKernelMax = atoi(kernelMax);
+            if (sKernelMax >= MAX_CPU - 1) {
+                ALOGW("kernel_max %d but MAX_CPU %d", sKernelMax, MAX_CPU);
+                sKernelMax = MAX_CPU;
+            } else if (sKernelMax < 0) {
+                ALOGW("kernel_max invalid %d", sKernelMax);
+                sKernelMax = 1;
+            } else {
+                ++sKernelMax;
+                ALOGV("number of CPUs %d", sKernelMax);
+            }
+        } else {
+            ALOGW("Can't read number of CPUs");
+        }
+        (void) close(fd);
+    } else {
+        ALOGW("Can't open number of CPUs");
+    }
+    int i;
+    for (i = 0; i < MAX_CPU; ++i) {
+        sScalingFds[i] = -1;
+    }
+}
+
+uint32_t ThreadCpuUsage::getCpukHz(int cpuNum)
+{
+    if (cpuNum < 0 || cpuNum >= MAX_CPU) {
+        ALOGW("getCpukHz called with invalid CPU %d", cpuNum);
+        return 0;
+    }
+    // double-checked locking idiom is not broken for atomic values such as fd
+    int fd = sScalingFds[cpuNum];
+    if (fd < 0) {
+        // some kernels can't open a scaling file until hot plug complete
+        pthread_mutex_lock(&sMutex);
+        fd = sScalingFds[cpuNum];
+        if (fd < 0) {
+#define FREQ_SIZE 64
+            char freq_path[FREQ_SIZE];
+#define FREQ_DIGIT 27
+            COMPILE_TIME_ASSERT_FUNCTION_SCOPE(MAX_CPU <= 10);
+#define FREQ_PATH "/sys/devices/system/cpu/cpu?/cpufreq/scaling_cur_freq"
+            strlcpy(freq_path, FREQ_PATH, sizeof(freq_path));
+            freq_path[FREQ_DIGIT] = cpuNum + '0';
+            fd = open(freq_path, O_RDONLY | O_CLOEXEC);
+            // keep this fd until process exit or exec
+            sScalingFds[cpuNum] = fd;
+        }
+        pthread_mutex_unlock(&sMutex);
+        if (fd < 0) {
+            ALOGW("getCpukHz can't open CPU %d", cpuNum);
+            return 0;
+        }
+    }
+#define KHZ_SIZE 12
+    char kHz[KHZ_SIZE];   // kHz base 10
+    ssize_t actual = pread(fd, kHz, sizeof(kHz), (off_t) 0);
+    uint32_t ret;
+    if (actual >= 2 && kHz[actual-1] == '\n') {
+        ret = atoi(kHz);
+    } else {
+        ret = 0;
+    }
+    if (ret != mCurrentkHz[cpuNum]) {
+        if (ret > 0) {
+            ALOGV("CPU %d frequency %u kHz", cpuNum, ret);
+        } else {
+            ALOGW("Can't read CPU %d frequency", cpuNum);
+        }
+        mCurrentkHz[cpuNum] = ret;
+    }
+    return ret;
+}
+
+}   // namespace android
diff --git a/media/libeffects/data/audio_effects.conf b/media/libeffects/data/audio_effects.conf
index 93f27cb..c3c4b67 100644
--- a/media/libeffects/data/audio_effects.conf
+++ b/media/libeffects/data/audio_effects.conf
@@ -6,6 +6,23 @@
 #        }
 #    }
 libraries {
+# This is a proxy library that will be an abstraction for
+# the HW and SW effects
+
+  #proxy {
+    #path /system/lib/soundfx/libeffectproxy.so
+  #}
+
+# This is the SW implementation library of the effect
+  #libSW {
+    #path /system/lib/soundfx/libswwrapper.so
+  #}
+
+# This is the HW implementation library for the effect
+  #libHW {
+    #path /system/lib/soundfx/libhwwrapper.so
+  #}
+
   bundle {
     path /system/lib/soundfx/libbundlewrapper.so
   }
@@ -18,6 +35,9 @@
   downmix {
     path /system/lib/soundfx/libdownmix.so
   }
+  loudness_enhancer {
+    path /system/lib/soundfx/libldnhncr.so
+  }
 }
 
 # Default pre-processing library. Add to audio_effect.conf "libraries" section if
@@ -43,6 +63,28 @@
 #    }
 
 effects {
+
+# additions for the proxy implementation
+# Proxy implementation
+  #effectname {
+    #library proxy
+    #uuid  xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+
+    # SW implemetation of the effect. Added as a node under the proxy to
+    # indicate this as a sub effect.
+      #libsw {
+         #library libSW
+         #uuid  yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
+      #} End of SW effect
+
+    # HW implementation of the effect. Added as a node under the proxy to
+    # indicate this as a sub effect.
+      #libhw {
+         #library libHW
+         #uuid  zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz
+      #}End of HW effect
+  #} End of effect proxy
+
   bassboost {
     library bundle
     uuid 8631f300-72e2-11df-b57e-0002a5d5c51b
@@ -83,6 +125,10 @@
     library downmix
     uuid 93f04452-e4fe-41cc-91f9-e475b6d1d69f
   }
+  loudness_enhancer {
+    library loudness_enhancer
+    uuid fa415329-2034-4bea-b5dc-5b381c8d1e2c
+  }
 }
 
 # Default pre-processing effects. Add to audio_effect.conf "effects" section if
diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c
index f17a6e8..d571f17 100644
--- a/media/libeffects/downmix/EffectDownmix.c
+++ b/media/libeffects/downmix/EffectDownmix.c
@@ -160,8 +160,8 @@
 /*--- Effect Library Interface Implementation ---*/
 
 int32_t DownmixLib_Create(const effect_uuid_t *uuid,
-        int32_t sessionId,
-        int32_t ioId,
+        int32_t sessionId __unused,
+        int32_t ioId __unused,
         effect_handle_t *pHandle) {
     int ret;
     int i;
@@ -384,7 +384,7 @@
 
     switch (cmdCode) {
     case EFFECT_CMD_INIT:
-        if (pReplyData == NULL || *replySize != sizeof(int)) {
+        if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
             return -EINVAL;
         }
         *(int *) pReplyData = Downmix_Init(pDwmModule);
@@ -392,7 +392,7 @@
 
     case EFFECT_CMD_SET_CONFIG:
         if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
-                || pReplyData == NULL || *replySize != sizeof(int)) {
+                || pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
             return -EINVAL;
         }
         *(int *) pReplyData = Downmix_Configure(pDwmModule,
@@ -407,7 +407,7 @@
         ALOGV("Downmix_Command EFFECT_CMD_GET_PARAM pCmdData %p, *replySize %d, pReplyData: %p",
                 pCmdData, *replySize, pReplyData);
         if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
-                pReplyData == NULL ||
+                pReplyData == NULL || replySize == NULL ||
                 *replySize < (int) sizeof(effect_param_t) + 2 * sizeof(int32_t)) {
             return -EINVAL;
         }
@@ -424,7 +424,7 @@
         ALOGV("Downmix_Command EFFECT_CMD_SET_PARAM cmdSize %d pCmdData %p, *replySize %d, " \
                 "pReplyData %p", cmdSize, pCmdData, *replySize, pReplyData);
         if (pCmdData == NULL || (cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)))
-                || pReplyData == NULL || *replySize != (int)sizeof(int32_t)) {
+                || pReplyData == NULL || replySize == NULL || *replySize != (int)sizeof(int32_t)) {
             return -EINVAL;
         }
         effect_param_t *cmd = (effect_param_t *) pCmdData;
@@ -443,7 +443,7 @@
         break;
 
     case EFFECT_CMD_ENABLE:
-        if (pReplyData == NULL || *replySize != sizeof(int)) {
+        if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
             return -EINVAL;
         }
         if (pDownmixer->state != DOWNMIX_STATE_INITIALIZED) {
@@ -455,7 +455,7 @@
         break;
 
     case EFFECT_CMD_DISABLE:
-        if (pReplyData == NULL || *replySize != sizeof(int)) {
+        if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
             return -EINVAL;
         }
         if (pDownmixer->state != DOWNMIX_STATE_ACTIVE) {
@@ -670,7 +670,7 @@
  *----------------------------------------------------------------------------
  */
 
-int Downmix_Reset(downmix_object_t *pDownmixer, bool init) {
+int Downmix_Reset(downmix_object_t *pDownmixer __unused, bool init __unused) {
     // nothing to do here
     return 0;
 }
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index f158929..6d30d64 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -28,6 +28,9 @@
 
 static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects
 static list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries
+// list of effect_descriptor and list of sub effects : all currently loaded
+// It does not contain effects without sub effects.
+static list_sub_elem_t *gSubEffectList;
 static pthread_mutex_t gLibLock = PTHREAD_MUTEX_INITIALIZER; // controls access to gLibraryList
 static uint32_t gNumEffects;         // total number number of effects
 static list_elem_t *gCurLib;    // current library in enumeration process
@@ -50,6 +53,8 @@
 static int loadLibrary(cnode *root, const char *name);
 static int loadEffects(cnode *root);
 static int loadEffect(cnode *node);
+// To get and add the effect pointed by the passed node to the gSubEffectList
+static int addSubEffect(cnode *root);
 static lib_entry_t *getLibrary(const char *path);
 static void resetEffectEnumeration();
 static uint32_t updateNumEffects();
@@ -57,6 +62,10 @@
                const effect_uuid_t *uuid,
                lib_entry_t **lib,
                effect_descriptor_t **desc);
+// To search a subeffect in the gSubEffectList
+int findSubEffect(const effect_uuid_t *uuid,
+               lib_entry_t **lib,
+               effect_descriptor_t **desc);
 static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len);
 static int stringToUuid(const char *str, effect_uuid_t *uuid);
 static int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen);
@@ -287,7 +296,12 @@
 
     ret = findEffect(NULL, uuid, &l, &d);
     if (ret < 0){
-        goto exit;
+        // Sub effects are not associated with the library->effects,
+        // so, findEffect will fail. Search for the effect in gSubEffectList.
+        ret = findSubEffect(uuid, &l, &d);
+        if (ret < 0 ) {
+            goto exit;
+        }
     }
 
     // create effect in library
@@ -380,6 +394,47 @@
     return 1;
 }
 
+// Function to get the sub effect descriptors of the effect whose uuid
+// is pointed by the first argument. It searches the gSubEffectList for the
+// matching uuid and then copies the corresponding sub effect descriptors
+// to the inout param
+int EffectGetSubEffects(const effect_uuid_t *uuid, sub_effect_entry_t **pSube,
+                        size_t size)
+{
+   ALOGV("EffectGetSubEffects() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X"
+          "%02X\n",uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
+          uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2],
+          uuid->node[3],uuid->node[4],uuid->node[5]);
+
+   // Check if the size of the desc buffer is large enough for 2 subeffects
+   if ((uuid == NULL) || (pSube == NULL) || (size < 2)) {
+       ALOGW("NULL pointer or insufficient memory. Cannot query subeffects");
+       return -EINVAL;
+   }
+   int ret = init();
+   if (ret < 0)
+      return ret;
+   list_sub_elem_t *e = gSubEffectList;
+   sub_effect_entry_t *subeffect;
+   effect_descriptor_t *d;
+   int count = 0;
+   while (e != NULL) {
+       d = (effect_descriptor_t*)e->object;
+       if (memcmp(uuid, &d->uuid, sizeof(effect_uuid_t)) == 0) {
+           ALOGV("EffectGetSubEffects: effect found in the list");
+           list_elem_t *subefx = e->sub_elem;
+           while (subefx != NULL) {
+               subeffect = (sub_effect_entry_t*)subefx->object;
+               pSube[count++] = subeffect;
+               subefx = subefx->next;
+           }
+           ALOGV("EffectGetSubEffects end - copied the sub effect structures");
+           return count;
+       }
+       e = e->next;
+   }
+   return -ENOENT;
+}
 /////////////////////////////////////////////////
 //      Local functions
 /////////////////////////////////////////////////
@@ -503,6 +558,65 @@
     return -EINVAL;
 }
 
+// This will find the library and UUID tags of the sub effect pointed by the
+// node, gets the effect descriptor and lib_entry_t and adds the subeffect -
+// sub_entry_t to the gSubEffectList
+int addSubEffect(cnode *root)
+{
+    ALOGV("addSubEffect");
+    cnode *node;
+    effect_uuid_t uuid;
+    effect_descriptor_t *d;
+    lib_entry_t *l;
+    list_elem_t *e;
+    node = config_find(root, LIBRARY_TAG);
+    if (node == NULL) {
+        return -EINVAL;
+    }
+    l = getLibrary(node->value);
+    if (l == NULL) {
+        ALOGW("addSubEffect() could not get library %s", node->value);
+        return -EINVAL;
+    }
+    node = config_find(root, UUID_TAG);
+    if (node == NULL) {
+        return -EINVAL;
+    }
+    if (stringToUuid(node->value, &uuid) != 0) {
+        ALOGW("addSubEffect() invalid uuid %s", node->value);
+        return -EINVAL;
+    }
+    d = malloc(sizeof(effect_descriptor_t));
+    if (l->desc->get_descriptor(&uuid, d) != 0) {
+        char s[40];
+        uuidToString(&uuid, s, 40);
+        ALOGW("Error querying effect %s on lib %s", s, l->name);
+        free(d);
+        return -EINVAL;
+    }
+#if (LOG_NDEBUG==0)
+    char s[256];
+    dumpEffectDescriptor(d, s, 256);
+    ALOGV("addSubEffect() read descriptor %p:%s",d, s);
+#endif
+    if (EFFECT_API_VERSION_MAJOR(d->apiVersion) !=
+            EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) {
+        ALOGW("Bad API version %08x on lib %s", d->apiVersion, l->name);
+        free(d);
+        return -EINVAL;
+    }
+    sub_effect_entry_t *sub_effect = malloc(sizeof(sub_effect_entry_t));
+    sub_effect->object = d;
+    // lib_entry_t is stored since the sub effects are not linked to the library
+    sub_effect->lib = l;
+    e = malloc(sizeof(list_elem_t));
+    e->object = sub_effect;
+    e->next = gSubEffectList->sub_elem;
+    gSubEffectList->sub_elem = e;
+    ALOGV("addSubEffect end");
+    return 0;
+}
+
 int loadEffects(cnode *root)
 {
     cnode *node;
@@ -571,9 +685,101 @@
     e->next = l->effects;
     l->effects = e;
 
+    // After the UUID node in the config_tree, if node->next is valid,
+    // that would be sub effect node.
+    // Find the sub effects and add them to the gSubEffectList
+    node = node->next;
+    int count = 2;
+    bool hwSubefx = false, swSubefx = false;
+    list_sub_elem_t *sube = NULL;
+    if (node != NULL) {
+        ALOGV("Adding the effect to gEffectSubList as there are sub effects");
+        sube = malloc(sizeof(list_sub_elem_t));
+        sube->object = d;
+        sube->sub_elem = NULL;
+        sube->next = gSubEffectList;
+        gSubEffectList = sube;
+    }
+    while (node != NULL && count) {
+       if (addSubEffect(node)) {
+           ALOGW("loadEffect() could not add subEffect %s", node->value);
+           // Change the gSubEffectList to point to older list;
+           gSubEffectList = sube->next;
+           free(sube->sub_elem);// Free an already added sub effect
+           sube->sub_elem = NULL;
+           free(sube);
+           return -ENOENT;
+       }
+       sub_effect_entry_t *subEntry = (sub_effect_entry_t*)gSubEffectList->sub_elem->object;
+       effect_descriptor_t *subEffectDesc = (effect_descriptor_t*)(subEntry->object);
+       // Since we return a dummy descriptor for the proxy during
+       // get_descriptor call,we replace it with the correspoding
+       // sw effect descriptor, but with Proxy UUID
+       // check for Sw desc
+        if (!((subEffectDesc->flags & EFFECT_FLAG_HW_ACC_MASK) ==
+                                           EFFECT_FLAG_HW_ACC_TUNNEL)) {
+             swSubefx = true;
+             *d = *subEffectDesc;
+             d->uuid = uuid;
+             ALOGV("loadEffect() Changed the Proxy desc");
+       } else
+           hwSubefx = true;
+       count--;
+       node = node->next;
+    }
+    // 1 HW and 1 SW sub effect found. Set the offload flag in the Proxy desc
+    if (hwSubefx && swSubefx) {
+        d->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED;
+    }
     return 0;
 }
 
+// Searches the sub effect matching to the specified uuid
+// in the gSubEffectList. It gets the lib_entry_t for
+// the matched sub_effect . Used in EffectCreate of sub effects
+int findSubEffect(const effect_uuid_t *uuid,
+               lib_entry_t **lib,
+               effect_descriptor_t **desc)
+{
+    list_sub_elem_t *e = gSubEffectList;
+    list_elem_t *subefx;
+    sub_effect_entry_t *effect;
+    lib_entry_t *l = NULL;
+    effect_descriptor_t *d = NULL;
+    int found = 0;
+    int ret = 0;
+
+    if (uuid == NULL)
+        return -EINVAL;
+
+    while (e != NULL && !found) {
+        subefx = (list_elem_t*)(e->sub_elem);
+        while (subefx != NULL) {
+            effect = (sub_effect_entry_t*)subefx->object;
+            l = (lib_entry_t *)effect->lib;
+            d = (effect_descriptor_t *)effect->object;
+            if (memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
+                ALOGV("uuid matched");
+                found = 1;
+                break;
+            }
+            subefx = subefx->next;
+        }
+        e = e->next;
+    }
+    if (!found) {
+        ALOGV("findSubEffect() effect not found");
+        ret = -ENOENT;
+    } else {
+        ALOGV("findSubEffect() found effect: %s in lib %s", d->name, l->name);
+        *lib = l;
+        if (desc != NULL) {
+            *desc = d;
+        }
+    }
+    return ret;
+}
+
 lib_entry_t *getLibrary(const char *name)
 {
     list_elem_t *e;
diff --git a/media/libeffects/factory/EffectsFactory.h b/media/libeffects/factory/EffectsFactory.h
index c1d4319..560b485 100644
--- a/media/libeffects/factory/EffectsFactory.h
+++ b/media/libeffects/factory/EffectsFactory.h
@@ -20,7 +20,7 @@
 #include <cutils/log.h>
 #include <pthread.h>
 #include <dirent.h>
-#include <media/EffectsFactoryApi.h>
+#include <hardware/audio_effect.h>
 
 #if __cplusplus
 extern "C" {
@@ -32,6 +32,15 @@
     struct list_elem_s *next;
 } list_elem_t;
 
+// Structure used for storing effects with their sub effects.
+// Used in creating gSubEffectList. Here,
+// object holds the effect desc and the list sub_elem holds the sub effects
+typedef struct list_sub_elem_s {
+    void *object;
+    list_elem_t *sub_elem;
+    struct list_sub_elem_s *next;
+} list_sub_elem_t;
+
 typedef struct lib_entry_s {
     audio_effect_library_t *desc;
     char *name;
@@ -47,6 +56,42 @@
     lib_entry_t *lib;
 } effect_entry_t;
 
+// Structure used to store the lib entry
+// and the descriptor of the sub effects.
+// The library entry is to be stored in case of
+// sub effects as the sub effects are not linked
+// to the library list - gLibraryList.
+typedef struct sub_effect_entry_s {
+    lib_entry_t *lib;
+    void *object;
+} sub_effect_entry_t;
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//    Function:       EffectGetSubEffects
+//
+//    Description:    Returns the descriptors of the sub effects of the effect
+//                    whose uuid is pointed to by first argument.
+//
+//    Input:
+//          pEffectUuid:    pointer to the effect uuid.
+//          size:           max number of sub_effect_entry_t * in pSube.
+//
+//    Input/Output:
+//          pSube:          address where to return the sub effect structures.
+//    Output:
+//        returned value:    0          successful operation.
+//                          -ENODEV     factory failed to initialize
+//                          -EINVAL     invalid pEffectUuid or pDescriptor
+//                          -ENOENT     no effect with this uuid found
+//        *pDescriptor:     updated with the sub effect descriptors.
+//
+////////////////////////////////////////////////////////////////////////////////
+int EffectGetSubEffects(const effect_uuid_t *pEffectUuid,
+                        sub_effect_entry_t **pSube,
+                        size_t size);
+
 #if __cplusplus
 }  // extern "C"
 #endif
diff --git a/media/libeffects/loudness/Android.mk b/media/libeffects/loudness/Android.mk
new file mode 100644
index 0000000..dcb7b27
--- /dev/null
+++ b/media/libeffects/loudness/Android.mk
@@ -0,0 +1,27 @@
+LOCAL_PATH:= $(call my-dir)
+
+# LoudnessEnhancer library
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	EffectLoudnessEnhancer.cpp \
+	dsp/core/dynamic_range_compression.cpp
+
+LOCAL_CFLAGS+= -O2 -fvisibility=hidden
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	liblog \
+	libstlport
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
+LOCAL_MODULE:= libldnhncr
+
+LOCAL_C_INCLUDES := \
+	$(call include-path-for, audio-effects) \
+	bionic \
+	bionic/libstdc++/include \
+	external/stlport/stlport
+
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
new file mode 100644
index 0000000..5510caf
--- /dev/null
+++ b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "EffectLE"
+//#define LOG_NDEBUG 0
+#include <cutils/log.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <new>
+#include <time.h>
+#include <math.h>
+#include <audio_effects/effect_loudnessenhancer.h>
+#include "dsp/core/dynamic_range_compression.h"
+
+extern "C" {
+
+// effect_handle_t interface implementation for LE effect
+extern const struct effect_interface_s gLEInterface;
+
+// AOSP Loudness Enhancer UUID: fa415329-2034-4bea-b5dc-5b381c8d1e2c
+const effect_descriptor_t gLEDescriptor = {
+        {0xfe3199be, 0xaed0, 0x413f, 0x87bb, {0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}, // type
+        {0xfa415329, 0x2034, 0x4bea, 0xb5dc, {0x5b, 0x38, 0x1c, 0x8d, 0x1e, 0x2c}}, // uuid
+        EFFECT_CONTROL_API_VERSION,
+        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST),
+        0, // TODO
+        1,
+        "Loudness Enhancer",
+        "The Android Open Source Project",
+};
+
+enum le_state_e {
+    LOUDNESS_ENHANCER_STATE_UNINITIALIZED,
+    LOUDNESS_ENHANCER_STATE_INITIALIZED,
+    LOUDNESS_ENHANCER_STATE_ACTIVE,
+};
+
+struct LoudnessEnhancerContext {
+    const struct effect_interface_s *mItfe;
+    effect_config_t mConfig;
+    uint8_t mState;
+    int32_t mTargetGainmB;// target gain in mB
+    // in this implementation, there is no coupling between the compression on the left and right
+    // channels
+    le_fx::AdaptiveDynamicRangeCompression* mCompressor;
+};
+
+//
+//--- Local functions (not directly used by effect interface)
+//
+
+void LE_reset(LoudnessEnhancerContext *pContext)
+{
+    ALOGV("  > LE_reset(%p)", pContext);
+
+    if (pContext->mCompressor != NULL) {
+        float targetAmp = pow(10, pContext->mTargetGainmB/2000.0f); // mB to linear amplification
+        ALOGV("LE_reset(): Target gain=%dmB <=> factor=%.2fX", pContext->mTargetGainmB, targetAmp);
+        pContext->mCompressor->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
+    } else {
+        ALOGE("LE_reset(%p): null compressors, can't apply target gain", pContext);
+    }
+}
+
+static inline int16_t clamp16(int32_t sample)
+{
+    if ((sample>>15) ^ (sample>>31))
+        sample = 0x7FFF ^ (sample>>31);
+    return sample;
+}
+
+//----------------------------------------------------------------------------
+// LE_setConfig()
+//----------------------------------------------------------------------------
+// Purpose: Set input and output audio configuration.
+//
+// Inputs:
+//  pContext:   effect engine context
+//  pConfig:    pointer to effect_config_t structure holding input and output
+//      configuration parameters
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+int LE_setConfig(LoudnessEnhancerContext *pContext, effect_config_t *pConfig)
+{
+    ALOGV("LE_setConfig(%p)", pContext);
+
+    if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL;
+    if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL;
+    if (pConfig->inputCfg.format != pConfig->outputCfg.format) return -EINVAL;
+    if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
+    if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
+            pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
+    if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL;
+
+    pContext->mConfig = *pConfig;
+
+    LE_reset(pContext);
+
+    return 0;
+}
+
+
+//----------------------------------------------------------------------------
+// LE_getConfig()
+//----------------------------------------------------------------------------
+// Purpose: Get input and output audio configuration.
+//
+// Inputs:
+//  pContext:   effect engine context
+//  pConfig:    pointer to effect_config_t structure holding input and output
+//      configuration parameters
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+void LE_getConfig(LoudnessEnhancerContext *pContext, effect_config_t *pConfig)
+{
+    *pConfig = pContext->mConfig;
+}
+
+
+//----------------------------------------------------------------------------
+// LE_init()
+//----------------------------------------------------------------------------
+// Purpose: Initialize engine with default configuration.
+//
+// Inputs:
+//  pContext:   effect engine context
+//
+// Outputs:
+//
+//----------------------------------------------------------------------------
+
+int LE_init(LoudnessEnhancerContext *pContext)
+{
+    ALOGV("LE_init(%p)", pContext);
+
+    pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
+    pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+    pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    pContext->mConfig.inputCfg.samplingRate = 44100;
+    pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
+    pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
+    pContext->mConfig.inputCfg.bufferProvider.cookie = NULL;
+    pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
+    pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
+    pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+    pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+    pContext->mConfig.outputCfg.samplingRate = 44100;
+    pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
+    pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
+    pContext->mConfig.outputCfg.bufferProvider.cookie = NULL;
+    pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
+
+    pContext->mTargetGainmB = LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB;
+    float targetAmp = pow(10, pContext->mTargetGainmB/2000.0f); // mB to linear amplification
+    ALOGV("LE_init(): Target gain=%dmB <=> factor=%.2fX", pContext->mTargetGainmB, targetAmp);
+
+    if (pContext->mCompressor == NULL) {
+        pContext->mCompressor = new le_fx::AdaptiveDynamicRangeCompression();
+        pContext->mCompressor->Initialize(targetAmp, pContext->mConfig.inputCfg.samplingRate);
+    }
+
+    LE_setConfig(pContext, &pContext->mConfig);
+
+    return 0;
+}
+
+//
+//--- Effect Library Interface Implementation
+//
+
+int LELib_Create(const effect_uuid_t *uuid,
+                         int32_t sessionId __unused,
+                         int32_t ioId __unused,
+                         effect_handle_t *pHandle) {
+    ALOGV("LELib_Create()");
+    int ret;
+    int i;
+
+    if (pHandle == NULL || uuid == NULL) {
+        return -EINVAL;
+    }
+
+    if (memcmp(uuid, &gLEDescriptor.uuid, sizeof(effect_uuid_t)) != 0) {
+        return -EINVAL;
+    }
+
+    LoudnessEnhancerContext *pContext = new LoudnessEnhancerContext;
+
+    pContext->mItfe = &gLEInterface;
+    pContext->mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED;
+
+    pContext->mCompressor = NULL;
+    ret = LE_init(pContext);
+    if (ret < 0) {
+        ALOGW("LELib_Create() init failed");
+        delete pContext;
+        return ret;
+    }
+
+    *pHandle = (effect_handle_t)pContext;
+
+    pContext->mState = LOUDNESS_ENHANCER_STATE_INITIALIZED;
+
+    ALOGV("  LELib_Create context is %p", pContext);
+
+    return 0;
+
+}
+
+int LELib_Release(effect_handle_t handle) {
+    LoudnessEnhancerContext * pContext = (LoudnessEnhancerContext *)handle;
+
+    ALOGV("LELib_Release %p", handle);
+    if (pContext == NULL) {
+        return -EINVAL;
+    }
+    pContext->mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED;
+    if (pContext->mCompressor != NULL) {
+        delete pContext->mCompressor;
+        pContext->mCompressor = NULL;
+    }
+    delete pContext;
+
+    return 0;
+}
+
+int LELib_GetDescriptor(const effect_uuid_t *uuid,
+                                effect_descriptor_t *pDescriptor) {
+
+    if (pDescriptor == NULL || uuid == NULL){
+        ALOGV("LELib_GetDescriptor() called with NULL pointer");
+        return -EINVAL;
+    }
+
+    if (memcmp(uuid, &gLEDescriptor.uuid, sizeof(effect_uuid_t)) == 0) {
+        *pDescriptor = gLEDescriptor;
+        return 0;
+    }
+
+    return  -EINVAL;
+} /* end LELib_GetDescriptor */
+
+//
+//--- Effect Control Interface Implementation
+//
+int LE_process(
+        effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
+{
+    LoudnessEnhancerContext * pContext = (LoudnessEnhancerContext *)self;
+
+    if (pContext == NULL) {
+        return -EINVAL;
+    }
+
+    if (inBuffer == NULL || inBuffer->raw == NULL ||
+        outBuffer == NULL || outBuffer->raw == NULL ||
+        inBuffer->frameCount != outBuffer->frameCount ||
+        inBuffer->frameCount == 0) {
+        return -EINVAL;
+    }
+
+    //ALOGV("LE about to process %d samples", inBuffer->frameCount);
+    uint16_t inIdx;
+    float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f);
+    float leftSample, rightSample;
+    for (inIdx = 0 ; inIdx < inBuffer->frameCount ; inIdx++) {
+        // makeup gain is applied on the input of the compressor
+        leftSample  = inputAmp * (float)inBuffer->s16[2*inIdx];
+        rightSample = inputAmp * (float)inBuffer->s16[2*inIdx +1];
+        pContext->mCompressor->Compress(&leftSample, &rightSample);
+        inBuffer->s16[2*inIdx]    = (int16_t) leftSample;
+        inBuffer->s16[2*inIdx +1] = (int16_t) rightSample;
+    }
+
+    if (inBuffer->raw != outBuffer->raw) {
+        if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+            for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
+                outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
+            }
+        } else {
+            memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
+        }
+    }
+    if (pContext->mState != LOUDNESS_ENHANCER_STATE_ACTIVE) {
+        return -ENODATA;
+    }
+    return 0;
+}
+
+int LE_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
+        void *pCmdData, uint32_t *replySize, void *pReplyData) {
+
+    LoudnessEnhancerContext * pContext = (LoudnessEnhancerContext *)self;
+    int retsize;
+
+    if (pContext == NULL || pContext->mState == LOUDNESS_ENHANCER_STATE_UNINITIALIZED) {
+        return -EINVAL;
+    }
+
+//    ALOGV("LE_command command %d cmdSize %d",cmdCode, cmdSize);
+    switch (cmdCode) {
+    case EFFECT_CMD_INIT:
+        if (pReplyData == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        *(int *) pReplyData = LE_init(pContext);
+        break;
+    case EFFECT_CMD_SET_CONFIG:
+        if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
+                || pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        *(int *) pReplyData = LE_setConfig(pContext,
+                (effect_config_t *) pCmdData);
+        break;
+    case EFFECT_CMD_GET_CONFIG:
+        if (pReplyData == NULL ||
+            *replySize != sizeof(effect_config_t)) {
+            return -EINVAL;
+        }
+        LE_getConfig(pContext, (effect_config_t *)pReplyData);
+        break;
+    case EFFECT_CMD_RESET:
+        LE_reset(pContext);
+        break;
+    case EFFECT_CMD_ENABLE:
+        if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        if (pContext->mState != LOUDNESS_ENHANCER_STATE_INITIALIZED) {
+            return -ENOSYS;
+        }
+        pContext->mState = LOUDNESS_ENHANCER_STATE_ACTIVE;
+        ALOGV("EFFECT_CMD_ENABLE() OK");
+        *(int *)pReplyData = 0;
+        break;
+    case EFFECT_CMD_DISABLE:
+        if (pReplyData == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        if (pContext->mState != LOUDNESS_ENHANCER_STATE_ACTIVE) {
+            return -ENOSYS;
+        }
+        pContext->mState = LOUDNESS_ENHANCER_STATE_INITIALIZED;
+        ALOGV("EFFECT_CMD_DISABLE() OK");
+        *(int *)pReplyData = 0;
+        break;
+    case EFFECT_CMD_GET_PARAM: {
+        if (pCmdData == NULL ||
+            cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
+            pReplyData == NULL || replySize == NULL ||
+            *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
+            return -EINVAL;
+        }
+        memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + sizeof(uint32_t));
+        effect_param_t *p = (effect_param_t *)pReplyData;
+        p->status = 0;
+        *replySize = sizeof(effect_param_t) + sizeof(uint32_t);
+        if (p->psize != sizeof(uint32_t)) {
+            p->status = -EINVAL;
+            break;
+        }
+        switch (*(uint32_t *)p->data) {
+        case LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB:
+            ALOGV("get target gain(mB) = %d", pContext->mTargetGainmB);
+            *((int32_t *)p->data + 1) = pContext->mTargetGainmB;
+            p->vsize = sizeof(int32_t);
+            *replySize += sizeof(int32_t);
+            break;
+        default:
+            p->status = -EINVAL;
+        }
+        } break;
+    case EFFECT_CMD_SET_PARAM: {
+        if (pCmdData == NULL ||
+            cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
+            pReplyData == NULL || replySize == NULL || *replySize != sizeof(int32_t)) {
+            return -EINVAL;
+        }
+        *(int32_t *)pReplyData = 0;
+        effect_param_t *p = (effect_param_t *)pCmdData;
+        if (p->psize != sizeof(uint32_t) || p->vsize != sizeof(uint32_t)) {
+            *(int32_t *)pReplyData = -EINVAL;
+            break;
+        }
+        switch (*(uint32_t *)p->data) {
+        case LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB:
+            pContext->mTargetGainmB = *((int32_t *)p->data + 1);
+            ALOGV("set target gain(mB) = %d", pContext->mTargetGainmB);
+            LE_reset(pContext); // apply parameter update
+            break;
+        default:
+            *(int32_t *)pReplyData = -EINVAL;
+        }
+        } break;
+    case EFFECT_CMD_SET_DEVICE:
+    case EFFECT_CMD_SET_VOLUME:
+    case EFFECT_CMD_SET_AUDIO_MODE:
+        break;
+
+    default:
+        ALOGW("LE_command invalid command %d",cmdCode);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+/* Effect Control Interface Implementation: get_descriptor */
+int LE_getDescriptor(effect_handle_t   self,
+                                    effect_descriptor_t *pDescriptor)
+{
+    LoudnessEnhancerContext * pContext = (LoudnessEnhancerContext *) self;
+
+    if (pContext == NULL || pDescriptor == NULL) {
+        ALOGV("LE_getDescriptor() invalid param");
+        return -EINVAL;
+    }
+
+    *pDescriptor = gLEDescriptor;
+
+    return 0;
+}   /* end LE_getDescriptor */
+
+// effect_handle_t interface implementation for DRC effect
+const struct effect_interface_s gLEInterface = {
+        LE_process,
+        LE_command,
+        LE_getDescriptor,
+        NULL,
+};
+
+// This is the only symbol that needs to be exported
+__attribute__ ((visibility ("default")))
+audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
+    tag : AUDIO_EFFECT_LIBRARY_TAG,
+    version : EFFECT_LIBRARY_API_VERSION,
+    name : "Loudness Enhancer Library",
+    implementor : "The Android Open Source Project",
+    create_effect : LELib_Create,
+    release_effect : LELib_Release,
+    get_descriptor : LELib_GetDescriptor,
+};
+
+}; // extern "C"
+
diff --git a/media/libeffects/loudness/MODULE_LICENSE_APACHE2 b/media/libeffects/loudness/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libeffects/loudness/MODULE_LICENSE_APACHE2
diff --git a/media/libeffects/loudness/NOTICE b/media/libeffects/loudness/NOTICE
new file mode 100644
index 0000000..ad6ed94
--- /dev/null
+++ b/media/libeffects/loudness/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2013, The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/media/libeffects/loudness/common/core/basic_types.h b/media/libeffects/loudness/common/core/basic_types.h
new file mode 100644
index 0000000..593e914
--- /dev/null
+++ b/media/libeffects/loudness/common/core/basic_types.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LE_FX_ENGINE_COMMON_CORE_BASIC_TYPES_H_
+#define LE_FX_ENGINE_COMMON_CORE_BASIC_TYPES_H_
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string>
+using ::std::string;
+using ::std::basic_string;
+#include <vector>
+using ::std::vector;
+
+#include "common/core/os.h"
+
+// -----------------------------------------------------------------------------
+// Definitions of common basic types:
+// -----------------------------------------------------------------------------
+
+#if !defined(G_COMPILE) && !defined(BASE_INTEGRAL_TYPES_H_)
+
+namespace le_fx {
+
+typedef signed char         schar;
+typedef signed char         int8;
+typedef short               int16;
+typedef int                 int32;
+typedef long long           int64;
+
+typedef unsigned char       uint8;
+typedef unsigned short      uint16;
+typedef unsigned int        uint32;
+typedef unsigned long long  uint64;
+
+}  // namespace le_fx
+
+#endif
+
+namespace le_fx {
+
+struct FloatArray {
+  int length;
+  float *data;
+
+  FloatArray(void) {
+    data = NULL;
+    length = 0;
+  }
+};
+
+struct Int16Array {
+  int length;
+  int16 *data;
+
+  Int16Array(void) {
+    data = NULL;
+    length = 0;
+  }
+};
+
+struct Int32Array {
+  int length;
+  int32 *data;
+
+  Int32Array(void) {
+    data = NULL;
+    length = 0;
+  }
+};
+
+struct Int8Array {
+  int length;
+  uint8 *data;
+
+  Int8Array(void) {
+    data = NULL;
+    length = 0;
+  }
+};
+
+//
+// Simple wrapper for waveform data:
+//
+class WaveData : public vector<int16> {
+ public:
+  WaveData();
+  ~WaveData();
+
+  void Set(int number_samples, int sampling_rate, int16 *data);
+  int sample_rate(void) const;
+  void set_sample_rate(int sample_rate);
+  bool Equals(const WaveData &wave_data, int threshold = 0) const;
+
+ private:
+  int sample_rate_;
+};
+
+}  // namespace le_fx
+
+#endif  // LE_FX_ENGINE_COMMON_CORE_BASIC_TYPES_H_
diff --git a/media/libeffects/loudness/common/core/byte_swapper.h b/media/libeffects/loudness/common/core/byte_swapper.h
new file mode 100644
index 0000000..8f0caf3
--- /dev/null
+++ b/media/libeffects/loudness/common/core/byte_swapper.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LE_FX_ENGINE_COMMON_CORE_BYTE_SWAPPER_H_
+#define LE_FX_ENGINE_COMMON_CORE_BYTE_SWAPPER_H_
+
+#include <stdio.h>
+#include <string.h>
+
+#include "common/core/basic_types.h"
+#include "common/core/os.h"
+
+namespace le_fx {
+
+namespace arch {
+
+inline bool IsLittleEndian(void) {
+  int16 word = 1;
+  char *cp = reinterpret_cast<char *>(&word);
+  return cp[0] != 0;
+}
+
+inline bool IsBigEndian(void) {
+  return !IsLittleEndian();
+}
+
+template <typename T, unsigned int kValSize>
+struct ByteSwapper {
+  static T Swap(const T &val) {
+    T new_val = val;
+    char *first = &new_val, *last = first + kValSize - 1, x;
+    for (; first < last; ++first, --last) {
+      x = *last;
+      *last = *first;
+      *first = x;
+    }
+    return new_val;
+  }
+};
+
+template <typename T>
+struct ByteSwapper<T, 1> {
+  static T Swap(const T &val) {
+    return val;
+  }
+};
+
+template <typename T>
+struct ByteSwapper<T, 2> {
+  static T Swap(const T &val) {
+    T new_val;
+    const char *o = (const char *)&val;
+    char *p = reinterpret_cast<char *>(&new_val);
+    p[0] = o[1];
+    p[1] = o[0];
+    return new_val;
+  }
+};
+
+template <typename T>
+struct ByteSwapper<T, 4> {
+  static T Swap(const T &val) {
+    T new_val;
+    const char *o = (const char *)&val;
+    char *p = reinterpret_cast<char *>(&new_val);
+    p[0] = o[3];
+    p[1] = o[2];
+    p[2] = o[1];
+    p[3] = o[0];
+    return new_val;
+  }
+};
+
+template <typename T>
+struct ByteSwapper<T, 8> {
+  static T Swap(const T &val) {
+    T new_val = val;
+    const char *o = (const char *)&val;
+    char *p = reinterpret_cast<char *>(&new_val);
+    p[0] = o[7];
+    p[1] = o[6];
+    p[2] = o[5];
+    p[3] = o[4];
+    p[4] = o[3];
+    p[5] = o[2];
+    p[6] = o[1];
+    p[7] = o[0];
+    return new_val;
+  }
+};
+
+template <typename T>
+T SwapBytes(const T &val, bool force_swap) {
+  if (force_swap) {
+#if !defined(LE_FX__NEED_BYTESWAP)
+    return ByteSwapper<T, sizeof(T)>::Swap(val);
+#else
+    return val;
+#endif  // !LE_FX_NEED_BYTESWAP
+  } else {
+#if !defined(LE_FX_NEED_BYTESWAP)
+    return val;
+#else
+    return ByteSwapper<T, sizeof(T)>::Swap(val);
+#endif  // !LE_FX_NEED_BYTESWAP
+  }
+}
+
+template <typename T>
+const T *SwapBytes(const T *vals, unsigned int num_items, bool force_swap) {
+  if (force_swap) {
+#if !defined(LE_FX_NEED_BYTESWAP)
+    T *writeable_vals = const_cast<T *>(vals);
+    for (unsigned int i = 0; i < num_items; i++) {
+      writeable_vals[i] = ByteSwapper<T, sizeof(T)>::Swap(vals[i]);
+    }
+    return writeable_vals;
+#else
+    return vals;
+#endif  // !LE_FX_NEED_BYTESWAP
+  } else {
+#if !defined(LE_FX_NEED_BYTESWAP)
+    return vals;
+#else
+    T *writeable_vals = const_cast<T *>(vals);
+    for (unsigned int i = 0; i < num_items; i++) {
+      writeable_vals[i] = ByteSwapper<T, sizeof(T)>::Swap(vals[i]);
+    }
+    return writeable_vals;
+#endif  // !LE_FX_NEED_BYTESWAP
+  }
+}
+
+}  // namespace arch
+
+}  // namespace le_fx
+
+#endif  // LE_FX_ENGINE_COMMON_CORE_BYTE_SWAPPER_H_
diff --git a/media/libeffects/loudness/common/core/math.h b/media/libeffects/loudness/common/core/math.h
new file mode 100644
index 0000000..3f302cc
--- /dev/null
+++ b/media/libeffects/loudness/common/core/math.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LE_FX_ENGINE_COMMON_CORE_MATH_H_
+#define LE_FX_ENGINE_COMMON_CORE_MATH_H_
+
+#include <math.h>
+#include <algorithm>
+using ::std::min;
+using ::std::max;
+using ::std::fill;
+using ::std::fill_n;using ::std::lower_bound;
+#include <cmath>
+#include <math.h>
+//using ::std::fpclassify;
+
+#include "common/core/os.h"
+#include "common/core/types.h"
+
+namespace le_fx {
+namespace math {
+
+// A fast approximation to log2(.)
+inline float fast_log2(float val) {
+  int* const exp_ptr = reinterpret_cast <int *> (&val);
+  int x = *exp_ptr;
+  const int log_2 = ((x >> 23) & 255) - 128;
+  x &= ~(255 << 23);
+  x += 127 << 23;
+  *exp_ptr = x;
+  val = ((-1.0f / 3) * val + 2) * val - 2.0f / 3;
+  return static_cast<float>(val + log_2);
+}
+
+// A fast approximation to log(.)
+inline float fast_log(float val) {
+  return fast_log2(val) *
+      0.693147180559945286226763982995180413126945495605468750f;
+}
+
+// An approximation of the exp(.) function using a 5-th order Taylor expansion.
+// It's pretty accurate between +-0.1 and accurate to 10e-3 between +-1
+template <typename T>
+inline T ExpApproximationViaTaylorExpansionOrder5(T x) {
+  const T x2 = x * x;
+  const T x3 = x2 * x;
+  const T x4 = x2 * x2;
+  const T x5 = x3 * x2;
+  return 1.0f + x + 0.5f * x2 +
+      0.16666666666666665741480812812369549646973609924316406250f * x3 +
+      0.0416666666666666643537020320309238741174340248107910156250f * x4 +
+      0.008333333333333333217685101601546193705871701240539550781250f * x5;
+}
+
+}  // namespace math
+}  // namespace le_fx
+
+// Math functions missing in Android NDK:
+#if defined(LE_FX_OS_ANDROID)
+
+namespace std {
+
+//
+// Round to the nearest integer: We need this implementation
+// since std::round is missing on android.
+//
+template <typename T>
+inline T round(const T &x) {
+  return static_cast<T>(std::floor(static_cast<double>(x) + 0.5));
+}
+
+}  // namespace std
+
+#endif  // LE_FX_OS_ANDROID
+
+#endif  // LE_FX_ENGINE_COMMON_CORE_MATH_H_
diff --git a/media/libeffects/loudness/common/core/os.h b/media/libeffects/loudness/common/core/os.h
new file mode 100644
index 0000000..4a8ce82
--- /dev/null
+++ b/media/libeffects/loudness/common/core/os.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LE_FX_ENGINE_COMMON_CORE_OS_H_
+#define LE_FX_ENGINE_COMMON_CORE_OS_H_
+
+// -----------------------------------------------------------------------------
+// OS Identification:
+// -----------------------------------------------------------------------------
+
+#define LE_FX_OS_UNIX
+#if defined(__ANDROID__)
+#    define LE_FX_OS_ANDROID
+#endif  // Android
+
+#endif // LE_FX_ENGINE_COMMON_CORE_OS_H_
diff --git a/media/libeffects/loudness/common/core/types.h b/media/libeffects/loudness/common/core/types.h
new file mode 100644
index 0000000..d1b6c6a
--- /dev/null
+++ b/media/libeffects/loudness/common/core/types.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LE_FX_ENGINE_COMMON_CORE_TYPES_H_
+#define LE_FX_ENGINE_COMMON_CORE_TYPES_H_
+
+#include "common/core/os.h"
+
+#include "common/core/basic_types.h"
+
+#ifndef LE_FX_DISALLOW_COPY_AND_ASSIGN
+#define LE_FX_DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&); \
+  void operator=(const TypeName&)
+#endif  // LE_FX_DISALLOW_COPY_AND_ASSIGN
+
+
+#endif  // LE_FX_ENGINE_COMMON_CORE_TYPES_H_
diff --git a/media/libeffects/loudness/dsp/core/basic-inl.h b/media/libeffects/loudness/dsp/core/basic-inl.h
new file mode 100644
index 0000000..3f77147
--- /dev/null
+++ b/media/libeffects/loudness/dsp/core/basic-inl.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LE_FX_ENGINE_DSP_CORE_BASIC_INL_H_
+#define LE_FX_ENGINE_DSP_CORE_BASIC_INL_H_
+
+#include <math.h>
+
+namespace le_fx {
+
+namespace sigmod {
+
+template <typename T>
+int SearchIndex(const T x_data[],
+                T x,
+                int start_index,
+                int end_index) {
+  int start = start_index;
+  int end = end_index;
+  while (end > start + 1) {
+    int i = (end + start) / 2;
+    if (x_data[i] > x) {
+      end = i;
+    } else {
+      start = i;
+    }
+  }
+  return start;
+}
+
+}  // namespace sigmod
+
+}  // namespace le_fx
+
+#endif  // LE_FX_ENGINE_DSP_CORE_BASIC_INL_H_
diff --git a/media/libeffects/loudness/dsp/core/basic.h b/media/libeffects/loudness/dsp/core/basic.h
new file mode 100644
index 0000000..27e0a8d
--- /dev/null
+++ b/media/libeffects/loudness/dsp/core/basic.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LE_FX_ENGINE_DSP_CORE_BASIC_H_
+#define LE_FX_ENGINE_DSP_CORE_BASIC_H_
+
+#include <limits.h>
+#include "common/core/math.h"
+#include "common/core/types.h"
+
+namespace le_fx {
+
+namespace sigmod {
+
+// Searchs for the interval that contains <x> using a divide-and-conquer
+// algorithm.
+// X[]: a vector of sorted values (X[i+1] > X[i])
+// x:   a value
+// StartIndex: the minimum searched index
+// EndIndex: the maximum searched index
+// returns: the index <i> that satisfies: X[i] <= x <= X[i+1] &&
+//          StartIndex <= i <= (EndIndex-1)
+template <typename T>
+int SearchIndex(const T x_data[],
+                T x,
+                int start_index,
+                int end_index);
+
+}  // namespace sigmod
+
+}  // namespace le_fx
+
+#include "dsp/core/basic-inl.h"
+
+#endif  // LE_FX_ENGINE_DSP_CORE_BASIC_H_
diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h b/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
new file mode 100644
index 0000000..da75ceb
--- /dev/null
+++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression-inl.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_INL_H_
+#define LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_INL_H_
+
+//#define LOG_NDEBUG 0
+#include <cutils/log.h>
+
+
+namespace le_fx {
+
+
+inline void AdaptiveDynamicRangeCompression::set_knee_threshold(float decibel) {
+  // Converts to 1og-base
+  knee_threshold_in_decibel_ = decibel;
+  knee_threshold_ = 0.1151292546497023061569109358970308676362037658691406250f *
+      decibel + 10.39717719035538401328722102334722876548767089843750f;
+}
+
+
+inline void AdaptiveDynamicRangeCompression::set_knee_threshold_via_target_gain(
+    float target_gain) {
+  const float decibel = target_gain_to_knee_threshold_.Interpolate(
+        target_gain);
+  ALOGV("set_knee_threshold_via_target_gain: decibel =%.3fdB", decibel);
+  set_knee_threshold(decibel);
+}
+
+}  // namespace le_fx
+
+
+#endif  // LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_INL_H_
diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp b/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp
new file mode 100644
index 0000000..7bd068e
--- /dev/null
+++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cmath>
+
+#include "common/core/math.h"
+#include "common/core/types.h"
+#include "dsp/core/basic.h"
+#include "dsp/core/interpolation.h"
+#include "dsp/core/dynamic_range_compression.h"
+
+//#define LOG_NDEBUG 0
+#include <cutils/log.h>
+
+
+namespace le_fx {
+
+// Definitions for static const class members declared in
+// dynamic_range_compression.h.
+const float AdaptiveDynamicRangeCompression::kMinAbsValue = 0.000001f;
+const float AdaptiveDynamicRangeCompression::kMinLogAbsValue =
+    0.032766999999999997517097227728299912996590137481689453125f;
+const float AdaptiveDynamicRangeCompression::kFixedPointLimit = 32767.0f;
+const float AdaptiveDynamicRangeCompression::kInverseFixedPointLimit =
+    1.0f / AdaptiveDynamicRangeCompression::kFixedPointLimit;
+const float AdaptiveDynamicRangeCompression::kDefaultKneeThresholdInDecibel =
+    -8.0f;
+const float AdaptiveDynamicRangeCompression::kCompressionRatio = 7.0f;
+const float AdaptiveDynamicRangeCompression::kTauAttack = 0.001f;
+const float AdaptiveDynamicRangeCompression::kTauRelease = 0.015f;
+
+AdaptiveDynamicRangeCompression::AdaptiveDynamicRangeCompression() {
+  static const float kTargetGain[] = {
+      1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
+  static const float kKneeThreshold[] = {
+      -8.0f, -8.0f, -8.5f, -9.0f, -10.0f };
+  target_gain_to_knee_threshold_.Initialize(
+      &kTargetGain[0], &kKneeThreshold[0],
+      sizeof(kTargetGain) / sizeof(kTargetGain[0]));
+}
+
+bool AdaptiveDynamicRangeCompression::Initialize(
+        float target_gain, float sampling_rate) {
+  set_knee_threshold_via_target_gain(target_gain);
+  sampling_rate_ = sampling_rate;
+  state_ = 0.0f;
+  compressor_gain_ = 1.0f;
+  if (kTauAttack > 0.0f) {
+    const float taufs = kTauAttack * sampling_rate_;
+    alpha_attack_ = std::exp(-1.0f / taufs);
+  } else {
+    alpha_attack_ = 0.0f;
+  }
+  if (kTauRelease > 0.0f) {
+    const float taufs = kTauRelease * sampling_rate_;
+    alpha_release_ = std::exp(-1.0f / taufs);
+  } else {
+    alpha_release_ = 0.0f;
+  }
+  // Feed-forward topology
+  slope_ = 1.0f / kCompressionRatio - 1.0f;
+  return true;
+}
+
+float AdaptiveDynamicRangeCompression::Compress(float x) {
+  const float max_abs_x = std::max(std::fabs(x), kMinLogAbsValue);
+  const float max_abs_x_dB = math::fast_log(max_abs_x);
+  // Subtract Threshold from log-encoded input to get the amount of overshoot
+  const float overshoot = max_abs_x_dB - knee_threshold_;
+  // Hard half-wave rectifier
+  const float rect = std::max(overshoot, 0.0f);
+  // Multiply rectified overshoot with slope
+  const float cv = rect * slope_;
+  const float prev_state = state_;
+  if (cv <= state_) {
+    state_ = alpha_attack_ * state_ + (1.0f - alpha_attack_) * cv;
+  } else {
+    state_ = alpha_release_ * state_ + (1.0f - alpha_release_) * cv;
+  }
+  compressor_gain_ *=
+      math::ExpApproximationViaTaylorExpansionOrder5(state_ - prev_state);
+  x *= compressor_gain_;
+  if (x > kFixedPointLimit) {
+    return kFixedPointLimit;
+  }
+  if (x < -kFixedPointLimit) {
+    return -kFixedPointLimit;
+  }
+  return x;
+}
+
+void AdaptiveDynamicRangeCompression::Compress(float *x1, float *x2) {
+  // Taking the maximum amplitude of both channels
+  const float max_abs_x = std::max(std::fabs(*x1),
+    std::max(std::fabs(*x2), kMinLogAbsValue));
+  const float max_abs_x_dB = math::fast_log(max_abs_x);
+  // Subtract Threshold from log-encoded input to get the amount of overshoot
+  const float overshoot = max_abs_x_dB - knee_threshold_;
+  // Hard half-wave rectifier
+  const float rect = std::max(overshoot, 0.0f);
+  // Multiply rectified overshoot with slope
+  const float cv = rect * slope_;
+  const float prev_state = state_;
+  if (cv <= state_) {
+    state_ = alpha_attack_ * state_ + (1.0f - alpha_attack_) * cv;
+  } else {
+    state_ = alpha_release_ * state_ + (1.0f - alpha_release_) * cv;
+  }
+  compressor_gain_ *=
+      math::ExpApproximationViaTaylorExpansionOrder5(state_ - prev_state);
+  *x1 *= compressor_gain_;
+  if (*x1 > kFixedPointLimit) {
+    *x1 = kFixedPointLimit;
+  }
+  if (*x1 < -kFixedPointLimit) {
+    *x1 = -kFixedPointLimit;
+  }
+  *x2 *= compressor_gain_;
+  if (*x2 > kFixedPointLimit) {
+    *x2 = kFixedPointLimit;
+  }
+  if (*x2 < -kFixedPointLimit) {
+    *x2 = -kFixedPointLimit;
+  }
+}
+
+}  // namespace le_fx
+
diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression.h b/media/libeffects/loudness/dsp/core/dynamic_range_compression.h
new file mode 100644
index 0000000..2821a78
--- /dev/null
+++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_H_
+#define LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_H_
+
+#include "common/core/types.h"
+#include "common/core/math.h"
+#include "dsp/core/basic.h"
+#include "dsp/core/interpolation.h"
+
+//#define LOG_NDEBUG 0
+#include <cutils/log.h>
+
+
+namespace le_fx {
+
+// An adaptive dynamic range compression algorithm. The gain adaptation is made
+// at the logarithmic domain and it is based on a Branching-Smooth compensated
+// digital peak detector with different time constants for attack and release.
+class AdaptiveDynamicRangeCompression {
+ public:
+    AdaptiveDynamicRangeCompression();
+
+    // Initializes the compressor using prior information. It assumes that the
+    // input signal is speech from high-quality recordings that is scaled and then
+    // fed to the compressor. The compressor is tuned according to the target gain
+    // that is expected to be applied.
+    //
+    // Target gain receives values between 0.0 and 10.0. The knee threshold is
+    // reduced as the target gain increases in order to fit the increased range of
+    // values.
+    //
+    // Values between 1.0 and 2.0 will only mildly affect your signal. Higher
+    // values will reduce the dynamic range of the signal to the benefit of
+    // increased loudness.
+    //
+    // If nothing is known regarding the input, a `target_gain` of 1.0f is a
+    // relatively safe choice for many signals.
+    bool Initialize(float target_gain, float sampling_rate);
+
+  // A fast version of the algorithm that uses approximate computations for the
+  // log(.) and exp(.).
+  float Compress(float x);
+
+  // Stereo channel version of the compressor
+  void Compress(float *x1, float *x2);
+
+  // This version is slower than Compress(.) but faster than CompressSlow(.)
+  float CompressNormalSpeed(float x);
+
+  // A slow version of the algorithm that is easier for further developement,
+  // tuning and debugging
+  float CompressSlow(float x);
+
+  // Sets knee threshold (in decibel).
+  void set_knee_threshold(float decibel);
+
+  // Sets knee threshold via the target gain using an experimentally derived
+  // relationship.
+  void set_knee_threshold_via_target_gain(float target_gain);
+
+ private:
+  // The minimum accepted absolute input value and it's natural logarithm. This
+  // is to prevent numerical issues when the input is close to zero
+  static const float kMinAbsValue;
+  static const float kMinLogAbsValue;
+  // Fixed-point arithmetic limits
+  static const float kFixedPointLimit;
+  static const float kInverseFixedPointLimit;
+  // The default knee threshold in decibel. The knee threshold defines when the
+  // compressor is actually starting to compress the value of the input samples
+  static const float kDefaultKneeThresholdInDecibel;
+  // The compression ratio is the reciprocal of the slope of the line segment
+  // above the threshold (in the log-domain). The ratio controls the
+  // effectiveness of the compression.
+  static const float kCompressionRatio;
+  // The attack time of the envelope detector
+  static const float kTauAttack;
+  // The release time of the envelope detector
+  static const float kTauRelease;
+
+  float sampling_rate_;
+  // the internal state of the envelope detector
+  float state_;
+  // the latest gain factor that was applied to the input signal
+  float compressor_gain_;
+  // attack constant for exponential dumping
+  float alpha_attack_;
+  // release constant for exponential dumping
+  float alpha_release_;
+  float slope_;
+  // The knee threshold
+  float knee_threshold_;
+  float knee_threshold_in_decibel_;
+  // This interpolator provides the function that relates target gain to knee
+  // threshold.
+  sigmod::InterpolatorLinear<float> target_gain_to_knee_threshold_;
+
+  LE_FX_DISALLOW_COPY_AND_ASSIGN(AdaptiveDynamicRangeCompression);
+};
+
+}  // namespace le_fx
+
+#include "dsp/core/dynamic_range_compression-inl.h"
+
+#endif  // LE_FX_ENGINE_DSP_CORE_DYNAMIC_RANGE_COMPRESSION_H_
diff --git a/media/libeffects/loudness/dsp/core/interpolation.h b/media/libeffects/loudness/dsp/core/interpolation.h
new file mode 100644
index 0000000..23c287c
--- /dev/null
+++ b/media/libeffects/loudness/dsp/core/interpolation.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef LE_FX_ENGINE_DSP_CORE_INTERPOLATION_H_
+#define LE_FX_ENGINE_DSP_CORE_INTERPOLATION_H_
+
+#include "common/core/math.h"
+#include "dsp/core/interpolator_base.h"
+#include "dsp/core/interpolator_linear.h"
+
+#endif  // LE_FX_ENGINE_DSP_CORE_INTERPOLATION_H_
+
diff --git a/media/libeffects/loudness/dsp/core/interpolator_base-inl.h b/media/libeffects/loudness/dsp/core/interpolator_base-inl.h
new file mode 100644
index 0000000..bd08b65
--- /dev/null
+++ b/media/libeffects/loudness/dsp/core/interpolator_base-inl.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_BASE_INL_H_
+#define LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_BASE_INL_H_
+
+#include "dsp/core/basic.h"
+
+//#define LOG_NDEBUG 0
+#include <cutils/log.h>
+
+
+namespace le_fx {
+
+namespace sigmod {
+
+template <typename T, class Algorithm>
+InterpolatorBase<T, Algorithm>::InterpolatorBase() {
+  status_ = false;
+  cached_index_ = 0;
+  x_data_ = NULL;
+  y_data_ = NULL;
+  data_length_ = 0;
+  own_x_data_ = false;
+  x_start_offset_ = 0.0;
+  last_element_index_ = -1;
+  x_inverse_sampling_interval_ = 0.0;
+  state_ = NULL;
+}
+
+template <typename T, class Algorithm>
+InterpolatorBase<T, Algorithm>::~InterpolatorBase() {
+  delete [] state_;
+  if (own_x_data_) {
+    delete [] x_data_;
+  }
+}
+
+template <typename T, class Algorithm>
+bool InterpolatorBase<T, Algorithm>::Initialize(const vector<T> &x_data,
+                                                const vector<T> &y_data) {
+#ifndef NDEBUG
+  if (x_data.size() != y_data.size()) {
+    LoggerError("InterpolatorBase::Initialize: xData size (%d) != yData size"
+                  " (%d)", x_data.size(), y_data.size());
+  }
+#endif
+  return Initialize(&x_data[0], &y_data[0], x_data.size());
+}
+
+template <typename T, class Algorithm>
+bool InterpolatorBase<T, Algorithm>::Initialize(double x_start_offset,
+                                                double x_sampling_interval,
+                                                const vector<T> &y_data) {
+  return Initialize(x_start_offset,
+                    x_sampling_interval,
+                    &y_data[0],
+                    y_data.size());
+}
+
+template <typename T, class Algorithm>
+bool InterpolatorBase<T, Algorithm>::Initialize(double x_start_offset,
+                                                double x_sampling_interval,
+                                                const T *y_data,
+                                                int data_length) {
+  // Constructs and populate x-axis data: `x_data_`
+  T *x_data_tmp = new T[data_length];
+  float time_offset = x_start_offset;
+  for (int n = 0; n < data_length; n++) {
+    x_data_tmp[n] = time_offset;
+    time_offset += x_sampling_interval;
+  }
+  Initialize(x_data_tmp, y_data, data_length);
+  // Sets-up the regularly sampled interpolation mode
+  x_start_offset_ = x_start_offset;
+  x_inverse_sampling_interval_ = 1.0 / x_sampling_interval;
+  own_x_data_ = true;
+  return status_;
+}
+
+
+template <typename T, class Algorithm>
+bool InterpolatorBase<T, Algorithm>::Initialize(
+    const T *x_data, const T *y_data, int data_length) {
+  // Default settings
+  cached_index_ = 0;
+  data_length_ = 0;
+  x_start_offset_ = 0;
+  x_inverse_sampling_interval_ = 0;
+  state_ = NULL;
+  // Input data is externally owned
+  own_x_data_ = false;
+  x_data_ = x_data;
+  y_data_ = y_data;
+  data_length_ = data_length;
+  last_element_index_ = data_length - 1;
+  // Check input data sanity
+  for (int n = 0; n < last_element_index_; ++n) {
+    if (x_data_[n + 1] <= x_data_[n]) {
+      ALOGE("InterpolatorBase::Initialize: xData are not ordered or "
+              "contain equal values (X[%d] <= X[%d]) (%.5e <= %.5e)",
+              n + 1, n, x_data_[n + 1], x_data_[n]);
+      status_ = false;
+      return false;
+    }
+  }
+  // Pre-compute internal state by calling the corresponding function of the
+  // derived class.
+  status_ = static_cast<Algorithm*>(this)->SetInternalState();
+  return status_;
+}
+
+template <typename T, class Algorithm>
+T InterpolatorBase<T, Algorithm>::Interpolate(T x) {
+#ifndef NDEBUG
+  if (cached_index_ < 0 || cached_index_ > data_length_ - 2) {
+    LoggerError("InterpolatorBase:Interpolate: CachedIndex_ out of bounds "
+                  "[0, %d, %d]", cached_index_, data_length_ - 2);
+  }
+#endif
+  // Search for the containing interval
+  if (x <= x_data_[cached_index_]) {
+    if (cached_index_ <= 0) {
+      cached_index_ = 0;
+      return y_data_[0];
+    }
+    if (x >= x_data_[cached_index_ - 1]) {
+      cached_index_--;  // Fast descending
+    } else {
+      if (x <= x_data_[0]) {
+        cached_index_ = 0;
+        return y_data_[0];
+      }
+      cached_index_ = SearchIndex(x_data_, x, 0, cached_index_);
+    }
+  } else {
+    if (cached_index_ >= last_element_index_) {
+      cached_index_ = last_element_index_;
+      return y_data_[last_element_index_];
+    }
+    if (x > x_data_[cached_index_ + 1]) {
+      if (cached_index_ + 2 > last_element_index_) {
+        cached_index_ = last_element_index_ - 1;
+        return y_data_[last_element_index_];
+      }
+      if (x <= x_data_[cached_index_ + 2]) {
+        cached_index_++;  // Fast ascending
+      } else {
+        if (x >= x_data_[last_element_index_]) {
+          cached_index_ = last_element_index_ - 1;
+          return y_data_[last_element_index_];
+        }
+        cached_index_ = SearchIndex(
+            x_data_, x, cached_index_, last_element_index_);
+      }
+    }
+  }
+  // Compute interpolated value by calling the corresponding function of the
+  // derived class.
+  return static_cast<Algorithm*>(this)->MethodSpecificInterpolation(x);
+}
+
+}  // namespace sigmod
+
+}  // namespace le_fx
+
+#endif  // LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_BASE_INL_H_
diff --git a/media/libeffects/loudness/dsp/core/interpolator_base.h b/media/libeffects/loudness/dsp/core/interpolator_base.h
new file mode 100644
index 0000000..0cd1a35
--- /dev/null
+++ b/media/libeffects/loudness/dsp/core/interpolator_base.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_BASE_H_
+#define LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_BASE_H_
+
+#include "common/core/types.h"
+
+namespace le_fx {
+
+namespace sigmod {
+
+// Interpolation base-class that provides the interface, while it is the derived
+// class that provides the specific interpolation algorithm. The following list
+// of interpolation algorithms are currently present:
+//
+// InterpolationSine<T>: weighted interpolation between y_data[n] and
+//                       y_data[n+1] using a sin(.) weighting factor from
+//                       0 to pi/4.
+// InterpolationLinear<T>: linear interpolation
+// InterpolationSplines<T>: spline-based interpolation
+//
+// Example (using derived spline-based interpolation class):
+//  InterpolatorSplines<float> interp(x_data, y_data, data_length);
+//  for (int n = 0; n < data_length; n++) Y[n] = interp.Interpolate(X[n]);
+//
+template <typename T, class Algorithm>
+class InterpolatorBase {
+ public:
+  InterpolatorBase();
+  ~InterpolatorBase();
+
+  // Generic random-access interpolation with arbitrary spaced x-axis samples.
+  // Below X[0], the interpolator returns Y[0]. Above X[data_length-1], it
+  // returns Y[data_length-1].
+  T Interpolate(T x);
+
+  bool get_status() const {
+    return status_;
+  }
+
+  // Initializes internal buffers.
+  //  x_data: [(data_length)x1] x-axis coordinates (searching axis)
+  //  y_data: [(data_length)x1] y-axis coordinates (interpolation axis)
+  //  data_length: number of points
+  // returns `true` if everything is ok, `false`, otherwise
+  bool Initialize(const T *x_data, const T *y_data, int data_length);
+
+  // Initializes internal buffers.
+  //  x_data: x-axis coordinates (searching axis)
+  //  y_data: y-axis coordinates (interpolating axis)
+  // returns `true` if everything is ok, `false`, otherwise
+  bool Initialize(const vector<T> &x_data, const vector<T> &y_data);
+
+  // Initialization for regularly sampled sequences, where:
+  //  x_data[i] = x_start_offset + i * x_sampling_interval
+  bool Initialize(double x_start_offset,
+                  double x_sampling_interval,
+                  const vector<T> &y_data);
+
+  // Initialization for regularly sampled sequences, where:
+  //  x_data[i] = x_start_offset + i * x_sampling_interval
+  bool Initialize(double x_start_offset,
+                  double x_sampling_interval,
+                  const T *y_data,
+                  int data_length);
+
+ protected:
+  // Is set to false if something goes wrong, and to true if everything is ok.
+  bool status_;
+
+  // The start-index of the previously searched interval
+  int cached_index_;
+
+  // Data points
+  const T *x_data_;  // Externally or internally owned, depending on own_x_data_
+  const T *y_data_;  // Externally owned (always)
+  int data_length_;
+  // Index of the last element `data_length_ - 1` kept here for optimization
+  int last_element_index_;
+  bool own_x_data_;
+  // For regularly-samples sequences, keep only the boundaries and the intervals
+  T x_start_offset_;
+  float x_inverse_sampling_interval_;
+
+  // Algorithm state (internally owned)
+  double *state_;
+
+ private:
+  LE_FX_DISALLOW_COPY_AND_ASSIGN(InterpolatorBase);
+};
+
+}  // namespace sigmod
+
+}  // namespace le_fx
+
+#include "dsp/core/interpolator_base-inl.h"
+
+#endif  // LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_BASE_H_
diff --git a/media/libeffects/loudness/dsp/core/interpolator_linear.h b/media/libeffects/loudness/dsp/core/interpolator_linear.h
new file mode 100644
index 0000000..434698a
--- /dev/null
+++ b/media/libeffects/loudness/dsp/core/interpolator_linear.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_LINEAR_H_
+#define LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_LINEAR_H_
+
+#include <math.h>
+#include "dsp/core/interpolator_base.h"
+
+namespace le_fx {
+
+namespace sigmod {
+
+// Linear interpolation class.
+//
+// The main functionality of this class is provided by it's base-class, so
+// please refer to: InterpolatorBase
+//
+// Example:
+//  InterpolatorLinear<float> interp(x_data, y_data, data_length);
+//  for (int n = 0; n < data_length; n++) Y[n] = interp.Interpolate(X[n]);
+//
+template <typename T>
+class InterpolatorLinear: public InterpolatorBase<T, InterpolatorLinear<T> > {
+ public:
+  InterpolatorLinear() { }
+  ~InterpolatorLinear() { }
+
+ protected:
+  // Provides the main implementation of the linear interpolation algorithm.
+  // Assumes that: X[cached_index_] < x < X[cached_index_ + 1]
+  T MethodSpecificInterpolation(T x);
+
+  // Pre-compute internal state_ parameters.
+  bool SetInternalState();
+
+ private:
+  friend class InterpolatorBase<T, InterpolatorLinear<T> >;
+  typedef InterpolatorBase<T, InterpolatorLinear<T> > BaseClass;
+  using BaseClass::status_;
+  using BaseClass::cached_index_;
+  using BaseClass::x_data_;
+  using BaseClass::y_data_;
+  using BaseClass::data_length_;
+  using BaseClass::state_;
+
+  LE_FX_DISALLOW_COPY_AND_ASSIGN(InterpolatorLinear<T>);
+};
+
+template <typename T>
+inline T InterpolatorLinear<T>::MethodSpecificInterpolation(T x) {
+  T dX = x_data_[cached_index_ + 1] - x_data_[cached_index_];
+  T dY = y_data_[cached_index_ + 1] - y_data_[cached_index_];
+  T dx = x - x_data_[cached_index_];
+  return y_data_[cached_index_] + (dY * dx) / dX;
+}
+
+template <typename T>
+bool InterpolatorLinear<T>::SetInternalState() {
+  state_ = NULL;
+  return true;
+}
+
+}  // namespace sigmod
+
+}  // namespace le_fx
+
+#endif  // LE_FX_ENGINE_DSP_CORE_INTERPOLATOR_LINEAR_H_
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 85232e7..9fcfba3 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -2752,7 +2752,7 @@
 
     switch (cmdCode){
         case EFFECT_CMD_INIT:
-            if (pReplyData == NULL || *replySize != sizeof(int)){
+            if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)){
                 ALOGV("\tLVM_ERROR, EFFECT_CMD_INIT: ERROR for effect type %d",
                         pContext->EffectType);
                 return -EINVAL;
@@ -2779,10 +2779,8 @@
 
         case EFFECT_CMD_SET_CONFIG:
             //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_CONFIG start");
-            if (pCmdData    == NULL||
-                cmdSize     != sizeof(effect_config_t)||
-                pReplyData  == NULL||
-                *replySize  != sizeof(int)){
+            if (pCmdData    == NULL || cmdSize     != sizeof(effect_config_t) ||
+                    pReplyData  == NULL || replySize == NULL || *replySize  != sizeof(int)) {
                 ALOGV("\tLVM_ERROR : Effect_command cmdCode Case: "
                         "EFFECT_CMD_SET_CONFIG: ERROR");
                 return -EINVAL;
@@ -2792,8 +2790,7 @@
             break;
 
         case EFFECT_CMD_GET_CONFIG:
-            if (pReplyData == NULL ||
-                *replySize != sizeof(effect_config_t)) {
+            if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(effect_config_t)) {
                 ALOGV("\tLVM_ERROR : Effect_command cmdCode Case: "
                         "EFFECT_CMD_GET_CONFIG: ERROR");
                 return -EINVAL;
@@ -2811,30 +2808,27 @@
         case EFFECT_CMD_GET_PARAM:{
             //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_GET_PARAM start");
 
+            effect_param_t *p = (effect_param_t *)pCmdData;
+
+            if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) ||
+                    cmdSize < (sizeof(effect_param_t) + p->psize) ||
+                    pReplyData == NULL || replySize == NULL ||
+                    *replySize < (sizeof(effect_param_t) + p->psize)) {
+                ALOGV("\tLVM_ERROR : EFFECT_CMD_GET_PARAM: ERROR");
+                return -EINVAL;
+            }
+
+            memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
+
+            p = (effect_param_t *)pReplyData;
+
+            int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+
             if(pContext->EffectType == LVM_BASS_BOOST){
-                if (pCmdData == NULL ||
-                        cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
-                        pReplyData == NULL ||
-                        *replySize < (int) (sizeof(effect_param_t) + sizeof(int32_t))){
-                    ALOGV("\tLVM_ERROR : BassBoost_command cmdCode Case: "
-                            "EFFECT_CMD_GET_PARAM: ERROR");
-                    return -EINVAL;
-                }
-                effect_param_t *p = (effect_param_t *)pCmdData;
-
-                memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
-
-                p = (effect_param_t *)pReplyData;
-
-                int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
-
                 p->status = android::BassBoost_getParameter(pContext,
                                                             p->data,
                                                             (size_t  *)&p->vsize,
                                                             p->data + voffset);
-
-                *replySize = sizeof(effect_param_t) + voffset + p->vsize;
-
                 //ALOGV("\tBassBoost_command EFFECT_CMD_GET_PARAM "
                 //        "*pCmdData %d, *replySize %d, *pReplyData %d ",
                 //        *(int32_t *)((char *)pCmdData + sizeof(effect_param_t)),
@@ -2843,29 +2837,11 @@
             }
 
             if(pContext->EffectType == LVM_VIRTUALIZER){
-                if (pCmdData == NULL ||
-                        cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
-                        pReplyData == NULL ||
-                        *replySize < (int) (sizeof(effect_param_t) + sizeof(int32_t))){
-                    ALOGV("\tLVM_ERROR : Virtualizer_command cmdCode Case: "
-                            "EFFECT_CMD_GET_PARAM: ERROR");
-                    return -EINVAL;
-                }
-                effect_param_t *p = (effect_param_t *)pCmdData;
-
-                memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
-
-                p = (effect_param_t *)pReplyData;
-
-                int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
-
                 p->status = android::Virtualizer_getParameter(pContext,
                                                              (void *)p->data,
                                                              (size_t  *)&p->vsize,
                                                               p->data + voffset);
 
-                *replySize = sizeof(effect_param_t) + voffset + p->vsize;
-
                 //ALOGV("\tVirtualizer_command EFFECT_CMD_GET_PARAM "
                 //        "*pCmdData %d, *replySize %d, *pReplyData %d ",
                 //        *(int32_t *)((char *)pCmdData + sizeof(effect_param_t)),
@@ -2875,29 +2851,11 @@
             if(pContext->EffectType == LVM_EQUALIZER){
                 //ALOGV("\tEqualizer_command cmdCode Case: "
                 //        "EFFECT_CMD_GET_PARAM start");
-                if (pCmdData == NULL ||
-                    cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
-                    pReplyData == NULL ||
-                    *replySize < (int) (sizeof(effect_param_t) + sizeof(int32_t))) {
-                    ALOGV("\tLVM_ERROR : Equalizer_command cmdCode Case: "
-                            "EFFECT_CMD_GET_PARAM");
-                    return -EINVAL;
-                }
-                effect_param_t *p = (effect_param_t *)pCmdData;
-
-                memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
-
-                p = (effect_param_t *)pReplyData;
-
-                int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
-
                 p->status = android::Equalizer_getParameter(pContext,
                                                             p->data,
                                                             &p->vsize,
                                                             p->data + voffset);
 
-                *replySize = sizeof(effect_param_t) + voffset + p->vsize;
-
                 //ALOGV("\tEqualizer_command EFFECT_CMD_GET_PARAM *pCmdData %d, *replySize %d, "
                 //       "*pReplyData %08x %08x",
                 //        *(int32_t *)((char *)pCmdData + sizeof(effect_param_t)), *replySize,
@@ -2907,35 +2865,19 @@
             }
             if(pContext->EffectType == LVM_VOLUME){
                 //ALOGV("\tVolume_command cmdCode Case: EFFECT_CMD_GET_PARAM start");
-                if (pCmdData == NULL ||
-                        cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
-                        pReplyData == NULL ||
-                        *replySize < (int) (sizeof(effect_param_t) + sizeof(int32_t))){
-                    ALOGV("\tLVM_ERROR : Volume_command cmdCode Case: "
-                            "EFFECT_CMD_GET_PARAM: ERROR");
-                    return -EINVAL;
-                }
-                effect_param_t *p = (effect_param_t *)pCmdData;
-
-                memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
-
-                p = (effect_param_t *)pReplyData;
-
-                int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
-
                 p->status = android::Volume_getParameter(pContext,
                                                          (void *)p->data,
                                                          (size_t  *)&p->vsize,
                                                          p->data + voffset);
 
-                *replySize = sizeof(effect_param_t) + voffset + p->vsize;
-
                 //ALOGV("\tVolume_command EFFECT_CMD_GET_PARAM "
                 //        "*pCmdData %d, *replySize %d, *pReplyData %d ",
                 //        *(int32_t *)((char *)pCmdData + sizeof(effect_param_t)),
                 //        *replySize,
                 //        *(int16_t *)((char *)pReplyData + sizeof(effect_param_t) + voffset));
             }
+            *replySize = sizeof(effect_param_t) + voffset + p->vsize;
+
             //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_GET_PARAM end");
         } break;
         case EFFECT_CMD_SET_PARAM:{
@@ -2946,10 +2888,9 @@
                 //       *replySize,
                 //       *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t)));
 
-                if (pCmdData   == NULL||
-                    cmdSize    != (int)(sizeof(effect_param_t) + sizeof(int32_t) +sizeof(int16_t))||
-                    pReplyData == NULL||
-                    *replySize != sizeof(int32_t)){
+                if (pCmdData   == NULL ||
+                        cmdSize    != (sizeof(effect_param_t) + sizeof(int32_t) +sizeof(int16_t)) ||
+                        pReplyData == NULL || replySize == NULL || *replySize != sizeof(int32_t)) {
                     ALOGV("\tLVM_ERROR : BassBoost_command cmdCode Case: "
                             "EFFECT_CMD_SET_PARAM: ERROR");
                     return -EINVAL;
@@ -2979,10 +2920,11 @@
               //        *replySize,
               //        *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t)));
 
-                if (pCmdData   == NULL||
-                    cmdSize    != (int)(sizeof(effect_param_t) + sizeof(int32_t) +sizeof(int16_t))||
-                    pReplyData == NULL||
-                    *replySize != sizeof(int32_t)){
+                if (pCmdData   == NULL ||
+                        // legal parameters are int16_t or int32_t
+                        cmdSize    > (sizeof(effect_param_t) + sizeof(int32_t) +sizeof(int32_t)) ||
+                        cmdSize    < (sizeof(effect_param_t) + sizeof(int32_t) +sizeof(int16_t)) ||
+                        pReplyData == NULL || replySize == NULL || *replySize != sizeof(int32_t)) {
                     ALOGV("\tLVM_ERROR : Virtualizer_command cmdCode Case: "
                             "EFFECT_CMD_SET_PARAM: ERROR");
                     return -EINVAL;
@@ -3014,8 +2956,8 @@
                //        *replySize,
                //        *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t)));
 
-                if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
-                    pReplyData == NULL || *replySize != sizeof(int32_t)) {
+                if (pCmdData == NULL || cmdSize < (sizeof(effect_param_t) + sizeof(int32_t)) ||
+                        pReplyData == NULL || replySize == NULL || *replySize != sizeof(int32_t)) {
                     ALOGV("\tLVM_ERROR : Equalizer_command cmdCode Case: "
                             "EFFECT_CMD_SET_PARAM: ERROR");
                     return -EINVAL;
@@ -3033,10 +2975,10 @@
                 //        *replySize,
                 //        *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) +sizeof(int32_t)));
 
-                if (    pCmdData   == NULL||
-                        cmdSize    < (int)(sizeof(effect_param_t) + sizeof(int32_t))||
-                        pReplyData == NULL||
-                        *replySize != sizeof(int32_t)){
+                if (pCmdData   == NULL ||
+                        cmdSize    < (sizeof(effect_param_t) + sizeof(int32_t)) ||
+                        pReplyData == NULL || replySize == NULL ||
+                        *replySize != sizeof(int32_t)) {
                     ALOGV("\tLVM_ERROR : Volume_command cmdCode Case: "
                             "EFFECT_CMD_SET_PARAM: ERROR");
                     return -EINVAL;
@@ -3052,7 +2994,7 @@
 
         case EFFECT_CMD_ENABLE:
             ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_ENABLE start");
-            if (pReplyData == NULL || *replySize != sizeof(int)){
+            if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
                 ALOGV("\tLVM_ERROR : Effect_command cmdCode Case: EFFECT_CMD_ENABLE: ERROR");
                 return -EINVAL;
             }
@@ -3062,7 +3004,7 @@
 
         case EFFECT_CMD_DISABLE:
             //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_DISABLE start");
-            if (pReplyData == NULL || *replySize != sizeof(int)){
+            if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
                 ALOGV("\tLVM_ERROR : Effect_command cmdCode Case: EFFECT_CMD_DISABLE: ERROR");
                 return -EINVAL;
             }
@@ -3072,6 +3014,11 @@
         case EFFECT_CMD_SET_DEVICE:
         {
             ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_DEVICE start");
+            if (pCmdData   == NULL){
+                ALOGV("\tLVM_ERROR : Effect_command cmdCode Case: EFFECT_CMD_SET_DEVICE: ERROR");
+                return -EINVAL;
+            }
+
             uint32_t device = *(uint32_t *)pCmdData;
 
             if (pContext->EffectType == LVM_BASS_BOOST) {
@@ -3158,8 +3105,8 @@
                 break;
             }
 
-            if (pCmdData == NULL ||
-                cmdSize != 2 * sizeof(uint32_t)) {
+            if (pCmdData == NULL || cmdSize != 2 * sizeof(uint32_t) || pReplyData == NULL ||
+                    replySize == NULL || *replySize < 2*sizeof(int32_t)) {
                 ALOGV("\tLVM_ERROR : Effect_command cmdCode Case: "
                         "EFFECT_CMD_SET_VOLUME: ERROR");
                 return -EINVAL;
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 8a96212..2e22532 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -188,8 +188,8 @@
 /* Effect Library Interface Implementation */
 
 extern "C" int EffectCreate(const effect_uuid_t *uuid,
-                            int32_t             sessionId,
-                            int32_t             ioId,
+                            int32_t             sessionId __unused,
+                            int32_t             ioId __unused,
                             effect_handle_t  *pHandle){
     int ret;
     int i;
@@ -1912,7 +1912,7 @@
             //ALOGV("\tReverb_command cmdCode Case: "
             //        "EFFECT_CMD_INIT start");
 
-            if (pReplyData == NULL || *replySize != sizeof(int)){
+            if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)){
                 ALOGV("\tLVM_ERROR : Reverb_command cmdCode Case: "
                         "EFFECT_CMD_INIT: ERROR");
                 return -EINVAL;
@@ -1923,10 +1923,8 @@
         case EFFECT_CMD_SET_CONFIG:
             //ALOGV("\tReverb_command cmdCode Case: "
             //        "EFFECT_CMD_SET_CONFIG start");
-            if (pCmdData == NULL ||
-                cmdSize != sizeof(effect_config_t) ||
-                pReplyData == NULL ||
-                *replySize != sizeof(int)) {
+            if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) ||
+                    pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
                 ALOGV("\tLVM_ERROR : Reverb_command cmdCode Case: "
                         "EFFECT_CMD_SET_CONFIG: ERROR");
                 return -EINVAL;
@@ -1936,8 +1934,7 @@
             break;
 
         case EFFECT_CMD_GET_CONFIG:
-            if (pReplyData == NULL ||
-                *replySize != sizeof(effect_config_t)) {
+            if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(effect_config_t)) {
                 ALOGV("\tLVM_ERROR : Reverb_command cmdCode Case: "
                         "EFFECT_CMD_GET_CONFIG: ERROR");
                 return -EINVAL;
@@ -1955,15 +1952,16 @@
         case EFFECT_CMD_GET_PARAM:{
             //ALOGV("\tReverb_command cmdCode Case: "
             //        "EFFECT_CMD_GET_PARAM start");
-            if (pCmdData == NULL ||
-                    cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) ||
-                    pReplyData == NULL ||
-                    *replySize < (int) (sizeof(effect_param_t) + sizeof(int32_t))){
+            effect_param_t *p = (effect_param_t *)pCmdData;
+
+            if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) ||
+                    cmdSize < (sizeof(effect_param_t) + p->psize) ||
+                    pReplyData == NULL || replySize == NULL ||
+                    *replySize < (sizeof(effect_param_t) + p->psize)) {
                 ALOGV("\tLVM_ERROR : Reverb_command cmdCode Case: "
                         "EFFECT_CMD_GET_PARAM: ERROR");
                 return -EINVAL;
             }
-            effect_param_t *p = (effect_param_t *)pCmdData;
 
             memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
 
@@ -1994,8 +1992,8 @@
             //        *replySize,
             //        *(int16_t *)((char *)pCmdData + sizeof(effect_param_t) + sizeof(int32_t)));
 
-            if (pCmdData == NULL || (cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)))
-                    || pReplyData == NULL || *replySize != (int)sizeof(int32_t)) {
+            if (pCmdData == NULL || (cmdSize < (sizeof(effect_param_t) + sizeof(int32_t))) ||
+                    pReplyData == NULL ||  replySize == NULL || *replySize != sizeof(int32_t)) {
                 ALOGV("\tLVM_ERROR : Reverb_command cmdCode Case: "
                         "EFFECT_CMD_SET_PARAM: ERROR");
                 return -EINVAL;
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index 25586e8..1eb5d40 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -575,16 +575,18 @@
     return 0;
 }
 
-int NsGetParameter(preproc_effect_t     *effect,
-                   void              *pParam,
-                   size_t            *pValueSize,
-                   void              *pValue)
+int NsGetParameter(preproc_effect_t  *effect __unused,
+                   void              *pParam __unused,
+                   uint32_t          *pValueSize __unused,
+                   void              *pValue __unused)
 {
     int status = 0;
     return status;
 }
 
-int NsSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
+int NsSetParameter (preproc_effect_t *effect __unused,
+                    void *pParam __unused,
+                    void *pValue __unused)
 {
     int status = 0;
     return status;
@@ -1434,16 +1436,17 @@
             }
             break;
 
-        case EFFECT_CMD_GET_PARAM:{
-            if (pCmdData == NULL ||
-                    cmdSize < (int)sizeof(effect_param_t) ||
-                    pReplyData == NULL ||
-                    *replySize < (int)sizeof(effect_param_t)){
+        case EFFECT_CMD_GET_PARAM: {
+            effect_param_t *p = (effect_param_t *)pCmdData;
+
+            if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) ||
+                    cmdSize < (sizeof(effect_param_t) + p->psize) ||
+                    pReplyData == NULL || replySize == NULL ||
+                    *replySize < (sizeof(effect_param_t) + p->psize)){
                 ALOGV("PreProcessingFx_Command cmdCode Case: "
                         "EFFECT_CMD_GET_PARAM: ERROR");
                 return -EINVAL;
             }
-            effect_param_t *p = (effect_param_t *)pCmdData;
 
             memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
 
@@ -1461,8 +1464,8 @@
 
         case EFFECT_CMD_SET_PARAM:{
             if (pCmdData == NULL||
-                    cmdSize < (int)sizeof(effect_param_t) ||
-                    pReplyData == NULL ||
+                    cmdSize < sizeof(effect_param_t) ||
+                    pReplyData == NULL || replySize == NULL ||
                     *replySize != sizeof(int32_t)){
                 ALOGV("PreProcessingFx_Command cmdCode Case: "
                         "EFFECT_CMD_SET_PARAM: ERROR");
@@ -1483,7 +1486,7 @@
         } break;
 
         case EFFECT_CMD_ENABLE:
-            if (pReplyData == NULL || *replySize != sizeof(int)){
+            if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)){
                 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_ENABLE: ERROR");
                 return -EINVAL;
             }
@@ -1491,7 +1494,7 @@
             break;
 
         case EFFECT_CMD_DISABLE:
-            if (pReplyData == NULL || *replySize != sizeof(int)){
+            if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)){
                 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_DISABLE: ERROR");
                 return -EINVAL;
             }
@@ -1711,7 +1714,7 @@
 
 int PreProcessingFx_ProcessReverse(effect_handle_t     self,
                                    audio_buffer_t    *inBuffer,
-                                   audio_buffer_t    *outBuffer)
+                                   audio_buffer_t    *outBuffer __unused)
 {
     preproc_effect_t * effect = (preproc_effect_t *)self;
     int    status = 0;
diff --git a/media/libeffects/proxy/Android.mk b/media/libeffects/proxy/Android.mk
new file mode 100644
index 0000000..a1894b7
--- /dev/null
+++ b/media/libeffects/proxy/Android.mk
@@ -0,0 +1,35 @@
+# Copyright 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_MODULE:= libeffectproxy
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
+LOCAL_MODULE_TAGS := optional
+
+
+LOCAL_SRC_FILES := \
+        EffectProxy.cpp
+
+LOCAL_CFLAGS+= -fvisibility=hidden
+
+LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libdl libeffects
+
+LOCAL_C_INCLUDES := \
+        system/media/audio_effects/include \
+        bionic/libc/include \
+        frameworks/av/media/libeffects/factory
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/media/libeffects/proxy/EffectProxy.cpp b/media/libeffects/proxy/EffectProxy.cpp
new file mode 100644
index 0000000..f93a143
--- /dev/null
+++ b/media/libeffects/proxy/EffectProxy.cpp
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "EffectProxy"
+//#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <new>
+#include <EffectProxy.h>
+#include <utils/threads.h>
+#include <media/EffectsFactoryApi.h>
+
+namespace android {
+// This is a dummy proxy descriptor just to return to Factory during the initial
+// GetDescriptor call. Later in the factory, it is replaced with the
+// SW sub effect descriptor
+// proxy UUID af8da7e0-2ca1-11e3-b71d-0002a5d5c51b
+const effect_descriptor_t gProxyDescriptor = {
+        EFFECT_UUID_INITIALIZER, // type
+        {0xaf8da7e0, 0x2ca1, 0x11e3, 0xb71d, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }}, // uuid
+        EFFECT_CONTROL_API_VERSION, //version of effect control API
+        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_LAST |
+         EFFECT_FLAG_VOLUME_CTRL), // effect capability flags
+        0, // CPU load
+        1, // Data memory
+        "Proxy", //effect name
+        "AOSP", //implementor name
+};
+
+
+static const effect_descriptor_t *const gDescriptors[] =
+{
+    &gProxyDescriptor,
+};
+
+
+int EffectProxyCreate(const effect_uuid_t *uuid,
+                            int32_t             sessionId,
+                            int32_t             ioId,
+                           effect_handle_t  *pHandle) {
+
+    effect_descriptor_t* desc;
+    audio_effect_library_t** aeli;
+    sub_effect_entry_t** sube;
+    EffectContext* pContext;
+    if (pHandle == NULL || uuid == NULL) {
+        ALOGE("EffectProxyCreate() called with NULL pointer");
+        return -EINVAL;
+    }
+    ALOGV("EffectProxyCreate start..");
+    pContext = new EffectContext;
+    pContext->sessionId = sessionId;
+    pContext->ioId = ioId;
+    pContext->uuid = *uuid;
+    pContext->common_itfe = &gEffectInterface;
+
+    // The sub effects will be created in effect_command when the first command
+    // for the effect is received
+    pContext->eHandle[SUB_FX_HOST] = pContext->eHandle[SUB_FX_OFFLOAD] = NULL;
+
+    // Get the HW and SW sub effect descriptors from the effects factory
+    desc = new effect_descriptor_t[SUB_FX_COUNT];
+    aeli = new audio_effect_library_t*[SUB_FX_COUNT];
+    sube = new sub_effect_entry_t*[SUB_FX_COUNT];
+    pContext->sube = new sub_effect_entry_t*[SUB_FX_COUNT];
+    pContext->desc = new effect_descriptor_t[SUB_FX_COUNT];
+    pContext->aeli = new audio_effect_library_t*[SUB_FX_COUNT];
+    int retValue = EffectGetSubEffects(uuid, sube, SUB_FX_COUNT);
+    // EffectGetSubEffects returns the number of sub-effects copied.
+    if (retValue != SUB_FX_COUNT) {
+       ALOGE("EffectCreate() could not get the sub effects");
+       delete[] sube;
+       delete[] desc;
+       delete[] aeli;
+       delete[] pContext->sube;
+       delete[] pContext->desc;
+       delete[] pContext->aeli;
+       return -EINVAL;
+    }
+    // Check which is the HW descriptor and copy the descriptors
+    // to the Context desc array
+    // Also check if there is only one HW and one SW descriptor.
+    // HW descriptor alone has the HW_TUNNEL flag.
+    desc[0] = *(effect_descriptor_t*)(sube[0])->object;
+    desc[1] = *(effect_descriptor_t*)(sube[1])->object;
+    aeli[0] = sube[0]->lib->desc;
+    aeli[1] = sube[1]->lib->desc;
+    if ((desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL) &&
+       !(desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) {
+        pContext->sube[SUB_FX_OFFLOAD] = sube[0];
+        pContext->desc[SUB_FX_OFFLOAD] = desc[0];
+        pContext->aeli[SUB_FX_OFFLOAD] = aeli[0];
+        pContext->sube[SUB_FX_HOST] = sube[1];
+        pContext->desc[SUB_FX_HOST] = desc[1];
+        pContext->aeli[SUB_FX_HOST] = aeli[1];
+    }
+    else if ((desc[1].flags & EFFECT_FLAG_HW_ACC_TUNNEL) &&
+             !(desc[0].flags & EFFECT_FLAG_HW_ACC_TUNNEL)) {
+        pContext->sube[SUB_FX_HOST] = sube[0];
+        pContext->desc[SUB_FX_HOST] = desc[0];
+        pContext->aeli[SUB_FX_HOST] = aeli[0];
+        pContext->sube[SUB_FX_OFFLOAD] = sube[1];
+        pContext->desc[SUB_FX_OFFLOAD] = desc[1];
+        pContext->aeli[SUB_FX_OFFLOAD] = aeli[1];
+    }
+    delete[] desc;
+    delete[] aeli;
+    delete[] sube;
+#if (LOG_NDEBUG == 0)
+    effect_uuid_t uuid_print = pContext->desc[SUB_FX_HOST].uuid;
+    ALOGV("EffectCreate() UUID of HOST: %08X-%04X-%04X-%04X-%02X%02X%02X%02X"
+        "%02X%02X\n",uuid_print.timeLow, uuid_print.timeMid,
+        uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0],
+        uuid_print.node[1], uuid_print.node[2], uuid_print.node[3],
+        uuid_print.node[4], uuid_print.node[5]);
+    ALOGV("EffectCreate() UUID of OFFLOAD: %08X-%04X-%04X-%04X-%02X%02X%02X%02X"
+        "%02X%02X\n", uuid_print.timeLow, uuid_print.timeMid,
+        uuid_print.timeHiAndVersion, uuid_print.clockSeq, uuid_print.node[0],
+        uuid_print.node[1], uuid_print.node[2], uuid_print.node[3],
+        uuid_print.node[4], uuid_print.node[5]);
+#endif
+
+    pContext->replySize = PROXY_REPLY_SIZE_DEFAULT;
+    pContext->replyData = (char *)malloc(PROXY_REPLY_SIZE_DEFAULT);
+
+    *pHandle = (effect_handle_t)pContext;
+    ALOGV("EffectCreate end");
+    return 0;
+} //end EffectProxyCreate
+
+int EffectProxyRelease(effect_handle_t handle) {
+    EffectContext * pContext = (EffectContext *)handle;
+    if (pContext == NULL) {
+        ALOGV("ERROR : EffectRelease called with NULL pointer");
+        return -EINVAL;
+    }
+    ALOGV("EffectRelease");
+    delete[] pContext->desc;
+    free(pContext->replyData);
+
+    if (pContext->eHandle[SUB_FX_HOST])
+       pContext->aeli[SUB_FX_HOST]->release_effect(pContext->eHandle[SUB_FX_HOST]);
+    if (pContext->eHandle[SUB_FX_OFFLOAD])
+       pContext->aeli[SUB_FX_OFFLOAD]->release_effect(pContext->eHandle[SUB_FX_OFFLOAD]);
+    delete[] pContext->aeli;
+    delete[] pContext->sube;
+    delete pContext;
+    pContext = NULL;
+    return 0;
+} /*end EffectProxyRelease */
+
+int EffectProxyGetDescriptor(const effect_uuid_t *uuid,
+                                   effect_descriptor_t *pDescriptor) {
+    const effect_descriptor_t *desc = NULL;
+
+    if (pDescriptor == NULL || uuid == NULL) {
+        ALOGV("EffectGetDescriptor() called with NULL pointer");
+        return -EINVAL;
+    }
+    desc = &gProxyDescriptor;
+    *pDescriptor = *desc;
+    return 0;
+} /* end EffectProxyGetDescriptor */
+
+/* Effect Control Interface Implementation: Process */
+int Effect_process(effect_handle_t     self,
+                              audio_buffer_t         *inBuffer,
+                              audio_buffer_t         *outBuffer) {
+
+    EffectContext *pContext = (EffectContext *) self;
+    int ret = 0;
+    if (pContext != NULL) {
+        int index = pContext->index;
+        // if the index refers to HW , do not do anything. Just return.
+        if (index == SUB_FX_HOST) {
+            ret = (*pContext->eHandle[index])->process(pContext->eHandle[index],
+                                                       inBuffer, outBuffer);
+        }
+    }
+    return ret;
+}   /* end Effect_process */
+
+/* Effect Control Interface Implementation: Command */
+int Effect_command(effect_handle_t  self,
+                              uint32_t            cmdCode,
+                              uint32_t            cmdSize,
+                              void                *pCmdData,
+                              uint32_t            *replySize,
+                              void                *pReplyData) {
+
+    EffectContext *pContext = (EffectContext *) self;
+    int status = 0;
+    if (pContext == NULL) {
+        ALOGV("Effect_command() Proxy context is NULL");
+        return -EINVAL;
+    }
+    if (pContext->eHandle[SUB_FX_HOST] == NULL) {
+        ALOGV("Effect_command() Calling HOST EffectCreate");
+        status = pContext->aeli[SUB_FX_HOST]->create_effect(
+                              &pContext->desc[SUB_FX_HOST].uuid,
+                              pContext->sessionId, pContext->ioId,
+                              &(pContext->eHandle[SUB_FX_HOST]));
+        if (status != NO_ERROR || (pContext->eHandle[SUB_FX_HOST] == NULL)) {
+            ALOGV("Effect_command() Error creating SW sub effect");
+            return status;
+        }
+    }
+    if (pContext->eHandle[SUB_FX_OFFLOAD] == NULL) {
+        ALOGV("Effect_command() Calling OFFLOAD EffectCreate");
+        status = pContext->aeli[SUB_FX_OFFLOAD]->create_effect(
+                              &pContext->desc[SUB_FX_OFFLOAD].uuid,
+                              pContext->sessionId, pContext->ioId,
+                              &(pContext->eHandle[SUB_FX_OFFLOAD]));
+        if (status != NO_ERROR || (pContext->eHandle[SUB_FX_OFFLOAD] == NULL)) {
+            ALOGV("Effect_command() Error creating HW effect");
+            pContext->eHandle[SUB_FX_OFFLOAD] = NULL;
+            // Do not return error here as SW effect is created
+            // Return error if the CMD_OFFLOAD sends the index as OFFLOAD
+        }
+        pContext->index = SUB_FX_HOST;
+    }
+    // EFFECT_CMD_OFFLOAD used to (1) send whether the thread is offload or not
+    // (2) Send the ioHandle of the effectThread when the effect
+    // is moved from one type of thread to another.
+    // pCmdData points to a memory holding effect_offload_param_t structure
+    if (cmdCode == EFFECT_CMD_OFFLOAD) {
+        ALOGV("Effect_command() cmdCode = EFFECT_CMD_OFFLOAD");
+        if (cmdSize == 0 || pCmdData == NULL) {
+            ALOGV("effectsOffload: Effect_command: CMD_OFFLOAD has no data");
+             *(int*)pReplyData = FAILED_TRANSACTION;
+            return FAILED_TRANSACTION;
+        }
+        effect_offload_param_t* offloadParam = (effect_offload_param_t*)pCmdData;
+        // Assign the effect context index based on isOffload field of the structure
+        pContext->index = offloadParam->isOffload ? SUB_FX_OFFLOAD : SUB_FX_HOST;
+        // if the index is HW and the HW effect is unavailable, return error
+        // and reset the index to SW
+        if (pContext->eHandle[pContext->index] == NULL) {
+            ALOGV("Effect_command()CMD_OFFLOAD sub effect unavailable");
+            *(int*)pReplyData = FAILED_TRANSACTION;
+            return FAILED_TRANSACTION;
+        }
+        pContext->ioId = offloadParam->ioHandle;
+        ALOGV("Effect_command()CMD_OFFLOAD index:%d io %d", pContext->index, pContext->ioId);
+        // Update the DSP wrapper with the new ioHandle.
+        // Pass the OFFLOAD command to the wrapper.
+        // The DSP wrapper needs to handle this CMD
+        if (pContext->eHandle[SUB_FX_OFFLOAD]) {
+            ALOGV("Effect_command: Calling OFFLOAD command");
+            return (*pContext->eHandle[SUB_FX_OFFLOAD])->command(
+                           pContext->eHandle[SUB_FX_OFFLOAD], cmdCode, cmdSize,
+                           pCmdData, replySize, pReplyData);
+        }
+        *(int*)pReplyData = NO_ERROR;
+        ALOGV("Effect_command OFFLOAD return 0, replyData %d",
+                                                *(int*)pReplyData);
+
+        return NO_ERROR;
+    }
+
+    int index = pContext->index;
+    if (index != SUB_FX_HOST && index != SUB_FX_OFFLOAD) {
+        ALOGV("Effect_command: effect index is neither offload nor host");
+        return -EINVAL;
+    }
+
+    // Getter commands are only sent to the active sub effect.
+    int *subStatus[SUB_FX_COUNT];
+    uint32_t *subReplySize[SUB_FX_COUNT];
+    void *subReplyData[SUB_FX_COUNT];
+    uint32_t tmpSize;
+    int tmpStatus;
+
+    // grow temp reply buffer if needed
+    if (replySize != NULL) {
+        tmpSize = pContext->replySize;
+        while (tmpSize < *replySize && tmpSize < PROXY_REPLY_SIZE_MAX) {
+            tmpSize *= 2;
+        }
+        if (tmpSize > pContext->replySize) {
+            ALOGV("Effect_command grow reply buf to %d", tmpSize);
+            pContext->replyData = (char *)realloc(pContext->replyData, tmpSize);
+            pContext->replySize = tmpSize;
+        }
+        if (tmpSize > *replySize) {
+            tmpSize = *replySize;
+        }
+    } else {
+        tmpSize = 0;
+    }
+    // tmpSize is now the actual reply size for the non active sub effect
+
+    // Send command to sub effects. The command is sent to all sub effects so that their internal
+    // state is kept in sync.
+    // Only the reply from the active sub effect is returned to the caller. The reply from the
+    // other sub effect is lost in pContext->replyData
+    for (int i = 0; i < SUB_FX_COUNT; i++) {
+        if (pContext->eHandle[i] == NULL) {
+            continue;
+        }
+        if (i == index) {
+            subStatus[i] = &status;
+            subReplySize[i] = replySize;
+            subReplyData[i] = pReplyData;
+        } else {
+            subStatus[i] = &tmpStatus;
+            subReplySize[i] = replySize == NULL ? NULL : &tmpSize;
+            subReplyData[i] = pReplyData == NULL ? NULL : pContext->replyData;
+        }
+        *subStatus[i] = (*pContext->eHandle[i])->command(
+                             pContext->eHandle[i], cmdCode, cmdSize,
+                             pCmdData, subReplySize[i], subReplyData[i]);
+    }
+
+    return status;
+}    /* end Effect_command */
+
+
+/* Effect Control Interface Implementation: get_descriptor */
+int Effect_getDescriptor(effect_handle_t   self,
+                         effect_descriptor_t *pDescriptor) {
+
+    EffectContext * pContext = (EffectContext *) self;
+    const effect_descriptor_t *desc;
+
+    ALOGV("Effect_getDescriptor");
+    if (pContext == NULL || pDescriptor == NULL) {
+        ALOGV("Effect_getDescriptor() invalid param");
+        return -EINVAL;
+    }
+    if (pContext->desc == NULL) {
+        ALOGV("Effect_getDescriptor() could not get descriptor");
+        return -EINVAL;
+    }
+    desc = &pContext->desc[SUB_FX_HOST];
+    *pDescriptor = *desc;
+    pDescriptor->uuid = pContext->uuid; // Replace the uuid with the Proxy UUID
+    // Also set/clear the EFFECT_FLAG_OFFLOAD_SUPPORTED flag based on the sub effects availability
+    if (pContext->eHandle[SUB_FX_OFFLOAD] != NULL)
+        pDescriptor->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED;
+    else
+        pDescriptor->flags &= ~EFFECT_FLAG_OFFLOAD_SUPPORTED;
+    return 0;
+} /* end Effect_getDescriptor */
+
+} // namespace android
+
+__attribute__ ((visibility ("default")))
+audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
+    tag : AUDIO_EFFECT_LIBRARY_TAG,
+    version : EFFECT_LIBRARY_API_VERSION,
+    name : "Effect Proxy",
+    implementor : "AOSP",
+    create_effect : android::EffectProxyCreate,
+    release_effect : android::EffectProxyRelease,
+    get_descriptor : android::EffectProxyGetDescriptor,
+};
diff --git a/media/libeffects/proxy/EffectProxy.h b/media/libeffects/proxy/EffectProxy.h
new file mode 100644
index 0000000..046b93e
--- /dev/null
+++ b/media/libeffects/proxy/EffectProxy.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hardware/audio.h>
+#include <hardware/audio_effect.h>
+#include "EffectsFactory.h"
+
+namespace android {
+enum {
+    SUB_FX_HOST,       // Index of HOST in the descriptor and handle arrays
+                       // of the Proxy context
+    SUB_FX_OFFLOAD,    // Index of OFFLOAD in the descriptor and handle arrays
+                       // of the Proxy context
+    SUB_FX_COUNT       // The number of sub effects for a Proxy(1 HW, 1 SW)
+};
+#if __cplusplus
+extern "C" {
+#endif
+
+int EffectProxyCreate(const effect_uuid_t *uuid,
+                          int32_t             sessionId,
+                          int32_t             ioId,
+                          effect_handle_t  *pHandle);
+int EffectProxyRelease(effect_handle_t handle);
+int EffectProxyGetDescriptor(const effect_uuid_t *uuid,
+                                 effect_descriptor_t *pDescriptor);
+/* Effect Control Interface Implementation: Process */
+int Effect_process(effect_handle_t     self,
+                            audio_buffer_t         *inBuffer,
+                            audio_buffer_t         *outBuffer);
+
+/* Effect Control Interface Implementation: Command */
+int Effect_command(effect_handle_t  self,
+                            uint32_t            cmdCode,
+                            uint32_t            cmdSize,
+                            void                *pCmdData,
+                            uint32_t            *replySize,
+                            void                *pReplyData);
+int Effect_getDescriptor(effect_handle_t   self,
+                       effect_descriptor_t *pDescriptor);
+
+const struct effect_interface_s gEffectInterface = {
+  Effect_process,
+  Effect_command,
+  Effect_getDescriptor,
+  NULL,
+};
+
+#define PROXY_REPLY_SIZE_MAX     (64 * 1024) // must be power of two
+#define PROXY_REPLY_SIZE_DEFAULT 32          // must be power of two
+
+struct EffectContext {
+  const struct effect_interface_s  *common_itfe; // Holds the itfe of the Proxy
+  sub_effect_entry_t** sube;                     // Points to the sub effects
+  effect_descriptor_t*  desc;                    // Points to the sub effect descriptors
+  audio_effect_library_t**  aeli;                // Points to the sub effect aeli
+  effect_handle_t       eHandle[SUB_FX_COUNT];   // The effect handles of the sub effects
+  int                   index;       // The index that is currently active - HOST or OFFLOAD
+  int32_t               sessionId;   // The sessiond in which the effect is created.
+                                     // Stored in context to pass on to sub effect creation
+  int32_t               ioId;        // The ioId in which the effect is created.
+                                     // Stored in context to pass on to sub effect creation
+  effect_uuid_t         uuid;        // UUID of the Proxy
+  char*                 replyData;   // temporary buffer for non active sub effect command reply
+  uint32_t              replySize;   // current size of temporary reply buffer
+};
+
+#if __cplusplus
+}  // extern "C"
+#endif
+} //namespace android
diff --git a/media/libeffects/testlibs/AudioFormatAdapter.h b/media/libeffects/testlibs/AudioFormatAdapter.h
index 41f1810..dea2734 100644
--- a/media/libeffects/testlibs/AudioFormatAdapter.h
+++ b/media/libeffects/testlibs/AudioFormatAdapter.h
@@ -75,6 +75,7 @@
         while (numSamples > 0) {
             uint32_t numSamplesIter = min(numSamples, mMaxSamplesPerCall);
             uint32_t nSamplesChannels = numSamplesIter * mNumChannels;
+            // This branch of "if" is untested
             if (mPcmFormat == AUDIO_FORMAT_PCM_8_24_BIT) {
                 if (mBehavior == EFFECT_BUFFER_ACCESS_WRITE) {
                     mpProcessor->process(
diff --git a/media/libeffects/testlibs/EffectEqualizer.cpp b/media/libeffects/testlibs/EffectEqualizer.cpp
index c35453b..8d00206 100644
--- a/media/libeffects/testlibs/EffectEqualizer.cpp
+++ b/media/libeffects/testlibs/EffectEqualizer.cpp
@@ -234,8 +234,7 @@
               (pConfig->inputCfg.channels == AUDIO_CHANNEL_OUT_STEREO));
     CHECK_ARG(pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE
               || pConfig->outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE);
-    CHECK_ARG(pConfig->inputCfg.format == AUDIO_FORMAT_PCM_8_24_BIT
-              || pConfig->inputCfg.format == AUDIO_FORMAT_PCM_16_BIT);
+    CHECK_ARG(pConfig->inputCfg.format == AUDIO_FORMAT_PCM_16_BIT);
 
     int channelCount;
     if (pConfig->inputCfg.channels == AUDIO_CHANNEL_OUT_MONO) {
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index e7eccf1..18bdb78 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -22,6 +22,7 @@
 #include <string.h>
 #include <new>
 #include <time.h>
+#include <math.h>
 #include <audio_effects/effect_visualizer.h>
 
 
@@ -54,6 +55,18 @@
 
 #define CAPTURE_BUF_SIZE 65536 // "64k should be enough for everyone"
 
+#define DISCARD_MEASUREMENTS_TIME_MS 2000 // discard measurements older than this number of ms
+
+// maximum number of buffers for which we keep track of the measurements
+#define MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS 25 // note: buffer index is stored in uint8_t
+
+
+struct BufferStats {
+    bool mIsValid;
+    uint16_t mPeakU16; // the positive peak of the absolute value of the samples in a buffer
+    float mRmsSquared; // the average square of the samples in a buffer
+};
+
 struct VisualizerContext {
     const struct effect_interface_s *mItfe;
     effect_config_t mConfig;
@@ -61,15 +74,38 @@
     uint32_t mCaptureSize;
     uint32_t mScalingMode;
     uint8_t mState;
-    uint8_t mLastCaptureIdx;
+    uint32_t mLastCaptureIdx;
     uint32_t mLatency;
     struct timespec mBufferUpdateTime;
     uint8_t mCaptureBuf[CAPTURE_BUF_SIZE];
+    // for measurements
+    uint8_t mChannelCount; // to avoid recomputing it every time a buffer is processed
+    uint32_t mMeasurementMode;
+    uint8_t mMeasurementWindowSizeInBuffers;
+    uint8_t mMeasurementBufferIdx;
+    BufferStats mPastMeasurements[MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS];
 };
 
 //
 //--- Local functions
 //
+uint32_t Visualizer_getDeltaTimeMsFromUpdatedTime(VisualizerContext* pContext) {
+    uint32_t deltaMs = 0;
+    if (pContext->mBufferUpdateTime.tv_sec != 0) {
+        struct timespec ts;
+        if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+            time_t secs = ts.tv_sec - pContext->mBufferUpdateTime.tv_sec;
+            long nsec = ts.tv_nsec - pContext->mBufferUpdateTime.tv_nsec;
+            if (nsec < 0) {
+                --secs;
+                nsec += 1000000000;
+            }
+            deltaMs = secs * 1000 + nsec / 1000000;
+        }
+    }
+    return deltaMs;
+}
+
 
 void Visualizer_reset(VisualizerContext *pContext)
 {
@@ -165,9 +201,21 @@
     pContext->mConfig.outputCfg.bufferProvider.cookie = NULL;
     pContext->mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
 
+    // visualization initialization
     pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX;
     pContext->mScalingMode = VISUALIZER_SCALING_MODE_NORMALIZED;
 
+    // measurement initialization
+    pContext->mChannelCount = popcount(pContext->mConfig.inputCfg.channels);
+    pContext->mMeasurementMode = MEASUREMENT_MODE_NONE;
+    pContext->mMeasurementWindowSizeInBuffers = MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS;
+    pContext->mMeasurementBufferIdx = 0;
+    for (uint32_t i=0 ; i<pContext->mMeasurementWindowSizeInBuffers ; i++) {
+        pContext->mPastMeasurements[i].mIsValid = false;
+        pContext->mPastMeasurements[i].mPeakU16 = 0;
+        pContext->mPastMeasurements[i].mRmsSquared = 0;
+    }
+
     Visualizer_setConfig(pContext, &pContext->mConfig);
 
     return 0;
@@ -270,6 +318,30 @@
         return -EINVAL;
     }
 
+    // perform measurements if needed
+    if (pContext->mMeasurementMode & MEASUREMENT_MODE_PEAK_RMS) {
+        // find the peak and RMS squared for the new buffer
+        uint32_t inIdx;
+        int16_t maxSample = 0;
+        float rmsSqAcc = 0;
+        for (inIdx = 0 ; inIdx < inBuffer->frameCount * pContext->mChannelCount ; inIdx++) {
+            if (inBuffer->s16[inIdx] > maxSample) {
+                maxSample = inBuffer->s16[inIdx];
+            } else if (-inBuffer->s16[inIdx] > maxSample) {
+                maxSample = -inBuffer->s16[inIdx];
+            }
+            rmsSqAcc += (inBuffer->s16[inIdx] * inBuffer->s16[inIdx]);
+        }
+        // store the measurement
+        pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mPeakU16 = (uint16_t)maxSample;
+        pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mRmsSquared =
+                rmsSqAcc / (inBuffer->frameCount * pContext->mChannelCount);
+        pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mIsValid = true;
+        if (++pContext->mMeasurementBufferIdx >= pContext->mMeasurementWindowSizeInBuffers) {
+            pContext->mMeasurementBufferIdx = 0;
+        }
+    }
+
     // all code below assumes stereo 16 bit PCM output and input
     int32_t shift;
 
@@ -350,21 +422,21 @@
 
     switch (cmdCode) {
     case EFFECT_CMD_INIT:
-        if (pReplyData == NULL || *replySize != sizeof(int)) {
+        if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
             return -EINVAL;
         }
         *(int *) pReplyData = Visualizer_init(pContext);
         break;
     case EFFECT_CMD_SET_CONFIG:
         if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
-                || pReplyData == NULL || *replySize != sizeof(int)) {
+                || pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
             return -EINVAL;
         }
         *(int *) pReplyData = Visualizer_setConfig(pContext,
                 (effect_config_t *) pCmdData);
         break;
     case EFFECT_CMD_GET_CONFIG:
-        if (pReplyData == NULL ||
+        if (pReplyData == NULL || replySize == NULL ||
             *replySize != sizeof(effect_config_t)) {
             return -EINVAL;
         }
@@ -374,7 +446,7 @@
         Visualizer_reset(pContext);
         break;
     case EFFECT_CMD_ENABLE:
-        if (pReplyData == NULL || *replySize != sizeof(int)) {
+        if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
             return -EINVAL;
         }
         if (pContext->mState != VISUALIZER_STATE_INITIALIZED) {
@@ -385,7 +457,7 @@
         *(int *)pReplyData = 0;
         break;
     case EFFECT_CMD_DISABLE:
-        if (pReplyData == NULL || *replySize != sizeof(int)) {
+        if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
             return -EINVAL;
         }
         if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
@@ -398,7 +470,7 @@
     case EFFECT_CMD_GET_PARAM: {
         if (pCmdData == NULL ||
             cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t)) ||
-            pReplyData == NULL ||
+            pReplyData == NULL || replySize == NULL ||
             *replySize < (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t))) {
             return -EINVAL;
         }
@@ -423,6 +495,12 @@
             p->vsize = sizeof(uint32_t);
             *replySize += sizeof(uint32_t);
             break;
+        case VISUALIZER_PARAM_MEASUREMENT_MODE:
+            ALOGV("get mMeasurementMode = %d", pContext->mMeasurementMode);
+            *((uint32_t *)p->data + 1) = pContext->mMeasurementMode;
+            p->vsize = sizeof(uint32_t);
+            *replySize += sizeof(uint32_t);
+            break;
         default:
             p->status = -EINVAL;
         }
@@ -430,7 +508,7 @@
     case EFFECT_CMD_SET_PARAM: {
         if (pCmdData == NULL ||
             cmdSize != (int)(sizeof(effect_param_t) + sizeof(uint32_t) + sizeof(uint32_t)) ||
-            pReplyData == NULL || *replySize != sizeof(int32_t)) {
+            pReplyData == NULL || replySize == NULL || *replySize != sizeof(int32_t)) {
             return -EINVAL;
         }
         *(int32_t *)pReplyData = 0;
@@ -452,6 +530,10 @@
             pContext->mLatency = *((uint32_t *)p->data + 1);
             ALOGV("set mLatency = %d", pContext->mLatency);
             break;
+        case VISUALIZER_PARAM_MEASUREMENT_MODE:
+            pContext->mMeasurementMode = *((uint32_t *)p->data + 1);
+            ALOGV("set mMeasurementMode = %d", pContext->mMeasurementMode);
+            break;
         default:
             *(int32_t *)pReplyData = -EINVAL;
         }
@@ -462,32 +544,21 @@
         break;
 
 
-    case VISUALIZER_CMD_CAPTURE:
-        if (pReplyData == NULL || *replySize != pContext->mCaptureSize) {
-            ALOGV("VISUALIZER_CMD_CAPTURE() error *replySize %d pContext->mCaptureSize %d",
-                    *replySize, pContext->mCaptureSize);
+    case VISUALIZER_CMD_CAPTURE: {
+        uint32_t captureSize = pContext->mCaptureSize;
+        if (pReplyData == NULL || replySize == NULL || *replySize != captureSize) {
+            ALOGV("VISUALIZER_CMD_CAPTURE() error *replySize %" PRIu32 " captureSize %" PRIu32,
+                    *replySize, captureSize);
             return -EINVAL;
         }
         if (pContext->mState == VISUALIZER_STATE_ACTIVE) {
             int32_t latencyMs = pContext->mLatency;
-            uint32_t deltaMs = 0;
-            if (pContext->mBufferUpdateTime.tv_sec != 0) {
-                struct timespec ts;
-                if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
-                    time_t secs = ts.tv_sec - pContext->mBufferUpdateTime.tv_sec;
-                    long nsec = ts.tv_nsec - pContext->mBufferUpdateTime.tv_nsec;
-                    if (nsec < 0) {
-                        --secs;
-                        nsec += 1000000000;
-                    }
-                    deltaMs = secs * 1000 + nsec / 1000000;
-                    latencyMs -= deltaMs;
-                    if (latencyMs < 0) {
-                        latencyMs = 0;
-                    }
-                }
+            const uint32_t deltaMs = Visualizer_getDeltaTimeMsFromUpdatedTime(pContext);
+            latencyMs -= deltaMs;
+            if (latencyMs < 0) {
+                latencyMs = 0;
             }
-            uint32_t deltaSmpl = pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000;
+            const uint32_t deltaSmpl = pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000;
 
             int32_t capturePoint = pContext->mCaptureIdx - pContext->mCaptureSize - deltaSmpl;
             int32_t captureSize = pContext->mCaptureSize;
@@ -499,7 +570,7 @@
                 memcpy(pReplyData,
                        pContext->mCaptureBuf + CAPTURE_BUF_SIZE + capturePoint,
                        size);
-                pReplyData += size;
+                pReplyData = (char *)pReplyData + size;
                 captureSize -= size;
                 capturePoint = 0;
             }
@@ -522,7 +593,55 @@
         } else {
             memset(pReplyData, 0x80, pContext->mCaptureSize);
         }
+        }
+        break;
 
+    case VISUALIZER_CMD_MEASURE: {
+        uint16_t peakU16 = 0;
+        float sumRmsSquared = 0.0f;
+        uint8_t nbValidMeasurements = 0;
+        // reset measurements if last measurement was too long ago (which implies stored
+        // measurements aren't relevant anymore and shouldn't bias the new one)
+        const int32_t delayMs = Visualizer_getDeltaTimeMsFromUpdatedTime(pContext);
+        if (delayMs > DISCARD_MEASUREMENTS_TIME_MS) {
+            ALOGV("Discarding measurements, last measurement is %dms old", delayMs);
+            for (uint32_t i=0 ; i<pContext->mMeasurementWindowSizeInBuffers ; i++) {
+                pContext->mPastMeasurements[i].mIsValid = false;
+                pContext->mPastMeasurements[i].mPeakU16 = 0;
+                pContext->mPastMeasurements[i].mRmsSquared = 0;
+            }
+            pContext->mMeasurementBufferIdx = 0;
+        } else {
+            // only use actual measurements, otherwise the first RMS measure happening before
+            // MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS have been played will always be artificially
+            // low
+            for (uint32_t i=0 ; i < pContext->mMeasurementWindowSizeInBuffers ; i++) {
+                if (pContext->mPastMeasurements[i].mIsValid) {
+                    if (pContext->mPastMeasurements[i].mPeakU16 > peakU16) {
+                        peakU16 = pContext->mPastMeasurements[i].mPeakU16;
+                    }
+                    sumRmsSquared += pContext->mPastMeasurements[i].mRmsSquared;
+                    nbValidMeasurements++;
+                }
+            }
+        }
+        float rms = nbValidMeasurements == 0 ? 0.0f : sqrtf(sumRmsSquared / nbValidMeasurements);
+        int32_t* pIntReplyData = (int32_t*)pReplyData;
+        // convert from I16 sample values to mB and write results
+        if (rms < 0.000016f) {
+            pIntReplyData[MEASUREMENT_IDX_RMS] = -9600; //-96dB
+        } else {
+            pIntReplyData[MEASUREMENT_IDX_RMS] = (int32_t) (2000 * log10(rms / 32767.0f));
+        }
+        if (peakU16 == 0) {
+            pIntReplyData[MEASUREMENT_IDX_PEAK] = -9600; //-96dB
+        } else {
+            pIntReplyData[MEASUREMENT_IDX_PEAK] = (int32_t) (2000 * log10(peakU16 / 32767.0f));
+        }
+        ALOGV("VISUALIZER_CMD_MEASURE peak=%d (%dmB), rms=%.1f (%dmB)",
+                peakU16, pIntReplyData[MEASUREMENT_IDX_PEAK],
+                rms, pIntReplyData[MEASUREMENT_IDX_RMS]);
+        }
         break;
 
     default:
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 2c0c3a5..56e7787 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -53,7 +53,8 @@
     Visualizer.cpp \
     MemoryLeakTrackUtil.cpp \
     SoundPool.cpp \
-    SoundPoolThread.cpp
+    SoundPoolThread.cpp \
+    StringArray.cpp
 
 LOCAL_SRC_FILES += ../libnbaio/roundup.c
 
@@ -61,6 +62,7 @@
 LOCAL_CFLAGS += -DANDROID_SMP=$(if $(findstring true,$(TARGET_CPU_SMP)),1,0)
 LOCAL_SRC_FILES += SingleStateQueue.cpp
 LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiations.cpp"'
+# Consider a separate a library for SingleStateQueueInstantiations.
 
 LOCAL_SHARED_LIBRARIES := \
 	libui liblog libcutils libutils libbinder libsonivox libicuuc libexpat \
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 40ff1bf..ccbc5a3 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -19,17 +19,13 @@
 #define LOG_TAG "AudioRecord"
 
 #include <sys/resource.h>
-#include <sys/types.h>
-
 #include <binder/IPCThreadState.h>
-#include <cutils/atomic.h>
-#include <cutils/compiler.h>
 #include <media/AudioRecord.h>
-#include <media/AudioSystem.h>
-#include <system/audio.h>
 #include <utils/Log.h>
-
 #include <private/media/AudioTrackShared.h>
+#include <media/IAudioFlinger.h>
+
+#define WAIT_PERIOD_MS          10
 
 namespace android {
 // ---------------------------------------------------------------------------
@@ -41,7 +37,9 @@
         audio_format_t format,
         audio_channel_mask_t channelMask)
 {
-    if (frameCount == NULL) return BAD_VALUE;
+    if (frameCount == NULL) {
+        return BAD_VALUE;
+    }
 
     // default to 0 in case of error
     *frameCount = 0;
@@ -62,10 +60,9 @@
     // We double the size of input buffer for ping pong use of record buffer.
     size <<= 1;
 
-    if (audio_is_linear_pcm(format)) {
-        uint32_t channelCount = popcount(channelMask);
-        size /= channelCount * audio_bytes_per_sample(format);
-    }
+    // Assumes audio_is_linear_pcm(format)
+    uint32_t channelCount = popcount(channelMask);
+    size /= channelCount * audio_bytes_per_sample(format);
 
     *frameCount = size;
     return NO_ERROR;
@@ -75,8 +72,7 @@
 
 AudioRecord::AudioRecord()
     : mStatus(NO_INIT), mSessionId(0),
-      mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT),
-      mProxy(NULL)
+      mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT)
 {
 }
 
@@ -89,14 +85,16 @@
         callback_t cbf,
         void* user,
         int notificationFrames,
-        int sessionId)
+        int sessionId,
+        transfer_type transferType,
+        audio_input_flags_t flags)
     : mStatus(NO_INIT), mSessionId(0),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
       mProxy(NULL)
 {
-    mStatus = set(inputSource, sampleRate, format, channelMask,
-            frameCount, cbf, user, notificationFrames, false /*threadCanCallJava*/, sessionId);
+    mStatus = set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user,
+            notificationFrames, false /*threadCanCallJava*/, sessionId, transferType);
 }
 
 AudioRecord::~AudioRecord()
@@ -107,15 +105,18 @@
         // Otherwise the callback thread will never exit.
         stop();
         if (mAudioRecordThread != 0) {
+            mProxy->interrupt();
             mAudioRecordThread->requestExit();  // see comment in AudioRecord.h
             mAudioRecordThread->requestExitAndWait();
             mAudioRecordThread.clear();
         }
-        mAudioRecord.clear();
+        if (mAudioRecord != 0) {
+            mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this);
+            mAudioRecord.clear();
+        }
         IPCThreadState::self()->flushCommands();
         AudioSystem::releaseAudioSessionId(mSessionId);
     }
-    delete mProxy;
 }
 
 status_t AudioRecord::set(
@@ -128,8 +129,33 @@
         void* user,
         int notificationFrames,
         bool threadCanCallJava,
-        int sessionId)
+        int sessionId,
+        transfer_type transferType,
+        audio_input_flags_t flags)
 {
+    switch (transferType) {
+    case TRANSFER_DEFAULT:
+        if (cbf == NULL || threadCanCallJava) {
+            transferType = TRANSFER_SYNC;
+        } else {
+            transferType = TRANSFER_CALLBACK;
+        }
+        break;
+    case TRANSFER_CALLBACK:
+        if (cbf == NULL) {
+            ALOGE("Transfer type TRANSFER_CALLBACK but cbf == NULL");
+            return BAD_VALUE;
+        }
+        break;
+    case TRANSFER_OBTAIN:
+    case TRANSFER_SYNC:
+        break;
+    default:
+        ALOGE("Invalid transfer type %d", transferType);
+        return BAD_VALUE;
+    }
+    mTransfer = transferType;
+
     // FIXME "int" here is legacy and will be replaced by size_t later
     if (frameCountInt < 0) {
         ALOGE("Invalid frame count %d", frameCountInt);
@@ -143,15 +169,18 @@
     AutoMutex lock(mLock);
 
     if (mAudioRecord != 0) {
+        ALOGE("Track already in use");
         return INVALID_OPERATION;
     }
 
     if (inputSource == AUDIO_SOURCE_DEFAULT) {
         inputSource = AUDIO_SOURCE_MIC;
     }
+    mInputSource = inputSource;
 
     if (sampleRate == 0) {
-        sampleRate = DEFAULT_SAMPLE_RATE;
+        ALOGE("Invalid sample rate %u", sampleRate);
+        return BAD_VALUE;
     }
     mSampleRate = sampleRate;
 
@@ -159,25 +188,50 @@
     if (format == AUDIO_FORMAT_DEFAULT) {
         format = AUDIO_FORMAT_PCM_16_BIT;
     }
+
     // validate parameters
     if (!audio_is_valid_format(format)) {
-        ALOGE("Invalid format");
+        ALOGE("Invalid format %d", format);
+        return BAD_VALUE;
+    }
+    // Temporary restriction: AudioFlinger currently supports 16-bit PCM only
+    if (format != AUDIO_FORMAT_PCM_16_BIT) {
+        ALOGE("Format %d is not supported", format);
         return BAD_VALUE;
     }
     mFormat = format;
 
     if (!audio_is_input_channel(channelMask)) {
+        ALOGE("Invalid channel mask %#x", channelMask);
         return BAD_VALUE;
     }
     mChannelMask = channelMask;
     uint32_t channelCount = popcount(channelMask);
     mChannelCount = channelCount;
 
-    if (audio_is_linear_pcm(format)) {
-        mFrameSize = channelCount * audio_bytes_per_sample(format);
-    } else {
-        mFrameSize = sizeof(uint8_t);
+    // Assumes audio_is_linear_pcm(format), else sizeof(uint8_t)
+    mFrameSize = channelCount * audio_bytes_per_sample(format);
+
+    // validate framecount
+    size_t minFrameCount = 0;
+    status_t status = AudioRecord::getMinFrameCount(&minFrameCount,
+            sampleRate, format, channelMask);
+    if (status != NO_ERROR) {
+        ALOGE("getMinFrameCount() failed; status %d", status);
+        return status;
     }
+    ALOGV("AudioRecord::set() minFrameCount = %d", minFrameCount);
+
+    if (frameCount == 0) {
+        frameCount = minFrameCount;
+    } else if (frameCount < minFrameCount) {
+        ALOGE("frameCount %u < minFrameCount %u", frameCount, minFrameCount);
+        return BAD_VALUE;
+    }
+    mFrameCount = frameCount;
+
+    mNotificationFramesReq = notificationFrames;
+    mNotificationFramesAct = 0;
 
     if (sessionId == 0 ) {
         mSessionId = AudioSystem::newAudioSessionId();
@@ -186,37 +240,11 @@
     }
     ALOGV("set(): mSessionId %d", mSessionId);
 
-    audio_io_handle_t input = AudioSystem::getInput(inputSource,
-                                                    sampleRate,
-                                                    format,
-                                                    channelMask,
-                                                    mSessionId);
-    if (input == 0) {
-        ALOGE("Could not get audio input for record source %d", inputSource);
-        return BAD_VALUE;
-    }
-
-    // validate framecount
-    size_t minFrameCount = 0;
-    status_t status = getMinFrameCount(&minFrameCount, sampleRate, format, channelMask);
-    if (status != NO_ERROR) {
-        return status;
-    }
-    ALOGV("AudioRecord::set() minFrameCount = %d", minFrameCount);
-
-    if (frameCount == 0) {
-        frameCount = minFrameCount;
-    } else if (frameCount < minFrameCount) {
-        return BAD_VALUE;
-    }
-
-    if (notificationFrames == 0) {
-        notificationFrames = frameCount/2;
-    }
+    mFlags = flags;
 
     // create the IAudioRecord
-    status = openRecord_l(sampleRate, format, frameCount, input);
-    if (status != NO_ERROR) {
+    status = openRecord_l(0 /*epoch*/);
+    if (status) {
         return status;
     }
 
@@ -232,8 +260,7 @@
 
     mActive = false;
     mCbf = cbf;
-    mNotificationFrames = notificationFrames;
-    mRemainingFrames = notificationFrames;
+    mRefreshRemaining = true;
     mUserData = user;
     // TODO: add audio hardware input latency here
     mLatency = (1000*mFrameCount) / sampleRate;
@@ -241,120 +268,79 @@
     mMarkerReached = false;
     mNewPosition = 0;
     mUpdatePeriod = 0;
-    mInputSource = inputSource;
-    mInput = input;
     AudioSystem::acquireAudioSessionId(mSessionId);
+    mSequence = 1;
+    mObservedSequence = mSequence;
+    mInOverrun = false;
 
     return NO_ERROR;
 }
 
-status_t AudioRecord::initCheck() const
-{
-    return mStatus;
-}
-
-// -------------------------------------------------------------------------
-
-uint32_t AudioRecord::latency() const
-{
-    return mLatency;
-}
-
-audio_format_t AudioRecord::format() const
-{
-    return mFormat;
-}
-
-uint32_t AudioRecord::channelCount() const
-{
-    return mChannelCount;
-}
-
-size_t AudioRecord::frameCount() const
-{
-    return mFrameCount;
-}
-
-audio_source_t AudioRecord::inputSource() const
-{
-    return mInputSource;
-}
-
 // -------------------------------------------------------------------------
 
 status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession)
 {
-    status_t ret = NO_ERROR;
-    sp<AudioRecordThread> t = mAudioRecordThread;
-
     ALOGV("start, sync event %d trigger session %d", event, triggerSession);
 
     AutoMutex lock(mLock);
-    // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
-    // while we are accessing the cblk
-    sp<IAudioRecord> audioRecord = mAudioRecord;
-    sp<IMemory> iMem = mCblkMemory;
-    audio_track_cblk_t* cblk = mCblk;
+    if (mActive) {
+        return NO_ERROR;
+    }
 
-    if (!mActive) {
+    // reset current position as seen by client to 0
+    mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());
+
+    mNewPosition = mProxy->getPosition() + mUpdatePeriod;
+    int32_t flags = android_atomic_acquire_load(&mCblk->mFlags);
+
+    status_t status = NO_ERROR;
+    if (!(flags & CBLK_INVALID)) {
+        ALOGV("mAudioRecord->start()");
+        status = mAudioRecord->start(event, triggerSession);
+        if (status == DEAD_OBJECT) {
+            flags |= CBLK_INVALID;
+        }
+    }
+    if (flags & CBLK_INVALID) {
+        status = restoreRecord_l("start");
+    }
+
+    if (status != NO_ERROR) {
+        ALOGE("start() status %d", status);
+    } else {
         mActive = true;
-
-        cblk->lock.lock();
-        if (!(cblk->flags & CBLK_INVALID)) {
-            cblk->lock.unlock();
-            ALOGV("mAudioRecord->start()");
-            ret = mAudioRecord->start(event, triggerSession);
-            cblk->lock.lock();
-            if (ret == DEAD_OBJECT) {
-                android_atomic_or(CBLK_INVALID, &cblk->flags);
-            }
-        }
-        if (cblk->flags & CBLK_INVALID) {
-            audio_track_cblk_t* temp = cblk;
-            ret = restoreRecord_l(temp);
-            cblk = temp;
-        }
-        cblk->lock.unlock();
-        if (ret == NO_ERROR) {
-            mNewPosition = cblk->user + mUpdatePeriod;
-            cblk->bufferTimeoutMs = (event == AudioSystem::SYNC_EVENT_NONE) ? MAX_RUN_TIMEOUT_MS :
-                                            AudioSystem::kSyncRecordStartTimeOutMs;
-            cblk->waitTimeMs = 0;
-            if (t != 0) {
-                t->resume();
-            } else {
-                mPreviousPriority = getpriority(PRIO_PROCESS, 0);
-                get_sched_policy(0, &mPreviousSchedulingGroup);
-                androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
-            }
+        sp<AudioRecordThread> t = mAudioRecordThread;
+        if (t != 0) {
+            t->resume();
         } else {
-            mActive = false;
+            mPreviousPriority = getpriority(PRIO_PROCESS, 0);
+            get_sched_policy(0, &mPreviousSchedulingGroup);
+            androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
         }
     }
 
-    return ret;
+    return status;
 }
 
 void AudioRecord::stop()
 {
-    sp<AudioRecordThread> t = mAudioRecordThread;
-
-    ALOGV("stop");
-
     AutoMutex lock(mLock);
-    if (mActive) {
-        mActive = false;
-        mCblk->cv.signal();
-        mAudioRecord->stop();
-        // the record head position will reset to 0, so if a marker is set, we need
-        // to activate it again
-        mMarkerReached = false;
-        if (t != 0) {
-            t->pause();
-        } else {
-            setpriority(PRIO_PROCESS, 0, mPreviousPriority);
-            set_sched_policy(0, mPreviousSchedulingGroup);
-        }
+    if (!mActive) {
+        return;
+    }
+
+    mActive = false;
+    mProxy->interrupt();
+    mAudioRecord->stop();
+    // the record head position will reset to 0, so if a marker is set, we need
+    // to activate it again
+    mMarkerReached = false;
+    sp<AudioRecordThread> t = mAudioRecordThread;
+    if (t != 0) {
+        t->pause();
+    } else {
+        setpriority(PRIO_PROCESS, 0, mPreviousPriority);
+        set_sched_policy(0, mPreviousSchedulingGroup);
     }
 }
 
@@ -364,14 +350,11 @@
     return !mActive;
 }
 
-uint32_t AudioRecord::getSampleRate() const
-{
-    return mSampleRate;
-}
-
 status_t AudioRecord::setMarkerPosition(uint32_t marker)
 {
-    if (mCbf == NULL) return INVALID_OPERATION;
+    if (mCbf == NULL) {
+        return INVALID_OPERATION;
+    }
 
     AutoMutex lock(mLock);
     mMarkerPosition = marker;
@@ -382,7 +365,9 @@
 
 status_t AudioRecord::getMarkerPosition(uint32_t *marker) const
 {
-    if (marker == NULL) return BAD_VALUE;
+    if (marker == NULL) {
+        return BAD_VALUE;
+    }
 
     AutoMutex lock(mLock);
     *marker = mMarkerPosition;
@@ -392,13 +377,12 @@
 
 status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
 {
-    if (mCbf == NULL) return INVALID_OPERATION;
-
-    uint32_t curPosition;
-    getPosition(&curPosition);
+    if (mCbf == NULL) {
+        return INVALID_OPERATION;
+    }
 
     AutoMutex lock(mLock);
-    mNewPosition = curPosition + updatePeriod;
+    mNewPosition = mProxy->getPosition() + updatePeriod;
     mUpdatePeriod = updatePeriod;
 
     return NO_ERROR;
@@ -406,7 +390,9 @@
 
 status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod) const
 {
-    if (updatePeriod == NULL) return BAD_VALUE;
+    if (updatePeriod == NULL) {
+        return BAD_VALUE;
+    }
 
     AutoMutex lock(mLock);
     *updatePeriod = mUpdatePeriod;
@@ -416,10 +402,12 @@
 
 status_t AudioRecord::getPosition(uint32_t *position) const
 {
-    if (position == NULL) return BAD_VALUE;
+    if (position == NULL) {
+        return BAD_VALUE;
+    }
 
     AutoMutex lock(mLock);
-    *position = mCblk->user;
+    *position = mProxy->getPosition();
 
     return NO_ERROR;
 }
@@ -427,17 +415,13 @@
 unsigned int AudioRecord::getInputFramesLost() const
 {
     // no need to check mActive, because if inactive this will return 0, which is what we want
-    return AudioSystem::getInputFramesLost(mInput);
+    return AudioSystem::getInputFramesLost(getInput());
 }
 
 // -------------------------------------------------------------------------
 
 // must be called with mLock held
-status_t AudioRecord::openRecord_l(
-        uint32_t sampleRate,
-        audio_format_t format,
-        size_t frameCount,
-        audio_io_handle_t input)
+status_t AudioRecord::openRecord_l(size_t epoch)
 {
     status_t status;
     const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
@@ -446,23 +430,53 @@
         return NO_INIT;
     }
 
+    IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
     pid_t tid = -1;
-    // FIXME see similar logic at AudioTrack
+
+    // Client can only express a preference for FAST.  Server will perform additional tests.
+    // The only supported use case for FAST is callback transfer mode.
+    if (mFlags & AUDIO_INPUT_FLAG_FAST) {
+        if ((mTransfer != TRANSFER_CALLBACK) || (mAudioRecordThread == 0)) {
+            ALOGW("AUDIO_INPUT_FLAG_FAST denied by client");
+            // once denied, do not request again if IAudioRecord is re-created
+            mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST);
+        } else {
+            trackFlags |= IAudioFlinger::TRACK_FAST;
+            tid = mAudioRecordThread->getTid();
+        }
+    }
+
+    mNotificationFramesAct = mNotificationFramesReq;
+
+    if (!(mFlags & AUDIO_INPUT_FLAG_FAST)) {
+        // Make sure that application is notified with sufficient margin before overrun
+        if (mNotificationFramesAct == 0 || mNotificationFramesAct > mFrameCount/2) {
+            mNotificationFramesAct = mFrameCount/2;
+        }
+    }
+
+    audio_io_handle_t input = AudioSystem::getInput(mInputSource, mSampleRate, mFormat,
+            mChannelMask, mSessionId);
+    if (input == 0) {
+        ALOGE("Could not get audio input for record source %d", mInputSource);
+        return BAD_VALUE;
+    }
 
     int originalSessionId = mSessionId;
     sp<IAudioRecord> record = audioFlinger->openRecord(input,
-                                                       sampleRate, format,
+                                                       mSampleRate, mFormat,
                                                        mChannelMask,
-                                                       frameCount,
-                                                       IAudioFlinger::TRACK_DEFAULT,
+                                                       mFrameCount,
+                                                       &trackFlags,
                                                        tid,
                                                        &mSessionId,
                                                        &status);
     ALOGE_IF(originalSessionId != 0 && mSessionId != originalSessionId,
             "session ID changed from %d to %d", originalSessionId, mSessionId);
 
-    if (record == 0) {
+    if (record == 0 || status != NO_ERROR) {
         ALOGE("AudioFlinger could not create record track, status: %d", status);
+        AudioSystem::releaseInput(input);
         return status;
     }
     sp<IMemory> iMem = record->getCblk();
@@ -470,133 +484,163 @@
         ALOGE("Could not get control block");
         return NO_INIT;
     }
-    mAudioRecord.clear();
+    void *iMemPointer = iMem->pointer();
+    if (iMemPointer == NULL) {
+        ALOGE("Could not get control block pointer");
+        return NO_INIT;
+    }
+    if (mAudioRecord != 0) {
+        mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this);
+        mDeathNotifier.clear();
+    }
+    mInput = input;
     mAudioRecord = record;
-    mCblkMemory.clear();
     mCblkMemory = iMem;
-    audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMem->pointer());
+    audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
     mCblk = cblk;
-    mBuffers = (char*)cblk + sizeof(audio_track_cblk_t);
-    cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
-    cblk->waitTimeMs = 0;
+    // FIXME missing fast track frameCount logic
+    mAwaitBoost = false;
+    if (mFlags & AUDIO_INPUT_FLAG_FAST) {
+        if (trackFlags & IAudioFlinger::TRACK_FAST) {
+            ALOGV("AUDIO_INPUT_FLAG_FAST successful; frameCount %u", mFrameCount);
+            mAwaitBoost = true;
+            // double-buffering is not required for fast tracks, due to tighter scheduling
+            if (mNotificationFramesAct == 0 || mNotificationFramesAct > mFrameCount) {
+                mNotificationFramesAct = mFrameCount;
+            }
+        } else {
+            ALOGV("AUDIO_INPUT_FLAG_FAST denied by server; frameCount %u", mFrameCount);
+            // once denied, do not request again if IAudioRecord is re-created
+            mFlags = (audio_input_flags_t) (mFlags & ~AUDIO_INPUT_FLAG_FAST);
+            if (mNotificationFramesAct == 0 || mNotificationFramesAct > mFrameCount/2) {
+                mNotificationFramesAct = mFrameCount/2;
+            }
+        }
+    }
+
+    // starting address of buffers in shared memory
+    void *buffers = (char*)cblk + sizeof(audio_track_cblk_t);
 
     // update proxy
-    delete mProxy;
-    mProxy = new AudioRecordClientProxy(cblk, mBuffers, frameCount, mFrameSize);
+    mProxy = new AudioRecordClientProxy(cblk, buffers, mFrameCount, mFrameSize);
+    mProxy->setEpoch(epoch);
+    mProxy->setMinimum(mNotificationFramesAct);
+
+    mDeathNotifier = new DeathNotifier(this);
+    mAudioRecord->asBinder()->linkToDeath(mDeathNotifier, this);
 
     return NO_ERROR;
 }
 
 status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
 {
-    ALOG_ASSERT(mStatus == NO_ERROR && mProxy != NULL);
+    if (audioBuffer == NULL) {
+        return BAD_VALUE;
+    }
+    if (mTransfer != TRANSFER_OBTAIN) {
+        audioBuffer->frameCount = 0;
+        audioBuffer->size = 0;
+        audioBuffer->raw = NULL;
+        return INVALID_OPERATION;
+    }
 
-    AutoMutex lock(mLock);
-    bool active;
-    status_t result = NO_ERROR;
-    audio_track_cblk_t* cblk = mCblk;
-    uint32_t framesReq = audioBuffer->frameCount;
-    uint32_t waitTimeMs = (waitCount < 0) ? cblk->bufferTimeoutMs : WAIT_PERIOD_MS;
+    const struct timespec *requested;
+    struct timespec timeout;
+    if (waitCount == -1) {
+        requested = &ClientProxy::kForever;
+    } else if (waitCount == 0) {
+        requested = &ClientProxy::kNonBlocking;
+    } else if (waitCount > 0) {
+        long long ms = WAIT_PERIOD_MS * (long long) waitCount;
+        timeout.tv_sec = ms / 1000;
+        timeout.tv_nsec = (int) (ms % 1000) * 1000000;
+        requested = &timeout;
+    } else {
+        ALOGE("%s invalid waitCount %d", __func__, waitCount);
+        requested = NULL;
+    }
+    return obtainBuffer(audioBuffer, requested);
+}
 
-    audioBuffer->frameCount  = 0;
-    audioBuffer->size        = 0;
+status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, const struct timespec *requested,
+        struct timespec *elapsed, size_t *nonContig)
+{
+    // previous and new IAudioRecord sequence numbers are used to detect track re-creation
+    uint32_t oldSequence = 0;
+    uint32_t newSequence;
 
-    size_t framesReady = mProxy->framesReady();
+    Proxy::Buffer buffer;
+    status_t status = NO_ERROR;
 
-    if (framesReady == 0) {
-        cblk->lock.lock();
-        goto start_loop_here;
-        while (framesReady == 0) {
-            active = mActive;
-            if (CC_UNLIKELY(!active)) {
-                cblk->lock.unlock();
-                return NO_MORE_BUFFERS;
-            }
-            if (CC_UNLIKELY(!waitCount)) {
-                cblk->lock.unlock();
-                return WOULD_BLOCK;
-            }
-            if (!(cblk->flags & CBLK_INVALID)) {
-                mLock.unlock();
-                // this condition is in shared memory, so if IAudioRecord and control block
-                // are replaced due to mediaserver death or IAudioRecord invalidation then
-                // cv won't be signalled, but fortunately the timeout will limit the wait
-                result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
-                cblk->lock.unlock();
-                mLock.lock();
-                if (!mActive) {
-                    return status_t(STOPPED);
-                }
-                // IAudioRecord may have been re-created while mLock was unlocked
-                cblk = mCblk;
-                cblk->lock.lock();
-            }
-            if (cblk->flags & CBLK_INVALID) {
-                goto create_new_record;
-            }
-            if (CC_UNLIKELY(result != NO_ERROR)) {
-                cblk->waitTimeMs += waitTimeMs;
-                if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
-                    ALOGW(   "obtainBuffer timed out (is the CPU pegged?) "
-                            "user=%08x, server=%08x", cblk->user, cblk->server);
-                    cblk->lock.unlock();
-                    // callback thread or sync event hasn't changed
-                    result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0);
-                    cblk->lock.lock();
-                    if (result == DEAD_OBJECT) {
-                        android_atomic_or(CBLK_INVALID, &cblk->flags);
-create_new_record:
-                        audio_track_cblk_t* temp = cblk;
-                        result = AudioRecord::restoreRecord_l(temp);
-                        cblk = temp;
+    static const int32_t kMaxTries = 5;
+    int32_t tryCounter = kMaxTries;
+
+    do {
+        // obtainBuffer() is called with mutex unlocked, so keep extra references to these fields to
+        // keep them from going away if another thread re-creates the track during obtainBuffer()
+        sp<AudioRecordClientProxy> proxy;
+        sp<IMemory> iMem;
+        {
+            // start of lock scope
+            AutoMutex lock(mLock);
+
+            newSequence = mSequence;
+            // did previous obtainBuffer() fail due to media server death or voluntary invalidation?
+            if (status == DEAD_OBJECT) {
+                // re-create track, unless someone else has already done so
+                if (newSequence == oldSequence) {
+                    status = restoreRecord_l("obtainBuffer");
+                    if (status != NO_ERROR) {
+                        break;
                     }
-                    if (result != NO_ERROR) {
-                        ALOGW("obtainBuffer create Track error %d", result);
-                        cblk->lock.unlock();
-                        return result;
-                    }
-                    cblk->waitTimeMs = 0;
-                }
-                if (--waitCount == 0) {
-                    cblk->lock.unlock();
-                    return TIMED_OUT;
                 }
             }
-            // read the server count again
-        start_loop_here:
-            framesReady = mProxy->framesReady();
-        }
-        cblk->lock.unlock();
+            oldSequence = newSequence;
+
+            // Keep the extra references
+            proxy = mProxy;
+            iMem = mCblkMemory;
+
+            // Non-blocking if track is stopped
+            if (!mActive) {
+                requested = &ClientProxy::kNonBlocking;
+            }
+
+        }   // end of lock scope
+
+        buffer.mFrameCount = audioBuffer->frameCount;
+        // FIXME starts the requested timeout and elapsed over from scratch
+        status = proxy->obtainBuffer(&buffer, requested, elapsed);
+
+    } while ((status == DEAD_OBJECT) && (tryCounter-- > 0));
+
+    audioBuffer->frameCount = buffer.mFrameCount;
+    audioBuffer->size = buffer.mFrameCount * mFrameSize;
+    audioBuffer->raw = buffer.mRaw;
+    if (nonContig != NULL) {
+        *nonContig = buffer.mNonContig;
     }
-
-    cblk->waitTimeMs = 0;
-    // reset time out to running value after obtaining a buffer
-    cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
-
-    if (framesReq > framesReady) {
-        framesReq = framesReady;
-    }
-
-    uint32_t u = cblk->user;
-    uint32_t bufferEnd = cblk->userBase + mFrameCount;
-
-    if (framesReq > bufferEnd - u) {
-        framesReq = bufferEnd - u;
-    }
-
-    audioBuffer->frameCount  = framesReq;
-    audioBuffer->size        = framesReq * mFrameSize;
-    audioBuffer->raw         = mProxy->buffer(u);
-    active = mActive;
-    return active ? status_t(NO_ERROR) : status_t(STOPPED);
+    return status;
 }
 
 void AudioRecord::releaseBuffer(Buffer* audioBuffer)
 {
-    ALOG_ASSERT(mStatus == NO_ERROR && mProxy != NULL);
+    // all TRANSFER_* are valid
+
+    size_t stepCount = audioBuffer->size / mFrameSize;
+    if (stepCount == 0) {
+        return;
+    }
+
+    Proxy::Buffer buffer;
+    buffer.mFrameCount = stepCount;
+    buffer.mRaw = audioBuffer->raw;
 
     AutoMutex lock(mLock);
-    (void) mProxy->stepUser(audioBuffer->frameCount);
+    mInOverrun = false;
+    mProxy->releaseBuffer(&buffer);
+
+    // the server does not automatically disable recorder on overrun, so no need to restart
 }
 
 audio_io_handle_t AudioRecord::getInput() const
@@ -605,226 +649,324 @@
     return mInput;
 }
 
-// must be called with mLock held
-audio_io_handle_t AudioRecord::getInput_l()
-{
-    mInput = AudioSystem::getInput(mInputSource,
-                                mSampleRate,
-                                mFormat,
-                                mChannelMask,
-                                mSessionId);
-    return mInput;
-}
-
-int AudioRecord::getSessionId() const
-{
-    // no lock needed because session ID doesn't change after first set()
-    return mSessionId;
-}
-
 // -------------------------------------------------------------------------
 
 ssize_t AudioRecord::read(void* buffer, size_t userSize)
 {
-    ssize_t read = 0;
-    Buffer audioBuffer;
-    int8_t *dst = static_cast<int8_t*>(buffer);
+    if (mTransfer != TRANSFER_SYNC) {
+        return INVALID_OPERATION;
+    }
 
-    if (ssize_t(userSize) < 0) {
-        // sanity-check. user is most-likely passing an error code.
-        ALOGE("AudioRecord::read(buffer=%p, size=%u (%d)",
-                buffer, userSize, userSize);
+    if (ssize_t(userSize) < 0 || (buffer == NULL && userSize != 0)) {
+        // sanity-check. user is most-likely passing an error code, and it would
+        // make the return value ambiguous (actualSize vs error).
+        ALOGE("AudioRecord::read(buffer=%p, size=%u (%d)", buffer, userSize, userSize);
         return BAD_VALUE;
     }
 
-    mLock.lock();
-    // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
-    // while we are accessing the cblk
-    sp<IAudioRecord> audioRecord = mAudioRecord;
-    sp<IMemory> iMem = mCblkMemory;
-    mLock.unlock();
+    ssize_t read = 0;
+    Buffer audioBuffer;
 
-    do {
+    while (userSize >= mFrameSize) {
+        audioBuffer.frameCount = userSize / mFrameSize;
 
-        audioBuffer.frameCount = userSize/frameSize();
-
-        // By using a wait count corresponding to twice the timeout period in
-        // obtainBuffer() we give a chance to recover once for a read timeout
-        // (if media_server crashed for instance) before returning a length of
-        // 0 bytes read to the client
-        status_t err = obtainBuffer(&audioBuffer, ((2 * MAX_RUN_TIMEOUT_MS) / WAIT_PERIOD_MS));
+        status_t err = obtainBuffer(&audioBuffer, &ClientProxy::kForever);
         if (err < 0) {
-            // out of buffers, return #bytes written
-            if (err == status_t(NO_MORE_BUFFERS)) {
+            if (read > 0) {
                 break;
             }
-            if (err == status_t(TIMED_OUT)) {
-                // return partial transfer count
-                return read;
-            }
             return ssize_t(err);
         }
 
         size_t bytesRead = audioBuffer.size;
-        memcpy(dst, audioBuffer.i8, bytesRead);
-
-        dst += bytesRead;
+        memcpy(buffer, audioBuffer.i8, bytesRead);
+        buffer = ((char *) buffer) + bytesRead;
         userSize -= bytesRead;
         read += bytesRead;
 
         releaseBuffer(&audioBuffer);
-    } while (userSize);
+    }
 
     return read;
 }
 
 // -------------------------------------------------------------------------
 
-bool AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread)
+nsecs_t AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread)
 {
-    Buffer audioBuffer;
-    uint32_t frames = mRemainingFrames;
-    size_t readSize;
-
     mLock.lock();
-    // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
-    // while we are accessing the cblk
-    sp<IAudioRecord> audioRecord = mAudioRecord;
-    sp<IMemory> iMem = mCblkMemory;
-    audio_track_cblk_t* cblk = mCblk;
-    bool active = mActive;
-    uint32_t markerPosition = mMarkerPosition;
-    uint32_t newPosition = mNewPosition;
-    uint32_t user = cblk->user;
-    // determine whether a marker callback will be needed, while locked
-    bool needMarker = !mMarkerReached && (mMarkerPosition > 0) && (user >= mMarkerPosition);
-    if (needMarker) {
-        mMarkerReached = true;
+    if (mAwaitBoost) {
+        mAwaitBoost = false;
+        mLock.unlock();
+        static const int32_t kMaxTries = 5;
+        int32_t tryCounter = kMaxTries;
+        uint32_t pollUs = 10000;
+        do {
+            int policy = sched_getscheduler(0);
+            if (policy == SCHED_FIFO || policy == SCHED_RR) {
+                break;
+            }
+            usleep(pollUs);
+            pollUs <<= 1;
+        } while (tryCounter-- > 0);
+        if (tryCounter < 0) {
+            ALOGE("did not receive expected priority boost on time");
+        }
+        // Run again immediately
+        return 0;
     }
-    // determine the number of new position callback(s) that will be needed, while locked
+
+    // Can only reference mCblk while locked
+    int32_t flags = android_atomic_and(~CBLK_OVERRUN, &mCblk->mFlags);
+
+    // Check for track invalidation
+    if (flags & CBLK_INVALID) {
+        (void) restoreRecord_l("processAudioBuffer");
+        mLock.unlock();
+        // Run again immediately, but with a new IAudioRecord
+        return 0;
+    }
+
+    bool active = mActive;
+
+    // Manage overrun callback, must be done under lock to avoid race with releaseBuffer()
+    bool newOverrun = false;
+    if (flags & CBLK_OVERRUN) {
+        if (!mInOverrun) {
+            mInOverrun = true;
+            newOverrun = true;
+        }
+    }
+
+    // Get current position of server
+    size_t position = mProxy->getPosition();
+
+    // Manage marker callback
+    bool markerReached = false;
+    size_t markerPosition = mMarkerPosition;
+    // FIXME fails for wraparound, need 64 bits
+    if (!mMarkerReached && (markerPosition > 0) && (position >= markerPosition)) {
+        mMarkerReached = markerReached = true;
+    }
+
+    // Determine the number of new position callback(s) that will be needed, while locked
+    size_t newPosCount = 0;
+    size_t newPosition = mNewPosition;
     uint32_t updatePeriod = mUpdatePeriod;
-    uint32_t needNewPos = updatePeriod > 0 && user >= newPosition ?
-            ((user - newPosition) / updatePeriod) + 1 : 0;
-    mNewPosition = newPosition + updatePeriod * needNewPos;
+    // FIXME fails for wraparound, need 64 bits
+    if (updatePeriod > 0 && position >= newPosition) {
+        newPosCount = ((position - newPosition) / updatePeriod) + 1;
+        mNewPosition += updatePeriod * newPosCount;
+    }
+
+    // Cache other fields that will be needed soon
+    size_t notificationFrames = mNotificationFramesAct;
+    if (mRefreshRemaining) {
+        mRefreshRemaining = false;
+        mRemainingFrames = notificationFrames;
+        mRetryOnPartialBuffer = false;
+    }
+    size_t misalignment = mProxy->getMisalignment();
+    int32_t sequence = mSequence;
+
+    // These fields don't need to be cached, because they are assigned only by set():
+    //      mTransfer, mCbf, mUserData, mSampleRate
+
     mLock.unlock();
 
-    // perform marker callback, while unlocked
-    if (needMarker) {
+    // perform callbacks while unlocked
+    if (newOverrun) {
+        mCbf(EVENT_OVERRUN, mUserData, NULL);
+    }
+    if (markerReached) {
         mCbf(EVENT_MARKER, mUserData, &markerPosition);
     }
-
-    // perform new position callback(s), while unlocked
-    for (; needNewPos > 0; --needNewPos) {
-        uint32_t temp = newPosition;
+    while (newPosCount > 0) {
+        size_t temp = newPosition;
         mCbf(EVENT_NEW_POS, mUserData, &temp);
         newPosition += updatePeriod;
+        newPosCount--;
+    }
+    if (mObservedSequence != sequence) {
+        mObservedSequence = sequence;
+        mCbf(EVENT_NEW_IAUDIORECORD, mUserData, NULL);
     }
 
-    do {
-        audioBuffer.frameCount = frames;
-        // Calling obtainBuffer() with a wait count of 1
-        // limits wait time to WAIT_PERIOD_MS. This prevents from being
-        // stuck here not being able to handle timed events (position, markers).
-        status_t err = obtainBuffer(&audioBuffer, 1);
-        if (err < NO_ERROR) {
-            if (err != TIMED_OUT) {
-                ALOGE_IF(err != status_t(NO_MORE_BUFFERS),
-                        "Error obtaining an audio buffer, giving up.");
-                return false;
+    // if inactive, then don't run me again until re-started
+    if (!active) {
+        return NS_INACTIVE;
+    }
+
+    // Compute the estimated time until the next timed event (position, markers)
+    uint32_t minFrames = ~0;
+    if (!markerReached && position < markerPosition) {
+        minFrames = markerPosition - position;
+    }
+    if (updatePeriod > 0 && updatePeriod < minFrames) {
+        minFrames = updatePeriod;
+    }
+
+    // If > 0, poll periodically to recover from a stuck server.  A good value is 2.
+    static const uint32_t kPoll = 0;
+    if (kPoll > 0 && mTransfer == TRANSFER_CALLBACK && kPoll * notificationFrames < minFrames) {
+        minFrames = kPoll * notificationFrames;
+    }
+
+    // Convert frame units to time units
+    nsecs_t ns = NS_WHENEVER;
+    if (minFrames != (uint32_t) ~0) {
+        // This "fudge factor" avoids soaking CPU, and compensates for late progress by server
+        static const nsecs_t kFudgeNs = 10000000LL; // 10 ms
+        ns = ((minFrames * 1000000000LL) / mSampleRate) + kFudgeNs;
+    }
+
+    // If not supplying data by EVENT_MORE_DATA, then we're done
+    if (mTransfer != TRANSFER_CALLBACK) {
+        return ns;
+    }
+
+    struct timespec timeout;
+    const struct timespec *requested = &ClientProxy::kForever;
+    if (ns != NS_WHENEVER) {
+        timeout.tv_sec = ns / 1000000000LL;
+        timeout.tv_nsec = ns % 1000000000LL;
+        ALOGV("timeout %ld.%03d", timeout.tv_sec, (int) timeout.tv_nsec / 1000000);
+        requested = &timeout;
+    }
+
+    while (mRemainingFrames > 0) {
+
+        Buffer audioBuffer;
+        audioBuffer.frameCount = mRemainingFrames;
+        size_t nonContig;
+        status_t err = obtainBuffer(&audioBuffer, requested, NULL, &nonContig);
+        LOG_ALWAYS_FATAL_IF((err != NO_ERROR) != (audioBuffer.frameCount == 0),
+                "obtainBuffer() err=%d frameCount=%u", err, audioBuffer.frameCount);
+        requested = &ClientProxy::kNonBlocking;
+        size_t avail = audioBuffer.frameCount + nonContig;
+        ALOGV("obtainBuffer(%u) returned %u = %u + %u",
+                mRemainingFrames, avail, audioBuffer.frameCount, nonContig);
+        if (err != NO_ERROR) {
+            if (err == TIMED_OUT || err == WOULD_BLOCK || err == -EINTR) {
+                break;
             }
-            break;
+            ALOGE("Error %d obtaining an audio buffer, giving up.", err);
+            return NS_NEVER;
         }
-        if (err == status_t(STOPPED)) return false;
+
+        if (mRetryOnPartialBuffer) {
+            mRetryOnPartialBuffer = false;
+            if (avail < mRemainingFrames) {
+                int64_t myns = ((mRemainingFrames - avail) *
+                        1100000000LL) / mSampleRate;
+                if (ns < 0 || myns < ns) {
+                    ns = myns;
+                }
+                return ns;
+            }
+        }
 
         size_t reqSize = audioBuffer.size;
         mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
-        readSize = audioBuffer.size;
+        size_t readSize = audioBuffer.size;
 
         // Sanity check on returned size
-        if (ssize_t(readSize) <= 0) {
-            // The callback is done filling buffers
-            // Keep this thread going to handle timed events and
-            // still try to get more data in intervals of WAIT_PERIOD_MS
-            // but don't just loop and block the CPU, so wait
-            usleep(WAIT_PERIOD_MS*1000);
-            break;
+        if (ssize_t(readSize) < 0 || readSize > reqSize) {
+            ALOGE("EVENT_MORE_DATA requested %u bytes but callback returned %d bytes",
+                    reqSize, (int) readSize);
+            return NS_NEVER;
         }
-        if (readSize > reqSize) readSize = reqSize;
 
-        audioBuffer.size = readSize;
-        audioBuffer.frameCount = readSize/frameSize();
-        frames -= audioBuffer.frameCount;
+        if (readSize == 0) {
+            // The callback is done consuming buffers
+            // Keep this thread going to handle timed events and
+            // still try to provide more data in intervals of WAIT_PERIOD_MS
+            // but don't just loop and block the CPU, so wait
+            return WAIT_PERIOD_MS * 1000000LL;
+        }
+
+        size_t releasedFrames = readSize / mFrameSize;
+        audioBuffer.frameCount = releasedFrames;
+        mRemainingFrames -= releasedFrames;
+        if (misalignment >= releasedFrames) {
+            misalignment -= releasedFrames;
+        } else {
+            misalignment = 0;
+        }
 
         releaseBuffer(&audioBuffer);
 
-    } while (frames);
-
-
-    // Manage overrun callback
-    if (active && (mProxy->framesAvailable() == 0)) {
-        // The value of active is stale, but we are almost sure to be active here because
-        // otherwise we would have exited when obtainBuffer returned STOPPED earlier.
-        ALOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
-        if (!(android_atomic_or(CBLK_UNDERRUN, &cblk->flags) & CBLK_UNDERRUN)) {
-            mCbf(EVENT_OVERRUN, mUserData, NULL);
+        // FIXME here is where we would repeat EVENT_MORE_DATA again on same advanced buffer
+        // if callback doesn't like to accept the full chunk
+        if (readSize < reqSize) {
+            continue;
         }
-    }
 
-    if (frames == 0) {
-        mRemainingFrames = mNotificationFrames;
-    } else {
-        mRemainingFrames = frames;
+        // There could be enough non-contiguous frames available to satisfy the remaining request
+        if (mRemainingFrames <= nonContig) {
+            continue;
+        }
+
+#if 0
+        // This heuristic tries to collapse a series of EVENT_MORE_DATA that would total to a
+        // sum <= notificationFrames.  It replaces that series by at most two EVENT_MORE_DATA
+        // that total to a sum == notificationFrames.
+        if (0 < misalignment && misalignment <= mRemainingFrames) {
+            mRemainingFrames = misalignment;
+            return (mRemainingFrames * 1100000000LL) / mSampleRate;
+        }
+#endif
+
     }
-    return true;
+    mRemainingFrames = notificationFrames;
+    mRetryOnPartialBuffer = true;
+
+    // A lot has transpired since ns was calculated, so run again immediately and re-calculate
+    return 0;
 }
 
-// must be called with mLock and cblk.lock held. Callers must also hold strong references on
-// the IAudioRecord and IMemory in case they are recreated here.
-// If the IAudioRecord is successfully restored, the cblk pointer is updated
-status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& refCblk)
+status_t AudioRecord::restoreRecord_l(const char *from)
 {
+    ALOGW("dead IAudioRecord, creating a new one from %s()", from);
+    ++mSequence;
     status_t result;
 
-    audio_track_cblk_t* cblk = refCblk;
-    audio_track_cblk_t* newCblk = cblk;
-    ALOGW("dead IAudioRecord, creating a new one");
-
-    // signal old cblk condition so that other threads waiting for available buffers stop
-    // waiting now
-    cblk->cv.broadcast();
-    cblk->lock.unlock();
-
     // if the new IAudioRecord is created, openRecord_l() will modify the
     // following member variables: mAudioRecord, mCblkMemory and mCblk.
     // It will also delete the strong references on previous IAudioRecord and IMemory
-    result = openRecord_l(mSampleRate, mFormat, mFrameCount, getInput_l());
+    size_t position = mProxy->getPosition();
+    mNewPosition = position + mUpdatePeriod;
+    result = openRecord_l(position);
     if (result == NO_ERROR) {
-        newCblk = mCblk;
-        // callback thread or sync event hasn't changed
-        result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0);
+        if (mActive) {
+            // callback thread or sync event hasn't changed
+            // FIXME this fails if we have a new AudioFlinger instance
+            result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0);
+        }
     }
     if (result != NO_ERROR) {
+        ALOGW("restoreRecord_l() failed status %d", result);
         mActive = false;
     }
 
-    ALOGV("restoreRecord_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x",
-        result, mActive, newCblk, cblk, newCblk->flags, cblk->flags);
-
-    if (result == NO_ERROR) {
-        // from now on we switch to the newly created cblk
-        refCblk = newCblk;
-    }
-    newCblk->lock.lock();
-
-    ALOGW_IF(result != NO_ERROR, "restoreRecord_l() error %d", result);
-
     return result;
 }
 
 // =========================================================================
 
+void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who)
+{
+    sp<AudioRecord> audioRecord = mAudioRecord.promote();
+    if (audioRecord != 0) {
+        AutoMutex lock(audioRecord->mLock);
+        audioRecord->mProxy->binderDied();
+    }
+}
+
+// =========================================================================
+
 AudioRecord::AudioRecordThread::AudioRecordThread(AudioRecord& receiver, bool bCanCallJava)
-    : Thread(bCanCallJava), mReceiver(receiver), mPaused(true)
+    : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL)
 {
 }
 
@@ -841,18 +983,46 @@
             // caller will check for exitPending()
             return true;
         }
+        if (mPausedInt) {
+            if (mPausedNs > 0) {
+                (void) mMyCond.waitRelative(mMyLock, mPausedNs);
+            } else {
+                mMyCond.wait(mMyLock);
+            }
+            mPausedInt = false;
+            return true;
+        }
     }
-    if (!mReceiver.processAudioBuffer(this)) {
-        pause();
+    nsecs_t ns =  mReceiver.processAudioBuffer(this);
+    switch (ns) {
+    case 0:
+        return true;
+    case NS_INACTIVE:
+        pauseInternal();
+        return true;
+    case NS_NEVER:
+        return false;
+    case NS_WHENEVER:
+        // FIXME increase poll interval, or make event-driven
+        ns = 1000000000LL;
+        // fall through
+    default:
+        LOG_ALWAYS_FATAL_IF(ns < 0, "processAudioBuffer() returned %lld", ns);
+        pauseInternal(ns);
+        return true;
     }
-    return true;
 }
 
 void AudioRecord::AudioRecordThread::requestExit()
 {
     // must be in this order to avoid a race condition
     Thread::requestExit();
-    resume();
+    AutoMutex _l(mMyLock);
+    if (mPaused || mPausedInt) {
+        mPaused = false;
+        mPausedInt = false;
+        mMyCond.signal();
+    }
 }
 
 void AudioRecord::AudioRecordThread::pause()
@@ -864,12 +1034,20 @@
 void AudioRecord::AudioRecordThread::resume()
 {
     AutoMutex _l(mMyLock);
-    if (mPaused) {
+    if (mPaused || mPausedInt) {
         mPaused = false;
+        mPausedInt = false;
         mMyCond.signal();
     }
 }
 
+void AudioRecord::AudioRecordThread::pauseInternal(nsecs_t ns)
+{
+    AutoMutex _l(mMyLock);
+    mPausedInt = true;
+    mPausedNs = ns;
+}
+
 // -------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 693df60..8033c2c 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -20,6 +20,7 @@
 #include <utils/Log.h>
 #include <binder/IServiceManager.h>
 #include <media/AudioSystem.h>
+#include <media/IAudioFlinger.h>
 #include <media/IAudioPolicyService.h>
 #include <math.h>
 
@@ -75,6 +76,14 @@
     return gAudioFlinger;
 }
 
+/* static */ status_t AudioSystem::checkAudioFlinger()
+{
+    if (defaultServiceManager()->checkService(String16("media.audio_flinger")) != 0) {
+        return NO_ERROR;
+    }
+    return DEAD_OBJECT;
+}
+
 status_t AudioSystem::muteMicrophone(bool state) {
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
@@ -361,8 +370,8 @@
     return af->setVoiceVolume(value);
 }
 
-status_t AudioSystem::getRenderPosition(size_t *halFrames, size_t *dspFrames,
-        audio_stream_type_t stream)
+status_t AudioSystem::getRenderPosition(audio_io_handle_t output, size_t *halFrames,
+                                        size_t *dspFrames, audio_stream_type_t stream)
 {
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
@@ -371,7 +380,11 @@
         stream = AUDIO_STREAM_MUSIC;
     }
 
-    return af->getRenderPosition(halFrames, dspFrames, getOutput(stream));
+    if (output == 0) {
+        output = getOutput(stream);
+    }
+
+    return af->getRenderPosition(halFrames, dspFrames, output);
 }
 
 size_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) {
@@ -442,14 +455,14 @@
 
         OutputDescriptor *outputDesc =  new OutputDescriptor(*desc);
         gOutputs.add(ioHandle, outputDesc);
-        ALOGV("ioConfigChanged() new output samplingRate %u, format %d channels %#x frameCount %u "
+        ALOGV("ioConfigChanged() new output samplingRate %u, format %d channel mask %#x frameCount %u "
                 "latency %d",
-                outputDesc->samplingRate, outputDesc->format, outputDesc->channels,
+                outputDesc->samplingRate, outputDesc->format, outputDesc->channelMask,
                 outputDesc->frameCount, outputDesc->latency);
         } break;
     case OUTPUT_CLOSED: {
         if (gOutputs.indexOfKey(ioHandle) < 0) {
-            ALOGW("ioConfigChanged() closing unknow output! %d", ioHandle);
+            ALOGW("ioConfigChanged() closing unknown output! %d", ioHandle);
             break;
         }
         ALOGV("ioConfigChanged() output %d closed", ioHandle);
@@ -460,16 +473,16 @@
     case OUTPUT_CONFIG_CHANGED: {
         int index = gOutputs.indexOfKey(ioHandle);
         if (index < 0) {
-            ALOGW("ioConfigChanged() modifying unknow output! %d", ioHandle);
+            ALOGW("ioConfigChanged() modifying unknown output! %d", ioHandle);
             break;
         }
         if (param2 == NULL) break;
         desc = (const OutputDescriptor *)param2;
 
-        ALOGV("ioConfigChanged() new config for output %d samplingRate %u, format %d channels %#x "
+        ALOGV("ioConfigChanged() new config for output %d samplingRate %u, format %d channel mask %#x "
                 "frameCount %d latency %d",
                 ioHandle, desc->samplingRate, desc->format,
-                desc->channels, desc->frameCount, desc->latency);
+                desc->channelMask, desc->frameCount, desc->latency);
         OutputDescriptor *outputDesc = gOutputs.valueAt(index);
         delete outputDesc;
         outputDesc =  new OutputDescriptor(*desc);
@@ -532,6 +545,8 @@
     return gAudioPolicyService;
 }
 
+// ---------------------------------------------------------------------------
+
 status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
                                                audio_policy_dev_state_t state,
                                                const char *device_address)
@@ -585,11 +600,12 @@
                                     uint32_t samplingRate,
                                     audio_format_t format,
                                     audio_channel_mask_t channelMask,
-                                    audio_output_flags_t flags)
+                                    audio_output_flags_t flags,
+                                    const audio_offload_info_t *offloadInfo)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return 0;
-    return aps->getOutput(stream, samplingRate, format, channelMask, flags);
+    return aps->getOutput(stream, samplingRate, format, channelMask, flags, offloadInfo);
 }
 
 status_t AudioSystem::startOutput(audio_io_handle_t output,
@@ -764,6 +780,13 @@
     return af->getPrimaryOutputFrameCount();
 }
 
+status_t AudioSystem::setLowRamDevice(bool isLowRamDevice)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    return af->setLowRamDevice(isLowRamDevice);
+}
+
 void AudioSystem::clearAudioConfigCache()
 {
     Mutex::Autolock _l(gLock);
@@ -771,6 +794,14 @@
     gOutputs.clear();
 }
 
+bool AudioSystem::isOffloadSupported(const audio_offload_info_t& info)
+{
+    ALOGV("isOffloadSupported()");
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return false;
+    return aps->isOffloadSupported(info);
+}
+
 // ---------------------------------------------------------------------------
 
 void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who) {
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 7eeb4f8..e290627 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -19,31 +19,17 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "AudioTrack"
 
-#include <stdint.h>
-#include <sys/types.h>
-#include <limits.h>
-
-#include <sched.h>
 #include <sys/resource.h>
-
-#include <private/media/AudioTrackShared.h>
-
-#include <media/AudioSystem.h>
-#include <media/AudioTrack.h>
-
-#include <utils/Log.h>
-#include <binder/Parcel.h>
-#include <binder/IPCThreadState.h>
-#include <utils/Timers.h>
-#include <utils/Atomic.h>
-
-#include <cutils/bitops.h>
-#include <cutils/compiler.h>
-
-#include <system/audio.h>
-#include <system/audio_policy.h>
-
 #include <audio_utils/primitives.h>
+#include <binder/IPCThreadState.h>
+#include <media/AudioTrack.h>
+#include <utils/Log.h>
+#include <private/media/AudioTrackShared.h>
+#include <media/IAudioFlinger.h>
+
+#define WAIT_PERIOD_MS                  10
+#define WAIT_STREAM_END_TIMEOUT_SEC     120
+
 
 namespace android {
 // ---------------------------------------------------------------------------
@@ -82,7 +68,9 @@
 
     // Ensure that buffer depth covers at least audio hardware latency
     uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate);
-    if (minBufCount < 2) minBufCount = 2;
+    if (minBufCount < 2) {
+        minBufCount = 2;
+    }
 
     *frameCount = (sampleRate == 0) ? afFrameCount * minBufCount :
             afFrameCount * minBufCount * sampleRate / afSampleRate;
@@ -98,7 +86,7 @@
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
-      mProxy(NULL)
+      mPausedPosition(0)
 {
 }
 
@@ -112,16 +100,20 @@
         callback_t cbf,
         void* user,
         int notificationFrames,
-        int sessionId)
+        int sessionId,
+        transfer_type transferType,
+        const audio_offload_info_t *offloadInfo,
+        int uid)
     : mStatus(NO_INIT),
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
-      mProxy(NULL)
+      mPausedPosition(0)
 {
     mStatus = set(streamType, sampleRate, format, channelMask,
             frameCount, flags, cbf, user, notificationFrames,
-            0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId);
+            0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType,
+            offloadInfo, uid);
 }
 
 AudioTrack::AudioTrack(
@@ -134,42 +126,39 @@
         callback_t cbf,
         void* user,
         int notificationFrames,
-        int sessionId)
+        int sessionId,
+        transfer_type transferType,
+        const audio_offload_info_t *offloadInfo,
+        int uid)
     : mStatus(NO_INIT),
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
-      mProxy(NULL)
+      mPausedPosition(0)
 {
-    if (sharedBuffer == 0) {
-        ALOGE("sharedBuffer must be non-0");
-        mStatus = BAD_VALUE;
-        return;
-    }
     mStatus = set(streamType, sampleRate, format, channelMask,
             0 /*frameCount*/, flags, cbf, user, notificationFrames,
-            sharedBuffer, false /*threadCanCallJava*/, sessionId);
+            sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo, uid);
 }
 
 AudioTrack::~AudioTrack()
 {
-    ALOGV_IF(mSharedBuffer != 0, "Destructor sharedBuffer: %p", mSharedBuffer->pointer());
-
     if (mStatus == NO_ERROR) {
         // Make sure that callback function exits in the case where
         // it is looping on buffer full condition in obtainBuffer().
         // Otherwise the callback thread will never exit.
         stop();
         if (mAudioTrackThread != 0) {
+            mProxy->interrupt();
             mAudioTrackThread->requestExit();   // see comment in AudioTrack.h
             mAudioTrackThread->requestExitAndWait();
             mAudioTrackThread.clear();
         }
+        mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
         mAudioTrack.clear();
         IPCThreadState::self()->flushCommands();
         AudioSystem::releaseAudioSessionId(mSessionId);
     }
-    delete mProxy;
 }
 
 status_t AudioTrack::set(
@@ -184,8 +173,46 @@
         int notificationFrames,
         const sp<IMemory>& sharedBuffer,
         bool threadCanCallJava,
-        int sessionId)
+        int sessionId,
+        transfer_type transferType,
+        const audio_offload_info_t *offloadInfo,
+        int uid)
 {
+    switch (transferType) {
+    case TRANSFER_DEFAULT:
+        if (sharedBuffer != 0) {
+            transferType = TRANSFER_SHARED;
+        } else if (cbf == NULL || threadCanCallJava) {
+            transferType = TRANSFER_SYNC;
+        } else {
+            transferType = TRANSFER_CALLBACK;
+        }
+        break;
+    case TRANSFER_CALLBACK:
+        if (cbf == NULL || sharedBuffer != 0) {
+            ALOGE("Transfer type TRANSFER_CALLBACK but cbf == NULL || sharedBuffer != 0");
+            return BAD_VALUE;
+        }
+        break;
+    case TRANSFER_OBTAIN:
+    case TRANSFER_SYNC:
+        if (sharedBuffer != 0) {
+            ALOGE("Transfer type TRANSFER_OBTAIN but sharedBuffer != 0");
+            return BAD_VALUE;
+        }
+        break;
+    case TRANSFER_SHARED:
+        if (sharedBuffer == 0) {
+            ALOGE("Transfer type TRANSFER_SHARED but sharedBuffer == 0");
+            return BAD_VALUE;
+        }
+        break;
+    default:
+        ALOGE("Invalid transfer type %d", transferType);
+        return BAD_VALUE;
+    }
+    mTransfer = transferType;
+
     // FIXME "int" here is legacy and will be replaced by size_t later
     if (frameCountInt < 0) {
         ALOGE("Invalid frame count %d", frameCountInt);
@@ -199,11 +226,15 @@
     ALOGV("set() streamType %d frameCount %u flags %04x", streamType, frameCount, flags);
 
     AutoMutex lock(mLock);
+
+    // invariant that mAudioTrack != 0 is true only after set() returns successfully
     if (mAudioTrack != 0) {
         ALOGE("Track already in use");
         return INVALID_OPERATION;
     }
 
+    mOutput = 0;
+
     // handle default values first.
     if (streamType == AUDIO_STREAM_DEFAULT) {
         streamType = AUDIO_STREAM_MUSIC;
@@ -228,7 +259,7 @@
 
     // validate parameters
     if (!audio_is_valid_format(format)) {
-        ALOGE("Invalid format");
+        ALOGE("Invalid format %d", format);
         return BAD_VALUE;
     }
 
@@ -239,7 +270,12 @@
     }
 
     // force direct flag if format is not linear PCM
-    if (!audio_is_linear_pcm(format)) {
+    // or offload was requested
+    if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
+            || !audio_is_linear_pcm(format)) {
+        ALOGV( (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
+                    ? "Offload request, forcing to Direct Output"
+                    : "Not linear PCM, forcing to Direct Output");
         flags = (audio_output_flags_t)
                 // FIXME why can't we allow direct AND fast?
                 ((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST);
@@ -268,7 +304,8 @@
     audio_io_handle_t output = AudioSystem::getOutput(
                                     streamType,
                                     sampleRate, format, channelMask,
-                                    flags);
+                                    flags,
+                                    offloadInfo);
 
     if (output == 0) {
         ALOGE("Could not get audio output for stream type %d", streamType);
@@ -281,7 +318,13 @@
     mFrameCount = frameCount;
     mReqFrameCount = frameCount;
     mNotificationFramesReq = notificationFrames;
+    mNotificationFramesAct = 0;
     mSessionId = sessionId;
+    if (uid == -1 || (IPCThreadState::self()->getCallingPid() != getpid())) {
+        mClientUid = IPCThreadState::self()->getCallingUid();
+    } else {
+        mClientUid = uid;
+    }
     mAuxEffectId = 0;
     mFlags = flags;
     mCbf = cbf;
@@ -298,178 +341,211 @@
                                   frameCount,
                                   flags,
                                   sharedBuffer,
-                                  output);
+                                  output,
+                                  0 /*epoch*/);
 
     if (status != NO_ERROR) {
         if (mAudioTrackThread != 0) {
-            mAudioTrackThread->requestExit();
+            mAudioTrackThread->requestExit();   // see comment in AudioTrack.h
+            mAudioTrackThread->requestExitAndWait();
             mAudioTrackThread.clear();
         }
+        //Use of direct and offloaded output streams is ref counted by audio policy manager.
+        // As getOutput was called above and resulted in an output stream to be opened,
+        // we need to release it.
+        AudioSystem::releaseOutput(output);
         return status;
     }
 
     mStatus = NO_ERROR;
-
     mStreamType = streamType;
     mFormat = format;
-
     mSharedBuffer = sharedBuffer;
-    mActive = false;
+    mState = STATE_STOPPED;
     mUserData = user;
-    mLoopCount = 0;
+    mLoopPeriod = 0;
     mMarkerPosition = 0;
     mMarkerReached = false;
     mNewPosition = 0;
     mUpdatePeriod = 0;
-    mFlushed = false;
     AudioSystem::acquireAudioSessionId(mSessionId);
+    mSequence = 1;
+    mObservedSequence = mSequence;
+    mInUnderrun = false;
+    mOutput = output;
+
     return NO_ERROR;
 }
 
 // -------------------------------------------------------------------------
 
-void AudioTrack::start()
+status_t AudioTrack::start()
 {
-    sp<AudioTrackThread> t = mAudioTrackThread;
-
-    ALOGV("start %p", this);
-
     AutoMutex lock(mLock);
-    // 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;
-    audio_track_cblk_t* cblk = mCblk;
 
-    if (!mActive) {
-        mFlushed = false;
-        mActive = true;
-        mNewPosition = cblk->server + mUpdatePeriod;
-        cblk->lock.lock();
-        cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
-        cblk->waitTimeMs = 0;
-        android_atomic_and(~CBLK_DISABLED, &cblk->flags);
-        if (t != 0) {
-            t->resume();
-        } else {
-            mPreviousPriority = getpriority(PRIO_PROCESS, 0);
-            get_sched_policy(0, &mPreviousSchedulingGroup);
-            androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
-        }
-
-        ALOGV("start %p before lock cblk %p", this, cblk);
-        status_t status = NO_ERROR;
-        if (!(cblk->flags & CBLK_INVALID)) {
-            cblk->lock.unlock();
-            ALOGV("mAudioTrack->start()");
-            status = mAudioTrack->start();
-            cblk->lock.lock();
-            if (status == DEAD_OBJECT) {
-                android_atomic_or(CBLK_INVALID, &cblk->flags);
-            }
-        }
-        if (cblk->flags & CBLK_INVALID) {
-            audio_track_cblk_t* temp = cblk;
-            status = restoreTrack_l(temp, true /*fromStart*/);
-            cblk = temp;
-        }
-        cblk->lock.unlock();
-        if (status != NO_ERROR) {
-            ALOGV("start() failed");
-            mActive = false;
-            if (t != 0) {
-                t->pause();
-            } else {
-                setpriority(PRIO_PROCESS, 0, mPreviousPriority);
-                set_sched_policy(0, mPreviousSchedulingGroup);
-            }
-        }
+    if (mState == STATE_ACTIVE) {
+        return INVALID_OPERATION;
     }
 
-}
+    mInUnderrun = true;
 
-void AudioTrack::stop()
-{
+    State previousState = mState;
+    if (previousState == STATE_PAUSED_STOPPING) {
+        mState = STATE_STOPPING;
+    } else {
+        mState = STATE_ACTIVE;
+    }
+    if (previousState == STATE_STOPPED || previousState == STATE_FLUSHED) {
+        // reset current position as seen by client to 0
+        mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());
+        // force refresh of remaining frames by processAudioBuffer() as last
+        // write before stop could be partial.
+        mRefreshRemaining = true;
+    }
+    mNewPosition = mProxy->getPosition() + mUpdatePeriod;
+    int32_t flags = android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags);
+
     sp<AudioTrackThread> t = mAudioTrackThread;
-
-    ALOGV("stop %p", this);
-
-    AutoMutex lock(mLock);
-    if (mActive) {
-        mActive = false;
-        mCblk->cv.signal();
-        mAudioTrack->stop();
-        // Cancel loops (If we are in the middle of a loop, playback
-        // would not stop until loopCount reaches 0).
-        setLoop_l(0, 0, 0);
-        // the playback head position will reset to 0, so if a marker is set, we need
-        // to activate it again
-        mMarkerReached = false;
-        // Force flush if a shared buffer is used otherwise audioflinger
-        // will not stop before end of buffer is reached.
-        // It may be needed to make sure that we stop playback, likely in case looping is on.
-        if (mSharedBuffer != 0) {
-            flush_l();
+    if (t != 0) {
+        if (previousState == STATE_STOPPING) {
+            mProxy->interrupt();
+        } else {
+            t->resume();
         }
+    } else {
+        mPreviousPriority = getpriority(PRIO_PROCESS, 0);
+        get_sched_policy(0, &mPreviousSchedulingGroup);
+        androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
+    }
+
+    status_t status = NO_ERROR;
+    if (!(flags & CBLK_INVALID)) {
+        status = mAudioTrack->start();
+        if (status == DEAD_OBJECT) {
+            flags |= CBLK_INVALID;
+        }
+    }
+    if (flags & CBLK_INVALID) {
+        status = restoreTrack_l("start");
+    }
+
+    if (status != NO_ERROR) {
+        ALOGE("start() status %d", status);
+        mState = previousState;
         if (t != 0) {
-            t->pause();
+            if (previousState != STATE_STOPPING) {
+                t->pause();
+            }
         } else {
             setpriority(PRIO_PROCESS, 0, mPreviousPriority);
             set_sched_policy(0, mPreviousSchedulingGroup);
         }
     }
 
+    return status;
+}
+
+void AudioTrack::stop()
+{
+    AutoMutex lock(mLock);
+    // FIXME pause then stop should not be a nop
+    if (mState != STATE_ACTIVE) {
+        return;
+    }
+
+    if (isOffloaded()) {
+        mState = STATE_STOPPING;
+    } else {
+        mState = STATE_STOPPED;
+    }
+
+    mProxy->interrupt();
+    mAudioTrack->stop();
+    // the playback head position will reset to 0, so if a marker is set, we need
+    // to activate it again
+    mMarkerReached = false;
+#if 0
+    // Force flush if a shared buffer is used otherwise audioflinger
+    // will not stop before end of buffer is reached.
+    // It may be needed to make sure that we stop playback, likely in case looping is on.
+    if (mSharedBuffer != 0) {
+        flush_l();
+    }
+#endif
+
+    sp<AudioTrackThread> t = mAudioTrackThread;
+    if (t != 0) {
+        if (!isOffloaded()) {
+            t->pause();
+        }
+    } else {
+        setpriority(PRIO_PROCESS, 0, mPreviousPriority);
+        set_sched_policy(0, mPreviousSchedulingGroup);
+    }
 }
 
 bool AudioTrack::stopped() const
 {
     AutoMutex lock(mLock);
-    return stopped_l();
+    return mState != STATE_ACTIVE;
 }
 
 void AudioTrack::flush()
 {
-    AutoMutex lock(mLock);
-    if (!mActive && mSharedBuffer == 0) {
-        flush_l();
+    if (mSharedBuffer != 0) {
+        return;
     }
+    AutoMutex lock(mLock);
+    if (mState == STATE_ACTIVE || mState == STATE_FLUSHED) {
+        return;
+    }
+    flush_l();
 }
 
 void AudioTrack::flush_l()
 {
-    ALOGV("flush");
-    ALOG_ASSERT(!mActive);
+    ALOG_ASSERT(mState != STATE_ACTIVE);
 
     // clear playback marker and periodic update counter
     mMarkerPosition = 0;
     mMarkerReached = false;
     mUpdatePeriod = 0;
+    mRefreshRemaining = true;
 
-    mFlushed = true;
+    mState = STATE_FLUSHED;
+    if (isOffloaded()) {
+        mProxy->interrupt();
+    }
+    mProxy->flush();
     mAudioTrack->flush();
-    // Release AudioTrack callback thread in case it was waiting for new buffers
-    // in AudioTrack::obtainBuffer()
-    mCblk->cv.signal();
 }
 
 void AudioTrack::pause()
 {
-    ALOGV("pause");
     AutoMutex lock(mLock);
-    if (mActive) {
-        mActive = false;
-        mCblk->cv.signal();
-        mAudioTrack->pause();
+    if (mState == STATE_ACTIVE) {
+        mState = STATE_PAUSED;
+    } else if (mState == STATE_STOPPING) {
+        mState = STATE_PAUSED_STOPPING;
+    } else {
+        return;
+    }
+    mProxy->interrupt();
+    mAudioTrack->pause();
+
+    if (isOffloaded()) {
+        if (mOutput != 0) {
+            uint32_t halFrames;
+            // OffloadThread sends HAL pause in its threadLoop.. time saved
+            // here can be slightly off
+            AudioSystem::getRenderPosition(mOutput, &halFrames, &mPausedPosition);
+            ALOGV("AudioTrack::pause for offload, cache current position %u", mPausedPosition);
+        }
     }
 }
 
 status_t AudioTrack::setVolume(float left, float right)
 {
-    if (mStatus != NO_ERROR) {
-        return mStatus;
-    }
-    ALOG_ASSERT(mProxy != NULL);
-
     if (left < 0.0f || left > 1.0f || right < 0.0f || right > 1.0f) {
         return BAD_VALUE;
     }
@@ -480,6 +556,9 @@
 
     mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
 
+    if (isOffloaded()) {
+        mAudioTrack->signal();
+    }
     return NO_ERROR;
 }
 
@@ -490,18 +569,11 @@
 
 status_t AudioTrack::setAuxEffectSendLevel(float level)
 {
-    ALOGV("setAuxEffectSendLevel(%f)", level);
-
-    if (mStatus != NO_ERROR) {
-        return mStatus;
-    }
-    ALOG_ASSERT(mProxy != NULL);
-
     if (level < 0.0f || level > 1.0f) {
         return BAD_VALUE;
     }
-    AutoMutex lock(mLock);
 
+    AutoMutex lock(mLock);
     mSendLevel = level;
     mProxy->setSendLevel(level);
 
@@ -511,18 +583,17 @@
 void AudioTrack::getAuxEffectSendLevel(float* level) const
 {
     if (level != NULL) {
-        *level  = mSendLevel;
+        *level = mSendLevel;
     }
 }
 
 status_t AudioTrack::setSampleRate(uint32_t rate)
 {
-    uint32_t afSamplingRate;
-
-    if (mIsTimed) {
+    if (mIsTimed || isOffloaded()) {
         return INVALID_OPERATION;
     }
 
+    uint32_t afSamplingRate;
     if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) {
         return NO_INIT;
     }
@@ -545,63 +616,63 @@
     }
 
     AutoMutex lock(mLock);
+
+    // sample rate can be updated during playback by the offloaded decoder so we need to
+    // query the HAL and update if needed.
+// FIXME use Proxy return channel to update the rate from server and avoid polling here
+    if (isOffloaded()) {
+        if (mOutput != 0) {
+            uint32_t sampleRate = 0;
+            status_t status = AudioSystem::getSamplingRate(mOutput, mStreamType, &sampleRate);
+            if (status == NO_ERROR) {
+                mSampleRate = sampleRate;
+            }
+        }
+    }
     return mSampleRate;
 }
 
 status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
 {
-    AutoMutex lock(mLock);
-    return setLoop_l(loopStart, loopEnd, loopCount);
-}
-
-// must be called with mLock held
-status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount)
-{
-    if (mSharedBuffer == 0 || mIsTimed) {
+    if (mSharedBuffer == 0 || mIsTimed || isOffloaded()) {
         return INVALID_OPERATION;
     }
 
-    audio_track_cblk_t* cblk = mCblk;
-
-    Mutex::Autolock _l(cblk->lock);
-
     if (loopCount == 0) {
-        cblk->loopStart = UINT_MAX;
-        cblk->loopEnd = UINT_MAX;
-        cblk->loopCount = 0;
-        mLoopCount = 0;
-        return NO_ERROR;
-    }
-
-    if (loopStart >= loopEnd ||
-        loopEnd - loopStart > mFrameCount ||
-        cblk->server > loopStart) {
-        ALOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, "
-              "user %d", loopStart, loopEnd, loopCount, mFrameCount, cblk->user);
+        ;
+    } else if (loopCount >= -1 && loopStart < loopEnd && loopEnd <= mFrameCount &&
+            loopEnd - loopStart >= MIN_LOOP) {
+        ;
+    } else {
         return BAD_VALUE;
     }
 
-    if ((mSharedBuffer != 0) && (loopEnd > mFrameCount)) {
-        ALOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, "
-            "framecount %d",
-            loopStart, loopEnd, mFrameCount);
-        return BAD_VALUE;
+    AutoMutex lock(mLock);
+    // See setPosition() regarding setting parameters such as loop points or position while active
+    if (mState == STATE_ACTIVE) {
+        return INVALID_OPERATION;
     }
-
-    cblk->loopStart = loopStart;
-    cblk->loopEnd = loopEnd;
-    cblk->loopCount = loopCount;
-    mLoopCount = loopCount;
-
+    setLoop_l(loopStart, loopEnd, loopCount);
     return NO_ERROR;
 }
 
+void AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount)
+{
+    // FIXME If setting a loop also sets position to start of loop, then
+    //       this is correct.  Otherwise it should be removed.
+    mNewPosition = mProxy->getPosition() + mUpdatePeriod;
+    mLoopPeriod = loopCount != 0 ? loopEnd - loopStart : 0;
+    mStaticProxy->setLoop(loopStart, loopEnd, loopCount);
+}
+
 status_t AudioTrack::setMarkerPosition(uint32_t marker)
 {
-    if (mCbf == NULL) {
+    // The only purpose of setting marker position is to get a callback
+    if (mCbf == NULL || isOffloaded()) {
         return INVALID_OPERATION;
     }
 
+    AutoMutex lock(mLock);
     mMarkerPosition = marker;
     mMarkerReached = false;
 
@@ -610,10 +681,14 @@
 
 status_t AudioTrack::getMarkerPosition(uint32_t *marker) const
 {
+    if (isOffloaded()) {
+        return INVALID_OPERATION;
+    }
     if (marker == NULL) {
         return BAD_VALUE;
     }
 
+    AutoMutex lock(mLock);
     *marker = mMarkerPosition;
 
     return NO_ERROR;
@@ -621,24 +696,27 @@
 
 status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod)
 {
-    if (mCbf == NULL) {
+    // The only purpose of setting position update period is to get a callback
+    if (mCbf == NULL || isOffloaded()) {
         return INVALID_OPERATION;
     }
 
-    uint32_t curPosition;
-    getPosition(&curPosition);
-    mNewPosition = curPosition + updatePeriod;
+    AutoMutex lock(mLock);
+    mNewPosition = mProxy->getPosition() + updatePeriod;
     mUpdatePeriod = updatePeriod;
-
     return NO_ERROR;
 }
 
 status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod) const
 {
+    if (isOffloaded()) {
+        return INVALID_OPERATION;
+    }
     if (updatePeriod == NULL) {
         return BAD_VALUE;
     }
 
+    AutoMutex lock(mLock);
     *updatePeriod = mUpdatePeriod;
 
     return NO_ERROR;
@@ -646,80 +724,114 @@
 
 status_t AudioTrack::setPosition(uint32_t position)
 {
-    if (mSharedBuffer == 0 || mIsTimed) {
+    if (mSharedBuffer == 0 || mIsTimed || isOffloaded()) {
         return INVALID_OPERATION;
     }
-
-    AutoMutex lock(mLock);
-
-    if (!stopped_l()) {
-        return INVALID_OPERATION;
-    }
-
-    audio_track_cblk_t* cblk = mCblk;
-    Mutex::Autolock _l(cblk->lock);
-
-    if (position > cblk->user) {
+    if (position > mFrameCount) {
         return BAD_VALUE;
     }
 
-    cblk->server = position;
-    android_atomic_or(CBLK_FORCEREADY, &cblk->flags);
+    AutoMutex lock(mLock);
+    // Currently we require that the player is inactive before setting parameters such as position
+    // or loop points.  Otherwise, there could be a race condition: the application could read the
+    // current position, compute a new position or loop parameters, and then set that position or
+    // loop parameters but it would do the "wrong" thing since the position has continued to advance
+    // in the mean time.  If we ever provide a sequencer in server, we could allow a way for the app
+    // to specify how it wants to handle such scenarios.
+    if (mState == STATE_ACTIVE) {
+        return INVALID_OPERATION;
+    }
+    mNewPosition = mProxy->getPosition() + mUpdatePeriod;
+    mLoopPeriod = 0;
+    // FIXME Check whether loops and setting position are incompatible in old code.
+    // If we use setLoop for both purposes we lose the capability to set the position while looping.
+    mStaticProxy->setLoop(position, mFrameCount, 0);
 
     return NO_ERROR;
 }
 
-status_t AudioTrack::getPosition(uint32_t *position)
+status_t AudioTrack::getPosition(uint32_t *position) const
 {
     if (position == NULL) {
         return BAD_VALUE;
     }
-    AutoMutex lock(mLock);
-    *position = mFlushed ? 0 : mCblk->server;
 
+    AutoMutex lock(mLock);
+    if (isOffloaded()) {
+        uint32_t dspFrames = 0;
+
+        if ((mState == STATE_PAUSED) || (mState == STATE_PAUSED_STOPPING)) {
+            ALOGV("getPosition called in paused state, return cached position %u", mPausedPosition);
+            *position = mPausedPosition;
+            return NO_ERROR;
+        }
+
+        if (mOutput != 0) {
+            uint32_t halFrames;
+            AudioSystem::getRenderPosition(mOutput, &halFrames, &dspFrames);
+        }
+        *position = dspFrames;
+    } else {
+        // IAudioTrack::stop() isn't synchronous; we don't know when presentation completes
+        *position = (mState == STATE_STOPPED || mState == STATE_FLUSHED) ? 0 :
+                mProxy->getPosition();
+    }
+    return NO_ERROR;
+}
+
+status_t AudioTrack::getBufferPosition(size_t *position)
+{
+    if (mSharedBuffer == 0 || mIsTimed) {
+        return INVALID_OPERATION;
+    }
+    if (position == NULL) {
+        return BAD_VALUE;
+    }
+
+    AutoMutex lock(mLock);