am 098b28fc: am 64727dd7: Merge "More precise 32-bit only for libstagefright/ subdirectories"

* commit '098b28fc88b3d96eada2f9db318d9c38c70cf674':
  More precise 32-bit only for libstagefright/ subdirectories
diff --git a/CleanSpec.mk b/CleanSpec.mk
index e6d9ebf..94aac5c 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -47,6 +47,8 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/lib/libmedia_native.so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/symbols/system/lib/libmedia_native.so)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libmedia_native.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libaudioflinger_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libaudioflinger.so)
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/camera/Android.mk b/camera/Android.mk
index e633450..369d0c5 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -1,3 +1,17 @@
+# Copyright 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
 CAMERA_CLIENT_LOCAL_PATH:= $(call my-dir)
 include $(call all-subdir-makefiles)
 include $(CLEAR_VARS)
@@ -21,6 +35,7 @@
 	camera2/CaptureRequest.cpp \
 	ProCamera.cpp \
 	CameraBase.cpp \
+	VendorTagDescriptor.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
@@ -34,6 +49,7 @@
 
 LOCAL_C_INCLUDES += \
 	system/media/camera/include \
+	system/media/private/camera/include
 
 LOCAL_MODULE:= libcamera_client
 
diff --git a/camera/CameraMetadata.cpp b/camera/CameraMetadata.cpp
index 7765914..6b726e0 100644
--- a/camera/CameraMetadata.cpp
+++ b/camera/CameraMetadata.cpp
@@ -25,6 +25,9 @@
 
 namespace android {
 
+#define ALIGN_TO(val, alignment) \
+    (((uintptr_t)(val) + ((alignment) - 1)) & ~((alignment) - 1))
+
 typedef Parcel::WritableBlob WritableBlob;
 typedef Parcel::ReadableBlob ReadableBlob;
 
@@ -431,40 +434,70 @@
         *out = NULL;
     }
 
-    // arg0 = metadataSize (int32)
-    int32_t metadataSizeTmp = -1;
-    if ((err = data.readInt32(&metadataSizeTmp)) != OK) {
+    // See CameraMetadata::writeToParcel for parcel data layout diagram and explanation.
+    // arg0 = blobSize (int32)
+    int32_t blobSizeTmp = -1;
+    if ((err = data.readInt32(&blobSizeTmp)) != 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);
+    const size_t blobSize = static_cast<size_t>(blobSizeTmp);
+    const size_t alignment = get_camera_metadata_alignment();
 
-    if (metadataSize == 0) {
+    // Special case: zero blob size means zero sized (NULL) metadata.
+    if (blobSize == 0) {
         ALOGV("%s: Read 0-sized metadata", __FUNCTION__);
         return OK;
     }
 
-    // NOTE: this doesn't make sense to me. shouldnt the blob
+    if (blobSize <= alignment) {
+        ALOGE("%s: metadata blob is malformed, blobSize(%zu) should be larger than alignment(%zu)",
+                __FUNCTION__, blobSize, alignment);
+        return BAD_VALUE;
+    }
+
+    const size_t metadataSize = blobSize - alignment;
+
+    // NOTE: this doesn't make sense to me. shouldn't 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 "
+        if ((err = data.readBlob(blobSize, &blob)) != OK) {
+            ALOGE("%s: Failed to read metadata blob (sized %zu). Possible "
                   " serialization bug. Error %d %s",
-                  __FUNCTION__, metadataSize, err, strerror(-err));
+                  __FUNCTION__, blobSize, err, strerror(-err));
             break;
         }
-        const camera_metadata_t* tmp =
-                       reinterpret_cast<const camera_metadata_t*>(blob.data());
 
+        // arg2 = offset (blob)
+        // Must be after blob since we don't know offset until after writeBlob.
+        int32_t offsetTmp;
+        if ((err = data.readInt32(&offsetTmp)) != OK) {
+            ALOGE("%s: Failed to read metadata offsetTmp (error %d %s)",
+                  __FUNCTION__, err, strerror(-err));
+            break;
+        }
+        const size_t offset = static_cast<size_t>(offsetTmp);
+        if (offset >= alignment) {
+            ALOGE("%s: metadata offset(%zu) should be less than alignment(%zu)",
+                    __FUNCTION__, blobSize, alignment);
+            err = BAD_VALUE;
+            break;
+        }
+
+        const uintptr_t metadataStart = reinterpret_cast<uintptr_t>(blob.data()) + offset;
+        const camera_metadata_t* tmp =
+                       reinterpret_cast<const camera_metadata_t*>(metadataStart);
+        ALOGV("%s: alignment is: %zu, metadata start: %p, offset: %zu",
+                __FUNCTION__, alignment, tmp, offset);
         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.
+            ALOGE("%s: metadata allocation and copy failed", __FUNCTION__);
             err = BAD_VALUE;
         }
     } while(0);
@@ -485,38 +518,79 @@
                                        const camera_metadata_t* metadata) {
     status_t res = OK;
 
-    // arg0 = metadataSize (int32)
+    /**
+     * Below is the camera metadata parcel layout:
+     *
+     * |--------------------------------------------|
+     * |             arg0: blobSize                 |
+     * |              (length = 4)                  |
+     * |--------------------------------------------|<--Skip the rest if blobSize == 0.
+     * |                                            |
+     * |                                            |
+     * |              arg1: blob                    |
+     * | (length = variable, see arg1 layout below) |
+     * |                                            |
+     * |                                            |
+     * |--------------------------------------------|
+     * |              arg2: offset                  |
+     * |              (length = 4)                  |
+     * |--------------------------------------------|
+     */
 
+    // arg0 = blobSize (int32)
     if (metadata == NULL) {
+        // Write zero blobSize for null metadata.
         return data.writeInt32(0);
     }
 
+    /**
+     * Always make the blob size sufficiently larger, as we need put alignment
+     * padding and metadata into the blob. Since we don't know the alignment
+     * offset before writeBlob. Then write the metadata to aligned offset.
+     */
     const size_t metadataSize = get_camera_metadata_compact_size(metadata);
-    res = data.writeInt32(static_cast<int32_t>(metadataSize));
+    const size_t alignment = get_camera_metadata_alignment();
+    const size_t blobSize = metadataSize + alignment;
+    res = data.writeInt32(static_cast<int32_t>(blobSize));
     if (res != OK) {
         return res;
     }
 
-    // arg1 = metadata (blob)
+    size_t offset = 0;
+    /**
+     * arg1 = metadata (blob).
+     *
+     * The blob size is the sum of front padding size, metadata size and back padding
+     * size, which is equal to metadataSize + alignment.
+     *
+     * The blob layout is:
+     * |------------------------------------|<----Start address of the blob (unaligned).
+     * |           front padding            |
+     * |          (size = offset)           |
+     * |------------------------------------|<----Aligned start address of metadata.
+     * |                                    |
+     * |                                    |
+     * |            metadata                |
+     * |       (size = metadataSize)        |
+     * |                                    |
+     * |                                    |
+     * |------------------------------------|
+     * |           back padding             |
+     * |     (size = alignment - offset)    |
+     * |------------------------------------|<----End address of blob.
+     *                                            (Blob start address + blob size).
+     */
     WritableBlob blob;
     do {
-        res = data.writeBlob(metadataSize, &blob);
+        res = data.writeBlob(blobSize, &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__);
-            }
-        }
+        const uintptr_t metadataStart = ALIGN_TO(blob.data(), alignment);
+        offset = metadataStart - reinterpret_cast<uintptr_t>(blob.data());
+        ALOGV("%s: alignment is: %zu, metadata start: %p, offset: %zu",
+                __FUNCTION__, alignment, metadataStart, offset);
+        copy_camera_metadata(reinterpret_cast<void*>(metadataStart), metadataSize, metadata);
 
         // Not too big of a problem since receiving side does hard validation
         // Don't check the size since the compact size could be larger
@@ -528,6 +602,9 @@
     } while(false);
     blob.release();
 
+    // arg2 = offset (int32)
+    res = data.writeInt32(static_cast<int32_t>(offset));
+
     return res;
 }
 
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index 5fc89fb..b86651f 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -17,6 +17,7 @@
 
 #define LOG_TAG "BpCameraService"
 #include <utils/Log.h>
+#include <utils/Errors.h>
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -34,6 +35,7 @@
 #include <camera/camera2/ICameraDeviceUser.h>
 #include <camera/camera2/ICameraDeviceCallbacks.h>
 #include <camera/CameraMetadata.h>
+#include <camera/VendorTagDescriptor.h>
 
 namespace android {
 
@@ -143,6 +145,24 @@
         return result;
     }
 
+    // Get enumeration and description of vendor tags for camera
+    virtual status_t getCameraVendorTagDescriptor(/*out*/sp<VendorTagDescriptor>& desc) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
+        remote()->transact(BnCameraService::GET_CAMERA_VENDOR_TAG_DESCRIPTOR, data, &reply);
+
+        if (readExceptionCode(reply)) return -EPROTO;
+        status_t result = reply.readInt32();
+
+        if (reply.readInt32() != 0) {
+            sp<VendorTagDescriptor> d;
+            if (VendorTagDescriptor::createFromParcel(&reply, /*out*/d) == OK) {
+                desc = d;
+            }
+        }
+        return result;
+    }
+
     // connect to camera service (android.hardware.Camera)
     virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
                              const String16 &clientPackageName, int clientUid,
@@ -275,6 +295,22 @@
             info.writeToParcel(reply);
             return NO_ERROR;
         } break;
+        case GET_CAMERA_VENDOR_TAG_DESCRIPTOR: {
+            CHECK_INTERFACE(ICameraService, data, reply);
+            sp<VendorTagDescriptor> d;
+            status_t result = getCameraVendorTagDescriptor(d);
+            reply->writeNoException();
+            reply->writeInt32(result);
+
+            // out-variables are after exception and return value
+            if (d == NULL) {
+                reply->writeInt32(0);
+            } else {
+                reply->writeInt32(1); // means the parcelable is included
+                d->writeToParcel(reply);
+            }
+            return NO_ERROR;
+        } break;
         case CONNECT: {
             CHECK_INTERFACE(ICameraService, data, reply);
             sp<ICameraClient> cameraClient =
@@ -284,7 +320,7 @@
             int32_t clientUid = data.readInt32();
             sp<ICamera> camera;
             status_t status = connect(cameraClient, cameraId,
-                    clientName, clientUid, /*out*/ camera);
+                    clientName, clientUid, /*out*/camera);
             reply->writeNoException();
             reply->writeInt32(status);
             if (camera != NULL) {
@@ -304,7 +340,7 @@
             int32_t clientUid = data.readInt32();
             sp<IProCameraUser> camera;
             status_t status = connectPro(cameraClient, cameraId,
-                    clientName, clientUid, /*out*/ camera);
+                    clientName, clientUid, /*out*/camera);
             reply->writeNoException();
             reply->writeInt32(status);
             if (camera != NULL) {
@@ -324,7 +360,7 @@
             int32_t clientUid = data.readInt32();
             sp<ICameraDeviceUser> camera;
             status_t status = connectDevice(cameraClient, cameraId,
-                    clientName, clientUid, /*out*/ camera);
+                    clientName, clientUid, /*out*/camera);
             reply->writeNoException();
             reply->writeInt32(status);
             if (camera != NULL) {
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index ba5a48c..48f8e8e 100644
--- a/camera/ProCamera.cpp
+++ b/camera/ProCamera.cpp
@@ -249,11 +249,14 @@
     sp <IProCameraUser> c = mCamera;
     if (c == 0) return NO_INIT;
 
-    sp<BufferQueue> bq = new BufferQueue();
-    sp<CpuConsumer> cc = new CpuConsumer(bq, heapCount/*, synchronousMode*/);
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    sp<CpuConsumer> cc = new CpuConsumer(consumer, heapCount
+            /*, synchronousMode*/);
     cc->setName(String8("ProCamera::mCpuConsumer"));
 
-    sp<Surface> stc = new Surface(bq);
+    sp<Surface> stc = new Surface(producer);
 
     status_t s = createStream(width, height, format,
                               stc->getIGraphicBufferProducer(),
diff --git a/camera/VendorTagDescriptor.cpp b/camera/VendorTagDescriptor.cpp
new file mode 100644
index 0000000..a0a6a51
--- /dev/null
+++ b/camera/VendorTagDescriptor.cpp
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VenderTagDescriptor"
+
+#include <binder/Parcel.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+#include <utils/Vector.h>
+#include <system/camera_metadata.h>
+#include <camera_metadata_hidden.h>
+
+#include "camera/VendorTagDescriptor.h"
+
+#include <string.h>
+
+namespace android {
+
+extern "C" {
+
+static int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* v);
+static void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* v, uint32_t* tagArray);
+static const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* v, uint32_t tag);
+static const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* v, uint32_t tag);
+static int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* v, uint32_t tag);
+
+} /* extern "C" */
+
+
+static Mutex sLock;
+static sp<VendorTagDescriptor> sGlobalVendorTagDescriptor;
+
+VendorTagDescriptor::VendorTagDescriptor() {}
+VendorTagDescriptor::~VendorTagDescriptor() {}
+
+status_t VendorTagDescriptor::createDescriptorFromOps(const vendor_tag_ops_t* vOps,
+            /*out*/
+            sp<VendorTagDescriptor>& descriptor) {
+    if (vOps == NULL) {
+        ALOGE("%s: vendor_tag_ops argument was NULL.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    int tagCount = vOps->get_tag_count(vOps);
+    if (tagCount < 0 || tagCount > INT32_MAX) {
+        ALOGE("%s: tag count %d from vendor ops is invalid.", __FUNCTION__, tagCount);
+        return BAD_VALUE;
+    }
+
+    Vector<uint32_t> tagArray;
+    LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
+            "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
+
+    vOps->get_all_tags(vOps, /*out*/tagArray.editArray());
+
+    sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
+    desc->mTagCount = tagCount;
+
+    for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
+        uint32_t tag = tagArray[i];
+        if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
+            ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
+            return BAD_VALUE;
+        }
+        const char *tagName = vOps->get_tag_name(vOps, tag);
+        if (tagName == NULL) {
+            ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
+            return BAD_VALUE;
+        }
+        desc->mTagToNameMap.add(tag, String8(tagName));
+        const char *sectionName = vOps->get_section_name(vOps, tag);
+        if (sectionName == NULL) {
+            ALOGE("%s: no section name defined for vendor tag %d.", __FUNCTION__, tag);
+            return BAD_VALUE;
+        }
+        desc->mTagToSectionMap.add(tag, String8(sectionName));
+        int tagType = vOps->get_tag_type(vOps, tag);
+        if (tagType < 0 || tagType >= NUM_TYPES) {
+            ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
+            return BAD_VALUE;
+        }
+        desc->mTagToTypeMap.add(tag, tagType);
+    }
+    descriptor = desc;
+    return OK;
+}
+
+status_t VendorTagDescriptor::createFromParcel(const Parcel* parcel,
+            /*out*/
+            sp<VendorTagDescriptor>& descriptor) {
+    status_t res = OK;
+    if (parcel == NULL) {
+        ALOGE("%s: parcel argument was NULL.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    int32_t tagCount = 0;
+    if ((res = parcel->readInt32(&tagCount)) != OK) {
+        ALOGE("%s: could not read tag count from parcel", __FUNCTION__);
+        return res;
+    }
+
+    if (tagCount < 0 || tagCount > INT32_MAX) {
+        ALOGE("%s: tag count %d from vendor ops is invalid.", __FUNCTION__, tagCount);
+        return BAD_VALUE;
+    }
+
+    sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
+    desc->mTagCount = tagCount;
+
+    uint32_t tag;
+    int32_t tagType;
+    for (int32_t i = 0; i < tagCount; ++i) {
+        if ((res = parcel->readInt32(reinterpret_cast<int32_t*>(&tag))) != OK) {
+            ALOGE("%s: could not read tag id from parcel for index %d", __FUNCTION__, i);
+            break;
+        }
+        if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
+            ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
+            res = BAD_VALUE;
+            break;
+        }
+        if ((res = parcel->readInt32(&tagType)) != OK) {
+            ALOGE("%s: could not read tag type from parcel for tag %d", __FUNCTION__, tag);
+            break;
+        }
+        if (tagType < 0 || tagType >= NUM_TYPES) {
+            ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
+            res = BAD_VALUE;
+            break;
+        }
+        String8 tagName = parcel->readString8();
+        if (tagName.isEmpty()) {
+            ALOGE("%s: parcel tag name was NULL for tag %d.", __FUNCTION__, tag);
+            res = NOT_ENOUGH_DATA;
+            break;
+        }
+        String8 sectionName = parcel->readString8();
+        if (sectionName.isEmpty()) {
+            ALOGE("%s: parcel section name was NULL for tag %d.", __FUNCTION__, tag);
+            res = NOT_ENOUGH_DATA;
+            break;
+        }
+
+        desc->mTagToNameMap.add(tag, tagName);
+        desc->mTagToSectionMap.add(tag, sectionName);
+        desc->mTagToTypeMap.add(tag, tagType);
+    }
+
+    if (res != OK) {
+        return res;
+    }
+
+    descriptor = desc;
+    return res;
+}
+
+int VendorTagDescriptor::getTagCount() const {
+    size_t size = mTagToNameMap.size();
+    if (size == 0) {
+        return VENDOR_TAG_COUNT_ERR;
+    }
+    return size;
+}
+
+void VendorTagDescriptor::getTagArray(uint32_t* tagArray) const {
+    size_t size = mTagToNameMap.size();
+    for (size_t i = 0; i < size; ++i) {
+        tagArray[i] = mTagToNameMap.keyAt(i);
+    }
+}
+
+const char* VendorTagDescriptor::getSectionName(uint32_t tag) const {
+    ssize_t index = mTagToSectionMap.indexOfKey(tag);
+    if (index < 0) {
+        return VENDOR_SECTION_NAME_ERR;
+    }
+    return mTagToSectionMap.valueAt(index).string();
+}
+
+const char* VendorTagDescriptor::getTagName(uint32_t tag) const {
+    ssize_t index = mTagToNameMap.indexOfKey(tag);
+    if (index < 0) {
+        return VENDOR_TAG_NAME_ERR;
+    }
+    return mTagToNameMap.valueAt(index).string();
+}
+
+int VendorTagDescriptor::getTagType(uint32_t tag) const {
+    ssize_t index = mTagToNameMap.indexOfKey(tag);
+    if (index < 0) {
+        return VENDOR_TAG_TYPE_ERR;
+    }
+    return mTagToTypeMap.valueFor(tag);
+}
+
+status_t VendorTagDescriptor::writeToParcel(Parcel* parcel) const {
+    status_t res = OK;
+    if (parcel == NULL) {
+        ALOGE("%s: parcel argument was NULL.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    if ((res = parcel->writeInt32(mTagCount)) != OK) {
+        return res;
+    }
+
+    size_t size = mTagToNameMap.size();
+    uint32_t tag;
+    int32_t tagType;
+    for (size_t i = 0; i < size; ++i) {
+        tag = mTagToNameMap.keyAt(i);
+        String8 tagName = mTagToNameMap[i];
+        String8 sectionName = mTagToSectionMap.valueFor(tag);
+        tagType = mTagToTypeMap.valueFor(tag);
+        if ((res = parcel->writeInt32(tag)) != OK) break;
+        if ((res = parcel->writeInt32(tagType)) != OK) break;
+        if ((res = parcel->writeString8(tagName)) != OK) break;
+        if ((res = parcel->writeString8(sectionName)) != OK) break;
+    }
+
+    return res;
+}
+
+status_t VendorTagDescriptor::setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc) {
+    status_t res = OK;
+    Mutex::Autolock al(sLock);
+    sGlobalVendorTagDescriptor = desc;
+
+    vendor_tag_ops_t* opsPtr = NULL;
+    if (desc != NULL) {
+        opsPtr = &(desc->mVendorOps);
+        opsPtr->get_tag_count = vendor_tag_descriptor_get_tag_count;
+        opsPtr->get_all_tags = vendor_tag_descriptor_get_all_tags;
+        opsPtr->get_section_name = vendor_tag_descriptor_get_section_name;
+        opsPtr->get_tag_name = vendor_tag_descriptor_get_tag_name;
+        opsPtr->get_tag_type = vendor_tag_descriptor_get_tag_type;
+    }
+    if((res = set_camera_metadata_vendor_ops(opsPtr)) != OK) {
+        ALOGE("%s: Could not set vendor tag descriptor, received error %s (%d)."
+                , __FUNCTION__, strerror(-res), res);
+    }
+    return res;
+}
+
+void VendorTagDescriptor::clearGlobalVendorTagDescriptor() {
+    Mutex::Autolock al(sLock);
+    set_camera_metadata_vendor_ops(NULL);
+    sGlobalVendorTagDescriptor.clear();
+}
+
+sp<VendorTagDescriptor> VendorTagDescriptor::getGlobalVendorTagDescriptor() {
+    Mutex::Autolock al(sLock);
+    return sGlobalVendorTagDescriptor;
+}
+
+extern "C" {
+
+int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* v) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return VENDOR_TAG_COUNT_ERR;
+    }
+    return sGlobalVendorTagDescriptor->getTagCount();
+}
+
+void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* v, uint32_t* tagArray) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return;
+    }
+    sGlobalVendorTagDescriptor->getTagArray(tagArray);
+}
+
+const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* v, uint32_t tag) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return VENDOR_SECTION_NAME_ERR;
+    }
+    return sGlobalVendorTagDescriptor->getSectionName(tag);
+}
+
+const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* v, uint32_t tag) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return VENDOR_TAG_NAME_ERR;
+    }
+    return sGlobalVendorTagDescriptor->getTagName(tag);
+}
+
+int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* v, uint32_t tag) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return VENDOR_TAG_TYPE_ERR;
+    }
+    return sGlobalVendorTagDescriptor->getTagType(tag);
+}
+
+} /* extern "C" */
+} /* namespace android */
diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk
index ec13911..61385e5 100644
--- a/camera/tests/Android.mk
+++ b/camera/tests/Android.mk
@@ -1,9 +1,24 @@
+# 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:= \
 	main.cpp \
 	ProCameraTests.cpp \
+	VendorTagDescriptorTests.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libutils \
@@ -26,6 +41,8 @@
 	external/gtest/include \
 	external/stlport/stlport \
 	system/media/camera/include \
+	system/media/private/camera/include \
+	system/media/camera/tests \
 	frameworks/av/services/camera/libcameraservice \
 	frameworks/av/include/camera \
 	frameworks/native/include \
diff --git a/camera/tests/VendorTagDescriptorTests.cpp b/camera/tests/VendorTagDescriptorTests.cpp
new file mode 100644
index 0000000..6624e79
--- /dev/null
+++ b/camera/tests/VendorTagDescriptorTests.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "VendorTagDescriptorTests"
+
+#include <binder/Parcel.h>
+#include <camera/VendorTagDescriptor.h>
+#include <camera_metadata_tests_fake_vendor.h>
+#include <camera_metadata_hidden.h>
+#include <system/camera_vendor_tags.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+
+#include <gtest/gtest.h>
+#include <stdint.h>
+
+using namespace android;
+
+enum {
+    BAD_TAG_ARRAY = 0xDEADBEEFu,
+    BAD_TAG = 0x8DEADBADu,
+};
+
+#define ARRAY_SIZE(a)      (sizeof(a) / sizeof((a)[0]))
+
+static bool ContainsTag(uint32_t* tagArray, size_t size, uint32_t tag) {
+    for (size_t i = 0; i < size; ++i) {
+        if (tag == tagArray[i]) return true;
+    }
+    return false;
+}
+
+#define EXPECT_CONTAINS_TAG(t, a) \
+    EXPECT_TRUE(ContainsTag(a, ARRAY_SIZE(a), t))
+
+#define ASSERT_NOT_NULL(x) \
+    ASSERT_TRUE((x) != NULL)
+
+extern "C" {
+
+static int default_get_tag_count(const vendor_tag_ops_t* vOps) {
+    return VENDOR_TAG_COUNT_ERR;
+}
+
+static void default_get_all_tags(const vendor_tag_ops_t* vOps, uint32_t* tagArray) {
+    //Noop
+}
+
+static const char* default_get_section_name(const vendor_tag_ops_t* vOps, uint32_t tag) {
+    return VENDOR_SECTION_NAME_ERR;
+}
+
+static const char* default_get_tag_name(const vendor_tag_ops_t* vOps, uint32_t tag) {
+    return VENDOR_TAG_NAME_ERR;
+}
+
+static int default_get_tag_type(const vendor_tag_ops_t* vOps, uint32_t tag) {
+    return VENDOR_TAG_TYPE_ERR;
+}
+
+} /*extern "C"*/
+
+// Set default vendor operations for a vendor_tag_ops struct
+static void FillWithDefaults(vendor_tag_ops_t* vOps) {
+    ASSERT_NOT_NULL(vOps);
+    vOps->get_tag_count = default_get_tag_count;
+    vOps->get_all_tags = default_get_all_tags;
+    vOps->get_section_name = default_get_section_name;
+    vOps->get_tag_name = default_get_tag_name;
+    vOps->get_tag_type = default_get_tag_type;
+}
+
+/**
+ * Test if values from VendorTagDescriptor methods match corresponding values
+ * from vendor_tag_ops functions.
+ */
+TEST(VendorTagDescriptorTest, ConsistentWithVendorTags) {
+    sp<VendorTagDescriptor> vDesc;
+    const vendor_tag_ops_t *vOps = &fakevendor_ops;
+    EXPECT_EQ(OK, VendorTagDescriptor::createDescriptorFromOps(vOps, /*out*/vDesc));
+
+    ASSERT_NOT_NULL(vDesc);
+
+    // Ensure reasonable tag count
+    int tagCount = vDesc->getTagCount();
+    EXPECT_EQ(tagCount, vOps->get_tag_count(vOps));
+
+    uint32_t descTagArray[tagCount];
+    uint32_t opsTagArray[tagCount];
+
+    // Get all tag ids
+    vDesc->getTagArray(descTagArray);
+    vOps->get_all_tags(vOps, opsTagArray);
+
+    ASSERT_NOT_NULL(descTagArray);
+    ASSERT_NOT_NULL(opsTagArray);
+
+    uint32_t tag;
+    for (int i = 0; i < tagCount; ++i) {
+        // For each tag id, check whether type, section name, tag name match
+        tag = descTagArray[i];
+        EXPECT_CONTAINS_TAG(tag, opsTagArray);
+        EXPECT_EQ(vDesc->getTagType(tag), vOps->get_tag_type(vOps, tag));
+        EXPECT_STREQ(vDesc->getSectionName(tag), vOps->get_section_name(vOps, tag));
+        EXPECT_STREQ(vDesc->getTagName(tag), vOps->get_tag_name(vOps, tag));
+    }
+}
+
+/**
+ * Test if values from VendorTagDescriptor methods stay consistent after being
+ * parcelled/unparcelled.
+ */
+TEST(VendorTagDescriptorTest, ConsistentAcrossParcel) {
+    sp<VendorTagDescriptor> vDescOriginal, vDescParceled;
+    const vendor_tag_ops_t *vOps = &fakevendor_ops;
+    EXPECT_EQ(OK, VendorTagDescriptor::createDescriptorFromOps(vOps, /*out*/vDescOriginal));
+
+    ASSERT_TRUE(vDescOriginal != NULL);
+
+    Parcel p;
+
+    // Check whether parcel read/write succeed
+    EXPECT_EQ(OK, vDescOriginal->writeToParcel(&p));
+    p.setDataPosition(0);
+    ASSERT_EQ(OK, VendorTagDescriptor::createFromParcel(&p, vDescParceled));
+
+    // Ensure consistent tag count
+    int tagCount = vDescOriginal->getTagCount();
+    ASSERT_EQ(tagCount, vDescParceled->getTagCount());
+
+    uint32_t descTagArray[tagCount];
+    uint32_t desc2TagArray[tagCount];
+
+    // Get all tag ids
+    vDescOriginal->getTagArray(descTagArray);
+    vDescParceled->getTagArray(desc2TagArray);
+
+    ASSERT_NOT_NULL(descTagArray);
+    ASSERT_NOT_NULL(desc2TagArray);
+
+    uint32_t tag;
+    for (int i = 0; i < tagCount; ++i) {
+        // For each tag id, check consistency between the two vendor tag
+        // descriptors for each type, section name, tag name
+        tag = descTagArray[i];
+        EXPECT_CONTAINS_TAG(tag, desc2TagArray);
+        EXPECT_EQ(vDescOriginal->getTagType(tag), vDescParceled->getTagType(tag));
+        EXPECT_STREQ(vDescOriginal->getSectionName(tag), vDescParceled->getSectionName(tag));
+        EXPECT_STREQ(vDescOriginal->getTagName(tag), vDescParceled->getTagName(tag));
+    }
+}
+
+/**
+ * Test defaults and error conditions.
+ */
+TEST(VendorTagDescriptorTest, ErrorConditions) {
+    sp<VendorTagDescriptor> vDesc;
+    vendor_tag_ops_t vOps;
+    FillWithDefaults(&vOps);
+
+    // Ensure create fails when using null vOps
+    EXPECT_EQ(BAD_VALUE, VendorTagDescriptor::createDescriptorFromOps(/*vOps*/NULL, vDesc));
+
+    // Ensure create works when there are no vtags defined in a well-formed vOps
+    ASSERT_EQ(OK, VendorTagDescriptor::createDescriptorFromOps(&vOps, vDesc));
+
+    // Ensure defaults are returned when no vtags are defined, or tag is unknown
+    EXPECT_EQ(VENDOR_TAG_COUNT_ERR, vDesc->getTagCount());
+    uint32_t* tagArray = reinterpret_cast<uint32_t*>(BAD_TAG_ARRAY);
+    uint32_t* testArray = tagArray;
+    vDesc->getTagArray(tagArray);
+    EXPECT_EQ(testArray, tagArray);
+    EXPECT_EQ(VENDOR_SECTION_NAME_ERR, vDesc->getSectionName(BAD_TAG));
+    EXPECT_EQ(VENDOR_TAG_NAME_ERR, vDesc->getTagName(BAD_TAG));
+    EXPECT_EQ(VENDOR_TAG_TYPE_ERR, vDesc->getTagType(BAD_TAG));
+
+    // Make sure global can be set/cleared
+    const vendor_tag_ops_t *fakeOps = &fakevendor_ops;
+    sp<VendorTagDescriptor> prevGlobal = VendorTagDescriptor::getGlobalVendorTagDescriptor();
+    VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+
+    EXPECT_TRUE(VendorTagDescriptor::getGlobalVendorTagDescriptor() == NULL);
+    EXPECT_EQ(OK, VendorTagDescriptor::setAsGlobalVendorTagDescriptor(vDesc));
+    EXPECT_TRUE(VendorTagDescriptor::getGlobalVendorTagDescriptor() != NULL);
+    EXPECT_EQ(VENDOR_SECTION_NAME_ERR, vDesc->getSectionName(BAD_TAG));
+    EXPECT_EQ(OK, VendorTagDescriptor::setAsGlobalVendorTagDescriptor(prevGlobal));
+    EXPECT_EQ(prevGlobal, VendorTagDescriptor::getGlobalVendorTagDescriptor());
+}
+
diff --git a/cmds/screenrecord/Android.mk b/cmds/screenrecord/Android.mk
index 57a2234..6ee2884 100644
--- a/cmds/screenrecord/Android.mk
+++ b/cmds/screenrecord/Android.mk
@@ -19,6 +19,7 @@
 LOCAL_SRC_FILES := \
 	screenrecord.cpp \
 	EglWindow.cpp \
+	FrameOutput.cpp \
 	TextRenderer.cpp \
 	Overlay.cpp \
 	Program.cpp
diff --git a/cmds/screenrecord/EglWindow.cpp b/cmds/screenrecord/EglWindow.cpp
index aa0517f..c16f2ad 100644
--- a/cmds/screenrecord/EglWindow.cpp
+++ b/cmds/screenrecord/EglWindow.cpp
@@ -35,11 +35,16 @@
 
 
 status_t EglWindow::createWindow(const sp<IGraphicBufferProducer>& surface) {
-    status_t err = eglSetupContext();
+    if (mEglSurface != EGL_NO_SURFACE) {
+        ALOGE("surface already created");
+        return UNKNOWN_ERROR;
+    }
+    status_t err = eglSetupContext(false);
     if (err != NO_ERROR) {
         return err;
     }
 
+    // Cache the current dimensions.  We're not expecting these to change.
     surface->query(NATIVE_WINDOW_WIDTH, &mWidth);
     surface->query(NATIVE_WINDOW_HEIGHT, &mHeight);
 
@@ -56,6 +61,34 @@
     return NO_ERROR;
 }
 
+status_t EglWindow::createPbuffer(int width, int height) {
+    if (mEglSurface != EGL_NO_SURFACE) {
+        ALOGE("surface already created");
+        return UNKNOWN_ERROR;
+    }
+    status_t err = eglSetupContext(true);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    mWidth = width;
+    mHeight = height;
+
+    EGLint pbufferAttribs[] = {
+            EGL_WIDTH, width,
+            EGL_HEIGHT, height,
+            EGL_NONE
+    };
+    mEglSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, pbufferAttribs);
+    if (mEglSurface == EGL_NO_SURFACE) {
+        ALOGE("eglCreatePbufferSurface error: %#x", eglGetError());
+        eglRelease();
+        return UNKNOWN_ERROR;
+    }
+
+    return NO_ERROR;
+}
+
 status_t EglWindow::makeCurrent() const {
     if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
         ALOGE("eglMakeCurrent failed: %#x", eglGetError());
@@ -64,7 +97,7 @@
     return NO_ERROR;
 }
 
-status_t EglWindow::eglSetupContext() {
+status_t EglWindow::eglSetupContext(bool forPbuffer) {
     EGLBoolean result;
 
     mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
@@ -82,17 +115,28 @@
     ALOGV("Initialized EGL v%d.%d", majorVersion, minorVersion);
 
     EGLint numConfigs = 0;
-    EGLint configAttribs[] = {
-        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
-        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-        EGL_RECORDABLE_ANDROID, 1,
-        EGL_RED_SIZE, 8,
-        EGL_GREEN_SIZE, 8,
-        EGL_BLUE_SIZE, 8,
-        EGL_NONE
+    EGLint windowConfigAttribs[] = {
+            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+            EGL_RECORDABLE_ANDROID, 1,
+            EGL_RED_SIZE, 8,
+            EGL_GREEN_SIZE, 8,
+            EGL_BLUE_SIZE, 8,
+            // no alpha
+            EGL_NONE
     };
-    result = eglChooseConfig(mEglDisplay, configAttribs, &mEglConfig, 1,
-            &numConfigs);
+    EGLint pbufferConfigAttribs[] = {
+            EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+            EGL_RED_SIZE, 8,
+            EGL_GREEN_SIZE, 8,
+            EGL_BLUE_SIZE, 8,
+            EGL_ALPHA_SIZE, 8,
+            EGL_NONE
+    };
+    result = eglChooseConfig(mEglDisplay,
+            forPbuffer ? pbufferConfigAttribs : windowConfigAttribs,
+            &mEglConfig, 1, &numConfigs);
     if (result != EGL_TRUE) {
         ALOGE("eglChooseConfig error: %#x", eglGetError());
         return UNKNOWN_ERROR;
diff --git a/cmds/screenrecord/EglWindow.h b/cmds/screenrecord/EglWindow.h
index 02a2efc..69d0c31 100644
--- a/cmds/screenrecord/EglWindow.h
+++ b/cmds/screenrecord/EglWindow.h
@@ -44,6 +44,9 @@
     // Creates an EGL window for the supplied surface.
     status_t createWindow(const sp<IGraphicBufferProducer>& surface);
 
+    // Creates an EGL pbuffer surface.
+    status_t createPbuffer(int width, int height);
+
     // Return width and height values (obtained from IGBP).
     int getWidth() const { return mWidth; }
     int getHeight() const { return mHeight; }
@@ -65,7 +68,7 @@
     EglWindow& operator=(const EglWindow&);
 
     // Init display, create config and context.
-    status_t eglSetupContext();
+    status_t eglSetupContext(bool forPbuffer);
     void eglRelease();
 
     // Basic EGL goodies.
diff --git a/cmds/screenrecord/FrameOutput.cpp b/cmds/screenrecord/FrameOutput.cpp
new file mode 100644
index 0000000..06b1f70
--- /dev/null
+++ b/cmds/screenrecord/FrameOutput.cpp
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ScreenRecord"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include "FrameOutput.h"
+
+using namespace android;
+
+static const bool kShowTiming = false;      // set to "true" for debugging
+static const int kGlBytesPerPixel = 4;      // GL_RGBA
+static const int kOutBytesPerPixel = 3;     // RGB only
+
+inline void FrameOutput::setValueLE(uint8_t* buf, uint32_t value) {
+    // Since we're running on an Android device, we're (almost) guaranteed
+    // to be little-endian, and (almost) guaranteed that unaligned 32-bit
+    // writes will work without any performance penalty... but do it
+    // byte-by-byte anyway.
+    buf[0] = (uint8_t) value;
+    buf[1] = (uint8_t) (value >> 8);
+    buf[2] = (uint8_t) (value >> 16);
+    buf[3] = (uint8_t) (value >> 24);
+}
+
+status_t FrameOutput::createInputSurface(int width, int height,
+        sp<IGraphicBufferProducer>* pBufferProducer) {
+    status_t err;
+
+    err = mEglWindow.createPbuffer(width, height);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    mEglWindow.makeCurrent();
+
+    glViewport(0, 0, width, height);
+    glDisable(GL_DEPTH_TEST);
+    glDisable(GL_CULL_FACE);
+
+    // Shader for rendering the external texture.
+    err = mExtTexProgram.setup(Program::PROGRAM_EXTERNAL_TEXTURE);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    // Input side (buffers from virtual display).
+    glGenTextures(1, &mExtTextureName);
+    if (mExtTextureName == 0) {
+        ALOGE("glGenTextures failed: %#x", glGetError());
+        return UNKNOWN_ERROR;
+    }
+
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    mGlConsumer = new GLConsumer(consumer, mExtTextureName,
+                GL_TEXTURE_EXTERNAL_OES);
+    mGlConsumer->setName(String8("virtual display"));
+    mGlConsumer->setDefaultBufferSize(width, height);
+    mGlConsumer->setDefaultMaxBufferCount(5);
+    mGlConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_TEXTURE);
+
+    mGlConsumer->setFrameAvailableListener(this);
+
+    mPixelBuf = new uint8_t[width * height * kGlBytesPerPixel];
+
+    *pBufferProducer = producer;
+
+    ALOGD("FrameOutput::createInputSurface OK");
+    return NO_ERROR;
+}
+
+status_t FrameOutput::copyFrame(FILE* fp, long timeoutUsec) {
+    Mutex::Autolock _l(mMutex);
+    ALOGV("copyFrame %ld\n", timeoutUsec);
+
+    if (!mFrameAvailable) {
+        nsecs_t timeoutNsec = (nsecs_t)timeoutUsec * 1000;
+        int cc = mEventCond.waitRelative(mMutex, timeoutNsec);
+        if (cc == -ETIMEDOUT) {
+            ALOGV("cond wait timed out");
+            return ETIMEDOUT;
+        } else if (cc != 0) {
+            ALOGW("cond wait returned error %d", cc);
+            return cc;
+        }
+    }
+    if (!mFrameAvailable) {
+        // This happens when Ctrl-C is hit.  Apparently POSIX says that the
+        // pthread wait call doesn't return EINTR, treating this instead as
+        // an instance of a "spurious wakeup".  We didn't get a frame, so
+        // we just treat it as a timeout.
+        return ETIMEDOUT;
+    }
+
+    // A frame is available.  Clear the flag for the next round.
+    mFrameAvailable = false;
+
+    float texMatrix[16];
+    mGlConsumer->updateTexImage();
+    mGlConsumer->getTransformMatrix(texMatrix);
+
+    // The data is in an external texture, so we need to render it to the
+    // pbuffer to get access to RGB pixel data.  We also want to flip it
+    // upside-down for easy conversion to a bitmap.
+    int width = mEglWindow.getWidth();
+    int height = mEglWindow.getHeight();
+    status_t err = mExtTexProgram.blit(mExtTextureName, texMatrix, 0, 0,
+            width, height, true);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    // GLES only guarantees that glReadPixels() will work with GL_RGBA, so we
+    // need to get 4 bytes/pixel and reduce it.  Depending on the size of the
+    // screen and the device capabilities, this can take a while.
+    int64_t startWhenNsec, pixWhenNsec, endWhenNsec;
+    if (kShowTiming) {
+        startWhenNsec = systemTime(CLOCK_MONOTONIC);
+    }
+    GLenum glErr;
+    glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, mPixelBuf);
+    if ((glErr = glGetError()) != GL_NO_ERROR) {
+        ALOGE("glReadPixels failed: %#x", glErr);
+        return UNKNOWN_ERROR;
+    }
+    if (kShowTiming) {
+        pixWhenNsec = systemTime(CLOCK_MONOTONIC);
+    }
+    reduceRgbaToRgb(mPixelBuf, width * height);
+    if (kShowTiming) {
+        endWhenNsec = systemTime(CLOCK_MONOTONIC);
+        ALOGD("got pixels (get=%.3f ms, reduce=%.3fms)",
+                (pixWhenNsec - startWhenNsec) / 1000000.0,
+                (endWhenNsec - pixWhenNsec) / 1000000.0);
+    }
+
+    // Fill out the header.
+    size_t headerLen = sizeof(uint32_t) * 5;
+    size_t rgbDataLen = width * height * kOutBytesPerPixel;
+    size_t packetLen = headerLen - sizeof(uint32_t) + rgbDataLen;
+    uint8_t header[headerLen];
+    setValueLE(&header[0], packetLen);
+    setValueLE(&header[4], width);
+    setValueLE(&header[8], height);
+    setValueLE(&header[12], width * kOutBytesPerPixel);
+    setValueLE(&header[16], HAL_PIXEL_FORMAT_RGB_888);
+
+    // Currently using buffered I/O rather than writev().  Not expecting it
+    // to make much of a difference, but it might be worth a test for larger
+    // frame sizes.
+    if (kShowTiming) {
+        startWhenNsec = systemTime(CLOCK_MONOTONIC);
+    }
+    fwrite(header, 1, headerLen, fp);
+    fwrite(mPixelBuf, 1, rgbDataLen, fp);
+    fflush(fp);
+    if (kShowTiming) {
+        endWhenNsec = systemTime(CLOCK_MONOTONIC);
+        ALOGD("wrote pixels (%.3f ms)",
+                (endWhenNsec - startWhenNsec) / 1000000.0);
+    }
+
+    if (ferror(fp)) {
+        // errno may not be useful; log it anyway
+        ALOGE("write failed (errno=%d)", errno);
+        return UNKNOWN_ERROR;
+    }
+
+    return NO_ERROR;
+}
+
+void FrameOutput::reduceRgbaToRgb(uint8_t* buf, unsigned int pixelCount) {
+    // Convert RGBA to RGB.
+    //
+    // Unaligned 32-bit accesses are allowed on ARM, so we could do this
+    // with 32-bit copies advancing at different rates (taking care at the
+    // end to not go one byte over).
+    const uint8_t* readPtr = buf;
+    for (unsigned int i = 0; i < pixelCount; i++) {
+        *buf++ = *readPtr++;
+        *buf++ = *readPtr++;
+        *buf++ = *readPtr++;
+        readPtr++;
+    }
+}
+
+// Callback; executes on arbitrary thread.
+void FrameOutput::onFrameAvailable() {
+    Mutex::Autolock _l(mMutex);
+    mFrameAvailable = true;
+    mEventCond.signal();
+}
diff --git a/cmds/screenrecord/FrameOutput.h b/cmds/screenrecord/FrameOutput.h
new file mode 100644
index 0000000..c1148d0
--- /dev/null
+++ b/cmds/screenrecord/FrameOutput.h
@@ -0,0 +1,99 @@
+/*
+ * 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 SCREENRECORD_FRAMEOUTPUT_H
+#define SCREENRECORD_FRAMEOUTPUT_H
+
+#include "Program.h"
+#include "EglWindow.h"
+
+#include <gui/BufferQueue.h>
+#include <gui/GLConsumer.h>
+
+namespace android {
+
+/*
+ * Support for "frames" output format.
+ */
+class FrameOutput : public GLConsumer::FrameAvailableListener {
+public:
+    FrameOutput() : mFrameAvailable(false),
+        mExtTextureName(0),
+        mPixelBuf(NULL)
+        {}
+
+    // Create an "input surface", similar in purpose to a MediaCodec input
+    // surface, that the virtual display can send buffers to.  Also configures
+    // EGL with a pbuffer surface on the current thread.
+    status_t createInputSurface(int width, int height,
+            sp<IGraphicBufferProducer>* pBufferProducer);
+
+    // Copy one from input to output.  If no frame is available, this will wait up to the
+    // specified number of microseconds.
+    //
+    // Returns ETIMEDOUT if the timeout expired before we found a frame.
+    status_t copyFrame(FILE* fp, long timeoutUsec);
+
+    // Prepare to copy frames.  Makes the EGL context used by this object current.
+    void prepareToCopy() {
+        mEglWindow.makeCurrent();
+    }
+
+private:
+    FrameOutput(const FrameOutput&);
+    FrameOutput& operator=(const FrameOutput&);
+
+    // Destruction via RefBase.
+    virtual ~FrameOutput() {
+        delete[] mPixelBuf;
+    }
+
+    // (overrides GLConsumer::FrameAvailableListener method)
+    virtual void onFrameAvailable();
+
+    // Reduces RGBA to RGB, in place.
+    static void reduceRgbaToRgb(uint8_t* buf, unsigned int pixelCount);
+
+    // Put a 32-bit value into a buffer, in little-endian byte order.
+    static void setValueLE(uint8_t* buf, uint32_t value);
+
+    // Used to wait for the FrameAvailableListener callback.
+    Mutex mMutex;
+    Condition mEventCond;
+
+    // Set by the FrameAvailableListener callback.
+    bool mFrameAvailable;
+
+    // This receives frames from the virtual display and makes them available
+    // as an external texture.
+    sp<GLConsumer> mGlConsumer;
+
+    // EGL display / context / surface.
+    EglWindow mEglWindow;
+
+    // GL rendering support.
+    Program mExtTexProgram;
+
+    // External texture, updated by GLConsumer.
+    GLuint mExtTextureName;
+
+    // Pixel data buffer.
+    uint8_t* mPixelBuf;
+};
+
+}; // namespace android
+
+#endif /*SCREENRECORD_FRAMEOUTPUT_H*/
diff --git a/cmds/screenrecord/Overlay.cpp b/cmds/screenrecord/Overlay.cpp
index 2e98874..94f560d 100644
--- a/cmds/screenrecord/Overlay.cpp
+++ b/cmds/screenrecord/Overlay.cpp
@@ -84,7 +84,7 @@
     assert(mState == RUNNING);
 
     ALOGV("Overlay::start successful");
-    *pBufferProducer = mBufferQueue;
+    *pBufferProducer = mProducer;
     return NO_ERROR;
 }
 
@@ -169,8 +169,9 @@
         return UNKNOWN_ERROR;
     }
 
-    mBufferQueue = new BufferQueue(/*new GraphicBufferAlloc()*/);
-    mGlConsumer = new GLConsumer(mBufferQueue, mExtTextureName,
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&mProducer, &consumer);
+    mGlConsumer = new GLConsumer(consumer, mExtTextureName,
                 GL_TEXTURE_EXTERNAL_OES);
     mGlConsumer->setName(String8("virtual display"));
     mGlConsumer->setDefaultBufferSize(width, height);
@@ -187,7 +188,7 @@
     ALOGV("Overlay::release_l");
     mOutputSurface.clear();
     mGlConsumer.clear();
-    mBufferQueue.clear();
+    mProducer.clear();
 
     mTexProgram.release();
     mExtTexProgram.release();
diff --git a/cmds/screenrecord/Overlay.h b/cmds/screenrecord/Overlay.h
index b8473b4..b1b5c29 100644
--- a/cmds/screenrecord/Overlay.h
+++ b/cmds/screenrecord/Overlay.h
@@ -47,7 +47,6 @@
         mLastFrameNumber(-1),
         mTotalDroppedFrames(0)
         {}
-    virtual ~Overlay() { assert(mState == UNINITIALIZED || mState == STOPPED); }
 
     // Creates a thread that performs the overlay.  Pass in the surface that
     // output will be sent to.
@@ -71,6 +70,9 @@
     Overlay(const Overlay&);
     Overlay& operator=(const Overlay&);
 
+    // Destruction via RefBase.
+    virtual ~Overlay() { assert(mState == UNINITIALIZED || mState == STOPPED); }
+
     // Draw the initial info screen.
     static void doDrawInfoPage(const EglWindow& window,
             const Program& texRender, TextRenderer& textRenderer);
@@ -120,9 +122,9 @@
     // surface.
     sp<IGraphicBufferProducer> mOutputSurface;
 
-    // Our queue.  The producer side is passed to the virtual display, the
-    // consumer side feeds into our GLConsumer.
-    sp<BufferQueue> mBufferQueue;
+    // Producer side of queue, passed into the virtual display.
+    // The consumer end feeds into our GLConsumer.
+    sp<IGraphicBufferProducer> mProducer;
 
     // This receives frames from the virtual display and makes them available
     // as an external texture.
diff --git a/cmds/screenrecord/Program.cpp b/cmds/screenrecord/Program.cpp
index a198204..73cae6e 100644
--- a/cmds/screenrecord/Program.cpp
+++ b/cmds/screenrecord/Program.cpp
@@ -201,7 +201,7 @@
 
 
 status_t Program::blit(GLuint texName, const float* texMatrix,
-        int32_t x, int32_t y, int32_t w, int32_t h) const {
+        int32_t x, int32_t y, int32_t w, int32_t h, bool invert) const {
     ALOGV("Program::blit %d xy=%d,%d wh=%d,%d", texName, x, y, w, h);
 
     const float pos[] = {
@@ -218,7 +218,7 @@
     };
     status_t err;
 
-    err = beforeDraw(texName, texMatrix, pos, uv);
+    err = beforeDraw(texName, texMatrix, pos, uv, invert);
     if (err == NO_ERROR) {
         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
         err = afterDraw();
@@ -232,7 +232,7 @@
 
     status_t err;
 
-    err = beforeDraw(texName, texMatrix, vertices, texes);
+    err = beforeDraw(texName, texMatrix, vertices, texes, false);
     if (err == NO_ERROR) {
         glDrawArrays(GL_TRIANGLES, 0, count);
         err = afterDraw();
@@ -241,7 +241,7 @@
 }
 
 status_t Program::beforeDraw(GLuint texName, const float* texMatrix,
-        const float* vertices, const float* texes) const {
+        const float* vertices, const float* texes, bool invert) const {
     // Create an orthographic projection matrix based on viewport size.
     GLint vp[4];
     glGetIntegerv(GL_VIEWPORT, vp);
@@ -251,6 +251,10 @@
         0.0f,               0.0f,               1.0f,   0.0f,
         -1.0f,              1.0f,               0.0f,   1.0f,
     };
+    if (invert) {
+        screenToNdc[5] = -screenToNdc[5];
+        screenToNdc[13] = -screenToNdc[13];
+    }
 
     glUseProgram(mProgram);
 
diff --git a/cmds/screenrecord/Program.h b/cmds/screenrecord/Program.h
index e47bc0d..558be8d 100644
--- a/cmds/screenrecord/Program.h
+++ b/cmds/screenrecord/Program.h
@@ -51,9 +51,11 @@
     // Release the program and associated resources.
     void release();
 
-    // Blit the specified texture to { x, y, x+w, y+h }.
+    // Blit the specified texture to { x, y, x+w, y+h }.  Inverts the
+    // content if "invert" is set.
     status_t blit(GLuint texName, const float* texMatrix,
-            int32_t x, int32_t y, int32_t w, int32_t h) const;
+            int32_t x, int32_t y, int32_t w, int32_t h,
+            bool invert = false) const;
 
     // Draw a number of triangles.
     status_t drawTriangles(GLuint texName, const float* texMatrix,
@@ -67,7 +69,7 @@
 
     // Common code for draw functions.
     status_t beforeDraw(GLuint texName, const float* texMatrix,
-            const float* vertices, const float* texes) const;
+            const float* vertices, const float* texes, bool invert) const;
     status_t afterDraw() const;
 
     // GLES 2 shader utilities.
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 61f83e3..a17fc51 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -45,10 +45,12 @@
 #include <signal.h>
 #include <getopt.h>
 #include <sys/wait.h>
+#include <termios.h>
 #include <assert.h>
 
 #include "screenrecord.h"
 #include "Overlay.h"
+#include "FrameOutput.h"
 
 using namespace android;
 
@@ -57,10 +59,14 @@
 static const uint32_t kMaxTimeLimitSec = 180;       // 3 minutes
 static const uint32_t kFallbackWidth = 1280;        // 720p
 static const uint32_t kFallbackHeight = 720;
+static const char* kMimeTypeAvc = "video/avc";
 
 // Command-line parameters.
 static bool gVerbose = false;           // chatty on stdout
 static bool gRotate = false;            // rotate 90 degrees
+static enum {
+    FORMAT_MP4, FORMAT_H264, FORMAT_FRAMES
+} gOutputFormat = FORMAT_MP4;           // data format for output
 static bool gSizeSpecified = false;     // was size explicitly requested?
 static bool gWantInfoScreen = false;    // do we want initial info screen?
 static bool gWantFrameTime = false;     // do we want times on each frame?
@@ -140,14 +146,14 @@
     status_t err;
 
     if (gVerbose) {
-        printf("Configuring recorder for %dx%d video at %.2fMbps\n",
-                gVideoWidth, gVideoHeight, gBitRate / 1000000.0);
+        printf("Configuring recorder for %dx%d %s at %.2fMbps\n",
+                gVideoWidth, gVideoHeight, kMimeTypeAvc, gBitRate / 1000000.0);
     }
 
     sp<AMessage> format = new AMessage;
     format->setInt32("width", gVideoWidth);
     format->setInt32("height", gVideoHeight);
-    format->setString("mime", "video/avc");
+    format->setString("mime", kMimeTypeAvc);
     format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
     format->setInt32("bitrate", gBitRate);
     format->setFloat("frame-rate", displayFps);
@@ -157,16 +163,18 @@
     looper->setName("screenrecord_looper");
     looper->start();
     ALOGV("Creating codec");
-    sp<MediaCodec> codec = MediaCodec::CreateByType(looper, "video/avc", true);
+    sp<MediaCodec> codec = MediaCodec::CreateByType(looper, kMimeTypeAvc, true);
     if (codec == NULL) {
-        fprintf(stderr, "ERROR: unable to create video/avc codec instance\n");
+        fprintf(stderr, "ERROR: unable to create %s codec instance\n",
+                kMimeTypeAvc);
         return UNKNOWN_ERROR;
     }
 
     err = codec->configure(format, NULL, NULL,
             MediaCodec::CONFIGURE_FLAG_ENCODE);
     if (err != NO_ERROR) {
-        fprintf(stderr, "ERROR: unable to configure codec (err=%d)\n", err);
+        fprintf(stderr, "ERROR: unable to configure %s codec at %dx%d (err=%d)\n",
+                kMimeTypeAvc, gVideoWidth, gVideoHeight, err);
         codec->release();
         return err;
     }
@@ -298,10 +306,12 @@
  * input frames are coming from the virtual display as fast as SurfaceFlinger
  * wants to send them.
  *
+ * Exactly one of muxer or rawFp must be non-null.
+ *
  * The muxer must *not* have been started before calling.
  */
 static status_t runEncoder(const sp<MediaCodec>& encoder,
-        const sp<MediaMuxer>& muxer, const sp<IBinder>& mainDpy,
+        const sp<MediaMuxer>& muxer, FILE* rawFp, const sp<IBinder>& mainDpy,
         const sp<IBinder>& virtualDpy, uint8_t orientation) {
     static int kTimeout = 250000;   // be responsive on signal
     status_t err;
@@ -311,6 +321,8 @@
     int64_t endWhenNsec = startWhenNsec + seconds_to_nanoseconds(gTimeLimitSec);
     DisplayInfo mainDpyInfo;
 
+    assert((rawFp == NULL && muxer != NULL) || (rawFp != NULL && muxer == NULL));
+
     Vector<sp<ABuffer> > buffers;
     err = encoder->getOutputBuffers(&buffers);
     if (err != NO_ERROR) {
@@ -342,15 +354,16 @@
         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;
+                ALOGV("Got codec config buffer (%u bytes)", size);
+                if (muxer != NULL) {
+                    // ignore this -- we passed the CSD into MediaMuxer when
+                    // we got the format change notification
+                    size = 0;
+                }
             }
             if (size != 0) {
                 ALOGV("Got data in buffer %d, size=%d, pts=%lld",
                         bufIndex, size, ptsUsec);
-                assert(trackIdx != -1);
 
                 { // scope
                     ATRACE_NAME("orientation");
@@ -379,14 +392,23 @@
                     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).
-                //
-                // If this blocks for too long we could drop frames.  We may
-                // want to queue these up and do them on a different thread.
-                { // scope
+                if (muxer == NULL) {
+                    fwrite(buffers[bufIndex]->data(), 1, size, rawFp);
+                    // Flush the data immediately in case we're streaming.
+                    // We don't want to do this if all we've written is
+                    // the SPS/PPS data because mplayer gets confused.
+                    if ((flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) == 0) {
+                        fflush(rawFp);
+                    }
+                } else {
+                    // 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).
+                    //
+                    // If this blocks for too long we could drop frames.  We may
+                    // want to queue these up and do them on a different thread.
                     ATRACE_NAME("write sample");
+                    assert(trackIdx != -1);
                     err = muxer->writeSampleData(buffers[bufIndex], trackIdx,
                             ptsUsec, flags);
                     if (err != NO_ERROR) {
@@ -418,12 +440,14 @@
                 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;
+                if (muxer != NULL) {
+                    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;
@@ -457,7 +481,45 @@
 }
 
 /*
- * Main "do work" method.
+ * Raw H.264 byte stream output requested.  Send the output to stdout
+ * if desired.  If the output is a tty, reconfigure it to avoid the
+ * CRLF line termination that we see with "adb shell" commands.
+ */
+static FILE* prepareRawOutput(const char* fileName) {
+    FILE* rawFp = NULL;
+
+    if (strcmp(fileName, "-") == 0) {
+        if (gVerbose) {
+            fprintf(stderr, "ERROR: verbose output and '-' not compatible");
+            return NULL;
+        }
+        rawFp = stdout;
+    } else {
+        rawFp = fopen(fileName, "w");
+        if (rawFp == NULL) {
+            fprintf(stderr, "fopen raw failed: %s\n", strerror(errno));
+            return NULL;
+        }
+    }
+
+    int fd = fileno(rawFp);
+    if (isatty(fd)) {
+        // best effort -- reconfigure tty for "raw"
+        ALOGD("raw video output to tty (fd=%d)", fd);
+        struct termios term;
+        if (tcgetattr(fd, &term) == 0) {
+            cfmakeraw(&term);
+            if (tcsetattr(fd, TCSANOW, &term) == 0) {
+                ALOGD("tty successfully configured for raw");
+            }
+        }
+    }
+
+    return rawFp;
+}
+
+/*
+ * Main "do work" start point.
  *
  * Configures codec, muxer, and virtual display, then starts moving bits
  * around.
@@ -499,30 +561,40 @@
 
     // Configure and start the encoder.
     sp<MediaCodec> encoder;
+    sp<FrameOutput> frameOutput;
     sp<IGraphicBufferProducer> encoderInputSurface;
-    err = prepareEncoder(mainDpyInfo.fps, &encoder, &encoderInputSurface);
+    if (gOutputFormat != FORMAT_FRAMES) {
+        err = prepareEncoder(mainDpyInfo.fps, &encoder, &encoderInputSurface);
 
-    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,
-                    &encoderInputSurface);
+        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,
+                        &encoderInputSurface);
+            }
+        }
+        if (err != NO_ERROR) return err;
+
+        // From here on, we must explicitly release() the encoder before it goes
+        // out of scope, or we will get an assertion failure from stagefright
+        // later on in a different thread.
+    } else {
+        // We're not using an encoder at all.  The "encoder input surface" we hand to
+        // SurfaceFlinger will just feed directly to us.
+        frameOutput = new FrameOutput();
+        err = frameOutput->createInputSurface(gVideoWidth, gVideoHeight, &encoderInputSurface);
+        if (err != NO_ERROR) {
+            return err;
         }
     }
-    if (err != NO_ERROR) return err;
-
-    // From here on, we must explicitly release() the encoder before it goes
-    // out of scope, or we will get an assertion failure from stagefright
-    // later on in a different thread.
-
 
     // Draw the "info" page by rendering a frame with GLES and sending
     // it directly to the encoder.
@@ -539,7 +611,7 @@
         overlay = new Overlay();
         err = overlay->start(encoderInputSurface, &bufferProducer);
         if (err != NO_ERROR) {
-            encoder->release();
+            if (encoder != NULL) encoder->release();
             return err;
         }
         if (gVerbose) {
@@ -554,40 +626,91 @@
     sp<IBinder> dpy;
     err = prepareVirtualDisplay(mainDpyInfo, bufferProducer, &dpy);
     if (err != NO_ERROR) {
-        encoder->release();
+        if (encoder != NULL) encoder->release();
         return err;
     }
 
-    // Configure muxer.  We have to wait for the CSD blob from the encoder
-    // before we can start it.
-    sp<MediaMuxer> muxer = new MediaMuxer(fileName,
-            MediaMuxer::OUTPUT_FORMAT_MPEG_4);
-    if (gRotate) {
-        muxer->setOrientationHint(90);  // TODO: does this do anything?
+    sp<MediaMuxer> muxer = NULL;
+    FILE* rawFp = NULL;
+    switch (gOutputFormat) {
+        case FORMAT_MP4: {
+            // Configure muxer.  We have to wait for the CSD blob from the encoder
+            // before we can start it.
+            muxer = new MediaMuxer(fileName, MediaMuxer::OUTPUT_FORMAT_MPEG_4);
+            if (gRotate) {
+                muxer->setOrientationHint(90);  // TODO: does this do anything?
+            }
+            break;
+        }
+        case FORMAT_H264:
+        case FORMAT_FRAMES: {
+            rawFp = prepareRawOutput(fileName);
+            if (rawFp == NULL) {
+                if (encoder != NULL) encoder->release();
+                return -1;
+            }
+            break;
+        }
+        default:
+            fprintf(stderr, "ERROR: unknown format %d\n", gOutputFormat);
+            abort();
     }
 
-    // Main encoder loop.
-    err = runEncoder(encoder, muxer, mainDpy, dpy, mainDpyInfo.orientation);
-    if (err != NO_ERROR) {
-        fprintf(stderr, "Encoder failed (err=%d)\n", err);
-        // fall through to cleanup
-    }
+    if (gOutputFormat == FORMAT_FRAMES) {
+        // TODO: if we want to make this a proper feature, we should output
+        //       an outer header with version info.  Right now we never change
+        //       the frame size or format, so we could conceivably just send
+        //       the current frame header once and then follow it with an
+        //       unbroken stream of data.
 
-    if (gVerbose) {
-        printf("Stopping encoder and muxer\n");
+        // Make the EGL context current again.  This gets unhooked if we're
+        // using "--bugreport" mode.
+        // TODO: figure out if we can eliminate this
+        frameOutput->prepareToCopy();
+
+        while (!gStopRequested) {
+            // Poll for frames, the same way we do for MediaCodec.  We do
+            // all of the work on the main thread.
+            //
+            // Ideally we'd sleep indefinitely and wake when the
+            // stop was requested, but this will do for now.  (It almost
+            // works because wait() wakes when a signal hits, but we
+            // need to handle the edge cases.)
+            err = frameOutput->copyFrame(rawFp, 250000);
+            if (err == ETIMEDOUT) {
+                err = NO_ERROR;
+            } else if (err != NO_ERROR) {
+                ALOGE("Got error %d from copyFrame()", err);
+                break;
+            }
+        }
+    } else {
+        // Main encoder loop.
+        err = runEncoder(encoder, muxer, rawFp, mainDpy, dpy,
+                mainDpyInfo.orientation);
+        if (err != NO_ERROR) {
+            fprintf(stderr, "Encoder failed (err=%d)\n", err);
+            // fall through to cleanup
+        }
+
+        if (gVerbose) {
+            printf("Stopping encoder and muxer\n");
+        }
     }
 
     // Shut everything down, starting with the producer side.
     encoderInputSurface = NULL;
     SurfaceComposerClient::destroyDisplay(dpy);
-    if (overlay != NULL) {
-        overlay->stop();
+    if (overlay != NULL) overlay->stop();
+    if (encoder != NULL) encoder->stop();
+    if (muxer != NULL) {
+        // If we don't stop muxer explicitly, i.e. let the destructor run,
+        // it may hang (b/11050628).
+        muxer->stop();
+    } else if (rawFp != stdout) {
+        fclose(rawFp);
     }
-    encoder->stop();
-    // If we don't stop muxer explicitly, i.e. let the destructor run,
-    // it may hang (b/11050628).
-    muxer->stop();
-    encoder->release();
+    if (encoder != NULL) encoder->release();
 
     return err;
 }
@@ -749,10 +872,12 @@
         { "size",               required_argument,  NULL, 's' },
         { "bit-rate",           required_argument,  NULL, 'b' },
         { "time-limit",         required_argument,  NULL, 't' },
+        { "bugreport",          no_argument,        NULL, 'u' },
+        // "unofficial" options
         { "show-device-info",   no_argument,        NULL, 'i' },
         { "show-frame-time",    no_argument,        NULL, 'f' },
-        { "bugreport",          no_argument,        NULL, 'u' },
         { "rotate",             no_argument,        NULL, 'r' },
+        { "output-format",      required_argument,  NULL, 'o' },
         { NULL,                 0,                  NULL, 0 }
     };
 
@@ -804,20 +929,32 @@
                 return 2;
             }
             break;
+        case 'u':
+            gWantInfoScreen = true;
+            gWantFrameTime = true;
+            break;
         case 'i':
             gWantInfoScreen = true;
             break;
         case 'f':
             gWantFrameTime = true;
             break;
-        case 'u':
-            gWantInfoScreen = true;
-            gWantFrameTime = true;
-            break;
         case 'r':
             // experimental feature
             gRotate = true;
             break;
+        case 'o':
+            if (strcmp(optarg, "mp4") == 0) {
+                gOutputFormat = FORMAT_MP4;
+            } else if (strcmp(optarg, "h264") == 0) {
+                gOutputFormat = FORMAT_H264;
+            } else if (strcmp(optarg, "frames") == 0) {
+                gOutputFormat = FORMAT_FRAMES;
+            } else {
+                fprintf(stderr, "Unknown format '%s'\n", optarg);
+                return 2;
+            }
+            break;
         default:
             if (ic != '?') {
                 fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
@@ -831,17 +968,19 @@
         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;
+    if (gOutputFormat == FORMAT_MP4) {
+        // 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.
+        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);
     }
-    close(fd);
 
     status_t err = recordScreen(fileName);
     if (err == NO_ERROR) {
diff --git a/cmds/screenrecord/screenrecord.h b/cmds/screenrecord/screenrecord.h
index 95e8a68..9b058c2 100644
--- a/cmds/screenrecord/screenrecord.h
+++ b/cmds/screenrecord/screenrecord.h
@@ -18,6 +18,6 @@
 #define SCREENRECORD_SCREENRECORD_H
 
 #define kVersionMajor 1
-#define kVersionMinor 1
+#define kVersionMinor 2
 
 #endif /*SCREENRECORD_SCREENRECORD_H*/
diff --git a/cmds/stagefright/SimplePlayer.cpp b/cmds/stagefright/SimplePlayer.cpp
index 5d2d721..1b2f792 100644
--- a/cmds/stagefright/SimplePlayer.cpp
+++ b/cmds/stagefright/SimplePlayer.cpp
@@ -23,6 +23,7 @@
 #include <gui/Surface.h>
 #include <media/AudioTrack.h>
 #include <media/ICrypto.h>
+#include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -275,7 +276,8 @@
 
     mExtractor = new NuMediaExtractor;
 
-    status_t err = mExtractor->setDataSource(mPath.c_str());
+    status_t err = mExtractor->setDataSource(
+            NULL /* httpService */, mPath.c_str());
 
     if (err != OK) {
         mExtractor.clear();
diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp
index 14b4306..587077a 100644
--- a/cmds/stagefright/SineSource.cpp
+++ b/cmds/stagefright/SineSource.cpp
@@ -24,7 +24,7 @@
     }
 }
 
-status_t SineSource::start(MetaData *params) {
+status_t SineSource::start(MetaData * /* params */) {
     CHECK(!mStarted);
 
     mGroup = new MediaBufferGroup;
@@ -58,7 +58,7 @@
 }
 
 status_t SineSource::read(
-        MediaBuffer **out, const ReadOptions *options) {
+        MediaBuffer **out, const ReadOptions * /* options */) {
     *out = NULL;
 
     MediaBuffer *buffer;
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index d125ad1..fd02bcc 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -24,6 +24,7 @@
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <media/ICrypto.h>
+#include <media/IMediaHTTPService.h>
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -76,7 +77,7 @@
     static int64_t kTimeout = 500ll;
 
     sp<NuMediaExtractor> extractor = new NuMediaExtractor;
-    if (extractor->setDataSource(path) != OK) {
+    if (extractor->setDataSource(NULL /* httpService */, path) != OK) {
         fprintf(stderr, "unable to instantiate extractor.\n");
         return 1;
     }
diff --git a/cmds/stagefright/muxer.cpp b/cmds/stagefright/muxer.cpp
index 90daea2..f4a33e8 100644
--- a/cmds/stagefright/muxer.cpp
+++ b/cmds/stagefright/muxer.cpp
@@ -20,6 +20,7 @@
 #include <utils/Log.h>
 
 #include <binder/ProcessState.h>
+#include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -59,7 +60,7 @@
         int trimEndTimeMs,
         int rotationDegrees) {
     sp<NuMediaExtractor> extractor = new NuMediaExtractor;
-    if (extractor->setDataSource(path) != OK) {
+    if (extractor->setDataSource(NULL /* httpService */, path) != OK) {
         fprintf(stderr, "unable to instantiate extractor. %s\n", path);
         return 1;
     }
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index b7a40c2..fdc352e 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -296,7 +296,7 @@
 }
 #else
 
-int main(int argc, char **argv) {
+int main(int /* argc */, char ** /* argv */) {
     android::ProcessState::self()->startThreadPool();
 
     OMXClient client;
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index b2b9ce5..3c0c7ec 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -19,8 +19,12 @@
 #include <inttypes.h>
 #include <utils/Log.h>
 
+#include <signal.h>
+
 #include <binder/ProcessState.h>
 
+#include <media/IMediaHTTPService.h>
+
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -43,6 +47,18 @@
 
 using namespace android;
 
+volatile static bool ctrlc = false;
+
+static sighandler_t oldhandler = NULL;
+
+static void mysighandler(int signum) {
+    if (signum == SIGINT) {
+        ctrlc = true;
+        return;
+    }
+    oldhandler(signum);
+}
+
 struct Controller : public AHandler {
     Controller(const char *uri, bool decodeAudio,
                const sp<Surface> &surface, bool renderToSurface)
@@ -63,7 +79,30 @@
     virtual ~Controller() {
     }
 
+    virtual void printStatistics() {
+        int64_t delayUs = ALooper::GetNowUs() - mStartTimeUs;
+
+        if (mDecodeAudio) {
+            printf("%" PRId64 " bytes received. %.2f KB/sec\n",
+            mTotalBytesReceived,
+            mTotalBytesReceived * 1E6 / 1024 / delayUs);
+        } else {
+            printf("%d frames decoded, %.2f fps. %" PRId64 " bytes "
+                    "received. %.2f KB/sec\n",
+            mNumOutputBuffersReceived,
+            mNumOutputBuffersReceived * 1E6 / delayUs,
+            mTotalBytesReceived,
+            mTotalBytesReceived * 1E6 / 1024 / delayUs);
+        }
+    }
+
     virtual void onMessageReceived(const sp<AMessage> &msg) {
+        if (ctrlc) {
+            printf("\n");
+            printStatistics();
+            (new AMessage(kWhatStop, id()))->post();
+            ctrlc = false;
+        }
         switch (msg->what()) {
             case kWhatStart:
             {
@@ -76,7 +115,8 @@
 #endif
 
                 sp<DataSource> dataSource =
-                    DataSource::CreateFromURI(mURI.c_str());
+                    DataSource::CreateFromURI(
+                            NULL /* httpService */, mURI.c_str());
 
                 sp<MediaExtractor> extractor =
                     MediaExtractor::Create(dataSource);
@@ -99,7 +139,10 @@
                         break;
                     }
                 }
-                CHECK(mSource != NULL);
+                if (mSource == NULL) {
+                    printf("no %s track found\n", mDecodeAudio ? "audio" : "video");
+                    exit (1);
+                }
 
                 CHECK_EQ(mSource->start(), (status_t)OK);
 
@@ -181,21 +224,7 @@
                         || what == ACodec::kWhatError) {
                     printf((what == ACodec::kWhatEOS) ? "$\n" : "E\n");
 
-                    int64_t delayUs = ALooper::GetNowUs() - mStartTimeUs;
-
-                    if (mDecodeAudio) {
-                        printf("%" PRId64 " bytes received. %.2f KB/sec\n",
-                               mTotalBytesReceived,
-                               mTotalBytesReceived * 1E6 / 1024 / delayUs);
-                    } else {
-                        printf("%d frames decoded, %.2f fps. %" PRId64 " bytes "
-                               "received. %.2f KB/sec\n",
-                               mNumOutputBuffersReceived,
-                               mNumOutputBuffersReceived * 1E6 / delayUs,
-                               mTotalBytesReceived,
-                               mTotalBytesReceived * 1E6 / 1024 / delayUs);
-                    }
-
+                    printStatistics();
                     (new AMessage(kWhatStop, id()))->post();
                 } else if (what == ACodec::kWhatFlushCompleted) {
                     mSeekState = SEEK_FLUSH_COMPLETED;
@@ -639,6 +668,8 @@
 
     looper->registerHandler(controller);
 
+    signal(SIGINT, mysighandler);
+
     controller->startAsync();
 
     CHECK_EQ(looper->start(true /* runOnCallingThread */), (status_t)OK);
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 8efb39e..daaea27 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -29,6 +29,7 @@
 
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
+#include <media/IMediaHTTPService.h>
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include "include/NuCachedSource2.h"
@@ -960,7 +961,8 @@
 
         const char *filename = argv[k];
 
-        sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
+        sp<DataSource> dataSource =
+            DataSource::CreateFromURI(NULL /* httpService */, filename);
 
         if (strncasecmp(filename, "sine:", 5) && dataSource == NULL) {
             fprintf(stderr, "Unable to create data source.\n");
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index dba67a9..b2abc0f 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -21,6 +21,7 @@
 #include <binder/ProcessState.h>
 #include <cutils/properties.h> // for property_get
 
+#include <media/IMediaHTTPService.h>
 #include <media/IStreamSource.h>
 #include <media/mediaplayer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -159,7 +160,9 @@
 MyConvertingStreamSource::MyConvertingStreamSource(const char *filename)
     : mCurrentBufferIndex(-1),
       mCurrentBufferOffset(0) {
-    sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
+    sp<DataSource> dataSource =
+        DataSource::CreateFromURI(NULL /* httpService */, filename);
+
     CHECK(dataSource != NULL);
 
     sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
index 234aef2..f400732 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
@@ -316,6 +316,7 @@
 
     if (-1 < fileDesc) {
         if (FwdLockFile_attach(fileDesc) < 0) {
+            close(fileDesc);
             return mimeString;
         }
         const char* pMimeType = FwdLockFile_GetContentType(fileDesc);
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index f342122..6e48f22 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -31,6 +31,7 @@
 class ICameraDeviceUser;
 class ICameraDeviceCallbacks;
 class CameraMetadata;
+class VendorTagDescriptor;
 
 class ICameraService : public IInterface
 {
@@ -47,6 +48,7 @@
         ADD_LISTENER,
         REMOVE_LISTENER,
         GET_CAMERA_CHARACTERISTICS,
+        GET_CAMERA_VENDOR_TAG_DESCRIPTOR,
     };
 
     enum {
@@ -58,10 +60,16 @@
 
     virtual int32_t  getNumberOfCameras() = 0;
     virtual status_t getCameraInfo(int cameraId,
-                                          struct CameraInfo* cameraInfo) = 0;
+            /*out*/
+            struct CameraInfo* cameraInfo) = 0;
 
     virtual status_t getCameraCharacteristics(int cameraId,
-                                              CameraMetadata* cameraInfo) = 0;
+            /*out*/
+            CameraMetadata* cameraInfo) = 0;
+
+    virtual status_t getCameraVendorTagDescriptor(
+            /*out*/
+            sp<VendorTagDescriptor>& desc) = 0;
 
     // Returns 'OK' if operation succeeded
     // - Errors: ALREADY_EXISTS if the listener was already added
diff --git a/include/camera/VendorTagDescriptor.h b/include/camera/VendorTagDescriptor.h
new file mode 100644
index 0000000..ea21d31
--- /dev/null
+++ b/include/camera/VendorTagDescriptor.h
@@ -0,0 +1,124 @@
+/*
+ * 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 VENDOR_TAG_DESCRIPTOR_H
+
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/RefBase.h>
+#include <system/camera_vendor_tags.h>
+
+#include <stdint.h>
+
+namespace android {
+
+class Parcel;
+
+/**
+ * VendorTagDescriptor objects are parcelable containers for the vendor tag
+ * definitions provided, and are typically used to pass the vendor tag
+ * information enumerated by the HAL to clients of the camera service.
+ */
+class VendorTagDescriptor
+        : public LightRefBase<VendorTagDescriptor> {
+    public:
+        virtual ~VendorTagDescriptor();
+
+        /**
+         * The following 'get*' methods implement the corresponding
+         * functions defined in
+         * system/media/camera/include/system/camera_vendor_tags.h
+         */
+
+        // Returns the number of vendor tags defined.
+        int getTagCount() const;
+
+        // Returns an array containing the id's of vendor tags defined.
+        void getTagArray(uint32_t* tagArray) const;
+
+        // Returns the section name string for a given vendor tag id.
+        const char* getSectionName(uint32_t tag) const;
+
+        // Returns the tag name string for a given vendor tag id.
+        const char* getTagName(uint32_t tag) const;
+
+        // Returns the tag type for a given vendor tag id.
+        int getTagType(uint32_t tag) const;
+
+        /**
+         * Write the VendorTagDescriptor object into the given parcel.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        status_t writeToParcel(
+                /*out*/
+                Parcel* parcel) const;
+
+        // Static methods:
+
+        /**
+         * Create a VendorTagDescriptor object from the given parcel.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        static status_t createFromParcel(const Parcel* parcel,
+                /*out*/
+                sp<VendorTagDescriptor>& descriptor);
+
+        /**
+         * Create a VendorTagDescriptor object from the given vendor_tag_ops_t
+         * struct.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        static status_t createDescriptorFromOps(const vendor_tag_ops_t* vOps,
+                /*out*/
+                sp<VendorTagDescriptor>& descriptor);
+
+        /**
+         * Sets the global vendor tag descriptor to use for this process.
+         * Camera metadata operations that access vendor tags will use the
+         * vendor tag definitions set this way.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        static status_t setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc);
+
+        /**
+         * Clears the global vendor tag descriptor used by this process.
+         */
+        static void clearGlobalVendorTagDescriptor();
+
+        /**
+         * Returns the global vendor tag descriptor used by this process.
+         * This will contain NULL if no vendor tags are defined.
+         */
+        static sp<VendorTagDescriptor> getGlobalVendorTagDescriptor();
+    protected:
+        VendorTagDescriptor();
+        KeyedVector<uint32_t, String8> mTagToNameMap;
+        KeyedVector<uint32_t, String8> mTagToSectionMap;
+        KeyedVector<uint32_t, int32_t> mTagToTypeMap;
+        // must be int32_t to be compatible with Parcel::writeInt32
+        int32_t mTagCount;
+    private:
+        vendor_tag_ops mVendorOps;
+};
+
+} /* namespace android */
+
+#define VENDOR_TAG_DESCRIPTOR_H
+#endif /* VENDOR_TAG_DESCRIPTOR_H */
diff --git a/include/media/AudioBufferProvider.h b/include/media/AudioBufferProvider.h
index ef392f0..7be449c 100644
--- a/include/media/AudioBufferProvider.h
+++ b/include/media/AudioBufferProvider.h
@@ -61,6 +61,17 @@
     //  buffer->frameCount  0
     virtual status_t getNextBuffer(Buffer* buffer, int64_t pts = kInvalidPTS) = 0;
 
+    // Release (a portion of) the buffer previously obtained by getNextBuffer().
+    // It is permissible to call releaseBuffer() multiple times per getNextBuffer().
+    // On entry:
+    //  buffer->frameCount  number of frames to release, must be <= number of frames
+    //                      obtained but not yet released
+    //  buffer->raw         unused
+    // On return:
+    //  buffer->frameCount  0; implementation MUST set to zero
+    //  buffer->raw         undefined; implementation is PERMITTED to set to any value,
+    //                      so if caller needs to continue using this buffer it must
+    //                      keep track of the pointer itself
     virtual void releaseBuffer(Buffer* buffer) = 0;
 };
 
diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h
index 05d834d..f3024b7 100644
--- a/include/media/AudioEffect.h
+++ b/include/media/AudioEffect.h
@@ -36,7 +36,7 @@
 
 // ----------------------------------------------------------------------------
 
-class effect_param_cblk_t;
+struct effect_param_cblk_t;
 
 // ----------------------------------------------------------------------------
 
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 052064d..b3c44a8 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -26,7 +26,7 @@
 
 // ----------------------------------------------------------------------------
 
-class audio_track_cblk_t;
+struct audio_track_cblk_t;
 class AudioRecordClientProxy;
 
 // ----------------------------------------------------------------------------
@@ -39,8 +39,12 @@
      * Keep in sync with frameworks/base/media/java/android/media/AudioRecord.java NATIVE_EVENT_*.
      */
     enum event_type {
-        EVENT_MORE_DATA = 0,        // Request to read more data from PCM buffer.
-        EVENT_OVERRUN = 1,          // PCM buffer overrun occurred.
+        EVENT_MORE_DATA = 0,        // Request to read available data from buffer.
+                                    // If this event is delivered but the callback handler
+                                    // does not want to read the available data, the handler must
+                                    // explicitly
+                                    // ignore the event by setting frameCount to zero.
+        EVENT_OVERRUN = 1,          // Buffer overrun occurred.
         EVENT_MARKER = 2,           // Record head is at the specified marker position
                                     // (See setMarkerPosition()).
         EVENT_NEW_POS = 3,          // Record head is at a new position
@@ -60,9 +64,10 @@
         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)
+                                    // (currently ignored but will make the primary field in future)
 
         size_t      size;           // input/output in bytes == frameCount * frameSize
+                                    // on output is the number of bytes actually drained
                                     // 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
@@ -76,7 +81,7 @@
 
     /* 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 ready or various conditions occur.
+     * invokes the callback when a new buffer becomes available or various conditions occur.
      * Parameters:
      *
      * event:   type of event notified (see enum AudioRecord::event_type).
@@ -99,6 +104,8 @@
      *  - NO_ERROR: successful operation
      *  - NO_INIT: audio server or audio hardware not initialized
      *  - BAD_VALUE: unsupported configuration
+     * frameCount is guaranteed to be non-zero if status is NO_ERROR,
+     * and is undefined otherwise.
      */
 
      static status_t getMinFrameCount(size_t* frameCount,
@@ -109,7 +116,7 @@
     /* How data is transferred from AudioRecord
      */
     enum transfer_type {
-        TRANSFER_DEFAULT,   // not specified explicitly; determine from other parameters
+        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 read()
@@ -137,7 +144,7 @@
      *                     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 and inform of marker, position updates, etc.
+     *                     to consume new 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.
@@ -151,11 +158,11 @@
                                     uint32_t sampleRate,
                                     audio_format_t format,
                                     audio_channel_mask_t channelMask,
-                                    int frameCount      = 0,
+                                    size_t frameCount = 0,
                                     callback_t cbf = NULL,
                                     void* user = NULL,
-                                    int notificationFrames = 0,
-                                    int sessionId = 0,
+                                    uint32_t notificationFrames = 0,
+                                    int sessionId = AUDIO_SESSION_ALLOCATE,
                                     transfer_type transferType = TRANSFER_DEFAULT,
                                     audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE);
 
@@ -171,9 +178,10 @@
      * Returned status (from utils/Errors.h) can be:
      *  - NO_ERROR: successful intialization
      *  - INVALID_OPERATION: AudioRecord is already initialized or record device is already in use
-     *  - BAD_VALUE: invalid parameter (channels, format, sampleRate...)
+     *  - BAD_VALUE: invalid parameter (channelMask, format, sampleRate...)
      *  - NO_INIT: audio server or audio hardware not initialized
      *  - PERMISSION_DENIED: recording is not allowed for the requesting process
+     * If status is not equal to NO_ERROR, don't call any other APIs on this AudioRecord.
      *
      * Parameters not listed in the AudioRecord constructors above:
      *
@@ -183,16 +191,16 @@
                             uint32_t sampleRate,
                             audio_format_t format,
                             audio_channel_mask_t channelMask,
-                            int frameCount      = 0,
+                            size_t frameCount = 0,
                             callback_t cbf = NULL,
                             void* user = NULL,
-                            int notificationFrames = 0,
+                            uint32_t notificationFrames = 0,
                             bool threadCanCallJava = false,
-                            int sessionId = 0,
+                            int sessionId = AUDIO_SESSION_ALLOCATE,
                             transfer_type transferType = TRANSFER_DEFAULT,
                             audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE);
 
-    /* Result of constructing the AudioRecord. This must be checked
+    /* Result of constructing the AudioRecord. This must be checked for successful initialization
      * before using any AudioRecord API (except for set()), because using
      * an uninitialized AudioRecord produces undefined results.
      * See set() method above for possible return codes.
@@ -221,7 +229,7 @@
             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.  Note that obtainBuffer() still
+    /* Stop a track.  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();
@@ -236,7 +244,7 @@
      * 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.
+     * a workaround is to 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.
      *
@@ -378,8 +386,10 @@
      * returning the current value by this function call.  Such loss typically occurs when the
      * user space process is blocked longer than the capacity of audio driver buffers.
      * Units: the number of input audio frames.
+     * FIXME The side-effect of resetting the counter may be incompatible with multi-client.
+     * Consider making it more like AudioTrack::getUnderrunFrames which doesn't have side effects.
      */
-            unsigned int  getInputFramesLost() const;
+            uint32_t    getInputFramesLost() const;
 
 private:
     /* copying audio record objects is not allowed */
@@ -412,6 +422,7 @@
         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 AudioRecordThread::threadLoop()
@@ -422,9 +433,10 @@
             //      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);
+            nsecs_t processAudioBuffer();
 
             // 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'
@@ -446,12 +458,13 @@
                                                     // notification callback
     uint32_t                mNotificationFramesAct; // actual number of frames between each
                                                     // notification callback
-    bool                    mRefreshRemaining;  // processAudioBuffer() should refresh next 2
+    bool                    mRefreshRemaining;      // processAudioBuffer() should refresh
+                                                    // mRemainingFrames and mRetryOnPartialBuffer
 
     // 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                mObservedSequence;      // last observed value of mSequence
 
     uint32_t                mMarkerPosition;    // in wrapping (overflow) frame units
     bool                    mMarkerReached;
@@ -460,9 +473,13 @@
 
     status_t                mStatus;
 
+    size_t                  mFrameCount;            // corresponds to current IAudioRecord, value is
+                                                    // reported back by AudioFlinger to the client
+    size_t                  mReqFrameCount;         // frame count to request the first or next time
+                                                    // a new IAudioRecord is needed, non-decreasing
+
     // constant after constructor or set()
     uint32_t                mSampleRate;
-    size_t                  mFrameCount;
     audio_format_t          mFormat;
     uint32_t                mChannelCount;
     size_t                  mFrameSize;         // app-level frame size == AudioFlinger frame size
@@ -473,12 +490,11 @@
     int                     mSessionId;
     transfer_type           mTransfer;
 
-    audio_io_handle_t       mInput;             // returned by AudioSystem::getInput()
-
-    // may be changed if IAudioRecord object is re-created
+    // Next 4 fields may be changed if IAudioRecord is re-created, but always != 0
     sp<IAudioRecord>        mAudioRecord;
     sp<IMemory>             mCblkMemory;
     audio_track_cblk_t*     mCblk;              // re-load after mLock.unlock()
+    audio_io_handle_t       mInput;             // returned by AudioSystem::getInput()
 
     int                     mPreviousPriority;  // before start()
     SchedPolicy             mPreviousSchedulingGroup;
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 4c22412..28fdfd4 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -67,20 +67,24 @@
 
     // returns true in *state if tracks are active on the specified stream or have been active
     // in the past inPastMs milliseconds
-    static status_t isStreamActive(audio_stream_type_t stream, bool *state, uint32_t inPastMs = 0);
+    static status_t isStreamActive(audio_stream_type_t stream, bool *state, uint32_t inPastMs);
     // returns true in *state if tracks are active for what qualifies as remote playback
     // on the specified stream or have been active in the past inPastMs milliseconds. Remote
     // playback isn't mutually exclusive with local playback.
     static status_t isStreamActiveRemotely(audio_stream_type_t stream, bool *state,
-            uint32_t inPastMs = 0);
+            uint32_t inPastMs);
     // returns true in *state if a recorder is currently recording with the specified source
     static status_t isSourceActive(audio_source_t source, bool *state);
 
     // set/get audio hardware parameters. The function accepts a list of parameters
     // key value pairs in the form: key1=value1;key2=value2;...
     // Some keys are reserved for standard parameters (See AudioParameter class).
+    // The versions with audio_io_handle_t are intended for internal media framework use only.
     static status_t setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs);
     static String8  getParameters(audio_io_handle_t ioHandle, const String8& keys);
+    // The versions without audio_io_handle_t are intended for JNI.
+    static status_t setParameters(const String8& keyValuePairs);
+    static String8  getParameters(const String8& keys);
 
     static void setErrorCallback(audio_error_callback cb);
 
@@ -90,12 +94,14 @@
     static float linearToLog(int volume);
     static int logToLinear(float volume);
 
+    // Returned samplingRate and frameCount output values are guaranteed
+    // to be non-zero if status == NO_ERROR
     static status_t getOutputSamplingRate(uint32_t* samplingRate,
-            audio_stream_type_t stream = AUDIO_STREAM_DEFAULT);
+            audio_stream_type_t stream);
     static status_t getOutputFrameCount(size_t* frameCount,
-            audio_stream_type_t stream = AUDIO_STREAM_DEFAULT);
+            audio_stream_type_t stream);
     static status_t getOutputLatency(uint32_t* latency,
-            audio_stream_type_t stream = AUDIO_STREAM_DEFAULT);
+            audio_stream_type_t stream);
     static status_t getSamplingRate(audio_io_handle_t output,
                                           audio_stream_type_t streamType,
                                           uint32_t* samplingRate);
@@ -112,6 +118,7 @@
 
     static bool routedToA2dpOutput(audio_stream_type_t streamType);
 
+    // return status NO_ERROR implies *buffSize > 0
     static status_t getInputBufferSize(uint32_t sampleRate, audio_format_t format,
         audio_channel_mask_t channelMask, size_t* buffSize);
 
@@ -132,11 +139,11 @@
                                       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);
+    static uint32_t getInputFramesLost(audio_io_handle_t ioHandle);
 
     static int newAudioSessionId();
-    static void acquireAudioSessionId(int audioSession);
-    static void releaseAudioSessionId(int audioSession);
+    static void acquireAudioSessionId(int audioSession, pid_t pid);
+    static void releaseAudioSessionId(int audioSession, pid_t pid);
 
     // types of io configuration change events received with ioConfigChanged()
     enum io_config_event {
@@ -155,7 +162,8 @@
     class OutputDescriptor {
     public:
         OutputDescriptor()
-        : samplingRate(0), format(AUDIO_FORMAT_DEFAULT), channelMask(0), frameCount(0), latency(0)  {}
+        : samplingRate(0), format(AUDIO_FORMAT_DEFAULT), channelMask(0), frameCount(0), latency(0)
+            {}
 
         uint32_t samplingRate;
         audio_format_t format;
@@ -193,24 +201,32 @@
     static status_t setPhoneState(audio_mode_t state);
     static status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config);
     static audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage);
+
+    // Client must successfully hand off the handle reference to AudioFlinger via createTrack(),
+    // or release it with releaseOutput().
     static audio_io_handle_t getOutput(audio_stream_type_t stream,
                                         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,
                                         const audio_offload_info_t *offloadInfo = NULL);
+
     static status_t startOutput(audio_io_handle_t output,
                                 audio_stream_type_t stream,
-                                int session = 0);
+                                int session);
     static status_t stopOutput(audio_io_handle_t output,
                                audio_stream_type_t stream,
-                               int session = 0);
+                               int session);
     static void releaseOutput(audio_io_handle_t output);
+
+    // Client must successfully hand off the handle reference to AudioFlinger via openRecord(),
+    // or release it with releaseInput().
     static audio_io_handle_t getInput(audio_source_t inputSource,
-                                    uint32_t samplingRate = 0,
-                                    audio_format_t format = AUDIO_FORMAT_DEFAULT,
-                                    audio_channel_mask_t channelMask = AUDIO_CHANNEL_IN_MONO,
-                                    int sessionId = 0);
+                                    uint32_t samplingRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t channelMask,
+                                    int sessionId);
+
     static status_t startInput(audio_io_handle_t input);
     static status_t stopInput(audio_io_handle_t input);
     static void releaseInput(audio_io_handle_t input);
diff --git a/include/media/AudioTimestamp.h b/include/media/AudioTimestamp.h
index c29c7e5..99e9c3e 100644
--- a/include/media/AudioTimestamp.h
+++ b/include/media/AudioTimestamp.h
@@ -19,6 +19,8 @@
 
 #include <time.h>
 
+namespace android {
+
 class AudioTimestamp {
 public:
     AudioTimestamp() : mPosition(0) {
@@ -30,4 +32,6 @@
     struct timespec mTime;     // corresponding CLOCK_MONOTONIC when frame is expected to present
 };
 
+}   // namespace
+
 #endif  // ANDROID_AUDIO_TIMESTAMP_H
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 4736369..647748b 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -27,7 +27,7 @@
 
 // ----------------------------------------------------------------------------
 
-class audio_track_cblk_t;
+struct audio_track_cblk_t;
 class AudioTrackClientProxy;
 class StaticAudioTrackClientProxy;
 
@@ -123,6 +123,8 @@
      *  - NO_ERROR: successful operation
      *  - NO_INIT: audio server or audio hardware not initialized
      *  - BAD_VALUE: unsupported configuration
+     * frameCount is guaranteed to be non-zero if status is NO_ERROR,
+     * and is undefined otherwise.
      */
 
     static status_t getMinFrameCount(size_t* frameCount,
@@ -158,7 +160,7 @@
      * 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.
+     * channelMask:        Channel mask, such that audio_is_output_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 AudioTrack could be
@@ -180,15 +182,16 @@
                                     uint32_t sampleRate,
                                     audio_format_t format,
                                     audio_channel_mask_t,
-                                    int frameCount       = 0,
+                                    size_t frameCount    = 0,
                                     audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                                     callback_t cbf       = NULL,
                                     void* user           = NULL,
-                                    int notificationFrames = 0,
-                                    int sessionId        = 0,
+                                    uint32_t notificationFrames = 0,
+                                    int sessionId        = AUDIO_SESSION_ALLOCATE,
                                     transfer_type transferType = TRANSFER_DEFAULT,
                                     const audio_offload_info_t *offloadInfo = NULL,
-                                    int uid = -1);
+                                    int uid = -1,
+                                    pid_t pid = -1);
 
     /* Creates an audio track and registers it with AudioFlinger.
      * With this constructor, the track is configured for static buffer mode.
@@ -209,11 +212,12 @@
                                     audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                                     callback_t cbf      = NULL,
                                     void* user          = NULL,
-                                    int notificationFrames = 0,
-                                    int sessionId       = 0,
+                                    uint32_t notificationFrames = 0,
+                                    int sessionId       = AUDIO_SESSION_ALLOCATE,
                                     transfer_type transferType = TRANSFER_DEFAULT,
                                     const audio_offload_info_t *offloadInfo = NULL,
-                                    int uid = -1);
+                                    int uid = -1,
+                                    pid_t pid = -1);
 
     /* Terminates the AudioTrack and unregisters it from AudioFlinger.
      * Also destroys all resources associated with the AudioTrack.
@@ -241,17 +245,18 @@
                             uint32_t sampleRate,
                             audio_format_t format,
                             audio_channel_mask_t channelMask,
-                            int frameCount      = 0,
+                            size_t frameCount   = 0,
                             audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                             callback_t cbf      = NULL,
                             void* user          = NULL,
-                            int notificationFrames = 0,
+                            uint32_t notificationFrames = 0,
                             const sp<IMemory>& sharedBuffer = 0,
                             bool threadCanCallJava = false,
-                            int sessionId       = 0,
+                            int sessionId       = AUDIO_SESSION_ALLOCATE,
                             transfer_type transferType = TRANSFER_DEFAULT,
                             const audio_offload_info_t *offloadInfo = NULL,
-                            int uid = -1);
+                            int uid = -1,
+                            pid_t pid = -1);
 
     /* Result of constructing the AudioTrack. This must be checked for successful initialization
      * before using any AudioTrack API (except for set()), because using
@@ -279,7 +284,7 @@
             size_t      frameSize() const   { return mFrameSize; }
 
             uint32_t    channelCount() const { return mChannelCount; }
-            uint32_t    frameCount() const  { return mFrameCount; }
+            size_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; }
@@ -336,7 +341,7 @@
      */
             status_t    setSampleRate(uint32_t sampleRate);
 
-    /* Return current source sample rate in Hz, or 0 if unknown */
+    /* Return current source sample rate in Hz */
             uint32_t    getSampleRate() const;
 
     /* Enables looping and sets the start and end points of looping.
@@ -361,7 +366,7 @@
     /* 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 ~0 or 1.
+     * a workaround is to 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.
      *
@@ -452,7 +457,7 @@
      * Returned value:
      *  handle on audio hardware output
      */
-            audio_io_handle_t    getOutput();
+            audio_io_handle_t    getOutput() const;
 
     /* Returns the unique session ID associated with this track.
      *
@@ -551,8 +556,11 @@
      *      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().
+     * Default behavior is to only return until all data has been transferred. Set 'blocking' to
+     * false for the method to return immediately without waiting to try multiple times to write
+     * the full content of the buffer.
      */
-            ssize_t     write(const void* buffer, size_t size);
+            ssize_t     write(const void* buffer, size_t size, bool blocking = true);
 
     /*
      * Dumps the state of an audio track.
@@ -566,7 +574,7 @@
             uint32_t    getUnderrunFrames() const;
 
     /* Get the flags */
-            audio_output_flags_t getFlags() const { return mFlags; }
+            audio_output_flags_t getFlags() const { AutoMutex _l(mLock); return mFlags; }
 
     /* Set parameters - only possible when using direct output */
             status_t    setParameters(const String8& keyValuePairs);
@@ -626,53 +634,50 @@
             //      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);
+            nsecs_t processAudioBuffer();
 
+            bool     isOffloaded() const;
 
             // 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,
-                                 size_t epoch);
+            status_t createTrack_l(size_t epoch);
 
             // can only be called when mState != STATE_ACTIVE
             void flush_l();
 
             void setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount);
-            audio_io_handle_t getOutput_l();
 
             // FIXME enum is faster than strcmp() for parameter 'from'
             status_t restoreTrack_l(const char *from);
 
-            bool     isOffloaded() const
+            bool     isOffloaded_l() const
                 { return (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0; }
 
-    // Next 3 fields may be changed if IAudioTrack is re-created, but always != 0
+    // Next 4 fields may be changed if IAudioTrack is re-created, but always != 0
     sp<IAudioTrack>         mAudioTrack;
     sp<IMemory>             mCblkMemory;
     audio_track_cblk_t*     mCblk;                  // re-load after mLock.unlock()
+    audio_io_handle_t       mOutput;                // returned by AudioSystem::getOutput()
 
     sp<AudioTrackThread>    mAudioTrackThread;
+
     float                   mVolume[2];
     float                   mSendLevel;
     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
-
+    size_t                  mFrameCount;            // corresponds to current IAudioTrack, value is
+                                                    // reported back by AudioFlinger to the client
+    size_t                  mReqFrameCount;         // frame count to request the first or next time
+                                                    // a new IAudioTrack is needed, non-decreasing
 
     // 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;
+    sp<IMemory>             mSharedBuffer;
     transfer_type           mTransfer;
+    audio_offload_info_t    mOffloadInfoCopy;
+    const audio_offload_info_t* mOffloadInfo;
 
     // 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.
@@ -705,21 +710,25 @@
     uint32_t                mNotificationFramesAct; // actual number of frames between each
                                                     // notification callback,
                                                     // at initial source sample rate
-    bool                    mRefreshRemaining;      // processAudioBuffer() should refresh next 2
+    bool                    mRefreshRemaining;      // processAudioBuffer() should refresh
+                                                    // mRemainingFrames and mRetryOnPartialBuffer
 
     // 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;
     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, zero means no EVENT_NEW_POS
 
     audio_output_flags_t    mFlags;
+        // const after set(), except for bits AUDIO_OUTPUT_FLAG_FAST and AUDIO_OUTPUT_FLAG_OFFLOAD.
+        // mLock must be held to read or write those bits reliably.
+
     int                     mSessionId;
     int                     mAuxEffectId;
 
@@ -739,7 +748,6 @@
     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:
@@ -754,8 +762,8 @@
 
     sp<DeathNotifier>       mDeathNotifier;
     uint32_t                mSequence;              // incremented for each new IAudioTrack attempt
-    audio_io_handle_t       mOutput;                // cached output io handle
     int                     mClientUid;
+    pid_t                   mClientPid;
 };
 
 class TimedAudioTrack : public AudioTrack
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 282f275..9101f06 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -64,25 +64,27 @@
                                 uint32_t sampleRate,
                                 audio_format_t format,
                                 audio_channel_mask_t channelMask,
-                                size_t frameCount,
+                                size_t *pFrameCount,
                                 track_flags_t *flags,
                                 const sp<IMemory>& sharedBuffer,
+                                // On successful return, AudioFlinger takes over the handle
+                                // reference and will release it when the track is destroyed.
+                                // However on failure, the client is responsible for release.
                                 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(
+                                // On successful return, AudioFlinger takes over the handle
+                                // reference and will release it when the track is destroyed.
+                                // However on failure, the client is responsible for release.
                                 audio_io_handle_t input,
                                 uint32_t sampleRate,
                                 audio_format_t format,
                                 audio_channel_mask_t channelMask,
-                                size_t frameCount,
+                                size_t *pFrameCount,
                                 track_flags_t *flags,
                                 pid_t tid,  // -1 means unused, otherwise must be valid non-0
                                 int *sessionId,
@@ -163,7 +165,7 @@
                                         audio_channel_mask_t *pChannelMask) = 0;
     virtual status_t closeInput(audio_io_handle_t input) = 0;
 
-    virtual status_t setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output) = 0;
+    virtual status_t invalidateStream(audio_stream_type_t stream) = 0;
 
     virtual status_t setVoiceVolume(float volume) = 0;
 
@@ -174,8 +176,8 @@
 
     virtual int newAudioSessionId() = 0;
 
-    virtual void acquireAudioSessionId(int audioSession) = 0;
-    virtual void releaseAudioSessionId(int audioSession) = 0;
+    virtual void acquireAudioSessionId(int audioSession, pid_t pid) = 0;
+    virtual void releaseAudioSessionId(int audioSession, pid_t pid) = 0;
 
     virtual status_t queryNumberEffects(uint32_t *numEffects) const = 0;
 
@@ -188,6 +190,7 @@
                                     effect_descriptor_t *pDesc,
                                     const sp<IEffectClient>& client,
                                     int32_t priority,
+                                    // AudioFlinger doesn't take over handle reference from client
                                     audio_io_handle_t output,
                                     int sessionId,
                                     status_t *status,
diff --git a/include/media/IMediaHTTPConnection.h b/include/media/IMediaHTTPConnection.h
new file mode 100644
index 0000000..2a63eb7
--- /dev/null
+++ b/include/media/IMediaHTTPConnection.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef I_MEDIA_HTTP_CONNECTION_H_
+
+#define I_MEDIA_HTTP_CONNECTION_H_
+
+#include <binder/IInterface.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+struct IMediaHTTPConnection;
+
+/** MUST stay in sync with IMediaHTTPConnection.aidl */
+
+struct IMediaHTTPConnection : public IInterface {
+    DECLARE_META_INTERFACE(MediaHTTPConnection);
+
+    virtual bool connect(
+            const char *uri, const KeyedVector<String8, String8> *headers) = 0;
+
+    virtual void disconnect() = 0;
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size) = 0;
+    virtual off64_t getSize() = 0;
+    virtual status_t getMIMEType(String8 *mimeType) = 0;
+    virtual status_t getUri(String8 *uri) = 0;
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(IMediaHTTPConnection);
+};
+
+}  // namespace android
+
+#endif  // I_MEDIA_HTTP_CONNECTION_H_
diff --git a/include/media/IMediaHTTPService.h b/include/media/IMediaHTTPService.h
new file mode 100644
index 0000000..f66d6c8
--- /dev/null
+++ b/include/media/IMediaHTTPService.h
@@ -0,0 +1,41 @@
+/*
+ * 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 I_MEDIA_HTTP_SERVICE_H_
+
+#define I_MEDIA_HTTP_SERVICE_H_
+
+#include <binder/IInterface.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+struct IMediaHTTPConnection;
+
+/** MUST stay in sync with IMediaHTTPService.aidl */
+
+struct IMediaHTTPService : public IInterface {
+    DECLARE_META_INTERFACE(MediaHTTPService);
+
+    virtual sp<IMediaHTTPConnection> makeHTTPConnection() = 0;
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(IMediaHTTPService);
+};
+
+}  // namespace android
+
+#endif  // I_MEDIA_HTTP_SERVICE_H_
diff --git a/include/media/IMediaMetadataRetriever.h b/include/media/IMediaMetadataRetriever.h
index 6dbb2d7..2529800 100644
--- a/include/media/IMediaMetadataRetriever.h
+++ b/include/media/IMediaMetadataRetriever.h
@@ -26,6 +26,8 @@
 
 namespace android {
 
+struct IMediaHTTPService;
+
 class IMediaMetadataRetriever: public IInterface
 {
 public:
@@ -33,6 +35,7 @@
     virtual void            disconnect() = 0;
 
     virtual status_t        setDataSource(
+            const sp<IMediaHTTPService> &httpService,
             const char *srcUrl,
             const KeyedVector<String8, String8> *headers = NULL) = 0;
 
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index 0cbd269..db62cd5 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -33,6 +33,7 @@
 class Surface;
 class IStreamSource;
 class IGraphicBufferProducer;
+struct IMediaHTTPService;
 
 class IMediaPlayer: public IInterface
 {
@@ -41,8 +42,11 @@
 
     virtual void            disconnect() = 0;
 
-    virtual status_t        setDataSource(const char *url,
-                                    const KeyedVector<String8, String8>* headers) = 0;
+    virtual status_t        setDataSource(
+            const sp<IMediaHTTPService> &httpService,
+            const char *url,
+            const KeyedVector<String8, String8>* headers) = 0;
+
     virtual status_t        setDataSource(int fd, int64_t offset, int64_t length) = 0;
     virtual status_t        setDataSource(const sp<IStreamSource>& source) = 0;
     virtual status_t        setVideoSurfaceTexture(
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index 2998b37..5b45376 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -34,6 +34,7 @@
 struct ICrypto;
 struct IDrm;
 struct IHDCP;
+struct IMediaHTTPService;
 class IMediaRecorder;
 class IOMX;
 class IRemoteDisplay;
@@ -49,9 +50,14 @@
     virtual sp<IMediaMetadataRetriever> createMetadataRetriever() = 0;
     virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client, int audioSessionId = 0) = 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(
+            const sp<IMediaHTTPService> &httpService,
+            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;
@@ -93,9 +99,6 @@
 
     virtual void addBatteryData(uint32_t params) = 0;
     virtual status_t pullBatteryData(Parcel* reply) = 0;
-
-    virtual status_t updateProxyConfig(
-            const char *host, int32_t port, const char *exclusionList) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 6643736..f6f9e7a 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -143,6 +143,8 @@
         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
+        INTERNAL_OPTION_START_TIME, // data is an int64_t
+        INTERNAL_OPTION_TIME_LAPSE, // data is an int64_t[2]
     };
     virtual status_t setInternalOption(
             node_id node,
diff --git a/include/media/MediaMetadataRetrieverInterface.h b/include/media/MediaMetadataRetrieverInterface.h
index ecc3b65..bb6b97b 100644
--- a/include/media/MediaMetadataRetrieverInterface.h
+++ b/include/media/MediaMetadataRetrieverInterface.h
@@ -24,6 +24,8 @@
 
 namespace android {
 
+struct IMediaHTTPService;
+
 // Abstract base class
 class MediaMetadataRetrieverBase : public RefBase
 {
@@ -32,6 +34,7 @@
     virtual             ~MediaMetadataRetrieverBase() {}
 
     virtual status_t    setDataSource(
+            const sp<IMediaHTTPService> &httpService,
             const char *url,
             const KeyedVector<String8, String8> *headers = NULL) = 0;
 
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 26d8729..87717da 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -137,6 +137,7 @@
     }
 
     virtual status_t    setDataSource(
+            const sp<IMediaHTTPService> &httpService,
             const char *url,
             const KeyedVector<String8, String8> *headers = NULL) = 0;
 
@@ -213,11 +214,6 @@
         return INVALID_OPERATION;
     }
 
-    virtual status_t updateProxyConfig(
-            const char *host, int32_t port, const char *exclusionList) {
-        return INVALID_OPERATION;
-    }
-
 private:
     friend class MediaPlayerService;
 
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 0df77c1..b35cf32 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -25,6 +25,7 @@
 
 namespace android {
 
+struct IMediaHTTPService;
 class IMediaPlayerService;
 class IMediaMetadataRetriever;
 
@@ -68,6 +69,7 @@
     void disconnect();
 
     status_t setDataSource(
+            const sp<IMediaHTTPService> &httpService,
             const char *dataSourceUrl,
             const KeyedVector<String8, String8> *headers = NULL);
 
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 4c05fc3..f8e4e3b 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -189,6 +189,8 @@
     virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
 };
 
+struct IMediaHTTPService;
+
 class MediaPlayer : public BnMediaPlayerClient,
                     public virtual IMediaDeathNotifier
 {
@@ -199,6 +201,7 @@
             void            disconnect();
 
             status_t        setDataSource(
+                    const sp<IMediaHTTPService> &httpService,
                     const char *url,
                     const KeyedVector<String8, String8> *headers);
 
@@ -224,9 +227,14 @@
             bool            isLooping();
             status_t        setVolume(float leftVolume, float rightVolume);
             void            notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
-    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(
+            const sp<IMediaHTTPService> &httpService,
+            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);
@@ -242,9 +250,6 @@
             status_t        setRetransmitEndpoint(const char* addrString, uint16_t port);
             status_t        setNextMediaPlayer(const sp<MediaPlayer>& player);
 
-            status_t updateProxyConfig(
-                    const char *host, int32_t port, const char *exclusionList);
-
 private:
             void            clear_l();
             status_t        seekTo_l(int msec);
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 88a42a0..142cb90 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -39,7 +39,7 @@
 enum video_source {
     VIDEO_SOURCE_DEFAULT = 0,
     VIDEO_SOURCE_CAMERA = 1,
-    VIDEO_SOURCE_GRALLOC_BUFFER = 2,
+    VIDEO_SOURCE_SURFACE = 2,
 
     VIDEO_SOURCE_LIST_END  // must be last - used to validate audio source type
 };
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
index a73403b..4537679 100644
--- a/include/media/mediascanner.h
+++ b/include/media/mediascanner.h
@@ -21,6 +21,7 @@
 #include <utils/threads.h>
 #include <utils/List.h>
 #include <utils/Errors.h>
+#include <utils/String8.h>
 #include <pthread.h>
 
 struct dirent;
@@ -29,6 +30,7 @@
 
 class MediaScannerClient;
 class StringArray;
+class CharacterEncodingDetector;
 
 enum MediaScanResult {
     // This file or directory was scanned successfully.
@@ -94,15 +96,9 @@
     virtual status_t setMimeType(const char* mimeType) = 0;
 
 protected:
-    void convertValues(uint32_t encoding);
-
-protected:
-    // cached name and value strings, for native encoding support.
-    StringArray*    mNames;
-    StringArray*    mValues;
-
-    // default encoding based on MediaScanner::mLocale string
-    uint32_t        mLocaleEncoding;
+    // default encoding from MediaScanner::mLocale
+    String8 mLocale;
+    CharacterEncodingDetector *mEncodingDetector;
 };
 
 }; // namespace android
diff --git a/include/media/nbaio/AudioBufferProviderSource.h b/include/media/nbaio/AudioBufferProviderSource.h
index 2c4aaff..b16e20a 100644
--- a/include/media/nbaio/AudioBufferProviderSource.h
+++ b/include/media/nbaio/AudioBufferProviderSource.h
@@ -27,7 +27,7 @@
 class AudioBufferProviderSource : public NBAIO_Source {
 
 public:
-    AudioBufferProviderSource(AudioBufferProvider *provider, NBAIO_Format format);
+    AudioBufferProviderSource(AudioBufferProvider *provider, const NBAIO_Format& format);
     virtual ~AudioBufferProviderSource();
 
     // NBAIO_Port interface
diff --git a/include/media/nbaio/AudioStreamInSource.h b/include/media/nbaio/AudioStreamInSource.h
index 07d8c89..eaea63c 100644
--- a/include/media/nbaio/AudioStreamInSource.h
+++ b/include/media/nbaio/AudioStreamInSource.h
@@ -43,7 +43,7 @@
 
     // This is an over-estimate, and could dupe the caller into making a blocking read()
     // FIXME Use an audio HAL API to query the buffer filling status when it's available.
-    virtual ssize_t availableToRead() { return mStreamBufferSizeBytes >> mBitShift; }
+    virtual ssize_t availableToRead() { return mStreamBufferSizeBytes / mFrameSize; }
 
     virtual ssize_t read(void *buffer, size_t count);
 
diff --git a/include/media/nbaio/AudioStreamOutSink.h b/include/media/nbaio/AudioStreamOutSink.h
index 7948d40..9949b88 100644
--- a/include/media/nbaio/AudioStreamOutSink.h
+++ b/include/media/nbaio/AudioStreamOutSink.h
@@ -43,7 +43,7 @@
 
     // This is an over-estimate, and could dupe the caller into making a blocking write()
     // FIXME Use an audio HAL API to query the buffer emptying status when it's available.
-    virtual ssize_t availableToWrite() const { return mStreamBufferSizeBytes >> mBitShift; }
+    virtual ssize_t availableToWrite() const { return mStreamBufferSizeBytes / mFrameSize; }
 
     virtual ssize_t write(const void *buffer, size_t count);
 
diff --git a/include/media/nbaio/MonoPipe.h b/include/media/nbaio/MonoPipe.h
index d3802fe..b09b35f 100644
--- a/include/media/nbaio/MonoPipe.h
+++ b/include/media/nbaio/MonoPipe.h
@@ -41,7 +41,7 @@
     // Note: whatever shares this object with another thread needs to do so in an SMP-safe way (like
     // creating it the object before creating the other thread, or storing the object with a
     // release_store). Otherwise the other thread could see a partially-constructed object.
-    MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock = false);
+    MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock = false);
     virtual ~MonoPipe();
 
     // NBAIO_Port interface
diff --git a/include/media/nbaio/NBAIO.h b/include/media/nbaio/NBAIO.h
index 1da0c73..be0c15b 100644
--- a/include/media/nbaio/NBAIO.h
+++ b/include/media/nbaio/NBAIO.h
@@ -29,6 +29,7 @@
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 #include <media/AudioTimestamp.h>
+#include <system/audio.h>
 
 namespace android {
 
@@ -52,31 +53,41 @@
 // the combinations that are actually needed within AudioFlinger.  If the list of combinations grows
 // too large, then this decision should be re-visited.
 // Sample rate and channel count are explicit, PCM interleaved 16-bit is assumed.
-typedef unsigned NBAIO_Format;
-enum {
-    Format_Invalid
+struct NBAIO_Format {
+// FIXME make this a class, and change Format_... global methods to class methods
+//private:
+    unsigned    mSampleRate;
+    unsigned    mChannelCount;
+    audio_format_t  mFormat;
+    size_t      mFrameSize;
 };
 
-// Return the frame size of an NBAIO_Format in bytes
-size_t Format_frameSize(NBAIO_Format format);
+extern const NBAIO_Format Format_Invalid;
 
-// Return the frame size of an NBAIO_Format as a bit shift
-size_t Format_frameBitShift(NBAIO_Format format);
+// Return the frame size of an NBAIO_Format in bytes
+size_t Format_frameSize(const NBAIO_Format& format);
 
 // Convert a sample rate in Hz and channel count to an NBAIO_Format
-NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount);
+// FIXME rename
+NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount, audio_format_t format);
 
 // Return the sample rate in Hz of an NBAIO_Format
-unsigned Format_sampleRate(NBAIO_Format format);
+unsigned Format_sampleRate(const NBAIO_Format& format);
 
 // Return the channel count of an NBAIO_Format
-unsigned Format_channelCount(NBAIO_Format format);
+unsigned Format_channelCount(const NBAIO_Format& format);
 
 // Callbacks used by NBAIO_Sink::writeVia() and NBAIO_Source::readVia() below.
 typedef ssize_t (*writeVia_t)(void *user, void *buffer, size_t count);
 typedef ssize_t (*readVia_t)(void *user, const void *buffer,
                              size_t count, int64_t readPTS);
 
+// Check whether an NBAIO_Format is valid
+bool Format_isValid(const NBAIO_Format& format);
+
+// Compare two NBAIO_Format values
+bool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2);
+
 // Abstract class (interface) representing a data port.
 class NBAIO_Port : public RefBase {
 
@@ -115,15 +126,15 @@
     virtual NBAIO_Format format() const { return mNegotiated ? mFormat : Format_Invalid; }
 
 protected:
-    NBAIO_Port(NBAIO_Format format) : mNegotiated(false), mFormat(format),
-                                      mBitShift(Format_frameBitShift(format)) { }
+    NBAIO_Port(const NBAIO_Format& format) : mNegotiated(false), mFormat(format),
+                                             mFrameSize(Format_frameSize(format)) { }
     virtual ~NBAIO_Port() { }
 
     // Implementations are free to ignore these if they don't need them
 
     bool            mNegotiated;    // mNegotiated implies (mFormat != Format_Invalid)
     NBAIO_Format    mFormat;        // (mFormat != Format_Invalid) does not imply mNegotiated
-    size_t          mBitShift;      // assign in parallel with any assignment to mFormat
+    size_t          mFrameSize;     // assign in parallel with any assignment to mFormat
 };
 
 // Abstract class (interface) representing a non-blocking data sink, for use by a data provider.
@@ -220,7 +231,7 @@
     virtual status_t getTimestamp(AudioTimestamp& timestamp) { return INVALID_OPERATION; }
 
 protected:
-    NBAIO_Sink(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0) { }
+    NBAIO_Sink(const NBAIO_Format& format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0) { }
     virtual ~NBAIO_Sink() { }
 
     // Implementations are free to ignore these if they don't need them
@@ -311,7 +322,7 @@
     virtual void    onTimestamp(const AudioTimestamp& timestamp) { }
 
 protected:
-    NBAIO_Source(NBAIO_Format format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0) { }
+    NBAIO_Source(const NBAIO_Format& format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0) { }
     virtual ~NBAIO_Source() { }
 
     // Implementations are free to ignore these if they don't need them
diff --git a/include/media/nbaio/NBLog.h b/include/media/nbaio/NBLog.h
index 6d59ea7..bcbbc04 100644
--- a/include/media/nbaio/NBLog.h
+++ b/include/media/nbaio/NBLog.h
@@ -25,6 +25,8 @@
 
 namespace android {
 
+class String8;
+
 class NBLog {
 
 public:
@@ -187,6 +189,10 @@
     const Shared* const mShared; // raw pointer to shared memory
     const sp<IMemory> mIMemory; // ref-counted version
     int32_t     mFront;         // index of oldest acknowledged Entry
+    int     mFd;                // file descriptor
+    int     mIndent;            // indentation level
+
+    void    dumpLine(const String8& timestamp, String8& body);
 
     static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
 };
diff --git a/include/media/nbaio/Pipe.h b/include/media/nbaio/Pipe.h
index 79a4eee..c784129 100644
--- a/include/media/nbaio/Pipe.h
+++ b/include/media/nbaio/Pipe.h
@@ -30,7 +30,7 @@
 
 public:
     // maxFrames will be rounded up to a power of 2, and all slots are available. Must be >= 2.
-    Pipe(size_t maxFrames, NBAIO_Format format);
+    Pipe(size_t maxFrames, const NBAIO_Format& format);
     virtual ~Pipe();
 
     // NBAIO_Port interface
diff --git a/include/media/nbaio/SourceAudioBufferProvider.h b/include/media/nbaio/SourceAudioBufferProvider.h
index cdfb6fe..daf6bc3 100644
--- a/include/media/nbaio/SourceAudioBufferProvider.h
+++ b/include/media/nbaio/SourceAudioBufferProvider.h
@@ -41,7 +41,7 @@
 
 private:
     const sp<NBAIO_Source> mSource;     // the wrapped source
-    /*const*/ size_t    mFrameBitShift; // log2(frame size in bytes)
+    /*const*/ size_t    mFrameSize; // frame size in bytes
     void*               mAllocated; // pointer to base of allocated memory
     size_t              mSize;      // size of mAllocated in frames
     size_t              mOffset;    // frame offset within mAllocated of valid data
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 7ba5acc..863a7d5 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -67,8 +67,6 @@
 
     void signalRequestIDRFrame();
 
-    bool isConfiguredForAdaptivePlayback() { return mIsConfiguredForAdaptivePlayback; }
-
     struct PortDescription : public RefBase {
         size_t countBuffers();
         IOMX::buffer_id bufferIDAt(size_t index) const;
@@ -178,6 +176,8 @@
     sp<MemoryDealer> mDealer[2];
 
     sp<ANativeWindow> mNativeWindow;
+    sp<AMessage> mInputFormat;
+    sp<AMessage> mOutputFormat;
 
     Vector<BufferInfo> mBuffers[2];
     bool mPortEOS[2];
@@ -189,7 +189,6 @@
     bool mIsEncoder;
     bool mUseMetadataOnEncoderOutput;
     bool mShutdownInProgress;
-    bool mIsConfiguredForAdaptivePlayback;
 
     // If "mKeepComponentAllocated" we only transition back to Loaded state
     // and do not release the component instance.
@@ -203,10 +202,16 @@
     unsigned mDequeueCounter;
     bool mStoreMetaDataInOutputBuffers;
     int32_t mMetaDataBuffersToSubmit;
+    size_t mNumUndequeuedBuffers;
 
     int64_t mRepeatFrameDelayUs;
     int64_t mMaxPtsGapUs;
 
+    int64_t mTimePerFrameUs;
+    int64_t mTimePerCaptureUs;
+
+    bool mCreateInputBuffersSuspended;
+
     status_t setCyclicIntraMacroblockRefresh(const sp<AMessage> &msg, int32_t mode);
     status_t allocateBuffersOnPort(OMX_U32 portIndex);
     status_t freeBuffersOnPort(OMX_U32 portIndex);
@@ -300,6 +305,7 @@
     void processDeferredMessages();
 
     void sendFormatChange(const sp<AMessage> &reply);
+    status_t getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify);
 
     void signalError(
             OMX_ERRORTYPE error = OMX_ErrorUndefined,
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index a829916..dd0a106 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -172,7 +172,7 @@
                  const sp<IGraphicBufferProducer>& surface,
                  bool storeMetaDataInVideoBuffers);
 
-    virtual void startCameraRecording();
+    virtual status_t startCameraRecording();
     virtual void releaseRecordingFrame(const sp<IMemory>& frame);
 
     // Returns true if need to skip the current frame.
@@ -185,6 +185,8 @@
     virtual void dataCallbackTimestamp(int64_t timestampUs, int32_t msgType,
             const sp<IMemory> &data);
 
+    void releaseCamera();
+
 private:
     friend class CameraSourceListener;
 
@@ -233,7 +235,6 @@
                     int32_t frameRate);
 
     void stopCameraRecording();
-    void releaseCamera();
     status_t reset();
 
     CameraSource(const CameraSource &);
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index 157b1aa..f8787dd 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -31,6 +31,7 @@
 namespace android {
 
 struct AMessage;
+struct IMediaHTTPService;
 class String8;
 
 class DataSource : public RefBase {
@@ -43,6 +44,7 @@
     };
 
     static sp<DataSource> CreateFromURI(
+            const sp<IMediaHTTPService> &httpService,
             const char *uri,
             const KeyedVector<String8, String8> *headers = NULL);
 
diff --git a/include/media/stagefright/DataURISource.h b/include/media/stagefright/DataURISource.h
new file mode 100644
index 0000000..693562e
--- /dev/null
+++ b/include/media/stagefright/DataURISource.h
@@ -0,0 +1,49 @@
+/*
+ * 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 DATA_URI_SOURCE_H_
+
+#define DATA_URI_SOURCE_H_
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+struct ABuffer;
+
+struct DataURISource : public DataSource {
+    static sp<DataURISource> Create(const char *uri);
+
+    virtual status_t initCheck() const;
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+    virtual status_t getSize(off64_t *size);
+
+protected:
+    virtual ~DataURISource();
+
+private:
+    sp<ABuffer> mBuffer;
+
+    DataURISource(const sp<ABuffer> &buffer);
+
+    DISALLOW_EVIL_CONSTRUCTORS(DataURISource);
+};
+
+}  // namespace android
+
+#endif  // DATA_URI_SOURCE_H_
+
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 76aa503..276543b 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -106,6 +106,7 @@
     status_t signalEndOfInputStream();
 
     status_t getOutputFormat(sp<AMessage> *format) const;
+    status_t getInputFormat(sp<AMessage> *format) const;
 
     status_t getInputBuffers(Vector<sp<ABuffer> > *buffers) const;
     status_t getOutputBuffers(Vector<sp<ABuffer> > *buffers) const;
@@ -159,6 +160,7 @@
         kWhatGetBuffers                     = 'getB',
         kWhatFlush                          = 'flus',
         kWhatGetOutputFormat                = 'getO',
+        kWhatGetInputFormat                 = 'getI',
         kWhatDequeueInputTimedOut           = 'dITO',
         kWhatDequeueOutputTimedOut          = 'dOTO',
         kWhatCodecNotify                    = 'codc',
@@ -199,6 +201,7 @@
     sp<Surface> mNativeWindow;
     SoftwareRenderer *mSoftRenderer;
     sp<AMessage> mOutputFormat;
+    sp<AMessage> mInputFormat;
 
     List<size_t> mAvailPortBuffers[2];
     Vector<BufferInfo> mPortBuffers[2];
diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h
new file mode 100644
index 0000000..4b18a0b
--- /dev/null
+++ b/include/media/stagefright/MediaCodecSource.h
@@ -0,0 +1,134 @@
+/*
+ * 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 MediaCodecSource_H_
+#define MediaCodecSource_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AHandlerReflector.h>
+#include <media/stagefright/MediaSource.h>
+
+namespace android {
+
+class ALooper;
+class AMessage;
+class IGraphicBufferProducer;
+class MediaCodec;
+class MetaData;
+
+struct MediaCodecSource : public MediaSource,
+                          public MediaBufferObserver {
+    enum FlagBits {
+        FLAG_USE_SURFACE_INPUT      = 1,
+        FLAG_USE_METADATA_INPUT     = 2,
+    };
+
+    static sp<MediaCodecSource> Create(
+            const sp<ALooper> &looper,
+            const sp<AMessage> &format,
+            const sp<MediaSource> &source,
+            uint32_t flags = 0);
+
+    bool isVideo() const { return mIsVideo; }
+    sp<IGraphicBufferProducer> getGraphicBufferProducer();
+
+    // MediaSource
+    virtual status_t start(MetaData *params = NULL);
+    virtual status_t stop();
+    virtual status_t pause();
+    virtual sp<MetaData> getFormat() { return mMeta; }
+    virtual status_t read(
+            MediaBuffer **buffer,
+            const ReadOptions *options = NULL);
+
+    // MediaBufferObserver
+    virtual void signalBufferReturned(MediaBuffer *buffer);
+
+    // for AHandlerReflector
+    void onMessageReceived(const sp<AMessage> &msg);
+
+protected:
+    virtual ~MediaCodecSource();
+
+private:
+    struct Puller;
+
+    enum {
+        kWhatPullerNotify,
+        kWhatEncoderActivity,
+        kWhatStart,
+        kWhatStop,
+        kWhatPause,
+    };
+
+    MediaCodecSource(
+            const sp<ALooper> &looper,
+            const sp<AMessage> &outputFormat,
+            const sp<MediaSource> &source,
+            uint32_t flags = 0);
+
+    status_t onStart(MetaData *params);
+    status_t init();
+    status_t initEncoder();
+    void releaseEncoder();
+    status_t feedEncoderInputBuffers();
+    void scheduleDoMoreWork();
+    status_t doMoreWork();
+    void suspend();
+    void resume(int64_t skipFramesBeforeUs = -1ll);
+    void signalEOS(status_t err = ERROR_END_OF_STREAM);
+    bool reachedEOS();
+    status_t postSynchronouslyAndReturnError(const sp<AMessage> &msg);
+
+    sp<ALooper> mLooper;
+    sp<ALooper> mCodecLooper;
+    sp<AHandlerReflector<MediaCodecSource> > mReflector;
+    sp<AMessage> mOutputFormat;
+    sp<MetaData> mMeta;
+    sp<Puller> mPuller;
+    sp<MediaCodec> mEncoder;
+    uint32_t mFlags;
+    List<uint32_t> mStopReplyIDQueue;
+    bool mIsVideo;
+    bool mStarted;
+    bool mStopping;
+    bool mDoMoreWorkPending;
+    bool mPullerReachedEOS;
+    sp<AMessage> mEncoderActivityNotify;
+    sp<IGraphicBufferProducer> mGraphicBufferProducer;
+    Vector<sp<ABuffer> > mEncoderInputBuffers;
+    Vector<sp<ABuffer> > mEncoderOutputBuffers;
+    List<MediaBuffer *> mInputBufferQueue;
+    List<size_t> mAvailEncoderInputIndices;
+    List<int64_t> mDecodingTimeQueue; // decoding time (us) for video
+
+    // audio drift time
+    int64_t mFirstSampleTimeUs;
+    List<int64_t> mDriftTimeQueue;
+
+    // following variables are protected by mOutputBufferLock
+    Mutex mOutputBufferLock;
+    Condition mOutputBufferCond;
+    List<MediaBuffer*> mOutputBufferQueue;
+    bool mEncodedReachedEOS;
+    status_t mErrorCode;
+
+    DISALLOW_EVIL_CONSTRUCTORS(MediaCodecSource);
+};
+
+} // namespace android
+
+#endif /* MediaCodecSource_H_ */
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index cf5beda..678d642 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -38,6 +38,7 @@
 extern const char *MEDIA_MIMETYPE_AUDIO_AAC;
 extern const char *MEDIA_MIMETYPE_AUDIO_QCELP;
 extern const char *MEDIA_MIMETYPE_AUDIO_VORBIS;
+extern const char *MEDIA_MIMETYPE_AUDIO_OPUS;
 extern const char *MEDIA_MIMETYPE_AUDIO_G711_ALAW;
 extern const char *MEDIA_MIMETYPE_AUDIO_G711_MLAW;
 extern const char *MEDIA_MIMETYPE_AUDIO_RAW;
diff --git a/include/media/stagefright/MediaHTTP.h b/include/media/stagefright/MediaHTTP.h
new file mode 100644
index 0000000..006d8d8
--- /dev/null
+++ b/include/media/stagefright/MediaHTTP.h
@@ -0,0 +1,77 @@
+/*
+ * 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 MEDIA_HTTP_H_
+
+#define MEDIA_HTTP_H_
+
+#include <media/stagefright/foundation/AString.h>
+
+#include "include/HTTPBase.h"
+
+namespace android {
+
+struct IMediaHTTPConnection;
+
+struct MediaHTTP : public HTTPBase {
+    MediaHTTP(const sp<IMediaHTTPConnection> &conn);
+
+    virtual status_t connect(
+            const char *uri,
+            const KeyedVector<String8, String8> *headers,
+            off64_t offset);
+
+    virtual void disconnect();
+
+    virtual status_t initCheck() const;
+
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+    virtual status_t getSize(off64_t *size);
+
+    virtual uint32_t flags();
+
+    virtual status_t reconnectAtOffset(off64_t offset);
+
+protected:
+    virtual ~MediaHTTP();
+
+    virtual sp<DecryptHandle> DrmInitialization(const char* mime);
+    virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
+    virtual String8 getUri();
+    virtual String8 getMIMEType() const;
+
+private:
+    status_t mInitCheck;
+    sp<IMediaHTTPConnection> mHTTPConnection;
+
+    KeyedVector<String8, String8> mLastHeaders;
+    AString mLastURI;
+
+    bool mCachedSizeValid;
+    off64_t mCachedSize;
+
+    sp<DecryptHandle> mDecryptHandle;
+    DrmManagerClient *mDrmManagerClient;
+
+    void clearDRMState_l();
+
+    DISALLOW_EVIL_CONSTRUCTORS(MediaHTTP);
+};
+
+}  // namespace android
+
+#endif  // MEDIA_HTTP_H_
diff --git a/include/media/stagefright/MediaMuxer.h b/include/media/stagefright/MediaMuxer.h
index ff6a66e..bbe4303 100644
--- a/include/media/stagefright/MediaMuxer.h
+++ b/include/media/stagefright/MediaMuxer.h
@@ -30,7 +30,7 @@
 struct MediaBuffer;
 struct MediaSource;
 struct MetaData;
-struct MPEG4Writer;
+struct MediaWriter;
 
 // MediaMuxer is used to mux multiple tracks into a video. Currently, we only
 // support a mp4 file as the output.
@@ -44,6 +44,7 @@
     // OutputFormat is updated.
     enum OutputFormat {
         OUTPUT_FORMAT_MPEG_4 = 0,
+        OUTPUT_FORMAT_WEBM   = 1,
         OUTPUT_FORMAT_LIST_END // must be last - used to validate format type
     };
 
@@ -115,7 +116,8 @@
                              int64_t timeUs, uint32_t flags) ;
 
 private:
-    sp<MPEG4Writer> mWriter;
+    const OutputFormat mFormat;
+    sp<MediaWriter> mWriter;
     Vector< sp<MediaAdapter> > mTrackList;  // Each track has its MediaAdapter.
     sp<MetaData> mFileMeta;  // Metadata for the whole file.
 
diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h
index 3818e63..204d1c6 100644
--- a/include/media/stagefright/MediaSource.h
+++ b/include/media/stagefright/MediaSource.h
@@ -105,7 +105,7 @@
     // This will be called after a successful start() and before the
     // first read() call.
     // Callee assumes ownership of the buffers if no error is returned.
-    virtual status_t setBuffers(const Vector<MediaBuffer *> &buffers) {
+    virtual status_t setBuffers(const Vector<MediaBuffer *> & /* buffers */) {
         return ERROR_UNSUPPORTED;
     }
 
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index db8216b..e862ec3 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -56,6 +56,9 @@
     kKeyD263              = 'd263',  // raw data
     kKeyVorbisInfo        = 'vinf',  // raw data
     kKeyVorbisBooks       = 'vboo',  // raw data
+    kKeyOpusHeader        = 'ohdr',  // raw data
+    kKeyOpusCodecDelay    = 'ocod',  // uint64_t (codec delay in ns)
+    kKeyOpusSeekPreRoll   = 'ospr',  // uint64_t (seek preroll in ns)
     kKeyWantsNALFragments = 'NALf',
     kKeyIsSyncFrame       = 'sync',  // int32_t (bool)
     kKeyIsCodecConfig     = 'conf',  // int32_t (bool)
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index 5ae6f6b..402e7f8 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -31,6 +31,7 @@
 struct ABuffer;
 struct AMessage;
 struct DataSource;
+struct IMediaHTTPService;
 struct MediaBuffer;
 struct MediaExtractor;
 struct MediaSource;
@@ -45,6 +46,7 @@
     NuMediaExtractor();
 
     status_t setDataSource(
+            const sp<IMediaHTTPService> &httpService,
             const char *path,
             const KeyedVector<String8, String8> *headers = NULL);
 
diff --git a/include/media/stagefright/SkipCutBuffer.h b/include/media/stagefright/SkipCutBuffer.h
index 2653b53..098aa69 100644
--- a/include/media/stagefright/SkipCutBuffer.h
+++ b/include/media/stagefright/SkipCutBuffer.h
@@ -47,6 +47,7 @@
  private:
     void write(const char *src, size_t num);
     size_t read(char *dst, size_t num);
+    int32_t mSkip;
     int32_t mFrontPadding;
     int32_t mBackPadding;
     int32_t mWriteHead;
diff --git a/include/media/stagefright/SurfaceMediaSource.h b/include/media/stagefright/SurfaceMediaSource.h
index db5f947..59e83c2 100644
--- a/include/media/stagefright/SurfaceMediaSource.h
+++ b/include/media/stagefright/SurfaceMediaSource.h
@@ -139,6 +139,10 @@
     // frames is separate than the one calling stop.
     virtual void onBuffersReleased();
 
+    // SurfaceMediaSource can't handle sideband streams, so this is not expected
+    // to ever be called. Does nothing.
+    virtual void onSidebandStreamChanged();
+
     static bool isExternalFormat(uint32_t format);
 
 private:
diff --git a/include/media/stagefright/timedtext/TimedTextDriver.h b/include/media/stagefright/timedtext/TimedTextDriver.h
index f23c337..37ef674 100644
--- a/include/media/stagefright/timedtext/TimedTextDriver.h
+++ b/include/media/stagefright/timedtext/TimedTextDriver.h
@@ -25,6 +25,7 @@
 namespace android {
 
 class ALooper;
+struct IMediaHTTPService;
 class MediaPlayerBase;
 class MediaSource;
 class Parcel;
@@ -34,7 +35,9 @@
 
 class TimedTextDriver {
 public:
-    TimedTextDriver(const wp<MediaPlayerBase> &listener);
+    TimedTextDriver(
+            const wp<MediaPlayerBase> &listener,
+            const sp<IMediaHTTPService> &httpService);
 
     ~TimedTextDriver();
 
@@ -77,6 +80,7 @@
     sp<ALooper> mLooper;
     sp<TimedTextPlayer> mPlayer;
     wp<MediaPlayerBase> mListener;
+    sp<IMediaHTTPService> mHTTPService;
 
     // Variables to be guarded by mLock.
     State mState;
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 2d033e6..3901e79 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -48,7 +48,7 @@
 #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
+#define MAX_RUN_OFFLOADED_TIMEOUT_MS 20000 // assuming up to a maximum of 20 seconds of offloaded
 
 struct AudioTrackSharedStreaming {
     // similar to NBAIO MonoPipe
@@ -98,11 +98,7 @@
                                         // 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
-                                            // renamed to "_" to detect incorrect use
+                uint32_t    mPad1;      // unused
 
     volatile    int32_t     mFutex;     // event flag: down (P) by client,
                                         // up (V) by server or binderDied() or interrupt()
diff --git a/libvideoeditor/lvpp/Android.mk b/libvideoeditor/lvpp/Android.mk
index f0afbc9..77a21ac 100755
--- a/libvideoeditor/lvpp/Android.mk
+++ b/libvideoeditor/lvpp/Android.mk
@@ -71,7 +71,6 @@
     $(TOP)/frameworks/av/media/libstagefright \
     $(TOP)/frameworks/av/media/libstagefright/include \
     $(TOP)/frameworks/av/media/libstagefright/rtsp \
-    $(call include-path-for, corecg graphics) \
     $(TOP)/frameworks/av/libvideoeditor/osal/inc \
     $(TOP)/frameworks/av/libvideoeditor/vss/common/inc \
     $(TOP)/frameworks/av/libvideoeditor/vss/mcs/inc \
diff --git a/libvideoeditor/lvpp/NativeWindowRenderer.cpp b/libvideoeditor/lvpp/NativeWindowRenderer.cpp
index 8b362ef..be0f747 100755
--- a/libvideoeditor/lvpp/NativeWindowRenderer.cpp
+++ b/libvideoeditor/lvpp/NativeWindowRenderer.cpp
@@ -568,9 +568,11 @@
 RenderInput::RenderInput(NativeWindowRenderer* renderer, GLuint textureId)
     : mRenderer(renderer)
     , mTextureId(textureId) {
-    sp<BufferQueue> bq = new BufferQueue();
-    mST = new GLConsumer(bq, mTextureId);
-    mSTC = new Surface(bq);
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    mST = new GLConsumer(consumer, mTextureId);
+    mSTC = new Surface(producer);
     native_window_connect(mSTC.get(), NATIVE_WINDOW_API_MEDIA);
 }
 
diff --git a/libvideoeditor/lvpp/PreviewPlayer.cpp b/libvideoeditor/lvpp/PreviewPlayer.cpp
index 2bd9f84..b36fe0a 100755
--- a/libvideoeditor/lvpp/PreviewPlayer.cpp
+++ b/libvideoeditor/lvpp/PreviewPlayer.cpp
@@ -21,6 +21,7 @@
 
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <media/IMediaHTTPService.h>
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
@@ -1160,7 +1161,8 @@
     sp<DataSource> dataSource;
     sp<MediaExtractor> extractor;
 
-    dataSource = DataSource::CreateFromURI(mUri.string(), NULL);
+    dataSource = DataSource::CreateFromURI(
+            NULL /* httpService */, mUri.string(), NULL);
 
     if (dataSource == NULL) {
         return UNKNOWN_ERROR;
diff --git a/libvideoeditor/lvpp/VideoEditorPlayer.cpp b/libvideoeditor/lvpp/VideoEditorPlayer.cpp
index 8d656c4..f9c3879 100755
--- a/libvideoeditor/lvpp/VideoEditorPlayer.cpp
+++ b/libvideoeditor/lvpp/VideoEditorPlayer.cpp
@@ -57,6 +57,7 @@
 
 
 status_t VideoEditorPlayer::setDataSource(
+        const sp<IMediaHTTPService> &httpService,
         const char *url, const KeyedVector<String8, String8> *headers) {
     ALOGI("setDataSource('%s')", url);
     if (headers != NULL) {
diff --git a/libvideoeditor/lvpp/VideoEditorPlayer.h b/libvideoeditor/lvpp/VideoEditorPlayer.h
index b8c1254..781e4bc 100755
--- a/libvideoeditor/lvpp/VideoEditorPlayer.h
+++ b/libvideoeditor/lvpp/VideoEditorPlayer.h
@@ -98,6 +98,7 @@
     virtual status_t initCheck();
 
     virtual status_t setDataSource(
+            const sp<IMediaHTTPService> &httpService,
             const char *url, const KeyedVector<String8, String8> *headers);
 
     virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
diff --git a/libvideoeditor/lvpp/VideoEditorPreviewController.cpp b/libvideoeditor/lvpp/VideoEditorPreviewController.cpp
index c3cd3d0..953f35a 100755
--- a/libvideoeditor/lvpp/VideoEditorPreviewController.cpp
+++ b/libvideoeditor/lvpp/VideoEditorPreviewController.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 
 #include <gui/Surface.h>
+#include <media/IMediaHTTPService.h>
 
 #include "VideoEditorAudioPlayer.h"
 #include "PreviewRenderer.h"
@@ -967,7 +968,8 @@
     ALOGV("preparePlayer: instance %d file %d", playerInstance, index);
 
     const char* fileName = (const char*) pController->mClipList[index]->pFile;
-    pController->mVePlayer[playerInstance]->setDataSource(fileName, NULL);
+    pController->mVePlayer[playerInstance]->setDataSource(
+            NULL /* httpService */, fileName, NULL);
 
     ALOGV("preparePlayer: setDataSource instance %s",
      (const char *)pController->mClipList[index]->pFile);
diff --git a/libvideoeditor/vss/stagefrightshells/src/Android.mk b/libvideoeditor/vss/stagefrightshells/src/Android.mk
index c603252..a060c0d 100755
--- a/libvideoeditor/vss/stagefrightshells/src/Android.mk
+++ b/libvideoeditor/vss/stagefrightshells/src/Android.mk
@@ -33,7 +33,6 @@
     $(TOP)/frameworks/av/media/libstagefright \
     $(TOP)/frameworks/av/media/libstagefright/include \
     $(TOP)/frameworks/av/media/libstagefright/rtsp \
-    $(call include-path-for, corecg graphics) \
     $(TOP)/frameworks/av/libvideoeditor/lvpp \
     $(TOP)/frameworks/av/libvideoeditor/osal/inc \
     $(TOP)/frameworks/av/libvideoeditor/vss/inc \
diff --git a/media/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk
index dd2d306..c92c543 100644
--- a/media/libeffects/visualizer/Android.mk
+++ b/media/libeffects/visualizer/Android.mk
@@ -17,7 +17,6 @@
 LOCAL_MODULE:= libvisualizer
 
 LOCAL_C_INCLUDES := \
-	$(call include-path-for, graphics corecg) \
 	$(call include-path-for, audio-effects)
 
 
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 56e7787..f3770e4 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -25,6 +25,8 @@
     AudioRecord.cpp \
     AudioSystem.cpp \
     mediaplayer.cpp \
+    IMediaHTTPConnection.cpp \
+    IMediaHTTPService.cpp \
     IMediaLogService.cpp \
     IMediaPlayerService.cpp \
     IMediaPlayerClient.cpp \
@@ -44,7 +46,7 @@
     IAudioPolicyService.cpp \
     MediaScanner.cpp \
     MediaScannerClient.cpp \
-    autodetect.cpp \
+    CharacterEncodingDetector.cpp \
     IMediaDeathNotifier.cpp \
     MediaProfiles.cpp \
     IEffect.cpp \
@@ -58,26 +60,34 @@
 
 LOCAL_SRC_FILES += ../libnbaio/roundup.c
 
-# for <cutils/atomic-inline.h>
-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 \
+	libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \
         libcamera_client libstagefright_foundation \
-        libgui libdl libaudioutils
+        libgui libdl libaudioutils libnbaio
+
+LOCAL_STATIC_LIBRARIES += libinstantssq
 
 LOCAL_WHOLE_STATIC_LIBRARY := libmedia_helper
 
 LOCAL_MODULE:= libmedia
 
 LOCAL_C_INCLUDES := \
-    $(call include-path-for, graphics corecg) \
     $(TOP)/frameworks/native/include/media/openmax \
     external/icu4c/common \
+    external/icu4c/i18n \
     $(call include-path-for, audio-effects) \
     $(call include-path-for, audio-utils)
 
 include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+# for <cutils/atomic-inline.h>
+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"'
+
+LOCAL_MODULE := libinstantssq
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 8dfffb3..35f6557 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -380,9 +380,9 @@
 }
 
 void AudioEffect::commandExecuted(uint32_t cmdCode,
-                                  uint32_t cmdSize,
+                                  uint32_t cmdSize __unused,
                                   void *cmdData,
-                                  uint32_t replySize,
+                                  uint32_t replySize __unused,
                                   void *replyData)
 {
     if (cmdData == NULL || replyData == NULL) {
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index ccbc5a3..961b0a2 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -41,37 +41,29 @@
         return BAD_VALUE;
     }
 
-    // default to 0 in case of error
-    *frameCount = 0;
-
-    size_t size = 0;
+    size_t size;
     status_t status = AudioSystem::getInputBufferSize(sampleRate, format, channelMask, &size);
     if (status != NO_ERROR) {
-        ALOGE("AudioSystem could not query the input buffer size; status %d", status);
-        return NO_INIT;
+        ALOGE("AudioSystem could not query the input buffer size for sampleRate %u, format %#x, "
+              "channelMask %#x; status %d", sampleRate, format, channelMask, status);
+        return status;
     }
 
-    if (size == 0) {
-        ALOGE("Unsupported configuration: sampleRate %u, format %d, channelMask %#x",
+    // We double the size of input buffer for ping pong use of record buffer.
+    // Assumes audio_is_linear_pcm(format)
+    if ((*frameCount = (size * 2) / (popcount(channelMask) * audio_bytes_per_sample(format))) == 0) {
+        ALOGE("Unsupported configuration: sampleRate %u, format %#x, channelMask %#x",
             sampleRate, format, channelMask);
         return BAD_VALUE;
     }
 
-    // We double the size of input buffer for ping pong use of record buffer.
-    size <<= 1;
-
-    // Assumes audio_is_linear_pcm(format)
-    uint32_t channelCount = popcount(channelMask);
-    size /= channelCount * audio_bytes_per_sample(format);
-
-    *frameCount = size;
     return NO_ERROR;
 }
 
 // ---------------------------------------------------------------------------
 
 AudioRecord::AudioRecord()
-    : mStatus(NO_INIT), mSessionId(0),
+    : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT)
 {
 }
@@ -81,14 +73,14 @@
         uint32_t sampleRate,
         audio_format_t format,
         audio_channel_mask_t channelMask,
-        int frameCount,
+        size_t frameCount,
         callback_t cbf,
         void* user,
-        int notificationFrames,
+        uint32_t notificationFrames,
         int sessionId,
         transfer_type transferType,
-        audio_input_flags_t flags)
-    : mStatus(NO_INIT), mSessionId(0),
+        audio_input_flags_t flags __unused)
+    : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
       mProxy(NULL)
@@ -110,12 +102,10 @@
             mAudioRecordThread->requestExitAndWait();
             mAudioRecordThread.clear();
         }
-        if (mAudioRecord != 0) {
-            mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this);
-            mAudioRecord.clear();
-        }
+        mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this);
+        mAudioRecord.clear();
         IPCThreadState::self()->flushCommands();
-        AudioSystem::releaseAudioSessionId(mSessionId);
+        AudioSystem::releaseAudioSessionId(mSessionId, -1);
     }
 }
 
@@ -124,15 +114,20 @@
         uint32_t sampleRate,
         audio_format_t format,
         audio_channel_mask_t channelMask,
-        int frameCountInt,
+        size_t frameCount,
         callback_t cbf,
         void* user,
-        int notificationFrames,
+        uint32_t notificationFrames,
         bool threadCanCallJava,
         int sessionId,
         transfer_type transferType,
         audio_input_flags_t flags)
 {
+    ALOGV("set(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
+          "notificationFrames %u, sessionId %d, transferType %d, flags %#x",
+          inputSource, sampleRate, format, channelMask, frameCount, notificationFrames,
+          sessionId, transferType, flags);
+
     switch (transferType) {
     case TRANSFER_DEFAULT:
         if (cbf == NULL || threadCanCallJava) {
@@ -156,23 +151,15 @@
     }
     mTransfer = transferType;
 
-    // FIXME "int" here is legacy and will be replaced by size_t later
-    if (frameCountInt < 0) {
-        ALOGE("Invalid frame count %d", frameCountInt);
-        return BAD_VALUE;
-    }
-    size_t frameCount = frameCountInt;
-
-    ALOGV("set(): sampleRate %u, channelMask %#x, frameCount %u", sampleRate, channelMask,
-            frameCount);
-
     AutoMutex lock(mLock);
 
+    // invariant that mAudioRecord != 0 is true only after set() returns successfully
     if (mAudioRecord != 0) {
         ALOGE("Track already in use");
         return INVALID_OPERATION;
     }
 
+    // handle default values first.
     if (inputSource == AUDIO_SOURCE_DEFAULT) {
         inputSource = AUDIO_SOURCE_MIC;
     }
@@ -191,12 +178,12 @@
 
     // validate parameters
     if (!audio_is_valid_format(format)) {
-        ALOGE("Invalid format %d", format);
+        ALOGE("Invalid format %#x", 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);
+        ALOGE("Format %#x is not supported", format);
         return BAD_VALUE;
     }
     mFormat = format;
@@ -209,15 +196,19 @@
     uint32_t channelCount = popcount(channelMask);
     mChannelCount = channelCount;
 
-    // Assumes audio_is_linear_pcm(format), else sizeof(uint8_t)
-    mFrameSize = channelCount * audio_bytes_per_sample(format);
+    if (audio_is_linear_pcm(format)) {
+        mFrameSize = channelCount * audio_bytes_per_sample(format);
+    } else {
+        mFrameSize = sizeof(uint8_t);
+    }
 
     // validate framecount
-    size_t minFrameCount = 0;
+    size_t minFrameCount;
     status_t status = AudioRecord::getMinFrameCount(&minFrameCount,
             sampleRate, format, channelMask);
     if (status != NO_ERROR) {
-        ALOGE("getMinFrameCount() failed; status %d", status);
+        ALOGE("getMinFrameCount() failed for sampleRate %u, format %#x, channelMask %#x; status %d",
+                sampleRate, format, channelMask, status);
         return status;
     }
     ALOGV("AudioRecord::set() minFrameCount = %d", minFrameCount);
@@ -228,12 +219,13 @@
         ALOGE("frameCount %u < minFrameCount %u", frameCount, minFrameCount);
         return BAD_VALUE;
     }
-    mFrameCount = frameCount;
+    // mFrameCount is initialized in openRecord_l
+    mReqFrameCount = frameCount;
 
     mNotificationFramesReq = notificationFrames;
     mNotificationFramesAct = 0;
 
-    if (sessionId == 0 ) {
+    if (sessionId == AUDIO_SESSION_ALLOCATE) {
         mSessionId = AudioSystem::newAudioSessionId();
     } else {
         mSessionId = sessionId;
@@ -241,26 +233,27 @@
     ALOGV("set(): mSessionId %d", mSessionId);
 
     mFlags = flags;
-
-    // create the IAudioRecord
-    status = openRecord_l(0 /*epoch*/);
-    if (status) {
-        return status;
-    }
+    mCbf = cbf;
 
     if (cbf != NULL) {
         mAudioRecordThread = new AudioRecordThread(*this, threadCanCallJava);
         mAudioRecordThread->run("AudioRecord", ANDROID_PRIORITY_AUDIO);
     }
 
+    // create the IAudioRecord
+    status = openRecord_l(0 /*epoch*/);
+
+    if (status != NO_ERROR) {
+        if (mAudioRecordThread != 0) {
+            mAudioRecordThread->requestExit();   // see comment in AudioRecord.h
+            mAudioRecordThread->requestExitAndWait();
+            mAudioRecordThread.clear();
+        }
+        return status;
+    }
+
     mStatus = NO_ERROR;
-
-    // Update buffer size in case it has been limited by AudioFlinger during track creation
-    mFrameCount = mCblk->frameCount_;
-
     mActive = false;
-    mCbf = cbf;
-    mRefreshRemaining = true;
     mUserData = user;
     // TODO: add audio hardware input latency here
     mLatency = (1000*mFrameCount) / sampleRate;
@@ -268,7 +261,7 @@
     mMarkerReached = false;
     mNewPosition = 0;
     mUpdatePeriod = 0;
-    AudioSystem::acquireAudioSessionId(mSessionId);
+    AudioSystem::acquireAudioSessionId(mSessionId, -1);
     mSequence = 1;
     mObservedSequence = mSequence;
     mInOverrun = false;
@@ -289,6 +282,9 @@
 
     // reset current position as seen by client to 0
     mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());
+    // force refresh of remaining frames by processAudioBuffer() as last
+    // read before stop could be partial.
+    mRefreshRemaining = true;
 
     mNewPosition = mProxy->getPosition() + mUpdatePeriod;
     int32_t flags = android_atomic_acquire_load(&mCblk->mFlags);
@@ -352,6 +348,7 @@
 
 status_t AudioRecord::setMarkerPosition(uint32_t marker)
 {
+    // The only purpose of setting marker position is to get a callback
     if (mCbf == NULL) {
         return INVALID_OPERATION;
     }
@@ -377,6 +374,7 @@
 
 status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
 {
+    // The only purpose of setting position update period is to get a callback
     if (mCbf == NULL) {
         return INVALID_OPERATION;
     }
@@ -412,7 +410,7 @@
     return NO_ERROR;
 }
 
-unsigned int AudioRecord::getInputFramesLost() const
+uint32_t AudioRecord::getInputFramesLost() const
 {
     // no need to check mActive, because if inactive this will return 0, which is what we want
     return AudioSystem::getInputFramesLost(getInput());
@@ -430,55 +428,82 @@
         return NO_INIT;
     }
 
-    IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
-    pid_t tid = -1;
+    // Fast tracks must be at the primary _output_ [sic] sampling rate,
+    // because there is currently no concept of a primary input sampling rate
+    uint32_t afSampleRate = AudioSystem::getPrimaryOutputSamplingRate();
+    if (afSampleRate == 0) {
+        ALOGW("getPrimaryOutputSamplingRate failed");
+    }
 
     // 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) && !(
+            // use case: callback transfer mode
+            (mTransfer == TRANSFER_CALLBACK) &&
+            // matching sample rate
+            (mSampleRate == afSampleRate))) {
+        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);
+    }
+
+    IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
+
+    pid_t tid = -1;
     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;
+        trackFlags |= IAudioFlinger::TRACK_FAST;
+        if (mAudioRecordThread != 0) {
             tid = mAudioRecordThread->getTid();
         }
     }
 
+    // FIXME Assume double buffering, because we don't know the true HAL sample rate
+    const uint32_t nBuffering = 2;
+
     mNotificationFramesAct = mNotificationFramesReq;
+    size_t frameCount = mReqFrameCount;
 
     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;
+        if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/2) {
+            mNotificationFramesAct = frameCount/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);
+        ALOGE("Could not get audio input for record source %d, sample rate %u, format %#x, "
+              "channel mask %#x, session %d",
+              mInputSource, mSampleRate, mFormat, mChannelMask, mSessionId);
         return BAD_VALUE;
     }
+    {
+    // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger,
+    // we must release it ourselves if anything goes wrong.
 
+    size_t temp = frameCount;   // temp may be replaced by a revised value of frameCount,
+                                // but we will still need the original value also
     int originalSessionId = mSessionId;
     sp<IAudioRecord> record = audioFlinger->openRecord(input,
                                                        mSampleRate, mFormat,
                                                        mChannelMask,
-                                                       mFrameCount,
+                                                       &temp,
                                                        &trackFlags,
                                                        tid,
                                                        &mSessionId,
                                                        &status);
-    ALOGE_IF(originalSessionId != 0 && mSessionId != originalSessionId,
+    ALOGE_IF(originalSessionId != AUDIO_SESSION_ALLOCATE && mSessionId != originalSessionId,
             "session ID changed from %d to %d", originalSessionId, mSessionId);
 
-    if (record == 0 || status != NO_ERROR) {
+    if (status != NO_ERROR) {
         ALOGE("AudioFlinger could not create record track, status: %d", status);
-        AudioSystem::releaseInput(input);
-        return status;
+        goto release;
     }
+    ALOG_ASSERT(record != 0);
+
+    // AudioFlinger now owns the reference to the I/O handle,
+    // so we are no longer responsible for releasing it.
+
     sp<IMemory> iMem = record->getCblk();
     if (iMem == 0) {
         ALOGE("Could not get control block");
@@ -489,38 +514,56 @@
         ALOGE("Could not get control block pointer");
         return NO_INIT;
     }
+    // invariant that mAudioRecord != 0 is true only after set() returns successfully
     if (mAudioRecord != 0) {
         mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this);
         mDeathNotifier.clear();
     }
-    mInput = input;
     mAudioRecord = record;
+
     mCblkMemory = iMem;
     audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
     mCblk = cblk;
-    // FIXME missing fast track frameCount logic
+    // note that temp is the (possibly revised) value of frameCount
+    if (temp < frameCount || (frameCount == 0 && temp == 0)) {
+        ALOGW("Requested frameCount %u but received frameCount %u", frameCount, temp);
+    }
+    frameCount = temp;
+
     mAwaitBoost = false;
     if (mFlags & AUDIO_INPUT_FLAG_FAST) {
         if (trackFlags & IAudioFlinger::TRACK_FAST) {
-            ALOGV("AUDIO_INPUT_FLAG_FAST successful; frameCount %u", mFrameCount);
+            ALOGV("AUDIO_INPUT_FLAG_FAST successful; frameCount %u", frameCount);
             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);
+            ALOGV("AUDIO_INPUT_FLAG_FAST denied by server; frameCount %u", frameCount);
             // 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;
-            }
+        }
+        // Theoretically double-buffering is not required for fast tracks,
+        // due to tighter scheduling.  But in practice, to accomodate kernels with
+        // scheduling jitter, and apps with computation jitter, we use double-buffering.
+        if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/nBuffering) {
+            mNotificationFramesAct = frameCount/nBuffering;
         }
     }
 
-    // starting address of buffers in shared memory
+    // We retain a copy of the I/O handle, but don't own the reference
+    mInput = input;
+    mRefreshRemaining = true;
+
+    // Starting address of buffers in shared memory, 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 *buffers = (char*)cblk + sizeof(audio_track_cblk_t);
 
+    mFrameCount = frameCount;
+    // If IAudioRecord is re-created, don't let the requested frameCount
+    // decrease.  This can confuse clients that cache frameCount().
+    if (frameCount > mReqFrameCount) {
+        mReqFrameCount = frameCount;
+    }
+
     // update proxy
     mProxy = new AudioRecordClientProxy(cblk, buffers, mFrameCount, mFrameSize);
     mProxy->setEpoch(epoch);
@@ -530,6 +573,14 @@
     mAudioRecord->asBinder()->linkToDeath(mDeathNotifier, this);
 
     return NO_ERROR;
+    }
+
+release:
+    AudioSystem::releaseInput(input);
+    if (status == NO_ERROR) {
+        status = NO_INIT;
+    }
+    return status;
 }
 
 status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
@@ -591,6 +642,9 @@
                 if (newSequence == oldSequence) {
                     status = restoreRecord_l("obtainBuffer");
                     if (status != NO_ERROR) {
+                        buffer.mFrameCount = 0;
+                        buffer.mRaw = NULL;
+                        buffer.mNonContig = 0;
                         break;
                     }
                 }
@@ -692,7 +746,7 @@
 
 // -------------------------------------------------------------------------
 
-nsecs_t AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread)
+nsecs_t AudioRecord::processAudioBuffer()
 {
     mLock.lock();
     if (mAwaitBoost) {
@@ -760,17 +814,17 @@
     }
 
     // Cache other fields that will be needed soon
-    size_t notificationFrames = mNotificationFramesAct;
+    uint32_t notificationFrames = mNotificationFramesAct;
     if (mRefreshRemaining) {
         mRefreshRemaining = false;
         mRemainingFrames = notificationFrames;
         mRetryOnPartialBuffer = false;
     }
     size_t misalignment = mProxy->getMisalignment();
-    int32_t sequence = mSequence;
+    uint32_t sequence = mSequence;
 
     // These fields don't need to be cached, because they are assigned only by set():
-    //      mTransfer, mCbf, mUserData, mSampleRate
+    //      mTransfer, mCbf, mUserData, mSampleRate, mFrameSize
 
     mLock.unlock();
 
@@ -844,8 +898,8 @@
                 "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);
+        ALOGV("obtainBuffer(%u) returned %u = %u + %u err %d",
+                mRemainingFrames, avail, audioBuffer.frameCount, nonContig, err);
         if (err != NO_ERROR) {
             if (err == TIMED_OUT || err == WOULD_BLOCK || err == -EINTR) {
                 break;
@@ -954,7 +1008,7 @@
 
 // =========================================================================
 
-void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who)
+void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
 {
     sp<AudioRecord> audioRecord = mAudioRecord.promote();
     if (audioRecord != 0) {
@@ -966,7 +1020,8 @@
 // =========================================================================
 
 AudioRecord::AudioRecordThread::AudioRecordThread(AudioRecord& receiver, bool bCanCallJava)
-    : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL)
+    : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
+      mIgnoreNextPausedInt(false)
 {
 }
 
@@ -983,6 +1038,10 @@
             // caller will check for exitPending()
             return true;
         }
+        if (mIgnoreNextPausedInt) {
+            mIgnoreNextPausedInt = false;
+            mPausedInt = false;
+        }
         if (mPausedInt) {
             if (mPausedNs > 0) {
                 (void) mMyCond.waitRelative(mMyLock, mPausedNs);
@@ -993,7 +1052,7 @@
             return true;
         }
     }
-    nsecs_t ns =  mReceiver.processAudioBuffer(this);
+    nsecs_t ns =  mReceiver.processAudioBuffer();
     switch (ns) {
     case 0:
         return true;
@@ -1017,12 +1076,7 @@
 {
     // must be in this order to avoid a race condition
     Thread::requestExit();
-    AutoMutex _l(mMyLock);
-    if (mPaused || mPausedInt) {
-        mPaused = false;
-        mPausedInt = false;
-        mMyCond.signal();
-    }
+    resume();
 }
 
 void AudioRecord::AudioRecordThread::pause()
@@ -1034,6 +1088,7 @@
 void AudioRecord::AudioRecordThread::resume()
 {
     AutoMutex _l(mMyLock);
+    mIgnoreNextPausedInt = true;
     if (mPaused || mPausedInt) {
         mPaused = false;
         mPausedInt = false;
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index cc5b810..140fb66 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -40,10 +40,10 @@
 DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(0);
 
 // Cached values for recording queries, all protected by gLock
-uint32_t AudioSystem::gPrevInSamplingRate = 16000;
-audio_format_t AudioSystem::gPrevInFormat = AUDIO_FORMAT_PCM_16_BIT;
-audio_channel_mask_t AudioSystem::gPrevInChannelMask = AUDIO_CHANNEL_IN_MONO;
-size_t AudioSystem::gInBuffSize = 0;
+uint32_t AudioSystem::gPrevInSamplingRate;
+audio_format_t AudioSystem::gPrevInFormat;
+audio_channel_mask_t AudioSystem::gPrevInChannelMask;
+size_t AudioSystem::gInBuffSize = 0;    // zero indicates cache is invalid
 
 
 // establish binder interface to AudioFlinger service
@@ -84,13 +84,15 @@
     return DEAD_OBJECT;
 }
 
-status_t AudioSystem::muteMicrophone(bool state) {
+status_t AudioSystem::muteMicrophone(bool state)
+{
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
     return af->setMicMute(state);
 }
 
-status_t AudioSystem::isMicrophoneMuted(bool* state) {
+status_t AudioSystem::isMicrophoneMuted(bool* state)
+{
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
     *state = af->getMicMute();
@@ -175,13 +177,15 @@
     return af->setMode(mode);
 }
 
-status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) {
+status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
+{
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return PERMISSION_DENIED;
     return af->setParameters(ioHandle, keyValuePairs);
 }
 
-String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& keys) {
+String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& keys)
+{
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     String8 result = String8("");
     if (af == 0) return result;
@@ -190,6 +194,16 @@
     return result;
 }
 
+status_t AudioSystem::setParameters(const String8& keyValuePairs)
+{
+    return setParameters((audio_io_handle_t) 0, keyValuePairs);
+}
+
+String8 AudioSystem::getParameters(const String8& keys)
+{
+    return getParameters((audio_io_handle_t) 0, keys);
+}
+
 // convert volume steps to natural log scale
 
 // change this value to change volume scaling
@@ -249,6 +263,11 @@
         *samplingRate = outputDesc->samplingRate;
         gLock.unlock();
     }
+    if (*samplingRate == 0) {
+        ALOGE("AudioSystem::getSamplingRate failed for output %d stream type %d",
+                output, streamType);
+        return BAD_VALUE;
+    }
 
     ALOGV("getSamplingRate() streamType %d, output %d, sampling rate %u", streamType, output,
             *samplingRate);
@@ -289,6 +308,11 @@
         *frameCount = outputDesc->frameCount;
         gLock.unlock();
     }
+    if (*frameCount == 0) {
+        ALOGE("AudioSystem::getFrameCount failed for output %d stream type %d",
+                output, streamType);
+        return BAD_VALUE;
+    }
 
     ALOGV("getFrameCount() streamType %d, output %d, frameCount %d", streamType, output,
             *frameCount);
@@ -313,7 +337,7 @@
 }
 
 status_t AudioSystem::getLatency(audio_io_handle_t output,
-                                 audio_stream_type_t streamType,
+                                 audio_stream_type_t streamType __unused,
                                  uint32_t* latency)
 {
     OutputDescriptor *outputDesc;
@@ -349,6 +373,12 @@
             return PERMISSION_DENIED;
         }
         inBuffSize = af->getInputBufferSize(sampleRate, format, channelMask);
+        if (inBuffSize == 0) {
+            ALOGE("AudioSystem::getInputBufferSize failed sampleRate %d format %#x channelMask %x",
+                    sampleRate, format, channelMask);
+            return BAD_VALUE;
+        }
+        // A benign race is possible here: we could overwrite a fresher cache entry
         gLock.lock();
         // save the request params
         gPrevInSamplingRate = sampleRate;
@@ -387,9 +417,10 @@
     return af->getRenderPosition(halFrames, dspFrames, output);
 }
 
-size_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) {
+uint32_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle)
+{
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
-    unsigned int result = 0;
+    uint32_t result = 0;
     if (af == 0) return result;
     if (ioHandle == 0) return result;
 
@@ -397,29 +428,33 @@
     return result;
 }
 
-int AudioSystem::newAudioSessionId() {
+int AudioSystem::newAudioSessionId()
+{
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af == 0) return 0;
     return af->newAudioSessionId();
 }
 
-void AudioSystem::acquireAudioSessionId(int audioSession) {
+void AudioSystem::acquireAudioSessionId(int audioSession, pid_t pid)
+{
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af != 0) {
-        af->acquireAudioSessionId(audioSession);
+        af->acquireAudioSessionId(audioSession, pid);
     }
 }
 
-void AudioSystem::releaseAudioSessionId(int audioSession) {
+void AudioSystem::releaseAudioSessionId(int audioSession, pid_t pid)
+{
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af != 0) {
-        af->releaseAudioSessionId(audioSession);
+        af->releaseAudioSessionId(audioSession, pid);
     }
 }
 
 // ---------------------------------------------------------------------------
 
-void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {
+void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who __unused)
+{
     Mutex::Autolock _l(AudioSystem::gLock);
 
     AudioSystem::gAudioFlinger.clear();
@@ -455,7 +490,7 @@
 
         OutputDescriptor *outputDesc =  new OutputDescriptor(*desc);
         gOutputs.add(ioHandle, outputDesc);
-        ALOGV("ioConfigChanged() new output samplingRate %u, format %d channel mask %#x frameCount %u "
+        ALOGV("ioConfigChanged() new output samplingRate %u, format %#x channel mask %#x frameCount %u "
                 "latency %d",
                 outputDesc->samplingRate, outputDesc->format, outputDesc->channelMask,
                 outputDesc->frameCount, outputDesc->latency);
@@ -479,7 +514,7 @@
         if (param2 == NULL) break;
         desc = (const OutputDescriptor *)param2;
 
-        ALOGV("ioConfigChanged() new config for output %d samplingRate %u, format %d channel mask %#x "
+        ALOGV("ioConfigChanged() new config for output %d samplingRate %u, format %#x channel mask %#x "
                 "frameCount %d latency %d",
                 ioHandle, desc->samplingRate, desc->format,
                 desc->channelMask, desc->frameCount, desc->latency);
@@ -496,12 +531,14 @@
     }
 }
 
-void AudioSystem::setErrorCallback(audio_error_callback cb) {
+void AudioSystem::setErrorCallback(audio_error_callback cb)
+{
     Mutex::Autolock _l(gLock);
     gAudioErrorCallback = cb;
 }
 
-bool AudioSystem::routedToA2dpOutput(audio_stream_type_t streamType) {
+bool AudioSystem::routedToA2dpOutput(audio_stream_type_t streamType)
+{
     switch (streamType) {
     case AUDIO_STREAM_MUSIC:
     case AUDIO_STREAM_VOICE_CALL:
@@ -709,7 +746,8 @@
 audio_io_handle_t AudioSystem::getOutputForEffect(const effect_descriptor_t *desc)
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
-    if (aps == 0) return PERMISSION_DENIED;
+    // FIXME change return type to status_t, and return PERMISSION_DENIED here
+    if (aps == 0) return 0;
     return aps->getOutputForEffect(desc);
 }
 
@@ -804,7 +842,8 @@
 
 // ---------------------------------------------------------------------------
 
-void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who) {
+void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused)
+{
     Mutex::Autolock _l(AudioSystem::gLock);
     AudioSystem::gAudioPolicyService.clear();
 
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 3f3a88c..20c1cdb 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -44,9 +44,6 @@
         return BAD_VALUE;
     }
 
-    // default to 0 in case of error
-    *frameCount = 0;
-
     // FIXME merge with similar code in createTrack_l(), except we're missing
     //       some information here that is available in createTrack_l():
     //          audio_io_handle_t output
@@ -54,16 +51,26 @@
     //          audio_channel_mask_t channelMask
     //          audio_output_flags_t flags
     uint32_t afSampleRate;
-    if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
-        return NO_INIT;
+    status_t status;
+    status = AudioSystem::getOutputSamplingRate(&afSampleRate, streamType);
+    if (status != NO_ERROR) {
+        ALOGE("Unable to query output sample rate for stream type %d; status %d",
+                streamType, status);
+        return status;
     }
     size_t afFrameCount;
-    if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
-        return NO_INIT;
+    status = AudioSystem::getOutputFrameCount(&afFrameCount, streamType);
+    if (status != NO_ERROR) {
+        ALOGE("Unable to query output frame count for stream type %d; status %d",
+                streamType, status);
+        return status;
     }
     uint32_t afLatency;
-    if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
-        return NO_INIT;
+    status = AudioSystem::getOutputLatency(&afLatency, streamType);
+    if (status != NO_ERROR) {
+        ALOGE("Unable to query output latency for stream type %d; status %d",
+                streamType, status);
+        return status;
     }
 
     // Ensure that buffer depth covers at least audio hardware latency
@@ -74,6 +81,13 @@
 
     *frameCount = (sampleRate == 0) ? afFrameCount * minBufCount :
             afFrameCount * minBufCount * sampleRate / afSampleRate;
+    // The formula above should always produce a non-zero value, but return an error
+    // in the unlikely event that it does not, as that's part of the API contract.
+    if (*frameCount == 0) {
+        ALOGE("AudioTrack::getMinFrameCount failed for streamType %d, sampleRate %d",
+                streamType, sampleRate);
+        return BAD_VALUE;
+    }
     ALOGV("getMinFrameCount=%d: afFrameCount=%d, minBufCount=%d, afSampleRate=%d, afLatency=%d",
             *frameCount, afFrameCount, minBufCount, afSampleRate, afLatency);
     return NO_ERROR;
@@ -95,15 +109,16 @@
         uint32_t sampleRate,
         audio_format_t format,
         audio_channel_mask_t channelMask,
-        int frameCount,
+        size_t frameCount,
         audio_output_flags_t flags,
         callback_t cbf,
         void* user,
-        int notificationFrames,
+        uint32_t notificationFrames,
         int sessionId,
         transfer_type transferType,
         const audio_offload_info_t *offloadInfo,
-        int uid)
+        int uid,
+        pid_t pid)
     : mStatus(NO_INIT),
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
@@ -113,7 +128,7 @@
     mStatus = set(streamType, sampleRate, format, channelMask,
             frameCount, flags, cbf, user, notificationFrames,
             0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType,
-            offloadInfo, uid);
+            offloadInfo, uid, pid);
 }
 
 AudioTrack::AudioTrack(
@@ -125,11 +140,12 @@
         audio_output_flags_t flags,
         callback_t cbf,
         void* user,
-        int notificationFrames,
+        uint32_t notificationFrames,
         int sessionId,
         transfer_type transferType,
         const audio_offload_info_t *offloadInfo,
-        int uid)
+        int uid,
+        pid_t pid)
     : mStatus(NO_INIT),
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
@@ -138,7 +154,8 @@
 {
     mStatus = set(streamType, sampleRate, format, channelMask,
             0 /*frameCount*/, flags, cbf, user, notificationFrames,
-            sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo, uid);
+            sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
+            uid, pid);
 }
 
 AudioTrack::~AudioTrack()
@@ -157,7 +174,9 @@
         mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
         mAudioTrack.clear();
         IPCThreadState::self()->flushCommands();
-        AudioSystem::releaseAudioSessionId(mSessionId);
+        ALOGV("~AudioTrack, releasing session id from %d on behalf of %d",
+                IPCThreadState::self()->getCallingPid(), mClientPid);
+        AudioSystem::releaseAudioSessionId(mSessionId, mClientPid);
     }
 }
 
@@ -166,18 +185,24 @@
         uint32_t sampleRate,
         audio_format_t format,
         audio_channel_mask_t channelMask,
-        int frameCountInt,
+        size_t frameCount,
         audio_output_flags_t flags,
         callback_t cbf,
         void* user,
-        int notificationFrames,
+        uint32_t notificationFrames,
         const sp<IMemory>& sharedBuffer,
         bool threadCanCallJava,
         int sessionId,
         transfer_type transferType,
         const audio_offload_info_t *offloadInfo,
-        int uid)
+        int uid,
+        pid_t pid)
 {
+    ALOGV("set(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
+          "flags #%x, notificationFrames %u, sessionId %d, transferType %d",
+          streamType, sampleRate, format, channelMask, frameCount, flags, notificationFrames,
+          sessionId, transferType);
+
     switch (transferType) {
     case TRANSFER_DEFAULT:
         if (sharedBuffer != 0) {
@@ -211,15 +236,9 @@
         ALOGE("Invalid transfer type %d", transferType);
         return BAD_VALUE;
     }
+    mSharedBuffer = sharedBuffer;
     mTransfer = transferType;
 
-    // FIXME "int" here is legacy and will be replaced by size_t later
-    if (frameCountInt < 0) {
-        ALOGE("Invalid frame count %d", frameCountInt);
-        return BAD_VALUE;
-    }
-    size_t frameCount = frameCountInt;
-
     ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(),
             sharedBuffer->size());
 
@@ -233,19 +252,24 @@
         return INVALID_OPERATION;
     }
 
-    mOutput = 0;
-
     // handle default values first.
     if (streamType == AUDIO_STREAM_DEFAULT) {
         streamType = AUDIO_STREAM_MUSIC;
     }
+    if (uint32_t(streamType) >= AUDIO_STREAM_CNT) {
+        ALOGE("Invalid stream type %d", streamType);
+        return BAD_VALUE;
+    }
+    mStreamType = streamType;
 
+    status_t status;
     if (sampleRate == 0) {
-        uint32_t afSampleRate;
-        if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
-            return NO_INIT;
+        status = AudioSystem::getOutputSamplingRate(&sampleRate, streamType);
+        if (status != NO_ERROR) {
+            ALOGE("Could not get output sample rate for stream type %d; status %d",
+                    streamType, status);
+            return status;
         }
-        sampleRate = afSampleRate;
     }
     mSampleRate = sampleRate;
 
@@ -253,15 +277,21 @@
     if (format == AUDIO_FORMAT_DEFAULT) {
         format = AUDIO_FORMAT_PCM_16_BIT;
     }
-    if (channelMask == 0) {
-        channelMask = AUDIO_CHANNEL_OUT_STEREO;
-    }
 
     // validate parameters
     if (!audio_is_valid_format(format)) {
-        ALOGE("Invalid format %d", format);
+        ALOGE("Invalid format %#x", format);
         return BAD_VALUE;
     }
+    mFormat = format;
+
+    if (!audio_is_output_channel(channelMask)) {
+        ALOGE("Invalid channel mask %#x", channelMask);
+        return BAD_VALUE;
+    }
+    mChannelMask = channelMask;
+    uint32_t channelCount = popcount(channelMask);
+    mChannelCount = channelCount;
 
     // AudioFlinger does not currently support 8-bit data in shared memory
     if (format == AUDIO_FORMAT_PCM_8_BIT && sharedBuffer != 0) {
@@ -285,14 +315,6 @@
         flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
     }
 
-    if (!audio_is_output_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);
         mFrameSizeAF = channelCount * sizeof(int16_t);
@@ -301,30 +323,36 @@
         mFrameSizeAF = sizeof(uint8_t);
     }
 
-    audio_io_handle_t output = AudioSystem::getOutput(
-                                    streamType,
-                                    sampleRate, format, channelMask,
-                                    flags,
-                                    offloadInfo);
-
-    if (output == 0) {
-        ALOGE("Could not get audio output for stream type %d", streamType);
-        return BAD_VALUE;
+    // Make copy of input parameter offloadInfo so that in the future:
+    //  (a) createTrack_l doesn't need it as an input parameter
+    //  (b) we can support re-creation of offloaded tracks
+    if (offloadInfo != NULL) {
+        mOffloadInfoCopy = *offloadInfo;
+        mOffloadInfo = &mOffloadInfoCopy;
+    } else {
+        mOffloadInfo = NULL;
     }
 
     mVolume[LEFT] = 1.0f;
     mVolume[RIGHT] = 1.0f;
     mSendLevel = 0.0f;
-    mFrameCount = frameCount;
+    // mFrameCount is initialized in createTrack_l
     mReqFrameCount = frameCount;
     mNotificationFramesReq = notificationFrames;
     mNotificationFramesAct = 0;
     mSessionId = sessionId;
-    if (uid == -1 || (IPCThreadState::self()->getCallingPid() != getpid())) {
+    int callingpid = IPCThreadState::self()->getCallingPid();
+    int mypid = getpid();
+    if (uid == -1 || (callingpid != mypid)) {
         mClientUid = IPCThreadState::self()->getCallingUid();
     } else {
         mClientUid = uid;
     }
+    if (pid == -1 || (callingpid != mypid)) {
+        mClientPid = callingpid;
+    } else {
+        mClientPid = pid;
+    }
     mAuxEffectId = 0;
     mFlags = flags;
     mCbf = cbf;
@@ -335,14 +363,7 @@
     }
 
     // create the IAudioTrack
-    status_t status = createTrack_l(streamType,
-                                  sampleRate,
-                                  format,
-                                  frameCount,
-                                  flags,
-                                  sharedBuffer,
-                                  output,
-                                  0 /*epoch*/);
+    status = createTrack_l(0 /*epoch*/);
 
     if (status != NO_ERROR) {
         if (mAudioTrackThread != 0) {
@@ -350,17 +371,20 @@
             mAudioTrackThread->requestExitAndWait();
             mAudioTrackThread.clear();
         }
+        // Use of direct and offloaded output streams is ref counted by audio policy manager.
+#if 0   // FIXME This should no longer be needed
         //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);
+        if (mOutput != 0) {
+            AudioSystem::releaseOutput(mOutput);
+            mOutput = 0;
+        }
+#endif
         return status;
     }
 
     mStatus = NO_ERROR;
-    mStreamType = streamType;
-    mFormat = format;
-    mSharedBuffer = sharedBuffer;
     mState = STATE_STOPPED;
     mUserData = user;
     mLoopPeriod = 0;
@@ -368,11 +392,10 @@
     mMarkerReached = false;
     mNewPosition = 0;
     mUpdatePeriod = 0;
-    AudioSystem::acquireAudioSessionId(mSessionId);
+    AudioSystem::acquireAudioSessionId(mSessionId, mClientPid);
     mSequence = 1;
     mObservedSequence = mSequence;
     mInUnderrun = false;
-    mOutput = output;
 
     return NO_ERROR;
 }
@@ -448,12 +471,11 @@
 void AudioTrack::stop()
 {
     AutoMutex lock(mLock);
-    // FIXME pause then stop should not be a nop
-    if (mState != STATE_ACTIVE) {
+    if (mState != STATE_ACTIVE && mState != STATE_PAUSED) {
         return;
     }
 
-    if (isOffloaded()) {
+    if (isOffloaded_l()) {
         mState = STATE_STOPPING;
     } else {
         mState = STATE_STOPPED;
@@ -475,7 +497,7 @@
 
     sp<AudioTrackThread> t = mAudioTrackThread;
     if (t != 0) {
-        if (!isOffloaded()) {
+        if (!isOffloaded_l()) {
             t->pause();
         }
     } else {
@@ -513,7 +535,7 @@
     mRefreshRemaining = true;
 
     mState = STATE_FLUSHED;
-    if (isOffloaded()) {
+    if (isOffloaded_l()) {
         mProxy->interrupt();
     }
     mProxy->flush();
@@ -533,7 +555,7 @@
     mProxy->interrupt();
     mAudioTrack->pause();
 
-    if (isOffloaded()) {
+    if (isOffloaded_l()) {
         if (mOutput != 0) {
             uint32_t halFrames;
             // OffloadThread sends HAL pause in its threadLoop.. time saved
@@ -556,7 +578,7 @@
 
     mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
 
-    if (isOffloaded()) {
+    if (isOffloaded_l()) {
         mAudioTrack->signal();
     }
     return NO_ERROR;
@@ -620,7 +642,7 @@
     // 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 (isOffloaded_l()) {
         if (mOutput != 0) {
             uint32_t sampleRate = 0;
             status_t status = AudioSystem::getSamplingRate(mOutput, mStreamType, &sampleRate);
@@ -704,6 +726,7 @@
     AutoMutex lock(mLock);
     mNewPosition = mProxy->getPosition() + updatePeriod;
     mUpdatePeriod = updatePeriod;
+
     return NO_ERROR;
 }
 
@@ -757,7 +780,7 @@
     }
 
     AutoMutex lock(mLock);
-    if (isOffloaded()) {
+    if (isOffloaded_l()) {
         uint32_t dspFrames = 0;
 
         if ((mState == STATE_PAUSED) || (mState == STATE_PAUSED_STOPPING)) {
@@ -812,23 +835,12 @@
     return NO_ERROR;
 }
 
-audio_io_handle_t AudioTrack::getOutput()
+audio_io_handle_t AudioTrack::getOutput() const
 {
     AutoMutex lock(mLock);
     return mOutput;
 }
 
-// must be called with mLock held
-audio_io_handle_t AudioTrack::getOutput_l()
-{
-    if (mOutput) {
-        return mOutput;
-    } else {
-        return AudioSystem::getOutput(mStreamType,
-                                      mSampleRate, mFormat, mChannelMask, mFlags);
-    }
-}
-
 status_t AudioTrack::attachAuxEffect(int effectId)
 {
     AutoMutex lock(mLock);
@@ -842,15 +854,7 @@
 // -------------------------------------------------------------------------
 
 // must be called with mLock held
-status_t AudioTrack::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,
-        size_t epoch)
+status_t AudioTrack::createTrack_l(size_t epoch)
 {
     status_t status;
     const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
@@ -859,50 +863,57 @@
         return NO_INIT;
     }
 
+    audio_io_handle_t output = AudioSystem::getOutput(mStreamType, mSampleRate, mFormat,
+            mChannelMask, mFlags, mOffloadInfo);
+    if (output == 0) {
+        ALOGE("Could not get audio output for stream type %d, sample rate %u, format %#x, "
+              "channel mask %#x, flags %#x",
+              mStreamType, mSampleRate, mFormat, mChannelMask, mFlags);
+        return BAD_VALUE;
+    }
+    {
+    // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger,
+    // we must release it ourselves if anything goes wrong.
+
     // Not all of these values are needed under all conditions, but it is easier to get them all
 
     uint32_t afLatency;
-    status = AudioSystem::getLatency(output, streamType, &afLatency);
+    status = AudioSystem::getLatency(output, mStreamType, &afLatency);
     if (status != NO_ERROR) {
         ALOGE("getLatency(%d) failed status %d", output, status);
-        return NO_INIT;
+        goto release;
     }
 
     size_t afFrameCount;
-    status = AudioSystem::getFrameCount(output, streamType, &afFrameCount);
+    status = AudioSystem::getFrameCount(output, mStreamType, &afFrameCount);
     if (status != NO_ERROR) {
-        ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, streamType, status);
-        return NO_INIT;
+        ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, mStreamType, status);
+        goto release;
     }
 
     uint32_t afSampleRate;
-    status = AudioSystem::getSamplingRate(output, streamType, &afSampleRate);
+    status = AudioSystem::getSamplingRate(output, mStreamType, &afSampleRate);
     if (status != NO_ERROR) {
-        ALOGE("getSamplingRate(output=%d, streamType=%d) status %d", output, streamType, status);
-        return NO_INIT;
+        ALOGE("getSamplingRate(output=%d, streamType=%d) status %d", output, mStreamType, status);
+        goto release;
     }
 
     // Client decides whether the track is TIMED (see below), but can only express a preference
     // for FAST.  Server will perform additional tests.
-    if ((flags & AUDIO_OUTPUT_FLAG_FAST) && !(
+    if ((mFlags & AUDIO_OUTPUT_FLAG_FAST) && !((
             // either of these use cases:
             // use case 1: shared buffer
-            (sharedBuffer != 0) ||
-            // use case 2: callback handler
-            (mCbf != NULL))) {
+            (mSharedBuffer != 0) ||
+            // use case 2: callback transfer mode
+            (mTransfer == TRANSFER_CALLBACK)) &&
+            // matching sample rate
+            (mSampleRate == afSampleRate))) {
         ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client");
         // once denied, do not request again if IAudioTrack is re-created
-        flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST);
-        mFlags = flags;
+        mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
     }
     ALOGV("createTrack_l() output %d afLatency %d", output, afLatency);
 
-    if ((flags & AUDIO_OUTPUT_FLAG_FAST) && sampleRate != afSampleRate) {
-        ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client due to mismatching sample rate (%d vs %d)",
-              sampleRate, afSampleRate);
-        flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST);
-    }
-
     // The client's AudioTrack buffer is divided into n parts for purpose of wakeup by server, where
     //  n = 1   fast track with single buffering; nBuffering is ignored
     //  n = 2   fast track with double buffering
@@ -910,43 +921,45 @@
     //  n = 3   normal track, with sample rate conversion
     //          (pessimistic; some non-1:1 conversion ratios don't actually need triple-buffering)
     //  n > 3   very high latency or very small notification interval; nBuffering is ignored
-    const uint32_t nBuffering = (sampleRate == afSampleRate) ? 2 : 3;
+    const uint32_t nBuffering = (mSampleRate == afSampleRate) ? 2 : 3;
 
     mNotificationFramesAct = mNotificationFramesReq;
 
-    if (!audio_is_linear_pcm(format)) {
+    size_t frameCount = mReqFrameCount;
+    if (!audio_is_linear_pcm(mFormat)) {
 
-        if (sharedBuffer != 0) {
+        if (mSharedBuffer != 0) {
             // Same comment as below about ignoring frameCount parameter for set()
-            frameCount = sharedBuffer->size();
+            frameCount = mSharedBuffer->size();
         } else if (frameCount == 0) {
             frameCount = afFrameCount;
         }
         if (mNotificationFramesAct != frameCount) {
             mNotificationFramesAct = frameCount;
         }
-    } else if (sharedBuffer != 0) {
+    } else if (mSharedBuffer != 0) {
 
         // Ensure that buffer alignment matches channel count
         // 8-bit data in shared memory is not currently supported by AudioFlinger
-        size_t alignment = /* format == AUDIO_FORMAT_PCM_8_BIT ? 1 : */ 2;
+        size_t alignment = /* mFormat == AUDIO_FORMAT_PCM_8_BIT ? 1 : */ 2;
         if (mChannelCount > 1) {
             // More than 2 channels does not require stronger alignment than stereo
             alignment <<= 1;
         }
-        if (((uintptr_t)sharedBuffer->pointer() & (alignment - 1)) != 0) {
+        if (((uintptr_t)mSharedBuffer->pointer() & (alignment - 1)) != 0) {
             ALOGE("Invalid buffer alignment: address %p, channel count %u",
-                    sharedBuffer->pointer(), mChannelCount);
-            return BAD_VALUE;
+                    mSharedBuffer->pointer(), mChannelCount);
+            status = BAD_VALUE;
+            goto release;
         }
 
         // When initializing a shared buffer AudioTrack via constructors,
         // there's no frameCount parameter.
         // But when initializing a shared buffer AudioTrack via set(),
         // there _is_ a frameCount parameter.  We silently ignore it.
-        frameCount = sharedBuffer->size()/mChannelCount/sizeof(int16_t);
+        frameCount = mSharedBuffer->size()/mChannelCount/sizeof(int16_t);
 
-    } else if (!(flags & AUDIO_OUTPUT_FLAG_FAST)) {
+    } else if (!(mFlags & AUDIO_OUTPUT_FLAG_FAST)) {
 
         // FIXME move these calculations and associated checks to server
 
@@ -958,10 +971,10 @@
             minBufCount = nBuffering;
         }
 
-        size_t minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
+        size_t minFrameCount = (afFrameCount*mSampleRate*minBufCount)/afSampleRate;
         ALOGV("minFrameCount: %u, afFrameCount=%d, minBufCount=%d, sampleRate=%u, afSampleRate=%u"
                 ", afLatency=%d",
-                minFrameCount, afFrameCount, minBufCount, sampleRate, afSampleRate, afLatency);
+                minFrameCount, afFrameCount, minBufCount, mSampleRate, afSampleRate, afLatency);
 
         if (frameCount == 0) {
             frameCount = minFrameCount;
@@ -986,52 +999,64 @@
     }
 
     pid_t tid = -1;
-    if (flags & AUDIO_OUTPUT_FLAG_FAST) {
+    if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
         trackFlags |= IAudioFlinger::TRACK_FAST;
         if (mAudioTrackThread != 0) {
             tid = mAudioTrackThread->getTid();
         }
     }
 
-    if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+    if (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
         trackFlags |= IAudioFlinger::TRACK_OFFLOAD;
     }
 
-    sp<IAudioTrack> track = audioFlinger->createTrack(streamType,
-                                                      sampleRate,
+    size_t temp = frameCount;   // temp may be replaced by a revised value of frameCount,
+                                // but we will still need the original value also
+    sp<IAudioTrack> track = audioFlinger->createTrack(mStreamType,
+                                                      mSampleRate,
                                                       // AudioFlinger only sees 16-bit PCM
-                                                      format == AUDIO_FORMAT_PCM_8_BIT ?
-                                                              AUDIO_FORMAT_PCM_16_BIT : format,
+                                                      mFormat == AUDIO_FORMAT_PCM_8_BIT ?
+                                                              AUDIO_FORMAT_PCM_16_BIT : mFormat,
                                                       mChannelMask,
-                                                      frameCount,
+                                                      &temp,
                                                       &trackFlags,
-                                                      sharedBuffer,
+                                                      mSharedBuffer,
                                                       output,
                                                       tid,
                                                       &mSessionId,
-                                                      mName,
                                                       mClientUid,
                                                       &status);
 
-    if (track == 0) {
+    if (status != NO_ERROR) {
         ALOGE("AudioFlinger could not create track, status: %d", status);
-        return status;
+        goto release;
     }
+    ALOG_ASSERT(track != 0);
+
+    // AudioFlinger now owns the reference to the I/O handle,
+    // so we are no longer responsible for releasing it.
+
     sp<IMemory> iMem = track->getCblk();
     if (iMem == 0) {
         ALOGE("Could not get control block");
         return NO_INIT;
     }
+    void *iMemPointer = iMem->pointer();
+    if (iMemPointer == NULL) {
+        ALOGE("Could not get control block pointer");
+        return NO_INIT;
+    }
     // invariant that mAudioTrack != 0 is true only after set() returns successfully
     if (mAudioTrack != 0) {
         mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
         mDeathNotifier.clear();
     }
     mAudioTrack = track;
+
     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;
-    size_t temp = cblk->frameCount_;
+    // note that temp is the (possibly revised) value of frameCount
     if (temp < frameCount || (frameCount == 0 && temp == 0)) {
         // In current design, AudioTrack client checks and ensures frame count validity before
         // passing it to AudioFlinger so AudioFlinger should not return a different value except
@@ -1039,12 +1064,13 @@
         ALOGW("Requested frameCount %u but received frameCount %u", frameCount, temp);
     }
     frameCount = temp;
+
     mAwaitBoost = false;
-    if (flags & AUDIO_OUTPUT_FLAG_FAST) {
+    if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
         if (trackFlags & IAudioFlinger::TRACK_FAST) {
             ALOGV("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %u", frameCount);
             mAwaitBoost = true;
-            if (sharedBuffer == 0) {
+            if (mSharedBuffer == 0) {
                 // Theoretically double-buffering is not required for fast tracks,
                 // due to tighter scheduling.  But in practice, to accommodate kernels with
                 // scheduling jitter, and apps with computation jitter, we use double-buffering.
@@ -1055,26 +1081,27 @@
         } else {
             ALOGV("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %u", frameCount);
             // once denied, do not request again if IAudioTrack is re-created
-            flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST);
-            mFlags = flags;
-            if (sharedBuffer == 0) {
+            mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
+            if (mSharedBuffer == 0) {
                 if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/nBuffering) {
                     mNotificationFramesAct = frameCount/nBuffering;
                 }
             }
         }
     }
-    if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+    if (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
         if (trackFlags & IAudioFlinger::TRACK_OFFLOAD) {
             ALOGV("AUDIO_OUTPUT_FLAG_OFFLOAD successful");
         } else {
             ALOGW("AUDIO_OUTPUT_FLAG_OFFLOAD denied by server");
-            flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
-            mFlags = flags;
-            return NO_INIT;
+            mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+            // FIXME This is a warning, not an error, so don't return error status
+            //return NO_INIT;
         }
     }
 
+    // We retain a copy of the I/O handle, but don't own the reference
+    mOutput = output;
     mRefreshRemaining = true;
 
     // Starting address of buffers in shared memory.  If there is a shared buffer, buffers
@@ -1082,15 +1109,16 @@
     // 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* buffers;
-    if (sharedBuffer == 0) {
+    if (mSharedBuffer == 0) {
         buffers = (char*)cblk + sizeof(audio_track_cblk_t);
     } else {
-        buffers = sharedBuffer->pointer();
+        buffers = mSharedBuffer->pointer();
     }
 
     mAudioTrack->attachAuxEffect(mAuxEffectId);
     // FIXME don't believe this lie
-    mLatency = afLatency + (1000*frameCount) / sampleRate;
+    mLatency = afLatency + (1000*frameCount) / mSampleRate;
+
     mFrameCount = frameCount;
     // If IAudioTrack is re-created, don't let the requested frameCount
     // decrease.  This can confuse clients that cache frameCount().
@@ -1099,7 +1127,7 @@
     }
 
     // update proxy
-    if (sharedBuffer == 0) {
+    if (mSharedBuffer == 0) {
         mStaticProxy.clear();
         mProxy = new AudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF);
     } else {
@@ -1117,6 +1145,14 @@
     mAudioTrack->asBinder()->linkToDeath(mDeathNotifier, this);
 
     return NO_ERROR;
+    }
+
+release:
+    AudioSystem::releaseOutput(output);
+    if (status == NO_ERROR) {
+        status = NO_INIT;
+    }
+    return status;
 }
 
 status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
@@ -1244,8 +1280,7 @@
     if (mState == STATE_ACTIVE) {
         audio_track_cblk_t* cblk = mCblk;
         if (android_atomic_and(~CBLK_DISABLED, &cblk->mFlags) & CBLK_DISABLED) {
-            ALOGW("releaseBuffer() track %p name=%s disabled due to previous underrun, restarting",
-                    this, mName.string());
+            ALOGW("releaseBuffer() track %p disabled due to previous underrun, restarting", this);
             // FIXME ignoring status
             mAudioTrack->start();
         }
@@ -1254,7 +1289,7 @@
 
 // -------------------------------------------------------------------------
 
-ssize_t AudioTrack::write(const void* buffer, size_t userSize)
+ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking)
 {
     if (mTransfer != TRANSFER_SYNC || mIsTimed) {
         return INVALID_OPERATION;
@@ -1273,7 +1308,8 @@
     while (userSize >= mFrameSize) {
         audioBuffer.frameCount = userSize / mFrameSize;
 
-        status_t err = obtainBuffer(&audioBuffer, &ClientProxy::kForever);
+        status_t err = obtainBuffer(&audioBuffer,
+                blocking ? &ClientProxy::kForever : &ClientProxy::kNonBlocking);
         if (err < 0) {
             if (written > 0) {
                 break;
@@ -1369,7 +1405,7 @@
 
 // -------------------------------------------------------------------------
 
-nsecs_t AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
+nsecs_t AudioTrack::processAudioBuffer()
 {
     // Currently the AudioTrack thread is not created if there are no callbacks.
     // Would it ever make sense to run the thread, even without callbacks?
@@ -1407,7 +1443,7 @@
         // for offloaded tracks restoreTrack_l() will just update the sequence and clear
         // AudioSystem cache. We should not exit here but after calling the callback so
         // that the upper layers can recreate the track
-        if (!isOffloaded() || (mSequence == mObservedSequence)) {
+        if (!isOffloaded_l() || (mSequence == mObservedSequence)) {
             status_t status = restoreTrack_l("processAudioBuffer");
             mLock.unlock();
             // Run again immediately, but with a new IAudioTrack
@@ -1462,7 +1498,7 @@
     // Cache other fields that will be needed soon
     uint32_t loopPeriod = mLoopPeriod;
     uint32_t sampleRate = mSampleRate;
-    size_t notificationFrames = mNotificationFramesAct;
+    uint32_t notificationFrames = mNotificationFramesAct;
     if (mRefreshRemaining) {
         mRefreshRemaining = false;
         mRemainingFrames = notificationFrames;
@@ -1626,7 +1662,6 @@
         size_t reqSize = audioBuffer.size;
         mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
         size_t writtenSize = audioBuffer.size;
-        size_t writtenFrames = writtenSize / mFrameSize;
 
         // Sanity check on returned size
         if (ssize_t(writtenSize) < 0 || writtenSize > reqSize) {
@@ -1692,22 +1727,19 @@
 status_t AudioTrack::restoreTrack_l(const char *from)
 {
     ALOGW("dead IAudioTrack, %s, creating a new one from %s()",
-          isOffloaded() ? "Offloaded" : "PCM", from);
+          isOffloaded_l() ? "Offloaded" : "PCM", from);
     ++mSequence;
     status_t result;
 
     // refresh the audio configuration cache in this process to make sure we get new
-    // output parameters in getOutput_l() and createTrack_l()
+    // output parameters in createTrack_l()
     AudioSystem::clearAudioConfigCache();
 
-    if (isOffloaded()) {
+    if (isOffloaded_l()) {
+        // FIXME re-creation of offloaded tracks is not yet implemented
         return DEAD_OBJECT;
     }
 
-    // force new output query from audio policy manager;
-    mOutput = 0;
-    audio_io_handle_t output = getOutput_l();
-
     // if the new IAudioTrack is created, createTrack_l() will modify the
     // following member variables: mAudioTrack, mCblkMemory and mCblk.
     // It will also delete the strong references on previous IAudioTrack and IMemory
@@ -1715,14 +1747,7 @@
     // take the frames that will be lost by track recreation into account in saved position
     size_t position = mProxy->getPosition() + mProxy->getFramesFilled();
     size_t bufferPosition = mStaticProxy != NULL ? mStaticProxy->getBufferPosition() : 0;
-    result = createTrack_l(mStreamType,
-                           mSampleRate,
-                           mFormat,
-                           mReqFrameCount,  // so that frame count never goes down
-                           mFlags,
-                           mSharedBuffer,
-                           output,
-                           position /*epoch*/);
+    result = createTrack_l(position /*epoch*/);
 
     if (result == NO_ERROR) {
         // continue playback from last known position, but
@@ -1750,10 +1775,16 @@
         }
     }
     if (result != NO_ERROR) {
+        // Use of direct and offloaded output streams is ref counted by audio policy manager.
+#if 0   // FIXME This should no longer be needed
         //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);
+        if (mOutput != 0) {
+            AudioSystem::releaseOutput(mOutput);
+            mOutput = 0;
+        }
+#endif
         ALOGW("restoreTrack_l() failed status %d", result);
         mState = STATE_STOPPED;
     }
@@ -1786,14 +1817,21 @@
 
 String8 AudioTrack::getParameters(const String8& keys)
 {
-    if (mOutput) {
-        return AudioSystem::getParameters(mOutput, keys);
+    audio_io_handle_t output = getOutput();
+    if (output != 0) {
+        return AudioSystem::getParameters(output, keys);
     } else {
         return String8::empty();
     }
 }
 
-status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
+bool AudioTrack::isOffloaded() const
+{
+    AutoMutex lock(mLock);
+    return isOffloaded_l();
+}
+
+status_t AudioTrack::dump(int fd, const Vector<String16>& args __unused) const
 {
 
     const size_t SIZE = 256;
@@ -1823,7 +1861,7 @@
 
 // =========================================================================
 
-void AudioTrack::DeathNotifier::binderDied(const wp<IBinder>& who)
+void AudioTrack::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
 {
     sp<AudioTrack> audioTrack = mAudioTrack.promote();
     if (audioTrack != 0) {
@@ -1867,7 +1905,7 @@
             return true;
         }
     }
-    nsecs_t ns = mReceiver.processAudioBuffer(this);
+    nsecs_t ns = mReceiver.processAudioBuffer();
     switch (ns) {
     case 0:
         return true;
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index e898109..fdd1a12 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -26,7 +26,7 @@
 namespace android {
 
 audio_track_cblk_t::audio_track_cblk_t()
-    : mServer(0), frameCount_(0), mFutex(0), mMinimum(0),
+    : mServer(0), mFutex(0), mMinimum(0),
     mVolumeLR(0x10001000), mSampleRate(0), mSendLevel(0), mFlags(0)
 {
     memset(&u, 0, sizeof(u));
@@ -771,7 +771,7 @@
     return (ssize_t) position;
 }
 
-status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
+status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush __unused)
 {
     if (mIsShutdown) {
         buffer->mFrameCount = 0;
@@ -854,7 +854,7 @@
     buffer->mNonContig = 0;
 }
 
-void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
+void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount __unused)
 {
     // Unlike AudioTrackServerProxy::tallyUnderrunFrames() used for streaming tracks,
     // we don't have a location to count underrun frames.  The underrun frame counter
diff --git a/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp
new file mode 100644
index 0000000..eb091ac
--- /dev/null
+++ b/media/libmedia/CharacterEncodingDetector.cpp
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CharacterEncodingDector"
+#include <utils/Log.h>
+
+#include "CharacterEncodingDetector.h"
+#include "CharacterEncodingDetectorTables.h"
+
+#include "utils/Vector.h"
+#include "StringArray.h"
+
+#include "unicode/ucnv.h"
+#include "unicode/ucsdet.h"
+#include "unicode/ustring.h"
+
+namespace android {
+
+CharacterEncodingDetector::CharacterEncodingDetector() {
+
+    UErrorCode status = U_ZERO_ERROR;
+    mUtf8Conv = ucnv_open("UTF-8", &status);
+    if (U_FAILURE(status)) {
+        ALOGE("could not create UConverter for UTF-8");
+        mUtf8Conv = NULL;
+    }
+}
+
+CharacterEncodingDetector::~CharacterEncodingDetector() {
+    ucnv_close(mUtf8Conv);
+}
+
+void CharacterEncodingDetector::addTag(const char *name, const char *value) {
+    mNames.push_back(name);
+    mValues.push_back(value);
+}
+
+size_t CharacterEncodingDetector::size() {
+    return mNames.size();
+}
+
+status_t CharacterEncodingDetector::getTag(int index, const char **name, const char**value) {
+    if (index >= mNames.size()) {
+        return BAD_VALUE;
+    }
+
+    *name = mNames.getEntry(index);
+    *value = mValues.getEntry(index);
+    return OK;
+}
+
+static bool isPrintableAscii(const char *value, size_t len) {
+    for (size_t i = 0; i < len; i++) {
+        if ((value[i] & 0x80) || value[i] < 0x20 || value[i] == 0x7f) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void CharacterEncodingDetector::detectAndConvert() {
+
+    int size = mNames.size();
+    ALOGV("%d tags before conversion", size);
+    for (int i = 0; i < size; i++) {
+        ALOGV("%s: %s", mNames.getEntry(i), mValues.getEntry(i));
+    }
+
+    if (size && mUtf8Conv) {
+
+        UErrorCode status = U_ZERO_ERROR;
+        UCharsetDetector *csd = ucsdet_open(&status);
+        const UCharsetMatch *ucm;
+
+        // try combined detection of artist/album/title etc.
+        char buf[1024];
+        buf[0] = 0;
+        int idx;
+        for (int i = 0; i < size; i++) {
+            const char *name = mNames.getEntry(i);
+            const char *value = mValues.getEntry(i);
+            if (!isPrintableAscii(value, strlen(value)) && (
+                        !strcmp(name, "artist") ||
+                        !strcmp(name, "albumartist") ||
+                        !strcmp(name, "composer") ||
+                        !strcmp(name, "genre") ||
+                        !strcmp(name, "album") ||
+                        !strcmp(name, "title"))) {
+                strlcat(buf, value, sizeof(buf));
+                // separate tags by space so ICU's ngram detector can do its job
+                strlcat(buf, " ", sizeof(buf));
+            }
+        }
+        ucsdet_setText(csd, buf, strlen(buf), &status);
+
+        int32_t matches;
+        const UCharsetMatch** ucma = ucsdet_detectAll(csd, &matches, &status);
+        const char *combinedenc = "???";
+
+        const UCharsetMatch* bestCombinedMatch = getPreferred(buf, strlen(buf), ucma, matches);
+
+        if (bestCombinedMatch != NULL) {
+            combinedenc = ucsdet_getName(bestCombinedMatch, &status);
+        }
+
+        for (int i = 0; i < size; i++) {
+            const char *name = mNames.getEntry(i);
+            uint8_t* src = (uint8_t *)mValues.getEntry(i);
+            int len = strlen((char *)src);
+            uint8_t* dest = src;
+
+            ALOGV("@@@ checking %s", name);
+            const char *s = mValues.getEntry(i);
+            int32_t inputLength = strlen(s);
+            const char *enc;
+
+            if (!strcmp(name, "artist") ||
+                    !strcmp(name, "albumartist") ||
+                    !strcmp(name, "composer") ||
+                    !strcmp(name, "genre") ||
+                    !strcmp(name, "album") ||
+                    !strcmp(name, "title")) {
+                // use encoding determined from the combination of artist/album/title etc.
+                enc = combinedenc;
+            } else {
+                ucsdet_setText(csd, s, inputLength, &status);
+                ucm = ucsdet_detect(csd, &status);
+                if (!ucm) {
+                    mValues.setEntry(i, "???");
+                    continue;
+                }
+                enc = ucsdet_getName(ucm, &status);
+                ALOGV("@@@@ recognized charset: %s for %s confidence %d",
+                        enc, mNames.getEntry(i), ucsdet_getConfidence(ucm, &status));
+            }
+
+            if (strcmp(enc,"UTF-8") != 0) {
+                // only convert if the source encoding isn't already UTF-8
+                ALOGV("@@@ using converter %s for %s", enc, mNames.getEntry(i));
+                UConverter *conv = ucnv_open(enc, &status);
+                if (U_FAILURE(status)) {
+                    ALOGE("could not create UConverter for %s", enc);
+                    continue;
+                }
+
+                // convert from native encoding to UTF-8
+                const char* source = mValues.getEntry(i);
+                int targetLength = len * 3 + 1;
+                char* buffer = new char[targetLength];
+                // don't normally check for NULL, but in this case targetLength may be large
+                if (!buffer)
+                    break;
+                char* target = buffer;
+
+                ucnv_convertEx(mUtf8Conv, conv, &target, target + targetLength,
+                        &source, source + strlen(source),
+                        NULL, NULL, NULL, NULL, TRUE, TRUE, &status);
+
+                if (U_FAILURE(status)) {
+                    ALOGE("ucnv_convertEx failed: %d", status);
+                    mValues.setEntry(i, "???");
+                } else {
+                    // zero terminate
+                    *target = 0;
+                    mValues.setEntry(i, buffer);
+                }
+
+                delete[] buffer;
+
+                ucnv_close(conv);
+            }
+        }
+
+        for (int i = size - 1; i >= 0; --i) {
+            if (strlen(mValues.getEntry(i)) == 0) {
+                ALOGV("erasing %s because entry is empty", mNames.getEntry(i));
+                mNames.erase(i);
+                mValues.erase(i);
+            }
+        }
+
+        ucsdet_close(csd);
+    }
+}
+
+/*
+ * When ICU detects multiple encoding matches, apply additional heuristics to determine
+ * which one is the best match, since ICU can't always be trusted to make the right choice.
+ *
+ * What this method does is:
+ * - decode the input using each of the matches found
+ * - recalculate the starting confidence level for multibyte encodings using a different
+ *   algorithm and larger frequent character lists than ICU
+ * - devalue encoding where the conversion contains unlikely characters (symbols, reserved, etc)
+ * - pick the highest match
+ */
+const UCharsetMatch *CharacterEncodingDetector::getPreferred(
+        const char *input, size_t len, const UCharsetMatch** ucma, size_t nummatches) {
+
+    Vector<const UCharsetMatch*> matches;
+    UErrorCode status = U_ZERO_ERROR;
+
+    ALOGV("%d matches", nummatches);
+    for (size_t i = 0; i < nummatches; i++) {
+        const char *encname = ucsdet_getName(ucma[i], &status);
+        int confidence = ucsdet_getConfidence(ucma[i], &status);
+        ALOGV("%d: %s %d", i, encname, confidence);
+        matches.push_back(ucma[i]);
+    }
+
+    size_t num = matches.size();
+    if (num == 0) {
+        return NULL;
+    }
+    if (num == 1) {
+        return matches[0];
+    }
+
+    ALOGV("considering %d matches", num);
+
+    // keep track of how many "special" characters result when converting the input using each
+    // encoding
+    Vector<int> newconfidence;
+    for (size_t i = 0; i < num; i++) {
+        const uint16_t *freqdata = NULL;
+        float freqcoverage = 0;
+        status = U_ZERO_ERROR;
+        const char *encname = ucsdet_getName(matches[i], &status);
+        int confidence = ucsdet_getConfidence(matches[i], &status);
+        if (!strcmp("GB18030", encname)) {
+            freqdata = frequent_zhCN;
+            freqcoverage = frequent_zhCN_coverage;
+        } else if (!strcmp("Big5", encname)) {
+            freqdata = frequent_zhTW;
+            freqcoverage = frequent_zhTW_coverage;
+        } else if (!strcmp("EUC-KR", encname)) {
+            freqdata = frequent_ko;
+            freqcoverage = frequent_ko_coverage;
+        } else if (!strcmp("EUC-JP", encname)) {
+            freqdata = frequent_ja;
+            freqcoverage = frequent_ja_coverage;
+        } else if (!strcmp("Shift_JIS", encname)) {
+            freqdata = frequent_ja;
+            freqcoverage = frequent_ja_coverage;
+        }
+
+        ALOGV("%d: %s %d", i, encname, confidence);
+        UConverter *conv = ucnv_open(encname, &status);
+        const char *source = input;
+        const char *sourceLimit = input + len;
+        status = U_ZERO_ERROR;
+        int demerit = 0;
+        int frequentchars = 0;
+        int totalchars = 0;
+        while (true) {
+            // demerit the current encoding for each "special" character found after conversion.
+            // The amount of demerit is somewhat arbitrarily chosen.
+            int inchar;
+            if (source != sourceLimit) {
+                inchar = (source[0] << 8) + source[1];
+            }
+            UChar32 c = ucnv_getNextUChar(conv, &source, sourceLimit, &status);
+            if (!U_SUCCESS(status)) {
+                break;
+            }
+            if (c < 0x20 || (c >= 0x7f && c <= 0x009f)) {
+                ALOGV("control character %x", c);
+                demerit += 100;
+            } else if ((c >= 0xa0 && c <= 0xbe)         // symbols, superscripts
+                    || (c == 0xd7) || (c == 0xf7)       // multiplication and division signs
+                    || (c >= 0x2000 && c <= 0x209f)) {  // punctuation, superscripts
+                ALOGV("unlikely character %x", c);
+                demerit += 10;
+            } else if (c >= 0xe000 && c <= 0xf8ff) {
+                ALOGV("private use character %x", c);
+                demerit += 30;
+            } else if (c >= 0x2190 && c <= 0x2bff) {
+                // this range comprises various symbol ranges that are unlikely to appear in
+                // music file metadata.
+                ALOGV("symbol %x", c);
+                demerit += 10;
+            } else if (c == 0xfffd) {
+                ALOGV("replacement character");
+                demerit += 50;
+            } else if (c >= 0xfff0 && c <= 0xfffc) {
+                ALOGV("unicode special %x", c);
+                demerit += 50;
+            } else if (freqdata != NULL) {
+                totalchars++;
+                if (isFrequent(freqdata, c)) {
+                    frequentchars++;
+                }
+            }
+        }
+        if (freqdata != NULL && totalchars != 0) {
+            int myconfidence = 10 + float((100 * frequentchars) / totalchars) / freqcoverage;
+            ALOGV("ICU confidence: %d, my confidence: %d (%d %d)", confidence, myconfidence,
+                    totalchars, frequentchars);
+            if (myconfidence > 100) myconfidence = 100;
+            if (myconfidence < 0) myconfidence = 0;
+            confidence = myconfidence;
+        }
+        ALOGV("%d-%d=%d", confidence, demerit, confidence - demerit);
+        newconfidence.push_back(confidence - demerit);
+        ucnv_close(conv);
+        if (i == 0 && (confidence - demerit) == 100) {
+            // no need to check any further, we'll end up using this match anyway
+            break;
+        }
+    }
+
+    // find match with highest confidence after adjusting for unlikely characters
+    int highest = newconfidence[0];
+    size_t highestidx = 0;
+    num = newconfidence.size();
+    for (size_t i = 1; i < num; i++) {
+        if (newconfidence[i] > highest) {
+            highest = newconfidence[i];
+            highestidx = i;
+        }
+    }
+    status = U_ZERO_ERROR;
+    ALOGV("selecting '%s' w/ %d confidence", ucsdet_getName(matches[highestidx], &status), highest);
+    return matches[highestidx];
+}
+
+
+bool CharacterEncodingDetector::isFrequent(const uint16_t *values, uint32_t c) {
+
+    int start = 0;
+    int end = 511; // All the tables have 512 entries
+    int mid = (start+end)/2;
+
+    while(start <= end) {
+        if(c == values[mid]) {
+            return true;
+        } else if (c > values[mid]) {
+            start = mid + 1;
+        } else {
+            end = mid - 1;
+        }
+
+        mid = (start + end) / 2;
+    }
+
+    return false;
+}
+
+
+}  // namespace android
diff --git a/media/libmedia/CharacterEncodingDetector.h b/media/libmedia/CharacterEncodingDetector.h
new file mode 100644
index 0000000..3655a91
--- /dev/null
+++ b/media/libmedia/CharacterEncodingDetector.h
@@ -0,0 +1,61 @@
+/*
+ * 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 _CHARACTER_ENCODING_DETECTOR_H
+#define _CHARACTER_ENCODING_DETECTOR_H
+
+#include <media/mediascanner.h>
+
+#include "StringArray.h"
+
+#include "unicode/ucnv.h"
+#include "unicode/ucsdet.h"
+#include "unicode/ustring.h"
+
+namespace android {
+
+class CharacterEncodingDetector {
+
+    public:
+    CharacterEncodingDetector();
+        ~CharacterEncodingDetector();
+
+        void addTag(const char *name, const char *value);
+        size_t size();
+
+        void detectAndConvert();
+        status_t getTag(int index, const char **name, const char**value);
+
+    private:
+        const UCharsetMatch *getPreferred(
+                const char *input, size_t len, const UCharsetMatch** ucma, size_t matches);
+
+        bool isFrequent(const uint16_t *values, uint32_t c);
+
+        // cached name and value strings, for native encoding support.
+        // TODO: replace these with byte blob arrays that don't require the data to be
+        // singlenullbyte-terminated
+        StringArray     mNames;
+        StringArray     mValues;
+
+        UConverter*     mUtf8Conv;
+};
+
+
+
+};  // namespace android
+
+#endif
diff --git a/media/libmedia/CharacterEncodingDetectorTables.h b/media/libmedia/CharacterEncodingDetectorTables.h
new file mode 100644
index 0000000..1fe1137
--- /dev/null
+++ b/media/libmedia/CharacterEncodingDetectorTables.h
@@ -0,0 +1,2092 @@
+/*
+ * 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.
+ */
+
+// The 512 most frequently occuring characters for the zhCN language in a sample of the Internet.
+// Ordered by codepoint, comment shows character and ranking by frequency
+const uint16_t frequent_zhCN[] = {
+    0x4E00, // 一, #2
+    0x4E07, // 万, #306
+    0x4E09, // 三, #138
+    0x4E0A, // 上, #16
+    0x4E0B, // 下, #25
+    0x4E0D, // 不, #7
+    0x4E0E, // 与, #133
+    0x4E13, // 专, #151
+    0x4E16, // 世, #346
+    0x4E1A, // 业, #39
+    0x4E1C, // 东, #197
+    0x4E24, // 两, #376
+    0x4E2A, // 个, #23
+    0x4E2D, // 中, #4
+    0x4E3A, // 为, #31
+    0x4E3B, // 主, #95
+    0x4E3E, // 举, #418
+    0x4E48, // 么, #93
+    0x4E4B, // 之, #131
+    0x4E50, // 乐, #130
+    0x4E5F, // 也, #145
+    0x4E66, // 书, #283
+    0x4E70, // 买, #483
+    0x4E86, // 了, #13
+    0x4E8B, // 事, #168
+    0x4E8C, // 二, #218
+    0x4E8E, // 于, #64
+    0x4E94, // 五, #430
+    0x4E9A, // 亚, #468
+    0x4E9B, // 些, #366
+    0x4EA4, // 交, #243
+    0x4EA7, // 产, #86
+    0x4EAB, // 享, #345
+    0x4EAC, // 京, #206
+    0x4EBA, // 人, #3
+    0x4EC0, // 什, #287
+    0x4ECB, // 介, #478
+    0x4ECE, // 从, #381
+    0x4ED6, // 他, #129
+    0x4EE3, // 代, #241
+    0x4EE5, // 以, #51
+    0x4EEC, // 们, #83
+    0x4EF6, // 件, #141
+    0x4EF7, // 价, #140
+    0x4EFB, // 任, #383
+    0x4F01, // 企, #439
+    0x4F18, // 优, #374
+    0x4F1A, // 会, #29
+    0x4F20, // 传, #222
+    0x4F46, // 但, #451
+    0x4F4D, // 位, #208
+    0x4F53, // 体, #98
+    0x4F55, // 何, #339
+    0x4F5C, // 作, #44
+    0x4F60, // 你, #76
+    0x4F7F, // 使, #272
+    0x4F9B, // 供, #375
+    0x4FDD, // 保, #180
+    0x4FE1, // 信, #84
+    0x4FEE, // 修, #437
+    0x503C, // 值, #450
+    0x505A, // 做, #368
+    0x5065, // 健, #484
+    0x50CF, // 像, #487
+    0x513F, // 儿, #326
+    0x5143, // 元, #202
+    0x5148, // 先, #485
+    0x5149, // 光, #254
+    0x514B, // 克, #503
+    0x514D, // 免, #349
+    0x5165, // 入, #156
+    0x5168, // 全, #47
+    0x516C, // 公, #35
+    0x5171, // 共, #448
+    0x5173, // 关, #49
+    0x5176, // 其, #195
+    0x5177, // 具, #329
+    0x5185, // 内, #109
+    0x518C, // 册, #225
+    0x519B, // 军, #466
+    0x51FA, // 出, #53
+    0x51FB, // 击, #359
+    0x5206, // 分, #22
+    0x5217, // 列, #410
+    0x521B, // 创, #399
+    0x5229, // 利, #296
+    0x522B, // 别, #372
+    0x5230, // 到, #33
+    0x5236, // 制, #192
+    0x524D, // 前, #117
+    0x529B, // 力, #173
+    0x529E, // 办, #436
+    0x529F, // 功, #455
+    0x52A0, // 加, #97
+    0x52A1, // 务, #100
+    0x52A8, // 动, #46
+    0x52A9, // 助, #365
+    0x5305, // 包, #331
+    0x5316, // 化, #155
+    0x5317, // 北, #194
+    0x533A, // 区, #105
+    0x533B, // 医, #234
+    0x5341, // 十, #294
+    0x534E, // 华, #205
+    0x5355, // 单, #259
+    0x5357, // 南, #182
+    0x535A, // 博, #153
+    0x5361, // 卡, #332
+    0x539F, // 原, #271
+    0x53BB, // 去, #282
+    0x53C2, // 参, #500
+    0x53CA, // 及, #255
+    0x53CB, // 友, #186
+    0x53CD, // 反, #422
+    0x53D1, // 发, #15
+    0x53D7, // 受, #507
+    0x53D8, // 变, #395
+    0x53E3, // 口, #293
+    0x53EA, // 只, #340
+    0x53EF, // 可, #45
+    0x53F0, // 台, #267
+    0x53F7, // 号, #121
+    0x53F8, // 司, #150
+    0x5404, // 各, #491
+    0x5408, // 合, #115
+    0x540C, // 同, #189
+    0x540D, // 名, #127
+    0x540E, // 后, #75
+    0x5411, // 向, #459
+    0x5427, // 吧, #353
+    0x544A, // 告, #318
+    0x5458, // 员, #232
+    0x5468, // 周, #347
+    0x548C, // 和, #43
+    0x54C1, // 品, #36
+    0x5546, // 商, #148
+    0x5668, // 器, #228
+    0x56DB, // 四, #352
+    0x56DE, // 回, #38
+    0x56E0, // 因, #355
+    0x56E2, // 团, #412
+    0x56ED, // 园, #470
+    0x56FD, // 国, #12
+    0x56FE, // 图, #32
+    0x5728, // 在, #10
+    0x5730, // 地, #30
+    0x573A, // 场, #177
+    0x575B, // 坛, #364
+    0x578B, // 型, #274
+    0x57CE, // 城, #172
+    0x57FA, // 基, #315
+    0x58EB, // 士, #434
+    0x58F0, // 声, #397
+    0x5904, // 处, #416
+    0x5907, // 备, #270
+    0x590D, // 复, #122
+    0x5916, // 外, #190
+    0x591A, // 多, #40
+    0x5927, // 大, #8
+    0x5929, // 天, #52
+    0x592A, // 太, #456
+    0x5934, // 头, #258
+    0x5973, // 女, #65
+    0x597D, // 好, #62
+    0x5982, // 如, #135
+    0x5A31, // 娱, #452
+    0x5B50, // 子, #37
+    0x5B57, // 字, #285
+    0x5B66, // 学, #19
+    0x5B89, // 安, #144
+    0x5B8C, // 完, #469
+    0x5B9A, // 定, #179
+    0x5B9D, // 宝, #188
+    0x5B9E, // 实, #154
+    0x5BA2, // 客, #174
+    0x5BB6, // 家, #26
+    0x5BB9, // 容, #307
+    0x5BC6, // 密, #471
+    0x5BF9, // 对, #90
+    0x5BFC, // 导, #348
+    0x5C06, // 将, #265
+    0x5C0F, // 小, #28
+    0x5C11, // 少, #379
+    0x5C14, // 尔, #490
+    0x5C31, // 就, #101
+    0x5C55, // 展, #291
+    0x5C71, // 山, #239
+    0x5DDE, // 州, #227
+    0x5DE5, // 工, #73
+    0x5DF1, // 己, #480
+    0x5DF2, // 已, #310
+    0x5E02, // 市, #78
+    0x5E03, // 布, #350
+    0x5E08, // 师, #277
+    0x5E16, // 帖, #396
+    0x5E26, // 带, #449
+    0x5E2E, // 帮, #461
+    0x5E38, // 常, #319
+    0x5E73, // 平, #217
+    0x5E74, // 年, #20
+    0x5E76, // 并, #440
+    0x5E7F, // 广, #166
+    0x5E93, // 库, #446
+    0x5E94, // 应, #187
+    0x5E97, // 店, #320
+    0x5EA6, // 度, #114
+    0x5EB7, // 康, #499
+    0x5EFA, // 建, #211
+    0x5F00, // 开, #72
+    0x5F0F, // 式, #207
+    0x5F15, // 引, #495
+    0x5F20, // 张, #385
+    0x5F3A, // 强, #404
+    0x5F53, // 当, #233
+    0x5F55, // 录, #146
+    0x5F62, // 形, #494
+    0x5F69, // 彩, #356
+    0x5F71, // 影, #214
+    0x5F88, // 很, #300
+    0x5F97, // 得, #193
+    0x5FAE, // 微, #245
+    0x5FC3, // 心, #70
+    0x5FEB, // 快, #324
+    0x6001, // 态, #508
+    0x600E, // 怎, #370
+    0x6027, // 性, #99
+    0x603B, // 总, #398
+    0x606F, // 息, #176
+    0x60A8, // 您, #251
+    0x60C5, // 情, #87
+    0x60F3, // 想, #290
+    0x610F, // 意, #184
+    0x611F, // 感, #253
+    0x620F, // 戏, #237
+    0x6210, // 成, #71
+    0x6211, // 我, #11
+    0x6216, // 或, #321
+    0x6218, // 战, #369
+    0x6237, // 户, #215
+    0x623F, // 房, #236
+    0x6240, // 所, #147
+    0x624B, // 手, #55
+    0x624D, // 才, #407
+    0x6253, // 打, #281
+    0x6280, // 技, #203
+    0x6295, // 投, #408
+    0x62A4, // 护, #502
+    0x62A5, // 报, #113
+    0x62DB, // 招, #363
+    0x6301, // 持, #403
+    0x6307, // 指, #414
+    0x636E, // 据, #409
+    0x6392, // 排, #377
+    0x63A5, // 接, #266
+    0x63A8, // 推, #244
+    0x63D0, // 提, #181
+    0x641C, // 搜, #301
+    0x64AD, // 播, #401
+    0x652F, // 支, #400
+    0x6536, // 收, #158
+    0x653E, // 放, #317
+    0x653F, // 政, #380
+    0x6548, // 效, #496
+    0x6559, // 教, #170
+    0x6570, // 数, #136
+    0x6587, // 文, #21
+    0x6599, // 料, #295
+    0x65AF, // 斯, #473
+    0x65B0, // 新, #14
+    0x65B9, // 方, #68
+    0x65C5, // 旅, #457
+    0x65E0, // 无, #164
+    0x65E5, // 日, #50
+    0x65F6, // 时, #18
+    0x660E, // 明, #132
+    0x6613, // 易, #428
+    0x661F, // 星, #240
+    0x662F, // 是, #6
+    0x663E, // 显, #486
+    0x66F4, // 更, #103
+    0x6700, // 最, #61
+    0x6708, // 月, #80
+    0x6709, // 有, #5
+    0x670D, // 服, #94
+    0x671F, // 期, #139
+    0x672C, // 本, #56
+    0x672F, // 术, #216
+    0x673A, // 机, #27
+    0x6743, // 权, #250
+    0x6761, // 条, #309
+    0x6765, // 来, #42
+    0x677F, // 板, #505
+    0x6797, // 林, #475
+    0x679C, // 果, #212
+    0x67E5, // 查, #165
+    0x6807, // 标, #269
+    0x6821, // 校, #462
+    0x6837, // 样, #314
+    0x683C, // 格, #238
+    0x6848, // 案, #378
+    0x697C, // 楼, #342
+    0x6A21, // 模, #413
+    0x6B21, // 次, #263
+    0x6B22, // 欢, #443
+    0x6B3E, // 款, #358
+    0x6B63, // 正, #219
+    0x6B64, // 此, #362
+    0x6BD4, // 比, #298
+    0x6C11, // 民, #279
+    0x6C14, // 气, #303
+    0x6C34, // 水, #163
+    0x6C42, // 求, #373
+    0x6C5F, // 江, #336
+    0x6CA1, // 没, #229
+    0x6CBB, // 治, #425
+    0x6CD5, // 法, #85
+    0x6CE8, // 注, #119
+    0x6D3B, // 活, #231
+    0x6D41, // 流, #280
+    0x6D4B, // 测, #460
+    0x6D77, // 海, #124
+    0x6D88, // 消, #415
+    0x6DF1, // 深, #477
+    0x6E05, // 清, #311
+    0x6E38, // 游, #81
+    0x6E90, // 源, #325
+    0x706B, // 火, #498
+    0x70B9, // 点, #58
+    0x70ED, // 热, #183
+    0x7136, // 然, #308
+    0x7167, // 照, #431
+    0x7231, // 爱, #223
+    0x7247, // 片, #128
+    0x7248, // 版, #91
+    0x724C, // 牌, #429
+    0x7269, // 物, #169
+    0x7279, // 特, #224
+    0x738B, // 王, #351
+    0x73A9, // 玩, #476
+    0x73B0, // 现, #125
+    0x7403, // 球, #367
+    0x7406, // 理, #69
+    0x751F, // 生, #24
+    0x7528, // 用, #17
+    0x7531, // 由, #441
+    0x7535, // 电, #34
+    0x7537, // 男, #275
+    0x754C, // 界, #419
+    0x75C5, // 病, #371
+    0x767B, // 登, #204
+    0x767D, // 白, #338
+    0x767E, // 百, #157
+    0x7684, // 的, #1
+    0x76D8, // 盘, #493
+    0x76EE, // 目, #261
+    0x76F4, // 直, #391
+    0x76F8, // 相, #143
+    0x7701, // 省, #464
+    0x770B, // 看, #54
+    0x771F, // 真, #249
+    0x7740, // 着, #302
+    0x77E5, // 知, #142
+    0x7801, // 码, #257
+    0x7814, // 研, #387
+    0x793A, // 示, #334
+    0x793E, // 社, #343
+    0x795E, // 神, #330
+    0x798F, // 福, #509
+    0x79BB, // 离, #454
+    0x79CD, // 种, #278
+    0x79D1, // 科, #126
+    0x79EF, // 积, #390
+    0x7A0B, // 程, #209
+    0x7A76, // 究, #504
+    0x7A7A, // 空, #312
+    0x7ACB, // 立, #393
+    0x7AD9, // 站, #107
+    0x7AE0, // 章, #304
+    0x7B2C, // 第, #96
+    0x7B49, // 等, #210
+    0x7B54, // 答, #256
+    0x7B80, // 简, #474
+    0x7BA1, // 管, #221
+    0x7C7B, // 类, #246
+    0x7CBE, // 精, #226
+    0x7CFB, // 系, #89
+    0x7D22, // 索, #354
+    0x7EA2, // 红, #417
+    0x7EA7, // 级, #178
+    0x7EBF, // 线, #108
+    0x7EC4, // 组, #389
+    0x7EC6, // 细, #442
+    0x7ECF, // 经, #74
+    0x7ED3, // 结, #333
+    0x7ED9, // 给, #384
+    0x7EDC, // 络, #472
+    0x7EDF, // 统, #344
+    0x7F16, // 编, #424
+    0x7F51, // 网, #9
+    0x7F6E, // 置, #411
+    0x7F8E, // 美, #60
+    0x8001, // 老, #292
+    0x8003, // 考, #288
+    0x8005, // 者, #106
+    0x800C, // 而, #297
+    0x8054, // 联, #159
+    0x80B2, // 育, #327
+    0x80FD, // 能, #59
+    0x81EA, // 自, #77
+    0x8272, // 色, #198
+    0x8282, // 节, #361
+    0x82B1, // 花, #299
+    0x82F1, // 英, #316
+    0x8350, // 荐, #402
+    0x836F, // 药, #481
+    0x8425, // 营, #394
+    0x85CF, // 藏, #337
+    0x884C, // 行, #41
+    0x8868, // 表, #104
+    0x88AB, // 被, #289
+    0x88C5, // 装, #161
+    0x897F, // 西, #199
+    0x8981, // 要, #48
+    0x89C1, // 见, #360
+    0x89C2, // 观, #423
+    0x89C4, // 规, #453
+    0x89C6, // 视, #120
+    0x89E3, // 解, #264
+    0x8A00, // 言, #433
+    0x8BA1, // 计, #191
+    0x8BA4, // 认, #482
+    0x8BA9, // 让, #421
+    0x8BAE, // 议, #427
+    0x8BAF, // 讯, #388
+    0x8BB0, // 记, #273
+    0x8BBA, // 论, #66
+    0x8BBE, // 设, #162
+    0x8BC1, // 证, #201
+    0x8BC4, // 评, #111
+    0x8BC6, // 识, #463
+    0x8BD5, // 试, #323
+    0x8BDD, // 话, #247
+    0x8BE2, // 询, #432
+    0x8BE5, // 该, #447
+    0x8BE6, // 详, #497
+    0x8BED, // 语, #268
+    0x8BF4, // 说, #112
+    0x8BF7, // 请, #213
+    0x8BFB, // 读, #341
+    0x8C03, // 调, #438
+    0x8D22, // 财, #488
+    0x8D28, // 质, #386
+    0x8D2D, // 购, #260
+    0x8D34, // 贴, #510
+    0x8D39, // 费, #242
+    0x8D44, // 资, #116
+    0x8D77, // 起, #220
+    0x8D85, // 超, #406
+    0x8DEF, // 路, #235
+    0x8EAB, // 身, #262
+    0x8F66, // 车, #82
+    0x8F6C, // 转, #322
+    0x8F7D, // 载, #175
+    0x8FBE, // 达, #435
+    0x8FC7, // 过, #118
+    0x8FD0, // 运, #357
+    0x8FD1, // 近, #492
+    0x8FD8, // 还, #171
+    0x8FD9, // 这, #57
+    0x8FDB, // 进, #160
+    0x8FDE, // 连, #489
+    0x9009, // 选, #328
+    0x901A, // 通, #137
+    0x901F, // 速, #458
+    0x9020, // 造, #511
+    0x9053, // 道, #79
+    0x90A3, // 那, #305
+    0x90E8, // 部, #102
+    0x90FD, // 都, #167
+    0x914D, // 配, #479
+    0x9152, // 酒, #444
+    0x91CC, // 里, #196
+    0x91CD, // 重, #230
+    0x91CF, // 量, #248
+    0x91D1, // 金, #134
+    0x9500, // 销, #465
+    0x957F, // 长, #152
+    0x95E8, // 门, #185
+    0x95EE, // 问, #92
+    0x95F4, // 间, #88
+    0x95FB, // 闻, #313
+    0x9605, // 阅, #467
+    0x9633, // 阳, #420
+    0x9645, // 际, #501
+    0x9650, // 限, #286
+    0x9662, // 院, #276
+    0x96C6, // 集, #284
+    0x9700, // 需, #405
+    0x9762, // 面, #123
+    0x97F3, // 音, #335
+    0x9875, // 页, #63
+    0x9879, // 项, #506
+    0x9891, // 频, #200
+    0x9898, // 题, #110
+    0x98CE, // 风, #252
+    0x98DF, // 食, #445
+    0x9996, // 首, #149
+    0x9999, // 香, #512
+    0x9A6C, // 马, #392
+    0x9A8C, // 验, #382
+    0x9AD8, // 高, #67
+    0x9F99, // 龙, #426
+};
+// the percentage of the sample covered by the above characters
+static const float frequent_zhCN_coverage=0.718950369339973;
+
+// The 512 most frequently occuring characters for the zhTW language in a sample of the Internet.
+// Ordered by codepoint, comment shows character and ranking by frequency
+const uint16_t frequent_zhTW[] = {
+    0x4E00, // 一, #2
+    0x4E09, // 三, #131
+    0x4E0A, // 上, #12
+    0x4E0B, // 下, #37
+    0x4E0D, // 不, #6
+    0x4E16, // 世, #312
+    0x4E26, // 並, #434
+    0x4E2D, // 中, #9
+    0x4E3B, // 主, #97
+    0x4E4B, // 之, #55
+    0x4E5F, // 也, #95
+    0x4E86, // 了, #19
+    0x4E8B, // 事, #128
+    0x4E8C, // 二, #187
+    0x4E94, // 五, #339
+    0x4E9B, // 些, #435
+    0x4E9E, // 亞, #432
+    0x4EA4, // 交, #264
+    0x4EAB, // 享, #160
+    0x4EBA, // 人, #3
+    0x4EC0, // 什, #483
+    0x4ECA, // 今, #380
+    0x4ECB, // 介, #468
+    0x4ED6, // 他, #65
+    0x4EE3, // 代, #284
+    0x4EE5, // 以, #26
+    0x4EF6, // 件, #234
+    0x4EFB, // 任, #381
+    0x4EFD, // 份, #447
+    0x4F46, // 但, #281
+    0x4F4D, // 位, #202
+    0x4F4F, // 住, #471
+    0x4F55, // 何, #334
+    0x4F5C, // 作, #56
+    0x4F60, // 你, #64
+    0x4F7F, // 使, #236
+    0x4F86, // 來, #38
+    0x4F9B, // 供, #397
+    0x4FBF, // 便, #440
+    0x4FC2, // 係, #506
+    0x4FDD, // 保, #161
+    0x4FE1, // 信, #268
+    0x4FEE, // 修, #473
+    0x500B, // 個, #27
+    0x5011, // 們, #109
+    0x505A, // 做, #383
+    0x5065, // 健, #415
+    0x5099, // 備, #461
+    0x50B3, // 傳, #277
+    0x50CF, // 像, #403
+    0x50F9, // 價, #93
+    0x512A, // 優, #396
+    0x5143, // 元, #158
+    0x5148, // 先, #382
+    0x5149, // 光, #216
+    0x514D, // 免, #321
+    0x5152, // 兒, #374
+    0x5165, // 入, #58
+    0x5167, // 內, #106
+    0x5168, // 全, #67
+    0x5169, // 兩, #322
+    0x516C, // 公, #53
+    0x516D, // 六, #493
+    0x5171, // 共, #456
+    0x5176, // 其, #148
+    0x5177, // 具, #328
+    0x518A, // 冊, #360
+    0x518D, // 再, #311
+    0x51FA, // 出, #44
+    0x5206, // 分, #15
+    0x5217, // 列, #259
+    0x5225, // 別, #361
+    0x5229, // 利, #251
+    0x5230, // 到, #29
+    0x5247, // 則, #511
+    0x524D, // 前, #82
+    0x5275, // 創, #409
+    0x529B, // 力, #176
+    0x529F, // 功, #430
+    0x52A0, // 加, #87
+    0x52A9, // 助, #465
+    0x52D5, // 動, #48
+    0x52D9, // 務, #102
+    0x5305, // 包, #248
+    0x5316, // 化, #223
+    0x5317, // 北, #145
+    0x5340, // 區, #60
+    0x5341, // 十, #242
+    0x5357, // 南, #261
+    0x535A, // 博, #484
+    0x5361, // 卡, #327
+    0x5370, // 印, #498
+    0x5373, // 即, #351
+    0x539F, // 原, #237
+    0x53BB, // 去, #190
+    0x53C3, // 參, #444
+    0x53C8, // 又, #426
+    0x53CA, // 及, #136
+    0x53CB, // 友, #142
+    0x53D6, // 取, #422
+    0x53D7, // 受, #410
+    0x53E3, // 口, #357
+    0x53EA, // 只, #250
+    0x53EF, // 可, #35
+    0x53F0, // 台, #34
+    0x53F8, // 司, #226
+    0x5403, // 吃, #362
+    0x5404, // 各, #454
+    0x5408, // 合, #147
+    0x540C, // 同, #173
+    0x540D, // 名, #108
+    0x544A, // 告, #186
+    0x548C, // 和, #130
+    0x54C1, // 品, #23
+    0x54E1, // 員, #150
+    0x5546, // 商, #75
+    0x554F, // 問, #120
+    0x559C, // 喜, #502
+    0x55AE, // 單, #210
+    0x55CE, // 嗎, #443
+    0x5668, // 器, #305
+    0x56DB, // 四, #318
+    0x56DE, // 回, #59
+    0x56E0, // 因, #253
+    0x570B, // 國, #21
+    0x5712, // 園, #345
+    0x5716, // 圖, #73
+    0x5718, // 團, #338
+    0x5728, // 在, #11
+    0x5730, // 地, #50
+    0x578B, // 型, #270
+    0x57CE, // 城, #466
+    0x57FA, // 基, #349
+    0x5831, // 報, #127
+    0x5834, // 場, #165
+    0x58EB, // 士, #372
+    0x5916, // 外, #152
+    0x591A, // 多, #54
+    0x5927, // 大, #8
+    0x5929, // 天, #43
+    0x592A, // 太, #343
+    0x5947, // 奇, #325
+    0x5973, // 女, #85
+    0x5979, // 她, #420
+    0x597D, // 好, #22
+    0x5982, // 如, #144
+    0x5B50, // 子, #46
+    0x5B57, // 字, #275
+    0x5B78, // 學, #49
+    0x5B89, // 安, #239
+    0x5B8C, // 完, #320
+    0x5B9A, // 定, #159
+    0x5BA2, // 客, #188
+    0x5BB6, // 家, #31
+    0x5BB9, // 容, #244
+    0x5BE6, // 實, #198
+    0x5BF6, // 寶, #367
+    0x5C07, // 將, #232
+    0x5C08, // 專, #133
+    0x5C0B, // 尋, #352
+    0x5C0D, // 對, #126
+    0x5C0E, // 導, #418
+    0x5C0F, // 小, #20
+    0x5C11, // 少, #368
+    0x5C31, // 就, #63
+    0x5C55, // 展, #341
+    0x5C71, // 山, #273
+    0x5DE5, // 工, #121
+    0x5DF1, // 己, #402
+    0x5DF2, // 已, #299
+    0x5E02, // 市, #81
+    0x5E2B, // 師, #262
+    0x5E36, // 帶, #470
+    0x5E38, // 常, #303
+    0x5E73, // 平, #297
+    0x5E74, // 年, #30
+    0x5E97, // 店, #171
+    0x5EA6, // 度, #220
+    0x5EB7, // 康, #441
+    0x5EE3, // 廣, #279
+    0x5EFA, // 建, #254
+    0x5F0F, // 式, #155
+    0x5F15, // 引, #346
+    0x5F35, // 張, #366
+    0x5F37, // 強, #437
+    0x5F71, // 影, #94
+    0x5F88, // 很, #177
+    0x5F8C, // 後, #66
+    0x5F97, // 得, #113
+    0x5F9E, // 從, #436
+    0x5FC3, // 心, #57
+    0x5FEB, // 快, #292
+    0x6027, // 性, #175
+    0x606F, // 息, #378
+    0x60A8, // 您, #252
+    0x60C5, // 情, #123
+    0x60F3, // 想, #178
+    0x610F, // 意, #168
+    0x611B, // 愛, #125
+    0x611F, // 感, #211
+    0x61C9, // 應, #164
+    0x6210, // 成, #86
+    0x6211, // 我, #7
+    0x6216, // 或, #199
+    0x6230, // 戰, #438
+    0x6232, // 戲, #309
+    0x6236, // 戶, #497
+    0x623F, // 房, #274
+    0x6240, // 所, #79
+    0x624B, // 手, #68
+    0x624D, // 才, #400
+    0x6253, // 打, #278
+    0x627E, // 找, #449
+    0x6280, // 技, #332
+    0x6295, // 投, #425
+    0x62C9, // 拉, #500
+    0x62CD, // 拍, #398
+    0x6307, // 指, #407
+    0x6392, // 排, #458
+    0x63A5, // 接, #326
+    0x63A8, // 推, #153
+    0x63D0, // 提, #235
+    0x641C, // 搜, #314
+    0x6469, // 摩, #472
+    0x6536, // 收, #249
+    0x6539, // 改, #508
+    0x653E, // 放, #331
+    0x653F, // 政, #295
+    0x6559, // 教, #184
+    0x6574, // 整, #394
+    0x6578, // 數, #134
+    0x6587, // 文, #16
+    0x6599, // 料, #167
+    0x65AF, // 斯, #476
+    0x65B0, // 新, #10
+    0x65B9, // 方, #96
+    0x65BC, // 於, #70
+    0x65C5, // 旅, #289
+    0x65E5, // 日, #18
+    0x660E, // 明, #118
+    0x6613, // 易, #482
+    0x661F, // 星, #205
+    0x662F, // 是, #5
+    0x6642, // 時, #13
+    0x66F4, // 更, #149
+    0x66F8, // 書, #209
+    0x6700, // 最, #51
+    0x6703, // 會, #14
+    0x6708, // 月, #25
+    0x6709, // 有, #4
+    0x670D, // 服, #99
+    0x671F, // 期, #139
+    0x672A, // 未, #404
+    0x672C, // 本, #45
+    0x6771, // 東, #221
+    0x677F, // 板, #364
+    0x6797, // 林, #330
+    0x679C, // 果, #179
+    0x67E5, // 查, #283
+    0x683C, // 格, #157
+    0x6848, // 案, #392
+    0x689D, // 條, #406
+    0x696D, // 業, #103
+    0x6A02, // 樂, #116
+    0x6A13, // 樓, #411
+    0x6A19, // 標, #384
+    0x6A23, // 樣, #306
+    0x6A5F, // 機, #40
+    0x6AA2, // 檢, #359
+    0x6B0A, // 權, #228
+    0x6B21, // 次, #227
+    0x6B3E, // 款, #276
+    0x6B4C, // 歌, #496
+    0x6B61, // 歡, #427
+    0x6B63, // 正, #206
+    0x6B64, // 此, #247
+    0x6BCF, // 每, #391
+    0x6BD4, // 比, #257
+    0x6C11, // 民, #230
+    0x6C23, // 氣, #200
+    0x6C34, // 水, #140
+    0x6C42, // 求, #501
+    0x6C92, // 沒, #162
+    0x6CD5, // 法, #89
+    0x6D3B, // 活, #124
+    0x6D41, // 流, #315
+    0x6D77, // 海, #258
+    0x6D88, // 消, #342
+    0x6E05, // 清, #329
+    0x6E2F, // 港, #293
+    0x6F14, // 演, #491
+    0x7063, // 灣, #195
+    0x70BA, // 為, #39
+    0x7121, // 無, #107
+    0x7136, // 然, #215
+    0x7167, // 照, #376
+    0x71B1, // 熱, #245
+    0x7247, // 片, #90
+    0x7248, // 版, #112
+    0x724C, // 牌, #467
+    0x7269, // 物, #110
+    0x7279, // 特, #183
+    0x738B, // 王, #287
+    0x73A9, // 玩, #354
+    0x73FE, // 現, #143
+    0x7403, // 球, #350
+    0x7406, // 理, #105
+    0x751F, // 生, #24
+    0x7522, // 產, #201
+    0x7528, // 用, #17
+    0x7531, // 由, #288
+    0x7537, // 男, #298
+    0x754C, // 界, #399
+    0x7559, // 留, #218
+    0x756B, // 畫, #412
+    0x7576, // 當, #185
+    0x767B, // 登, #138
+    0x767C, // 發, #28
+    0x767D, // 白, #377
+    0x767E, // 百, #393
+    0x7684, // 的, #1
+    0x76EE, // 目, #271
+    0x76F4, // 直, #379
+    0x76F8, // 相, #98
+    0x770B, // 看, #52
+    0x771F, // 真, #180
+    0x773C, // 眼, #433
+    0x77E5, // 知, #170
+    0x78BC, // 碼, #481
+    0x793A, // 示, #353
+    0x793E, // 社, #333
+    0x795E, // 神, #304
+    0x7968, // 票, #477
+    0x798F, // 福, #494
+    0x79C1, // 私, #507
+    0x79D1, // 科, #280
+    0x7A0B, // 程, #272
+    0x7A2E, // 種, #337
+    0x7A4D, // 積, #385
+    0x7A7A, // 空, #324
+    0x7ACB, // 立, #286
+    0x7AD9, // 站, #117
+    0x7AE0, // 章, #141
+    0x7B2C, // 第, #135
+    0x7B49, // 等, #240
+    0x7BA1, // 管, #340
+    0x7BC0, // 節, #431
+    0x7BC7, // 篇, #479
+    0x7C21, // 簡, #499
+    0x7CBE, // 精, #213
+    0x7CFB, // 系, #212
+    0x7D04, // 約, #462
+    0x7D05, // 紅, #452
+    0x7D1A, // 級, #267
+    0x7D30, // 細, #486
+    0x7D44, // 組, #335
+    0x7D50, // 結, #243
+    0x7D66, // 給, #355
+    0x7D71, // 統, #375
+    0x7D93, // 經, #111
+    0x7DB2, // 網, #32
+    0x7DDA, // 線, #151
+    0x7E23, // 縣, #439
+    0x7E3D, // 總, #370
+    0x7F8E, // 美, #41
+    0x7FA9, // 義, #504
+    0x8001, // 老, #290
+    0x8003, // 考, #428
+    0x8005, // 者, #92
+    0x800C, // 而, #217
+    0x805E, // 聞, #181
+    0x806F, // 聯, #310
+    0x8072, // 聲, #413
+    0x80A1, // 股, #390
+    0x80B2, // 育, #453
+    0x80FD, // 能, #71
+    0x8166, // 腦, #408
+    0x81EA, // 自, #61
+    0x81F3, // 至, #344
+    0x8207, // 與, #84
+    0x8209, // 舉, #463
+    0x8272, // 色, #192
+    0x82B1, // 花, #255
+    0x82F1, // 英, #348
+    0x83EF, // 華, #196
+    0x842C, // 萬, #316
+    0x843D, // 落, #308
+    0x8457, // 著, #233
+    0x85A6, // 薦, #401
+    0x85CF, // 藏, #503
+    0x85DD, // 藝, #488
+    0x8655, // 處, #419
+    0x865F, // 號, #191
+    0x884C, // 行, #47
+    0x8853, // 術, #395
+    0x8868, // 表, #77
+    0x88AB, // 被, #291
+    0x88DD, // 裝, #256
+    0x88E1, // 裡, #369
+    0x88FD, // 製, #510
+    0x897F, // 西, #300
+    0x8981, // 要, #36
+    0x898B, // 見, #307
+    0x8996, // 視, #204
+    0x89BA, // 覺, #450
+    0x89BD, // 覽, #387
+    0x89C0, // 觀, #365
+    0x89E3, // 解, #323
+    0x8A00, // 言, #169
+    0x8A02, // 訂, #423
+    0x8A08, // 計, #225
+    0x8A0A, // 訊, #156
+    0x8A0E, // 討, #373
+    0x8A18, // 記, #222
+    0x8A2D, // 設, #174
+    0x8A3B, // 註, #356
+    0x8A55, // 評, #246
+    0x8A66, // 試, #448
+    0x8A71, // 話, #229
+    0x8A72, // 該, #446
+    0x8A8D, // 認, #464
+    0x8A9E, // 語, #371
+    0x8AAA, // 說, #91
+    0x8ABF, // 調, #509
+    0x8ACB, // 請, #119
+    0x8AD6, // 論, #114
+    0x8B1D, // 謝, #389
+    0x8B49, // 證, #429
+    0x8B58, // 識, #416
+    0x8B70, // 議, #485
+    0x8B77, // 護, #475
+    0x8B80, // 讀, #386
+    0x8B8A, // 變, #388
+    0x8B93, // 讓, #336
+    0x8CA8, // 貨, #313
+    0x8CB7, // 買, #260
+    0x8CBB, // 費, #203
+    0x8CC7, // 資, #62
+    0x8CE3, // 賣, #294
+    0x8CEA, // 質, #457
+    0x8CFC, // 購, #189
+    0x8D77, // 起, #214
+    0x8D85, // 超, #296
+    0x8DDF, // 跟, #489
+    0x8DEF, // 路, #137
+    0x8EAB, // 身, #197
+    0x8ECA, // 車, #76
+    0x8F09, // 載, #301
+    0x8F49, // 轉, #282
+    0x8FD1, // 近, #414
+    0x9001, // 送, #363
+    0x9019, // 這, #42
+    0x901A, // 通, #207
+    0x901F, // 速, #495
+    0x9020, // 造, #455
+    0x9023, // 連, #285
+    0x9032, // 進, #231
+    0x904A, // 遊, #132
+    0x904B, // 運, #219
+    0x904E, // 過, #101
+    0x9053, // 道, #146
+    0x9054, // 達, #417
+    0x9078, // 選, #182
+    0x9084, // 還, #154
+    0x908A, // 邊, #487
+    0x90A3, // 那, #269
+    0x90E8, // 部, #78
+    0x90FD, // 都, #104
+    0x914D, // 配, #421
+    0x9152, // 酒, #512
+    0x91AB, // 醫, #358
+    0x91CD, // 重, #224
+    0x91CF, // 量, #319
+    0x91D1, // 金, #115
+    0x9304, // 錄, #302
+    0x9577, // 長, #172
+    0x9580, // 門, #193
+    0x958B, // 開, #72
+    0x9593, // 間, #80
+    0x95B1, // 閱, #405
+    0x95DC, // 關, #74
+    0x963F, // 阿, #460
+    0x9650, // 限, #265
+    0x9662, // 院, #474
+    0x9664, // 除, #478
+    0x969B, // 際, #459
+    0x96C6, // 集, #347
+    0x96E2, // 離, #442
+    0x96FB, // 電, #33
+    0x9700, // 需, #445
+    0x975E, // 非, #451
+    0x9762, // 面, #129
+    0x97F3, // 音, #194
+    0x9801, // 頁, #83
+    0x982D, // 頭, #238
+    0x984C, // 題, #122
+    0x985E, // 類, #163
+    0x98A8, // 風, #266
+    0x98DF, // 食, #208
+    0x9910, // 餐, #469
+    0x9928, // 館, #424
+    0x9996, // 首, #166
+    0x9999, // 香, #263
+    0x99AC, // 馬, #317
+    0x9A57, // 驗, #492
+    0x9AD4, // 體, #100
+    0x9AD8, // 高, #88
+    0x9EBC, // 麼, #241
+    0x9EC3, // 黃, #480
+    0x9ED1, // 黑, #490
+    0x9EDE, // 點, #69
+    0x9F8D, // 龍, #505
+};
+// the percentage of the sample covered by the above characters
+static const float frequent_zhTW_coverage=0.704841200026877;
+
+// The 512 most frequently occuring characters for the ja language in a sample of the Internet.
+// Ordered by codepoint, comment shows character and ranking by frequency
+const uint16_t frequent_ja[] = {
+    0x3005, // 々, #352
+    0x3041, // ぁ, #486
+    0x3042, // あ, #50
+    0x3044, // い, #2
+    0x3046, // う, #33
+    0x3048, // え, #83
+    0x304A, // お, #37
+    0x304B, // か, #21
+    0x304C, // が, #17
+    0x304D, // き, #51
+    0x304E, // ぎ, #324
+    0x304F, // く, #38
+    0x3050, // ぐ, #334
+    0x3051, // け, #60
+    0x3052, // げ, #296
+    0x3053, // こ, #34
+    0x3054, // ご, #100
+    0x3055, // さ, #31
+    0x3056, // ざ, #378
+    0x3057, // し, #4
+    0x3058, // じ, #121
+    0x3059, // す, #12
+    0x305A, // ず, #215
+    0x305B, // せ, #86
+    0x305D, // そ, #68
+    0x305F, // た, #11
+    0x3060, // だ, #42
+    0x3061, // ち, #67
+    0x3063, // っ, #23
+    0x3064, // つ, #73
+    0x3066, // て, #7
+    0x3067, // で, #6
+    0x3068, // と, #14
+    0x3069, // ど, #75
+    0x306A, // な, #8
+    0x306B, // に, #5
+    0x306D, // ね, #123
+    0x306E, // の, #1
+    0x306F, // は, #16
+    0x3070, // ば, #150
+    0x3071, // ぱ, #259
+    0x3072, // ひ, #364
+    0x3073, // び, #266
+    0x3075, // ふ, #484
+    0x3076, // ぶ, #330
+    0x3078, // へ, #146
+    0x3079, // べ, #207
+    0x307B, // ほ, #254
+    0x307E, // ま, #18
+    0x307F, // み, #74
+    0x3080, // む, #285
+    0x3081, // め, #78
+    0x3082, // も, #32
+    0x3083, // ゃ, #111
+    0x3084, // や, #85
+    0x3086, // ゆ, #392
+    0x3087, // ょ, #224
+    0x3088, // よ, #63
+    0x3089, // ら, #29
+    0x308A, // り, #28
+    0x308B, // る, #9
+    0x308C, // れ, #35
+    0x308D, // ろ, #127
+    0x308F, // わ, #88
+    0x3092, // を, #19
+    0x3093, // ん, #22
+    0x30A1, // ァ, #193
+    0x30A2, // ア, #27
+    0x30A3, // ィ, #70
+    0x30A4, // イ, #15
+    0x30A6, // ウ, #89
+    0x30A7, // ェ, #134
+    0x30A8, // エ, #81
+    0x30A9, // ォ, #225
+    0x30AA, // オ, #76
+    0x30AB, // カ, #52
+    0x30AC, // ガ, #147
+    0x30AD, // キ, #66
+    0x30AE, // ギ, #246
+    0x30AF, // ク, #25
+    0x30B0, // グ, #39
+    0x30B1, // ケ, #137
+    0x30B2, // ゲ, #200
+    0x30B3, // コ, #46
+    0x30B4, // ゴ, #183
+    0x30B5, // サ, #64
+    0x30B6, // ザ, #221
+    0x30B7, // シ, #48
+    0x30B8, // ジ, #55
+    0x30B9, // ス, #13
+    0x30BA, // ズ, #103
+    0x30BB, // セ, #109
+    0x30BC, // ゼ, #499
+    0x30BD, // ソ, #175
+    0x30BF, // タ, #45
+    0x30C0, // ダ, #104
+    0x30C1, // チ, #71
+    0x30C3, // ッ, #20
+    0x30C4, // ツ, #119
+    0x30C6, // テ, #59
+    0x30C7, // デ, #82
+    0x30C8, // ト, #10
+    0x30C9, // ド, #44
+    0x30CA, // ナ, #102
+    0x30CB, // ニ, #72
+    0x30CD, // ネ, #117
+    0x30CE, // ノ, #192
+    0x30CF, // ハ, #164
+    0x30D0, // バ, #62
+    0x30D1, // パ, #90
+    0x30D2, // ヒ, #398
+    0x30D3, // ビ, #77
+    0x30D4, // ピ, #135
+    0x30D5, // フ, #47
+    0x30D6, // ブ, #56
+    0x30D7, // プ, #43
+    0x30D8, // ヘ, #268
+    0x30D9, // ベ, #157
+    0x30DA, // ペ, #125
+    0x30DB, // ホ, #155
+    0x30DC, // ボ, #168
+    0x30DD, // ポ, #114
+    0x30DE, // マ, #57
+    0x30DF, // ミ, #97
+    0x30E0, // ム, #69
+    0x30E1, // メ, #53
+    0x30E2, // モ, #142
+    0x30E3, // ャ, #93
+    0x30E4, // ヤ, #258
+    0x30E5, // ュ, #79
+    0x30E6, // ユ, #405
+    0x30E7, // ョ, #98
+    0x30E9, // ラ, #26
+    0x30EA, // リ, #30
+    0x30EB, // ル, #24
+    0x30EC, // レ, #41
+    0x30ED, // ロ, #40
+    0x30EF, // ワ, #144
+    0x30F3, // ン, #3
+    0x30F4, // ヴ, #483
+    0x30FD, // ヽ, #501
+    0x4E00, // 一, #84
+    0x4E07, // 万, #337
+    0x4E09, // 三, #323
+    0x4E0A, // 上, #133
+    0x4E0B, // 下, #180
+    0x4E0D, // 不, #277
+    0x4E16, // 世, #385
+    0x4E2D, // 中, #87
+    0x4E3B, // 主, #432
+    0x4E88, // 予, #326
+    0x4E8B, // 事, #95
+    0x4E8C, // 二, #394
+    0x4E95, // 井, #468
+    0x4EA4, // 交, #410
+    0x4EAC, // 京, #260
+    0x4EBA, // 人, #61
+    0x4ECA, // 今, #184
+    0x4ECB, // 介, #358
+    0x4ED5, // 仕, #391
+    0x4ED6, // 他, #256
+    0x4ED8, // 付, #243
+    0x4EE3, // 代, #280
+    0x4EE5, // 以, #216
+    0x4EF6, // 件, #190
+    0x4F1A, // 会, #105
+    0x4F4D, // 位, #177
+    0x4F4F, // 住, #376
+    0x4F53, // 体, #223
+    0x4F55, // 何, #294
+    0x4F5C, // 作, #154
+    0x4F7F, // 使, #233
+    0x4F9B, // 供, #503
+    0x4FA1, // 価, #217
+    0x4FBF, // 便, #511
+    0x4FDD, // 保, #279
+    0x4FE1, // 信, #271
+    0x500B, // 個, #415
+    0x50CF, // 像, #178
+    0x512A, // 優, #403
+    0x5143, // 元, #384
+    0x5148, // 先, #311
+    0x5149, // 光, #488
+    0x5165, // 入, #115
+    0x5168, // 全, #173
+    0x516C, // 公, #287
+    0x5177, // 具, #447
+    0x5185, // 内, #169
+    0x5186, // 円, #131
+    0x5199, // 写, #275
+    0x51FA, // 出, #110
+    0x5206, // 分, #130
+    0x5207, // 切, #401
+    0x521D, // 初, #319
+    0x5225, // 別, #290
+    0x5229, // 利, #226
+    0x5236, // 制, #507
+    0x524D, // 前, #124
+    0x529B, // 力, #272
+    0x52A0, // 加, #249
+    0x52D5, // 動, #120
+    0x52D9, // 務, #421
+    0x52DF, // 募, #476
+    0x5316, // 化, #308
+    0x5317, // 北, #341
+    0x533A, // 区, #348
+    0x539F, // 原, #321
+    0x53C2, // 参, #452
+    0x53CB, // 友, #451
+    0x53D6, // 取, #237
+    0x53D7, // 受, #354
+    0x53E3, // 口, #289
+    0x53E4, // 古, #339
+    0x53EF, // 可, #298
+    0x53F0, // 台, #439
+    0x53F7, // 号, #361
+    0x5408, // 合, #118
+    0x540C, // 同, #263
+    0x540D, // 名, #65
+    0x5411, // 向, #434
+    0x544A, // 告, #386
+    0x5468, // 周, #393
+    0x5473, // 味, #299
+    0x548C, // 和, #350
+    0x54C1, // 品, #96
+    0x54E1, // 員, #293
+    0x5546, // 商, #198
+    0x554F, // 問, #158
+    0x55B6, // 営, #438
+    0x5668, // 器, #366
+    0x56DE, // 回, #143
+    0x56F3, // 図, #444
+    0x56FD, // 国, #153
+    0x5712, // 園, #435
+    0x571F, // 土, #239
+    0x5728, // 在, #351
+    0x5730, // 地, #163
+    0x578B, // 型, #430
+    0x5831, // 報, #112
+    0x5834, // 場, #139
+    0x58F2, // 売, #232
+    0x5909, // 変, #306
+    0x5916, // 外, #222
+    0x591A, // 多, #336
+    0x5927, // 大, #80
+    0x5929, // 天, #278
+    0x5973, // 女, #161
+    0x597D, // 好, #349
+    0x5A5A, // 婚, #479
+    0x5B50, // 子, #113
+    0x5B57, // 字, #492
+    0x5B66, // 学, #132
+    0x5B89, // 安, #295
+    0x5B9A, // 定, #145
+    0x5B9F, // 実, #220
+    0x5BA4, // 室, #482
+    0x5BAE, // 宮, #487
+    0x5BB6, // 家, #211
+    0x5BB9, // 容, #333
+    0x5BFE, // 対, #252
+    0x5C02, // 専, #474
+    0x5C0F, // 小, #212
+    0x5C11, // 少, #377
+    0x5C4B, // 屋, #284
+    0x5C71, // 山, #206
+    0x5CA1, // 岡, #429
+    0x5CF6, // 島, #297
+    0x5DDD, // 川, #253
+    0x5DE5, // 工, #374
+    0x5E02, // 市, #159
+    0x5E2F, // 帯, #416
+    0x5E38, // 常, #437
+    0x5E73, // 平, #390
+    0x5E74, // 年, #54
+    0x5E83, // 広, #367
+    0x5E97, // 店, #149
+    0x5EA6, // 度, #269
+    0x5EAB, // 庫, #380
+    0x5F0F, // 式, #265
+    0x5F15, // 引, #345
+    0x5F37, // 強, #446
+    0x5F53, // 当, #240
+    0x5F62, // 形, #502
+    0x5F8C, // 後, #230
+    0x5F97, // 得, #490
+    0x5FC3, // 心, #307
+    0x5FC5, // 必, #422
+    0x5FDC, // 応, #356
+    0x601D, // 思, #189
+    0x6027, // 性, #201
+    0x6075, // 恵, #400
+    0x60C5, // 情, #140
+    0x60F3, // 想, #477
+    0x610F, // 意, #305
+    0x611B, // 愛, #273
+    0x611F, // 感, #257
+    0x6210, // 成, #262
+    0x6226, // 戦, #365
+    0x6240, // 所, #236
+    0x624B, // 手, #160
+    0x6295, // 投, #129
+    0x6301, // 持, #355
+    0x6307, // 指, #425
+    0x63A2, // 探, #369
+    0x63B2, // 掲, #399
+    0x643A, // 携, #459
+    0x652F, // 支, #512
+    0x653E, // 放, #469
+    0x6559, // 教, #270
+    0x6570, // 数, #181
+    0x6587, // 文, #202
+    0x6599, // 料, #106
+    0x65B0, // 新, #99
+    0x65B9, // 方, #126
+    0x65C5, // 旅, #445
+    0x65E5, // 日, #36
+    0x660E, // 明, #300
+    0x6620, // 映, #418
+    0x6642, // 時, #107
+    0x66F4, // 更, #359
+    0x66F8, // 書, #174
+    0x6700, // 最, #152
+    0x6708, // 月, #49
+    0x6709, // 有, #302
+    0x671F, // 期, #332
+    0x6728, // 木, #203
+    0x672C, // 本, #92
+    0x6750, // 材, #489
+    0x6751, // 村, #466
+    0x6765, // 来, #267
+    0x6771, // 東, #191
+    0x677F, // 板, #411
+    0x679C, // 果, #441
+    0x6821, // 校, #327
+    0x682A, // 株, #412
+    0x683C, // 格, #228
+    0x691C, // 検, #179
+    0x696D, // 業, #166
+    0x697D, // 楽, #172
+    0x69D8, // 様, #255
+    0x6A5F, // 機, #235
+    0x6B21, // 次, #318
+    0x6B62, // 止, #475
+    0x6B63, // 正, #312
+    0x6C17, // 気, #116
+    0x6C34, // 水, #165
+    0x6C42, // 求, #465
+    0x6C7A, // 決, #370
+    0x6CBB, // 治, #505
+    0x6CC1, // 況, #462
+    0x6CD5, // 法, #227
+    0x6CE8, // 注, #372
+    0x6D3B, // 活, #303
+    0x6D41, // 流, #480
+    0x6D77, // 海, #274
+    0x6E08, // 済, #417
+    0x6F14, // 演, #504
+    0x706B, // 火, #264
+    0x70B9, // 点, #331
+    0x7121, // 無, #58
+    0x7248, // 版, #409
+    0x7269, // 物, #170
+    0x7279, // 特, #242
+    0x72B6, // 状, #458
+    0x73FE, // 現, #322
+    0x7406, // 理, #162
+    0x751F, // 生, #122
+    0x7523, // 産, #320
+    0x7528, // 用, #94
+    0x7530, // 田, #195
+    0x7537, // 男, #373
+    0x753A, // 町, #314
+    0x753B, // 画, #91
+    0x754C, // 界, #436
+    0x756A, // 番, #261
+    0x75C5, // 病, #428
+    0x767A, // 発, #194
+    0x767B, // 登, #231
+    0x767D, // 白, #419
+    0x7684, // 的, #251
+    0x76EE, // 目, #197
+    0x76F4, // 直, #497
+    0x76F8, // 相, #286
+    0x770C, // 県, #199
+    0x771F, // 真, #219
+    0x7740, // 着, #283
+    0x77E5, // 知, #185
+    0x77F3, // 石, #500
+    0x78BA, // 確, #383
+    0x793A, // 示, #241
+    0x793E, // 社, #167
+    0x795E, // 神, #315
+    0x798F, // 福, #423
+    0x79C1, // 私, #347
+    0x79D1, // 科, #420
+    0x7A0E, // 税, #368
+    0x7A2E, // 種, #455
+    0x7A3F, // 稿, #148
+    0x7A7A, // 空, #427
+    0x7ACB, // 立, #309
+    0x7B11, // 笑, #454
+    0x7B2C, // 第, #317
+    0x7B49, // 等, #457
+    0x7B54, // 答, #426
+    0x7BA1, // 管, #481
+    0x7CFB, // 系, #408
+    0x7D04, // 約, #276
+    0x7D20, // 素, #407
+    0x7D22, // 索, #214
+    0x7D30, // 細, #381
+    0x7D39, // 紹, #471
+    0x7D42, // 終, #456
+    0x7D44, // 組, #424
+    0x7D4C, // 経, #360
+    0x7D50, // 結, #291
+    0x7D9A, // 続, #357
+    0x7DCF, // 総, #467
+    0x7DDA, // 線, #338
+    0x7DE8, // 編, #453
+    0x7F8E, // 美, #204
+    0x8003, // 考, #387
+    0x8005, // 者, #151
+    0x805E, // 聞, #463
+    0x8077, // 職, #363
+    0x80B2, // 育, #433
+    0x80FD, // 能, #250
+    0x8179, // 腹, #396
+    0x81EA, // 自, #156
+    0x826F, // 良, #329
+    0x8272, // 色, #402
+    0x82B1, // 花, #440
+    0x82B8, // 芸, #413
+    0x82F1, // 英, #485
+    0x8449, // 葉, #472
+    0x884C, // 行, #128
+    0x8853, // 術, #460
+    0x8868, // 表, #209
+    0x88FD, // 製, #431
+    0x897F, // 西, #406
+    0x8981, // 要, #313
+    0x898B, // 見, #101
+    0x898F, // 規, #375
+    0x89A7, // 覧, #171
+    0x89E3, // 解, #388
+    0x8A00, // 言, #210
+    0x8A08, // 計, #343
+    0x8A18, // 記, #136
+    0x8A2D, // 設, #292
+    0x8A71, // 話, #213
+    0x8A73, // 詳, #371
+    0x8A8D, // 認, #404
+    0x8A9E, // 語, #234
+    0x8AAC, // 説, #494
+    0x8AAD, // 読, #301
+    0x8ABF, // 調, #443
+    0x8AC7, // 談, #448
+    0x8B77, // 護, #509
+    0x8C37, // 谷, #506
+    0x8CA9, // 販, #362
+    0x8CB7, // 買, #346
+    0x8CC7, // 資, #473
+    0x8CEA, // 質, #281
+    0x8CFC, // 購, #495
+    0x8EAB, // 身, #470
+    0x8ECA, // 車, #205
+    0x8EE2, // 転, #335
+    0x8F09, // 載, #342
+    0x8FBC, // 込, #229
+    0x8FD1, // 近, #304
+    0x8FD4, // 返, #461
+    0x8FFD, // 追, #379
+    0x9001, // 送, #186
+    0x901A, // 通, #182
+    0x901F, // 速, #340
+    0x9023, // 連, #244
+    0x904B, // 運, #382
+    0x904E, // 過, #498
+    0x9053, // 道, #282
+    0x9054, // 達, #450
+    0x9055, // 違, #414
+    0x9078, // 選, #288
+    0x90E8, // 部, #208
+    0x90FD, // 都, #344
+    0x914D, // 配, #389
+    0x91CD, // 重, #478
+    0x91CE, // 野, #245
+    0x91D1, // 金, #138
+    0x9332, // 録, #238
+    0x9577, // 長, #247
+    0x9580, // 門, #508
+    0x958B, // 開, #248
+    0x9593, // 間, #141
+    0x95A2, // 関, #188
+    0x962A, // 阪, #496
+    0x9650, // 限, #395
+    0x9662, // 院, #449
+    0x9664, // 除, #510
+    0x969B, // 際, #493
+    0x96C6, // 集, #196
+    0x96D1, // 雑, #442
+    0x96FB, // 電, #187
+    0x9762, // 面, #328
+    0x97F3, // 音, #325
+    0x984C, // 題, #310
+    0x985E, // 類, #491
+    0x98A8, // 風, #353
+    0x98DF, // 食, #218
+    0x9928, // 館, #464
+    0x99C5, // 駅, #316
+    0x9A13, // 験, #397
+    0x9AD8, // 高, #176
+    0xFF57, // w, #108
+};
+// the percentage of the sample covered by the above characters
+static const float frequent_ja_coverage=0.880569589120162;
+
+// The 512 most frequently occuring characters for the ko language in a sample of the Internet.
+// Ordered by codepoint, comment shows character and ranking by frequency
+const uint16_t frequent_ko[] = {
+    0x314B, // ㅋ, #148
+    0x314E, // ㅎ, #390
+    0x3160, // ㅠ, #354
+    0x318D, // ㆍ, #439
+    0xAC00, // 가, #6
+    0xAC01, // 각, #231
+    0xAC04, // 간, #106
+    0xAC08, // 갈, #362
+    0xAC10, // 감, #122
+    0xAC11, // 갑, #493
+    0xAC15, // 강, #155
+    0xAC19, // 같, #264
+    0xAC1C, // 개, #87
+    0xAC1D, // 객, #198
+    0xAC24, // 갤, #457
+    0xAC70, // 거, #91
+    0xAC74, // 건, #161
+    0xAC78, // 걸, #338
+    0xAC80, // 검, #184
+    0xAC83, // 것, #116
+    0xAC8C, // 게, #36
+    0xACA0, // 겠, #233
+    0xACA8, // 겨, #341
+    0xACA9, // 격, #245
+    0xACAC, // 견, #413
+    0xACB0, // 결, #202
+    0xACBD, // 경, #62
+    0xACC4, // 계, #142
+    0xACE0, // 고, #12
+    0xACE1, // 곡, #444
+    0xACE8, // 골, #379
+    0xACF3, // 곳, #388
+    0xACF5, // 공, #59
+    0xACFC, // 과, #69
+    0xAD00, // 관, #95
+    0xAD11, // 광, #235
+    0xAD50, // 교, #128
+    0xAD6C, // 구, #52
+    0xAD6D, // 국, #85
+    0xAD70, // 군, #293
+    0xAD74, // 굴, #487
+    0xAD81, // 궁, #441
+    0xAD8C, // 권, #192
+    0xADC0, // 귀, #386
+    0xADDC, // 규, #367
+    0xADF8, // 그, #30
+    0xADF9, // 극, #424
+    0xADFC, // 근, #241
+    0xAE00, // 글, #61
+    0xAE08, // 금, #138
+    0xAE09, // 급, #269
+    0xAE30, // 기, #3
+    0xAE34, // 긴, #465
+    0xAE38, // 길, #297
+    0xAE40, // 김, #205
+    0xAE4C, // 까, #171
+    0xAED8, // 께, #273
+    0xAF43, // 꽃, #475
+    0xB05D, // 끝, #505
+    0xB07C, // 끼, #490
+    0xB098, // 나, #39
+    0xB09C, // 난, #274
+    0xB0A0, // 날, #292
+    0xB0A8, // 남, #139
+    0xB0B4, // 내, #56
+    0xB108, // 너, #272
+    0xB110, // 널, #476
+    0xB118, // 넘, #492
+    0xB124, // 네, #100
+    0xB137, // 넷, #329
+    0xB140, // 녀, #288
+    0xB144, // 년, #151
+    0xB178, // 노, #149
+    0xB17C, // 논, #491
+    0xB180, // 놀, #464
+    0xB18D, // 농, #442
+    0xB204, // 누, #319
+    0xB208, // 눈, #383
+    0xB274, // 뉴, #173
+    0xB290, // 느, #368
+    0xB294, // 는, #5
+    0xB298, // 늘, #322
+    0xB2A5, // 능, #190
+    0xB2C8, // 니, #16
+    0xB2D8, // 님, #153
+    0xB2E4, // 다, #2
+    0xB2E8, // 단, #134
+    0xB2EB, // 닫, #195
+    0xB2EC, // 달, #243
+    0xB2F4, // 담, #254
+    0xB2F5, // 답, #287
+    0xB2F9, // 당, #159
+    0xB300, // 대, #33
+    0xB313, // 댓, #303
+    0xB354, // 더, #140
+    0xB358, // 던, #252
+    0xB367, // 덧, #463
+    0xB370, // 데, #104
+    0xB378, // 델, #429
+    0xB3C4, // 도, #25
+    0xB3C5, // 독, #301
+    0xB3CC, // 돌, #309
+    0xB3D9, // 동, #58
+    0xB418, // 되, #82
+    0xB41C, // 된, #189
+    0xB420, // 될, #408
+    0xB429, // 됩, #332
+    0xB450, // 두, #199
+    0xB4A4, // 뒤, #496
+    0xB4DC, // 드, #40
+    0xB4E0, // 든, #283
+    0xB4E4, // 들, #54
+    0xB4EF, // 듯, #478
+    0xB4F1, // 등, #90
+    0xB514, // 디, #133
+    0xB529, // 딩, #462
+    0xB530, // 따, #333
+    0xB54C, // 때, #240
+    0xB610, // 또, #313
+    0xB77C, // 라, #42
+    0xB77D, // 락, #355
+    0xB780, // 란, #290
+    0xB78C, // 람, #246
+    0xB78D, // 랍, #420
+    0xB791, // 랑, #270
+    0xB798, // 래, #174
+    0xB799, // 랙, #381
+    0xB79C, // 랜, #357
+    0xB7A8, // 램, #359
+    0xB7A9, // 랩, #402
+    0xB7C9, // 량, #346
+    0xB7EC, // 러, #130
+    0xB7F0, // 런, #312
+    0xB7FC, // 럼, #327
+    0xB7FD, // 럽, #447
+    0xB807, // 렇, #412
+    0xB808, // 레, #114
+    0xB80C, // 렌, #395
+    0xB824, // 려, #158
+    0xB825, // 력, #194
+    0xB828, // 련, #326
+    0xB839, // 령, #389
+    0xB85C, // 로, #4
+    0xB85D, // 록, #84
+    0xB860, // 론, #366
+    0xB8CC, // 료, #154
+    0xB8E8, // 루, #236
+    0xB958, // 류, #265
+    0xB974, // 르, #212
+    0xB978, // 른, #250
+    0xB97C, // 를, #35
+    0xB984, // 름, #276
+    0xB9AC, // 리, #19
+    0xB9AD, // 릭, #394
+    0xB9B0, // 린, #259
+    0xB9B4, // 릴, #485
+    0xB9BC, // 림, #305
+    0xB9BD, // 립, #217
+    0xB9C1, // 링, #351
+    0xB9C8, // 마, #67
+    0xB9C9, // 막, #310
+    0xB9CC, // 만, #65
+    0xB9CE, // 많, #257
+    0xB9D0, // 말, #188
+    0xB9DB, // 맛, #397
+    0xB9DD, // 망, #370
+    0xB9DE, // 맞, #399
+    0xB9E4, // 매, #125
+    0xB9E8, // 맨, #422
+    0xBA38, // 머, #311
+    0xBA39, // 먹, #377
+    0xBA3C, // 먼, #469
+    0xBA54, // 메, #147
+    0xBA70, // 며, #191
+    0xBA74, // 면, #72
+    0xBA85, // 명, #131
+    0xBAA8, // 모, #73
+    0xBAA9, // 목, #157
+    0xBAB0, // 몰, #401
+    0xBAB8, // 몸, #437
+    0xBABB, // 못, #336
+    0xBB34, // 무, #80
+    0xBB38, // 문, #57
+    0xBB3C, // 물, #94
+    0xBBA4, // 뮤, #431
+    0xBBF8, // 미, #76
+    0xBBFC, // 민, #200
+    0xBC00, // 밀, #308
+    0xBC0F, // 및, #249
+    0xBC14, // 바, #89
+    0xBC15, // 박, #226
+    0xBC18, // 반, #175
+    0xBC1B, // 받, #248
+    0xBC1C, // 발, #164
+    0xBC29, // 방, #92
+    0xBC30, // 배, #162
+    0xBC31, // 백, #256
+    0xBC84, // 버, #111
+    0xBC88, // 번, #167
+    0xBC8C, // 벌, #423
+    0xBC94, // 범, #427
+    0xBC95, // 법, #207
+    0xBCA0, // 베, #281
+    0xBCA4, // 벤, #378
+    0xBCA8, // 벨, #387
+    0xBCC0, // 변, #253
+    0xBCC4, // 별, #262
+    0xBCD1, // 병, #340
+    0xBCF4, // 보, #20
+    0xBCF5, // 복, #204
+    0xBCF8, // 본, #182
+    0xBCFC, // 볼, #385
+    0xBD09, // 봉, #405
+    0xBD80, // 부, #46
+    0xBD81, // 북, #261
+    0xBD84, // 분, #105
+    0xBD88, // 불, #225
+    0xBDF0, // 뷰, #350
+    0xBE0C, // 브, #214
+    0xBE14, // 블, #99
+    0xBE44, // 비, #55
+    0xBE4C, // 빌, #510
+    0xBE60, // 빠, #398
+    0xC0AC, // 사, #14
+    0xC0AD, // 삭, #342
+    0xC0B0, // 산, #121
+    0xC0B4, // 살, #279
+    0xC0BC, // 삼, #348
+    0xC0C1, // 상, #41
+    0xC0C8, // 새, #282
+    0xC0C9, // 색, #181
+    0xC0DD, // 생, #109
+    0xC11C, // 서, #21
+    0xC11D, // 석, #234
+    0xC120, // 선, #107
+    0xC124, // 설, #170
+    0xC131, // 성, #50
+    0xC138, // 세, #60
+    0xC139, // 섹, #456
+    0xC13C, // 센, #267
+    0xC154, // 셔, #455
+    0xC158, // 션, #237
+    0xC15C, // 셜, #448
+    0xC168, // 셨, #421
+    0xC18C, // 소, #51
+    0xC18D, // 속, #219
+    0xC190, // 손, #323
+    0xC1A1, // 송, #203
+    0xC1C4, // 쇄, #501
+    0xC1FC, // 쇼, #364
+    0xC218, // 수, #27
+    0xC219, // 숙, #467
+    0xC21C, // 순, #258
+    0xC220, // 술, #302
+    0xC26C, // 쉬, #511
+    0xC288, // 슈, #384
+    0xC2A4, // 스, #11
+    0xC2AC, // 슬, #438
+    0xC2B4, // 슴, #504
+    0xC2B5, // 습, #77
+    0xC2B9, // 승, #299
+    0xC2DC, // 시, #13
+    0xC2DD, // 식, #137
+    0xC2E0, // 신, #47
+    0xC2E4, // 실, #132
+    0xC2EC, // 심, #196
+    0xC2ED, // 십, #482
+    0xC2F6, // 싶, #352
+    0xC2F8, // 싸, #419
+    0xC4F0, // 쓰, #278
+    0xC528, // 씨, #360
+    0xC544, // 아, #23
+    0xC545, // 악, #296
+    0xC548, // 안, #71
+    0xC54A, // 않, #209
+    0xC54C, // 알, #222
+    0xC554, // 암, #460
+    0xC558, // 았, #349
+    0xC559, // 앙, #473
+    0xC55E, // 앞, #434
+    0xC560, // 애, #271
+    0xC561, // 액, #415
+    0xC571, // 앱, #477
+    0xC57C, // 야, #124
+    0xC57D, // 약, #229
+    0xC591, // 양, #177
+    0xC5B4, // 어, #24
+    0xC5B5, // 억, #407
+    0xC5B8, // 언, #294
+    0xC5BC, // 얼, #356
+    0xC5C4, // 엄, #426
+    0xC5C5, // 업, #118
+    0xC5C6, // 없, #178
+    0xC5C8, // 었, #165
+    0xC5D0, // 에, #9
+    0xC5D4, // 엔, #375
+    0xC5D8, // 엘, #506
+    0xC5EC, // 여, #66
+    0xC5ED, // 역, #186
+    0xC5EE, // 엮, #488
+    0xC5F0, // 연, #96
+    0xC5F4, // 열, #266
+    0xC5FC, // 염, #449
+    0xC600, // 였, #374
+    0xC601, // 영, #83
+    0xC608, // 예, #168
+    0xC624, // 오, #75
+    0xC628, // 온, #300
+    0xC62C, // 올, #306
+    0xC640, // 와, #119
+    0xC644, // 완, #361
+    0xC654, // 왔, #489
+    0xC655, // 왕, #418
+    0xC678, // 외, #218
+    0xC694, // 요, #43
+    0xC695, // 욕, #479
+    0xC6A9, // 용, #48
+    0xC6B0, // 우, #64
+    0xC6B1, // 욱, #503
+    0xC6B4, // 운, #108
+    0xC6B8, // 울, #223
+    0xC6C0, // 움, #317
+    0xC6C3, // 웃, #404
+    0xC6CC, // 워, #280
+    0xC6D0, // 원, #45
+    0xC6D4, // 월, #150
+    0xC6E8, // 웨, #446
+    0xC6F9, // 웹, #500
+    0xC704, // 위, #78
+    0xC720, // 유, #81
+    0xC721, // 육, #321
+    0xC724, // 윤, #416
+    0xC73C, // 으, #49
+    0xC740, // 은, #31
+    0xC744, // 을, #17
+    0xC74C, // 음, #112
+    0xC751, // 응, #461
+    0xC758, // 의, #8
+    0xC774, // 이, #1
+    0xC775, // 익, #403
+    0xC778, // 인, #18
+    0xC77C, // 일, #28
+    0xC784, // 임, #160
+    0xC785, // 입, #93
+    0xC788, // 있, #44
+    0xC790, // 자, #22
+    0xC791, // 작, #88
+    0xC798, // 잘, #347
+    0xC7A1, // 잡, #372
+    0xC7A5, // 장, #53
+    0xC7AC, // 재, #120
+    0xC7C1, // 쟁, #483
+    0xC800, // 저, #98
+    0xC801, // 적, #97
+    0xC804, // 전, #34
+    0xC808, // 절, #320
+    0xC810, // 점, #201
+    0xC811, // 접, #331
+    0xC815, // 정, #26
+    0xC81C, // 제, #29
+    0xC838, // 져, #414
+    0xC870, // 조, #86
+    0xC871, // 족, #373
+    0xC874, // 존, #432
+    0xC880, // 좀, #470
+    0xC885, // 종, #208
+    0xC88B, // 좋, #239
+    0xC8E0, // 죠, #451
+    0xC8FC, // 주, #38
+    0xC8FD, // 죽, #471
+    0xC900, // 준, #286
+    0xC904, // 줄, #392
+    0xC911, // 중, #103
+    0xC988, // 즈, #255
+    0xC98C, // 즌, #507
+    0xC990, // 즐, #371
+    0xC99D, // 증, #260
+    0xC9C0, // 지, #10
+    0xC9C1, // 직, #216
+    0xC9C4, // 진, #79
+    0xC9C8, // 질, #238
+    0xC9D1, // 집, #206
+    0xC9DC, // 짜, #411
+    0xC9F8, // 째, #494
+    0xCABD, // 쪽, #435
+    0xCC28, // 차, #146
+    0xCC29, // 착, #443
+    0xCC2C, // 찬, #481
+    0xCC30, // 찰, #440
+    0xCC38, // 참, #343
+    0xCC3D, // 창, #304
+    0xCC3E, // 찾, #335
+    0xCC44, // 채, #284
+    0xCC45, // 책, #298
+    0xCC98, // 처, #242
+    0xCC9C, // 천, #143
+    0xCCA0, // 철, #380
+    0xCCA8, // 첨, #452
+    0xCCAB, // 첫, #484
+    0xCCAD, // 청, #197
+    0xCCB4, // 체, #126
+    0xCCD0, // 쳐, #472
+    0xCD08, // 초, #220
+    0xCD1D, // 총, #406
+    0xCD5C, // 최, #179
+    0xCD94, // 추, #136
+    0xCD95, // 축, #337
+    0xCD9C, // 출, #166
+    0xCDA9, // 충, #369
+    0xCDE8, // 취, #210
+    0xCE20, // 츠, #215
+    0xCE21, // 측, #468
+    0xCE35, // 층, #512
+    0xCE58, // 치, #102
+    0xCE5C, // 친, #325
+    0xCE68, // 침, #263
+    0xCE74, // 카, #115
+    0xCE7C, // 칼, #466
+    0xCE90, // 캐, #454
+    0xCEE4, // 커, #285
+    0xCEE8, // 컨, #328
+    0xCEF4, // 컴, #417
+    0xCF00, // 케, #339
+    0xCF13, // 켓, #509
+    0xCF1C, // 켜, #508
+    0xCF54, // 코, #193
+    0xCF58, // 콘, #391
+    0xCFE0, // 쿠, #393
+    0xD035, // 퀵, #453
+    0xD06C, // 크, #101
+    0xD070, // 큰, #495
+    0xD074, // 클, #289
+    0xD0A4, // 키, #230
+    0xD0C0, // 타, #127
+    0xD0C1, // 탁, #314
+    0xD0C4, // 탄, #450
+    0xD0C8, // 탈, #436
+    0xD0DC, // 태, #221
+    0xD0DD, // 택, #275
+    0xD130, // 터, #70
+    0xD14C, // 테, #213
+    0xD150, // 텐, #324
+    0xD154, // 텔, #430
+    0xD15C, // 템, #382
+    0xD1A0, // 토, #145
+    0xD1B5, // 통, #156
+    0xD22C, // 투, #227
+    0xD2B8, // 트, #37
+    0xD2B9, // 특, #247
+    0xD2F0, // 티, #187
+    0xD305, // 팅, #410
+    0xD30C, // 파, #141
+    0xD310, // 판, #163
+    0xD314, // 팔, #499
+    0xD328, // 패, #307
+    0xD32C, // 팬, #459
+    0xD338, // 팸, #433
+    0xD37C, // 퍼, #344
+    0xD398, // 페, #172
+    0xD3B8, // 편, #251
+    0xD3C9, // 평, #291
+    0xD3EC, // 포, #68
+    0xD3ED, // 폭, #445
+    0xD3F0, // 폰, #318
+    0xD45C, // 표, #232
+    0xD480, // 풀, #497
+    0xD488, // 품, #113
+    0xD48D, // 풍, #425
+    0xD504, // 프, #110
+    0xD508, // 픈, #498
+    0xD50C, // 플, #211
+    0xD53C, // 피, #169
+    0xD544, // 필, #295
+    0xD551, // 핑, #376
+    0xD558, // 하, #7
+    0xD559, // 학, #129
+    0xD55C, // 한, #15
+    0xD560, // 할, #144
+    0xD568, // 함, #152
+    0xD569, // 합, #123
+    0xD56D, // 항, #268
+    0xD574, // 해, #32
+    0xD588, // 했, #180
+    0xD589, // 행, #135
+    0xD5A5, // 향, #345
+    0xD5C8, // 허, #396
+    0xD5D8, // 험, #316
+    0xD5E4, // 헤, #474
+    0xD604, // 현, #185
+    0xD611, // 협, #315
+    0xD615, // 형, #244
+    0xD61C, // 혜, #428
+    0xD638, // 호, #117
+    0xD63C, // 혼, #358
+    0xD648, // 홈, #330
+    0xD64D, // 홍, #363
+    0xD654, // 화, #63
+    0xD655, // 확, #183
+    0xD658, // 환, #224
+    0xD65C, // 활, #277
+    0xD669, // 황, #353
+    0xD68C, // 회, #74
+    0xD68D, // 획, #458
+    0xD69F, // 횟, #409
+    0xD6A8, // 효, #400
+    0xD6C4, // 후, #176
+    0xD6C8, // 훈, #486
+    0xD734, // 휴, #365
+    0xD754, // 흔, #480
+    0xD76C, // 희, #334
+    0xD788, // 히, #228
+    0xD798, // 힘, #502
+};
+// the percentage of the sample covered by the above characters
+static const float frequent_ko_coverage=0.948157021464184;
+
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 86ff8bd..762681e 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -58,7 +58,7 @@
     RESTORE_OUTPUT,
     OPEN_INPUT,
     CLOSE_INPUT,
-    SET_STREAM_OUTPUT,
+    INVALIDATE_STREAM,
     SET_VOICE_VOLUME,
     GET_RENDER_POSITION,
     GET_INPUT_FRAMES_LOST,
@@ -89,13 +89,12 @@
                                 uint32_t sampleRate,
                                 audio_format_t format,
                                 audio_channel_mask_t channelMask,
-                                size_t frameCount,
+                                size_t *pFrameCount,
                                 track_flags_t *flags,
                                 const sp<IMemory>& sharedBuffer,
                                 audio_io_handle_t output,
                                 pid_t tid,
                                 int *sessionId,
-                                String8& name,
                                 int clientUid,
                                 status_t *status)
     {
@@ -106,6 +105,7 @@
         data.writeInt32(sampleRate);
         data.writeInt32(format);
         data.writeInt32(channelMask);
+        size_t frameCount = pFrameCount != NULL ? *pFrameCount : 0;
         data.writeInt32(frameCount);
         track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT;
         data.writeInt32(lFlags);
@@ -117,7 +117,7 @@
         }
         data.writeInt32((int32_t) output);
         data.writeInt32((int32_t) tid);
-        int lSessionId = 0;
+        int lSessionId = AUDIO_SESSION_ALLOCATE;
         if (sessionId != NULL) {
             lSessionId = *sessionId;
         }
@@ -127,6 +127,10 @@
         if (lStatus != NO_ERROR) {
             ALOGE("createTrack error: %s", strerror(-lStatus));
         } else {
+            frameCount = reply.readInt32();
+            if (pFrameCount != NULL) {
+                *pFrameCount = frameCount;
+            }
             lFlags = reply.readInt32();
             if (flags != NULL) {
                 *flags = lFlags;
@@ -135,11 +139,21 @@
             if (sessionId != NULL) {
                 *sessionId = lSessionId;
             }
-            name = reply.readString8();
             lStatus = reply.readInt32();
             track = interface_cast<IAudioTrack>(reply.readStrongBinder());
+            if (lStatus == NO_ERROR) {
+                if (track == 0) {
+                    ALOGE("createTrack should have returned an IAudioTrack");
+                    lStatus = UNKNOWN_ERROR;
+                }
+            } else {
+                if (track != 0) {
+                    ALOGE("createTrack returned an IAudioTrack but with status %d", lStatus);
+                    track.clear();
+                }
+            }
         }
-        if (status) {
+        if (status != NULL) {
             *status = lStatus;
         }
         return track;
@@ -150,7 +164,7 @@
                                 uint32_t sampleRate,
                                 audio_format_t format,
                                 audio_channel_mask_t channelMask,
-                                size_t frameCount,
+                                size_t *pFrameCount,
                                 track_flags_t *flags,
                                 pid_t tid,
                                 int *sessionId,
@@ -163,11 +177,12 @@
         data.writeInt32(sampleRate);
         data.writeInt32(format);
         data.writeInt32(channelMask);
+        size_t frameCount = pFrameCount != NULL ? *pFrameCount : 0;
         data.writeInt32(frameCount);
         track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT;
         data.writeInt32(lFlags);
         data.writeInt32((int32_t) tid);
-        int lSessionId = 0;
+        int lSessionId = AUDIO_SESSION_ALLOCATE;
         if (sessionId != NULL) {
             lSessionId = *sessionId;
         }
@@ -176,6 +191,10 @@
         if (lStatus != NO_ERROR) {
             ALOGE("openRecord error: %s", strerror(-lStatus));
         } else {
+            frameCount = reply.readInt32();
+            if (pFrameCount != NULL) {
+                *pFrameCount = frameCount;
+            }
             lFlags = reply.readInt32();
             if (flags != NULL) {
                 *flags = lFlags;
@@ -198,7 +217,7 @@
                 }
             }
         }
-        if (status) {
+        if (status != NULL) {
             *status = lStatus;
         }
         return record;
@@ -415,15 +434,25 @@
         audio_io_handle_t output = (audio_io_handle_t) reply.readInt32();
         ALOGV("openOutput() returned output, %d", output);
         devices = (audio_devices_t)reply.readInt32();
-        if (pDevices != NULL) *pDevices = devices;
+        if (pDevices != NULL) {
+            *pDevices = devices;
+        }
         samplingRate = reply.readInt32();
-        if (pSamplingRate != NULL) *pSamplingRate = samplingRate;
+        if (pSamplingRate != NULL) {
+            *pSamplingRate = samplingRate;
+        }
         format = (audio_format_t) reply.readInt32();
-        if (pFormat != NULL) *pFormat = format;
+        if (pFormat != NULL) {
+            *pFormat = format;
+        }
         channelMask = (audio_channel_mask_t)reply.readInt32();
-        if (pChannelMask != NULL) *pChannelMask = channelMask;
+        if (pChannelMask != NULL) {
+            *pChannelMask = channelMask;
+        }
         latency = reply.readInt32();
-        if (pLatencyMs != NULL) *pLatencyMs = latency;
+        if (pLatencyMs != NULL) {
+            *pLatencyMs = latency;
+        }
         return output;
     }
 
@@ -487,13 +516,21 @@
         remote()->transact(OPEN_INPUT, data, &reply);
         audio_io_handle_t input = (audio_io_handle_t) reply.readInt32();
         devices = (audio_devices_t)reply.readInt32();
-        if (pDevices != NULL) *pDevices = devices;
+        if (pDevices != NULL) {
+            *pDevices = devices;
+        }
         samplingRate = reply.readInt32();
-        if (pSamplingRate != NULL) *pSamplingRate = samplingRate;
+        if (pSamplingRate != NULL) {
+            *pSamplingRate = samplingRate;
+        }
         format = (audio_format_t) reply.readInt32();
-        if (pFormat != NULL) *pFormat = format;
+        if (pFormat != NULL) {
+            *pFormat = format;
+        }
         channelMask = (audio_channel_mask_t)reply.readInt32();
-        if (pChannelMask != NULL) *pChannelMask = channelMask;
+        if (pChannelMask != NULL) {
+            *pChannelMask = channelMask;
+        }
         return input;
     }
 
@@ -506,13 +543,12 @@
         return reply.readInt32();
     }
 
-    virtual status_t setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output)
+    virtual status_t invalidateStream(audio_stream_type_t stream)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32((int32_t) stream);
-        data.writeInt32((int32_t) output);
-        remote()->transact(SET_STREAM_OUTPUT, data, &reply);
+        remote()->transact(INVALIDATE_STREAM, data, &reply);
         return reply.readInt32();
     }
 
@@ -535,11 +571,11 @@
         status_t status = reply.readInt32();
         if (status == NO_ERROR) {
             uint32_t tmp = reply.readInt32();
-            if (halFrames) {
+            if (halFrames != NULL) {
                 *halFrames = tmp;
             }
             tmp = reply.readInt32();
-            if (dspFrames) {
+            if (dspFrames != NULL) {
                 *dspFrames = tmp;
             }
         }
@@ -551,8 +587,11 @@
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32((int32_t) ioHandle);
-        remote()->transact(GET_INPUT_FRAMES_LOST, data, &reply);
-        return reply.readInt32();
+        status_t status = remote()->transact(GET_INPUT_FRAMES_LOST, data, &reply);
+        if (status != NO_ERROR) {
+            return 0;
+        }
+        return (uint32_t) reply.readInt32();
     }
 
     virtual int newAudioSessionId()
@@ -567,19 +606,21 @@
         return id;
     }
 
-    virtual void acquireAudioSessionId(int audioSession)
+    virtual void acquireAudioSessionId(int audioSession, int pid)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(audioSession);
+        data.writeInt32(pid);
         remote()->transact(ACQUIRE_AUDIO_SESSION_ID, data, &reply);
     }
 
-    virtual void releaseAudioSessionId(int audioSession)
+    virtual void releaseAudioSessionId(int audioSession, int pid)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(audioSession);
+        data.writeInt32(pid);
         remote()->transact(RELEASE_AUDIO_SESSION_ID, data, &reply);
     }
 
@@ -657,7 +698,7 @@
 
         if (pDesc == NULL) {
             return effect;
-            if (status) {
+            if (status != NULL) {
                 *status = BAD_VALUE;
             }
         }
@@ -675,7 +716,7 @@
         } else {
             lStatus = reply.readInt32();
             int tmp = reply.readInt32();
-            if (id) {
+            if (id != NULL) {
                 *id = tmp;
             }
             tmp = reply.readInt32();
@@ -685,7 +726,7 @@
             effect = interface_cast<IEffect>(reply.readStrongBinder());
             reply.read(pDesc, sizeof(effect_descriptor_t));
         }
-        if (status) {
+        if (status != NULL) {
             *status = lStatus;
         }
 
@@ -765,7 +806,6 @@
             pid_t tid = (pid_t) data.readInt32();
             int sessionId = data.readInt32();
             int clientUid = data.readInt32();
-            String8 name;
             status_t status;
             sp<IAudioTrack> track;
             if ((haveSharedBuffer && (buffer == 0)) ||
@@ -775,12 +815,13 @@
             } else {
                 track = createTrack(
                         (audio_stream_type_t) streamType, sampleRate, format,
-                        channelMask, frameCount, &flags, buffer, output, tid,
-                        &sessionId, name, clientUid, &status);
+                        channelMask, &frameCount, &flags, buffer, output, tid,
+                        &sessionId, clientUid, &status);
+                LOG_ALWAYS_FATAL_IF((track != 0) != (status == NO_ERROR));
             }
+            reply->writeInt32(frameCount);
             reply->writeInt32(flags);
             reply->writeInt32(sessionId);
-            reply->writeString8(name);
             reply->writeInt32(status);
             reply->writeStrongBinder(track->asBinder());
             return NO_ERROR;
@@ -797,8 +838,9 @@
             int sessionId = data.readInt32();
             status_t status;
             sp<IAudioRecord> record = openRecord(input,
-                    sampleRate, format, channelMask, frameCount, &flags, tid, &sessionId, &status);
+                    sampleRate, format, channelMask, &frameCount, &flags, tid, &sessionId, &status);
             LOG_ALWAYS_FATAL_IF((record != 0) != (status == NO_ERROR));
+            reply->writeInt32(frameCount);
             reply->writeInt32(flags);
             reply->writeInt32(sessionId);
             reply->writeInt32(status);
@@ -941,7 +983,7 @@
                                                  &latency,
                                                  flags,
                                                  hasOffloadInfo ? &offloadInfo : NULL);
-            ALOGV("OPEN_OUTPUT output, %p", output);
+            ALOGV("OPEN_OUTPUT output, %d", output);
             reply->writeInt32((int32_t) output);
             reply->writeInt32(devices);
             reply->writeInt32(samplingRate);
@@ -997,11 +1039,10 @@
             reply->writeInt32(closeInput((audio_io_handle_t) data.readInt32()));
             return NO_ERROR;
         } break;
-        case SET_STREAM_OUTPUT: {
+        case INVALIDATE_STREAM: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            uint32_t stream = data.readInt32();
-            audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
-            reply->writeInt32(setStreamOutput((audio_stream_type_t) stream, output));
+            audio_stream_type_t stream = (audio_stream_type_t) data.readInt32();
+            reply->writeInt32(invalidateStream(stream));
             return NO_ERROR;
         } break;
         case SET_VOICE_VOLUME: {
@@ -1026,7 +1067,7 @@
         case GET_INPUT_FRAMES_LOST: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             audio_io_handle_t ioHandle = (audio_io_handle_t) data.readInt32();
-            reply->writeInt32(getInputFramesLost(ioHandle));
+            reply->writeInt32((int32_t) getInputFramesLost(ioHandle));
             return NO_ERROR;
         } break;
         case NEW_AUDIO_SESSION_ID: {
@@ -1037,13 +1078,15 @@
         case ACQUIRE_AUDIO_SESSION_ID: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             int audioSession = data.readInt32();
-            acquireAudioSessionId(audioSession);
+            int pid = data.readInt32();
+            acquireAudioSessionId(audioSession, pid);
             return NO_ERROR;
         } break;
         case RELEASE_AUDIO_SESSION_ID: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             int audioSession = data.readInt32();
-            releaseAudioSessionId(audioSession);
+            int pid = data.readInt32();
+            releaseAudioSessionId(audioSession, pid);
             return NO_ERROR;
         } break;
         case QUERY_NUM_EFFECTS: {
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 4be3c09..1a027a6 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -476,10 +476,11 @@
         case START_OUTPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
-            uint32_t stream = data.readInt32();
+            audio_stream_type_t stream =
+                                static_cast <audio_stream_type_t>(data.readInt32());
             int session = data.readInt32();
             reply->writeInt32(static_cast <uint32_t>(startOutput(output,
-                                                                 (audio_stream_type_t)stream,
+                                                                 stream,
                                                                  session)));
             return NO_ERROR;
         } break;
@@ -487,10 +488,11 @@
         case STOP_OUTPUT: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             audio_io_handle_t output = static_cast <audio_io_handle_t>(data.readInt32());
-            uint32_t stream = data.readInt32();
+            audio_stream_type_t stream =
+                                static_cast <audio_stream_type_t>(data.readInt32());
             int session = data.readInt32();
             reply->writeInt32(static_cast <uint32_t>(stopOutput(output,
-                                                                (audio_stream_type_t)stream,
+                                                                stream,
                                                                 session)));
             return NO_ERROR;
         } break;
@@ -633,7 +635,7 @@
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             audio_stream_type_t stream = (audio_stream_type_t) data.readInt32();
             uint32_t inPastMs = (uint32_t)data.readInt32();
-            reply->writeInt32( isStreamActive((audio_stream_type_t) stream, inPastMs) );
+            reply->writeInt32( isStreamActive(stream, inPastMs) );
             return NO_ERROR;
         } break;
 
@@ -641,7 +643,7 @@
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             audio_stream_type_t stream = (audio_stream_type_t) data.readInt32();
             uint32_t inPastMs = (uint32_t)data.readInt32();
-            reply->writeInt32( isStreamActiveRemotely((audio_stream_type_t) stream, inPastMs) );
+            reply->writeInt32( isStreamActiveRemotely(stream, inPastMs) );
             return NO_ERROR;
         } break;
 
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index 4a7de65..9866d70 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -50,6 +50,9 @@
         status_t status = remote()->transact(GET_CBLK, data, &reply);
         if (status == NO_ERROR) {
             cblk = interface_cast<IMemory>(reply.readStrongBinder());
+            if (cblk != 0 && cblk->pointer() == NULL) {
+                cblk.clear();
+            }
         }
         return cblk;
     }
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index 3cd9cfd..ffc21fc 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -60,6 +60,9 @@
         status_t status = remote()->transact(GET_CBLK, data, &reply);
         if (status == NO_ERROR) {
             cblk = interface_cast<IMemory>(reply.readStrongBinder());
+            if (cblk != 0 && cblk->pointer() == NULL) {
+                cblk.clear();
+            }
         }
         return cblk;
     }
@@ -122,6 +125,9 @@
             status = reply.readInt32();
             if (status == NO_ERROR) {
                 *buffer = interface_cast<IMemory>(reply.readStrongBinder());
+                if (*buffer != 0 && (*buffer)->pointer() == NULL) {
+                    (*buffer).clear();
+                }
             }
         }
         return status;
diff --git a/media/libmedia/IEffect.cpp b/media/libmedia/IEffect.cpp
index a303a8f..b94012a 100644
--- a/media/libmedia/IEffect.cpp
+++ b/media/libmedia/IEffect.cpp
@@ -117,6 +117,9 @@
         status_t status = remote()->transact(GET_CBLK, data, &reply);
         if (status == NO_ERROR) {
             cblk = interface_cast<IMemory>(reply.readStrongBinder());
+            if (cblk != 0 && cblk->pointer() == NULL) {
+                cblk.clear();
+            }
         }
         return cblk;
     }
diff --git a/media/libmedia/IMediaDeathNotifier.cpp b/media/libmedia/IMediaDeathNotifier.cpp
index 9db5b1b..10b4934 100644
--- a/media/libmedia/IMediaDeathNotifier.cpp
+++ b/media/libmedia/IMediaDeathNotifier.cpp
@@ -75,7 +75,7 @@
 }
 
 void
-IMediaDeathNotifier::DeathNotifier::binderDied(const wp<IBinder>& who) {
+IMediaDeathNotifier::DeathNotifier::binderDied(const wp<IBinder>& who __unused) {
     ALOGW("media server died");
 
     // Need to do this with the lock held
diff --git a/media/libmedia/IMediaHTTPConnection.cpp b/media/libmedia/IMediaHTTPConnection.cpp
new file mode 100644
index 0000000..7e26ee6
--- /dev/null
+++ b/media/libmedia/IMediaHTTPConnection.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "IMediaHTTPConnection"
+#include <utils/Log.h>
+
+#include <media/IMediaHTTPConnection.h>
+
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+enum {
+    CONNECT = IBinder::FIRST_CALL_TRANSACTION,
+    DISCONNECT,
+    READ_AT,
+    GET_SIZE,
+    GET_MIME_TYPE,
+    GET_URI
+};
+
+struct BpMediaHTTPConnection : public BpInterface<IMediaHTTPConnection> {
+    BpMediaHTTPConnection(const sp<IBinder> &impl)
+        : BpInterface<IMediaHTTPConnection>(impl) {
+    }
+
+    virtual bool connect(
+            const char *uri, const KeyedVector<String8, String8> *headers) {
+        Parcel data, reply;
+        data.writeInterfaceToken(
+                IMediaHTTPConnection::getInterfaceDescriptor());
+
+        String16 tmp(uri);
+        data.writeString16(tmp);
+
+        tmp = String16("");
+        if (headers != NULL) {
+            for (size_t i = 0; i < headers->size(); ++i) {
+                String16 key(headers->keyAt(i).string());
+                String16 val(headers->valueAt(i).string());
+
+                tmp.append(key);
+                tmp.append(String16(": "));
+                tmp.append(val);
+                tmp.append(String16("\r\n"));
+            }
+        }
+        data.writeString16(tmp);
+
+        remote()->transact(CONNECT, data, &reply);
+
+        int32_t exceptionCode = reply.readExceptionCode();
+
+        if (exceptionCode) {
+            return UNKNOWN_ERROR;
+        }
+
+        sp<IBinder> binder = reply.readStrongBinder();
+        mMemory = interface_cast<IMemory>(binder);
+
+        return mMemory != NULL;
+    }
+
+    virtual void disconnect() {
+        Parcel data, reply;
+        data.writeInterfaceToken(
+                IMediaHTTPConnection::getInterfaceDescriptor());
+
+        remote()->transact(DISCONNECT, data, &reply);
+    }
+
+    virtual ssize_t readAt(off64_t offset, void *buffer, size_t size) {
+        Parcel data, reply;
+        data.writeInterfaceToken(
+                IMediaHTTPConnection::getInterfaceDescriptor());
+
+        data.writeInt64(offset);
+        data.writeInt32(size);
+
+        status_t err = remote()->transact(READ_AT, data, &reply);
+        if (err != OK) {
+            ALOGE("remote readAt failed");
+            return UNKNOWN_ERROR;
+        }
+
+        int32_t exceptionCode = reply.readExceptionCode();
+
+        if (exceptionCode) {
+            return UNKNOWN_ERROR;
+        }
+
+        int32_t len = reply.readInt32();
+
+        if (len > 0) {
+            memcpy(buffer, mMemory->pointer(), len);
+        }
+
+        return len;
+    }
+
+    virtual off64_t getSize() {
+        Parcel data, reply;
+        data.writeInterfaceToken(
+                IMediaHTTPConnection::getInterfaceDescriptor());
+
+        remote()->transact(GET_SIZE, data, &reply);
+
+        int32_t exceptionCode = reply.readExceptionCode();
+
+        if (exceptionCode) {
+            return UNKNOWN_ERROR;
+        }
+
+        return reply.readInt64();
+    }
+
+    virtual status_t getMIMEType(String8 *mimeType) {
+        *mimeType = String8("");
+
+        Parcel data, reply;
+        data.writeInterfaceToken(
+                IMediaHTTPConnection::getInterfaceDescriptor());
+
+        remote()->transact(GET_MIME_TYPE, data, &reply);
+
+        int32_t exceptionCode = reply.readExceptionCode();
+
+        if (exceptionCode) {
+            return UNKNOWN_ERROR;
+        }
+
+        *mimeType = String8(reply.readString16());
+
+        return OK;
+    }
+
+    virtual status_t getUri(String8 *uri) {
+        *uri = String8("");
+
+        Parcel data, reply;
+        data.writeInterfaceToken(
+                IMediaHTTPConnection::getInterfaceDescriptor());
+
+        remote()->transact(GET_URI, data, &reply);
+
+        int32_t exceptionCode = reply.readExceptionCode();
+
+        if (exceptionCode) {
+            return UNKNOWN_ERROR;
+        }
+
+        *uri = String8(reply.readString16());
+
+        return OK;
+    }
+
+private:
+    sp<IMemory> mMemory;
+};
+
+IMPLEMENT_META_INTERFACE(
+        MediaHTTPConnection, "android.media.IMediaHTTPConnection");
+
+}  // namespace android
+
diff --git a/media/libmedia/IMediaHTTPService.cpp b/media/libmedia/IMediaHTTPService.cpp
new file mode 100644
index 0000000..1260582
--- /dev/null
+++ b/media/libmedia/IMediaHTTPService.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "IMediaHTTPService"
+#include <utils/Log.h>
+
+#include <media/IMediaHTTPService.h>
+
+#include <binder/Parcel.h>
+#include <media/IMediaHTTPConnection.h>
+
+namespace android {
+
+enum {
+    MAKE_HTTP = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+struct BpMediaHTTPService : public BpInterface<IMediaHTTPService> {
+    BpMediaHTTPService(const sp<IBinder> &impl)
+        : BpInterface<IMediaHTTPService>(impl) {
+    }
+
+    virtual sp<IMediaHTTPConnection> makeHTTPConnection() {
+        Parcel data, reply;
+        data.writeInterfaceToken(
+                IMediaHTTPService::getInterfaceDescriptor());
+
+        remote()->transact(MAKE_HTTP, data, &reply);
+
+        status_t err = reply.readInt32();
+
+        if (err != OK) {
+            return NULL;
+        }
+
+        return interface_cast<IMediaHTTPConnection>(reply.readStrongBinder());
+    }
+};
+
+IMPLEMENT_META_INTERFACE(
+        MediaHTTPService, "android.media.IMediaHTTPService");
+
+}  // namespace android
+
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index bb066a0..c7d9d51 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -18,6 +18,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <binder/Parcel.h>
+#include <media/IMediaHTTPService.h>
 #include <media/IMediaMetadataRetriever.h>
 #include <utils/String8.h>
 #include <utils/KeyedVector.h>
@@ -84,10 +85,16 @@
     }
 
     status_t setDataSource(
-            const char *srcUrl, const KeyedVector<String8, String8> *headers)
+            const sp<IMediaHTTPService> &httpService,
+            const char *srcUrl,
+            const KeyedVector<String8, String8> *headers)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+        data.writeInt32(httpService != NULL);
+        if (httpService != NULL) {
+            data.writeStrongBinder(httpService->asBinder());
+        }
         data.writeCString(srcUrl);
 
         if (headers == NULL) {
@@ -195,6 +202,13 @@
         } break;
         case SET_DATA_SOURCE_URL: {
             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+
+            sp<IMediaHTTPService> httpService;
+            if (data.readInt32()) {
+                httpService =
+                    interface_cast<IMediaHTTPService>(data.readStrongBinder());
+            }
+
             const char* srcUrl = data.readCString();
 
             KeyedVector<String8, String8> headers;
@@ -206,7 +220,8 @@
             }
 
             reply->writeInt32(
-                    setDataSource(srcUrl, numHeaders > 0 ? &headers : NULL));
+                    setDataSource(
+                        httpService, srcUrl, numHeaders > 0 ? &headers : NULL));
 
             return NO_ERROR;
         } break;
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index e79bcd2..d778d05 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -21,6 +21,7 @@
 
 #include <binder/Parcel.h>
 
+#include <media/IMediaHTTPService.h>
 #include <media/IMediaPlayer.h>
 #include <media/IStreamSource.h>
 
@@ -75,11 +76,17 @@
         remote()->transact(DISCONNECT, data, &reply);
     }
 
-    status_t setDataSource(const char* url,
+    status_t setDataSource(
+            const sp<IMediaHTTPService> &httpService,
+            const char* url,
             const KeyedVector<String8, String8>* headers)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        data.writeInt32(httpService != NULL);
+        if (httpService != NULL) {
+            data.writeStrongBinder(httpService->asBinder());
+        }
         data.writeCString(url);
         if (headers == NULL) {
             data.writeInt32(0);
@@ -355,6 +362,13 @@
         } break;
         case SET_DATA_SOURCE_URL: {
             CHECK_INTERFACE(IMediaPlayer, data, reply);
+
+            sp<IMediaHTTPService> httpService;
+            if (data.readInt32()) {
+                httpService =
+                    interface_cast<IMediaHTTPService>(data.readStrongBinder());
+            }
+
             const char* url = data.readCString();
             KeyedVector<String8, String8> headers;
             int32_t numHeaders = data.readInt32();
@@ -363,7 +377,8 @@
                 String8 value = data.readString8();
                 headers.add(key, value);
             }
-            reply->writeInt32(setDataSource(url, numHeaders > 0 ? &headers : NULL));
+            reply->writeInt32(setDataSource(
+                        httpService, url, numHeaders > 0 ? &headers : NULL));
             return NO_ERROR;
         } break;
         case SET_DATA_SOURCE_FD: {
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 3c22b4c..d116b14 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -23,6 +23,7 @@
 #include <media/ICrypto.h>
 #include <media/IDrm.h>
 #include <media/IHDCP.h>
+#include <media/IMediaHTTPService.h>
 #include <media/IMediaPlayerService.h>
 #include <media/IMediaRecorder.h>
 #include <media/IOMX.h>
@@ -48,7 +49,6 @@
     ADD_BATTERY_DATA,
     PULL_BATTERY_DATA,
     LISTEN_FOR_REMOTE_DISPLAY,
-    UPDATE_PROXY_CONFIG,
 };
 
 class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
@@ -86,12 +86,21 @@
         return interface_cast<IMediaRecorder>(reply.readStrongBinder());
     }
 
-    virtual status_t decode(const char* url, uint32_t *pSampleRate, int* pNumChannels,
-                               audio_format_t* pFormat,
-                               const sp<IMemoryHeap>& heap, size_t *pSize)
+    virtual status_t decode(
+            const sp<IMediaHTTPService> &httpService,
+            const char* url,
+            uint32_t *pSampleRate,
+            int* pNumChannels,
+            audio_format_t* pFormat,
+            const sp<IMemoryHeap>& heap,
+            size_t *pSize)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+        data.writeInt32(httpService != NULL);
+        if (httpService != NULL) {
+            data.writeStrongBinder(httpService->asBinder());
+        }
         data.writeCString(url);
         data.writeStrongBinder(heap->asBinder());
         status_t status = remote()->transact(DECODE_URL, data, &reply);
@@ -182,25 +191,6 @@
         remote()->transact(LISTEN_FOR_REMOTE_DISPLAY, data, &reply);
         return interface_cast<IRemoteDisplay>(reply.readStrongBinder());
     }
-
-    virtual status_t updateProxyConfig(
-            const char *host, int32_t port, const char *exclusionList) {
-        Parcel data, reply;
-
-        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
-        if (host == NULL) {
-            data.writeInt32(0);
-        } else {
-            data.writeInt32(1);
-            data.writeCString(host);
-            data.writeInt32(port);
-            data.writeCString(exclusionList);
-        }
-
-        remote()->transact(UPDATE_PROXY_CONFIG, data, &reply);
-
-        return reply.readInt32();
-    }
 };
 
 IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService");
@@ -222,13 +212,25 @@
         } break;
         case DECODE_URL: {
             CHECK_INTERFACE(IMediaPlayerService, data, reply);
+            sp<IMediaHTTPService> httpService;
+            if (data.readInt32()) {
+                httpService =
+                    interface_cast<IMediaHTTPService>(data.readStrongBinder());
+            }
             const char* url = data.readCString();
             sp<IMemoryHeap> heap = interface_cast<IMemoryHeap>(data.readStrongBinder());
             uint32_t sampleRate;
             int numChannels;
             audio_format_t format;
             size_t size;
-            status_t status = decode(url, &sampleRate, &numChannels, &format, heap, &size);
+            status_t status =
+                decode(httpService,
+                       url,
+                       &sampleRate,
+                       &numChannels,
+                       &format,
+                       heap,
+                       &size);
             reply->writeInt32(status);
             if (status == NO_ERROR) {
                 reply->writeInt32(sampleRate);
@@ -316,24 +318,6 @@
             reply->writeStrongBinder(display->asBinder());
             return NO_ERROR;
         } break;
-        case UPDATE_PROXY_CONFIG:
-        {
-            CHECK_INTERFACE(IMediaPlayerService, data, reply);
-
-            const char *host = NULL;
-            int32_t port = 0;
-            const char *exclusionList = NULL;
-
-            if (data.readInt32()) {
-                host = data.readCString();
-                port = data.readInt32();
-                exclusionList = data.readCString();
-            }
-
-            reply->writeInt32(updateProxyConfig(host, port, exclusionList));
-
-            return OK;
-        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index e914b34..f0f1832 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -90,7 +90,7 @@
             pLibConfig->sampleRate,
             AUDIO_FORMAT_PCM_16_BIT,
             audio_channel_out_mask_from_count(pLibConfig->numChannels),
-            mTrackBufferSize,
+            (size_t) mTrackBufferSize,
             AUDIO_OUTPUT_FLAG_NONE);
 
     // create render and playback thread
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index 8319cd7..1074da9 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -81,8 +81,14 @@
     {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
 };
 
+#if LOG_NDEBUG
+#define UNUSED __unused
+#else
+#define UNUSED
+#endif
+
 /*static*/ void
-MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec)
+MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec UNUSED)
 {
     ALOGV("video codec:");
     ALOGV("codec = %d", codec.mCodec);
@@ -93,7 +99,7 @@
 }
 
 /*static*/ void
-MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec)
+MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec UNUSED)
 {
     ALOGV("audio codec:");
     ALOGV("codec = %d", codec.mCodec);
@@ -103,7 +109,7 @@
 }
 
 /*static*/ void
-MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap)
+MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap UNUSED)
 {
     ALOGV("video encoder cap:");
     ALOGV("codec = %d", cap.mCodec);
@@ -114,7 +120,7 @@
 }
 
 /*static*/ void
-MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap)
+MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap UNUSED)
 {
     ALOGV("audio encoder cap:");
     ALOGV("codec = %d", cap.mCodec);
@@ -124,21 +130,21 @@
 }
 
 /*static*/ void
-MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap)
+MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap UNUSED)
 {
     ALOGV("video decoder cap:");
     ALOGV("codec = %d", cap.mCodec);
 }
 
 /*static*/ void
-MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap)
+MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap UNUSED)
 {
     ALOGV("audio codec cap:");
     ALOGV("codec = %d", cap.mCodec);
 }
 
 /*static*/ void
-MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap)
+MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap UNUSED)
 {
     ALOGV("videoeditor cap:");
     ALOGV("mMaxInputFrameWidth = %d", cap.mMaxInputFrameWidth);
diff --git a/media/libmedia/MediaScannerClient.cpp b/media/libmedia/MediaScannerClient.cpp
index 93a4a4c..1661f04 100644
--- a/media/libmedia/MediaScannerClient.cpp
+++ b/media/libmedia/MediaScannerClient.cpp
@@ -14,217 +14,57 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaScannerClient"
+#include <utils/Log.h>
+
 #include <media/mediascanner.h>
 
+#include "CharacterEncodingDetector.h"
 #include "StringArray.h"
 
-#include "autodetect.h"
-#include "unicode/ucnv.h"
-#include "unicode/ustring.h"
-
 namespace android {
 
 MediaScannerClient::MediaScannerClient()
-    :   mNames(NULL),
-        mValues(NULL),
-        mLocaleEncoding(kEncodingNone)
+    :   mEncodingDetector(NULL)
 {
 }
 
 MediaScannerClient::~MediaScannerClient()
 {
-    delete mNames;
-    delete mValues;
+    delete mEncodingDetector;
 }
 
 void MediaScannerClient::setLocale(const char* locale)
 {
-    if (!locale) return;
-
-    if (!strncmp(locale, "ja", 2))
-        mLocaleEncoding = kEncodingShiftJIS;
-    else if (!strncmp(locale, "ko", 2))
-        mLocaleEncoding = kEncodingEUCKR;
-    else if (!strncmp(locale, "zh", 2)) {
-        if (!strcmp(locale, "zh_CN")) {
-            // simplified chinese for mainland China
-            mLocaleEncoding = kEncodingGBK;
-        } else {
-            // assume traditional for non-mainland Chinese locales (Taiwan, Hong Kong, Singapore)
-            mLocaleEncoding = kEncodingBig5;
-        }
-    }
+    mLocale = locale; // not currently used
 }
 
 void MediaScannerClient::beginFile()
 {
-    mNames = new StringArray;
-    mValues = new StringArray;
+    delete mEncodingDetector;
+    mEncodingDetector = new CharacterEncodingDetector();
 }
 
 status_t MediaScannerClient::addStringTag(const char* name, const char* value)
 {
-    if (mLocaleEncoding != kEncodingNone) {
-        // don't bother caching strings that are all ASCII.
-        // call handleStringTag directly instead.
-        // check to see if value (which should be utf8) has any non-ASCII characters
-        bool nonAscii = false;
-        const char* chp = value;
-        char ch;
-        while ((ch = *chp++)) {
-            if (ch & 0x80) {
-                nonAscii = true;
-                break;
-            }
-        }
-
-        if (nonAscii) {
-            // save the strings for later so they can be used for native encoding detection
-            mNames->push_back(name);
-            mValues->push_back(value);
-            return OK;
-        }
-        // else fall through
-    }
-
-    // autodetection is not necessary, so no need to cache the values
-    // pass directly to the client instead
-    return handleStringTag(name, value);
-}
-
-static uint32_t possibleEncodings(const char* s)
-{
-    uint32_t result = kEncodingAll;
-    // if s contains a native encoding, then it was mistakenly encoded in utf8 as if it were latin-1
-    // so we need to reverse the latin-1 -> utf8 conversion to get the native chars back
-    uint8_t ch1, ch2;
-    uint8_t* chp = (uint8_t *)s;
-
-    while ((ch1 = *chp++)) {
-        if (ch1 & 0x80) {
-            ch2 = *chp++;
-            ch1 = ((ch1 << 6) & 0xC0) | (ch2 & 0x3F);
-            // ch1 is now the first byte of the potential native char
-
-            ch2 = *chp++;
-            if (ch2 & 0x80)
-                ch2 = ((ch2 << 6) & 0xC0) | (*chp++ & 0x3F);
-            // ch2 is now the second byte of the potential native char
-            int ch = (int)ch1 << 8 | (int)ch2;
-            result &= findPossibleEncodings(ch);
-        }
-        // else ASCII character, which could be anything
-    }
-
-    return result;
-}
-
-void MediaScannerClient::convertValues(uint32_t encoding)
-{
-    const char* enc = NULL;
-    switch (encoding) {
-        case kEncodingShiftJIS:
-            enc = "shift-jis";
-            break;
-        case kEncodingGBK:
-            enc = "gbk";
-            break;
-        case kEncodingBig5:
-            enc = "Big5";
-            break;
-        case kEncodingEUCKR:
-            enc = "EUC-KR";
-            break;
-    }
-
-    if (enc) {
-        UErrorCode status = U_ZERO_ERROR;
-
-        UConverter *conv = ucnv_open(enc, &status);
-        if (U_FAILURE(status)) {
-            ALOGE("could not create UConverter for %s", enc);
-            return;
-        }
-        UConverter *utf8Conv = ucnv_open("UTF-8", &status);
-        if (U_FAILURE(status)) {
-            ALOGE("could not create UConverter for UTF-8");
-            ucnv_close(conv);
-            return;
-        }
-
-        // for each value string, convert from native encoding to UTF-8
-        for (int i = 0; i < mNames->size(); i++) {
-            // first we need to untangle the utf8 and convert it back to the original bytes
-            // since we are reducing the length of the string, we can do this in place
-            uint8_t* src = (uint8_t *)mValues->getEntry(i);
-            int len = strlen((char *)src);
-            uint8_t* dest = src;
-
-            uint8_t uch;
-            while ((uch = *src++)) {
-                if (uch & 0x80)
-                    *dest++ = ((uch << 6) & 0xC0) | (*src++ & 0x3F);
-                else
-                    *dest++ = uch;
-            }
-            *dest = 0;
-
-            // now convert from native encoding to UTF-8
-            const char* source = mValues->getEntry(i);
-            int targetLength = len * 3 + 1;
-            char* buffer = new char[targetLength];
-            // don't normally check for NULL, but in this case targetLength may be large
-            if (!buffer)
-                break;
-            char* target = buffer;
-
-            ucnv_convertEx(utf8Conv, conv, &target, target + targetLength,
-                    &source, (const char *)dest, NULL, NULL, NULL, NULL, TRUE, TRUE, &status);
-            if (U_FAILURE(status)) {
-                ALOGE("ucnv_convertEx failed: %d", status);
-                mValues->setEntry(i, "???");
-            } else {
-                // zero terminate
-                *target = 0;
-                mValues->setEntry(i, buffer);
-            }
-
-            delete[] buffer;
-        }
-
-        ucnv_close(conv);
-        ucnv_close(utf8Conv);
-    }
+    mEncodingDetector->addTag(name, value);
+    return OK;
 }
 
 void MediaScannerClient::endFile()
 {
-    if (mLocaleEncoding != kEncodingNone) {
-        int size = mNames->size();
-        uint32_t encoding = kEncodingAll;
+    mEncodingDetector->detectAndConvert();
 
-        // compute a bit mask containing all possible encodings
-        for (int i = 0; i < mNames->size(); i++)
-            encoding &= possibleEncodings(mValues->getEntry(i));
-
-        // if the locale encoding matches, then assume we have a native encoding.
-        if (encoding & mLocaleEncoding)
-            convertValues(mLocaleEncoding);
-
-        // finally, push all name/value pairs to the client
-        for (int i = 0; i < mNames->size(); i++) {
-            status_t status = handleStringTag(mNames->getEntry(i), mValues->getEntry(i));
-            if (status) {
-                break;
-            }
+    int size = mEncodingDetector->size();
+    if (size) {
+        for (int i = 0; i < size; i++) {
+            const char *name;
+            const char *value;
+            mEncodingDetector->getTag(i, &name, &value);
+            handleStringTag(name, value);
         }
     }
-    // else addStringTag() has done all the work so we have nothing to do
-
-    delete mNames;
-    delete mValues;
-    mNames = NULL;
-    mValues = NULL;
 }
 
 }  // namespace android
diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp
index 22e9fad..a55e09c 100644
--- a/media/libmedia/SoundPool.cpp
+++ b/media/libmedia/SoundPool.cpp
@@ -21,6 +21,7 @@
 #define USE_SHARED_MEM_BUFFER
 
 #include <media/AudioTrack.h>
+#include <media/IMediaHTTPService.h>
 #include <media/mediaplayer.h>
 #include <media/SoundPool.h>
 #include "SoundPoolThread.h"
@@ -199,7 +200,7 @@
     return NULL;
 }
 
-int SoundPool::load(const char* path, int priority)
+int SoundPool::load(const char* path, int priority __unused)
 {
     ALOGV("load: path=%s, priority=%d", path, priority);
     Mutex::Autolock lock(&mLock);
@@ -209,7 +210,7 @@
     return sample->sampleID();
 }
 
-int SoundPool::load(int fd, int64_t offset, int64_t length, int priority)
+int SoundPool::load(int fd, int64_t offset, int64_t length, int priority __unused)
 {
     ALOGV("load: fd=%d, offset=%lld, length=%lld, priority=%d",
             fd, offset, length, priority);
@@ -496,7 +497,14 @@
 
     ALOGV("Start decode");
     if (mUrl) {
-        status = MediaPlayer::decode(mUrl, &sampleRate, &numChannels, &format, mHeap, &mSize);
+        status = MediaPlayer::decode(
+                NULL /* httpService */,
+                mUrl,
+                &sampleRate,
+                &numChannels,
+                &format,
+                mHeap,
+                &mSize);
     } else {
         status = MediaPlayer::decode(mFd, mOffset, mLength, &sampleRate, &numChannels, &format,
                                      mHeap, &mSize);
@@ -579,7 +587,7 @@
         uint32_t sampleRate = uint32_t(float(sample->sampleRate()) * rate + 0.5);
         uint32_t totalFrames = (kDefaultBufferCount * afFrameCount * sampleRate) / afSampleRate;
         uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount;
-        uint32_t frameCount = 0;
+        size_t frameCount = 0;
 
         if (loop) {
             frameCount = sample->size()/numChannels/
@@ -600,16 +608,15 @@
         // wrong audio audio buffer size  (mAudioBufferSize)
         unsigned long toggle = mToggle ^ 1;
         void *userData = (void *)((unsigned long)this | toggle);
-        uint32_t channels = (numChannels == 2) ?
-                AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO;
+        audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(numChannels);
 
         // do not create a new audio track if current track is compatible with sample parameters
 #ifdef USE_SHARED_MEM_BUFFER
         newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
-                channels, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData);
+                channelMask, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData);
 #else
         newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
-                channels, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData,
+                channelMask, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData,
                 bufferFrames);
 #endif
         oldTrack = mAudioTrack;
@@ -730,7 +737,8 @@
                     count = b->size;
                 }
                 memcpy(q, p, count);
-//              ALOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size, count);
+//              ALOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size,
+//                      count);
             } else if (mPos < mAudioBufferSize) {
                 count = mAudioBufferSize - mPos;
                 if (count > b->size) {
diff --git a/media/libmedia/autodetect.cpp b/media/libmedia/autodetect.cpp
deleted file mode 100644
index be5c3b2..0000000
--- a/media/libmedia/autodetect.cpp
+++ /dev/null
@@ -1,885 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#include "autodetect.h"
-
-struct CharRange {
-    uint16_t first;
-    uint16_t last;
-};
-
-#define ARRAY_SIZE(x)   (sizeof(x) / sizeof(*x))
-
-// generated from http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP932.TXT
-static const CharRange kShiftJISRanges[] = {
-    { 0x8140, 0x817E },
-    { 0x8180, 0x81AC },
-    { 0x81B8, 0x81BF },
-    { 0x81C8, 0x81CE },
-    { 0x81DA, 0x81E8 },
-    { 0x81F0, 0x81F7 },
-    { 0x81FC, 0x81FC },
-    { 0x824F, 0x8258 },
-    { 0x8260, 0x8279 },
-    { 0x8281, 0x829A },
-    { 0x829F, 0x82F1 },
-    { 0x8340, 0x837E },
-    { 0x8380, 0x8396 },
-    { 0x839F, 0x83B6 },
-    { 0x83BF, 0x83D6 },
-    { 0x8440, 0x8460 },
-    { 0x8470, 0x847E },
-    { 0x8480, 0x8491 },
-    { 0x849F, 0x84BE },
-    { 0x8740, 0x875D },
-    { 0x875F, 0x8775 },
-    { 0x877E, 0x877E },
-    { 0x8780, 0x879C },
-    { 0x889F, 0x88FC },
-    { 0x8940, 0x897E },
-    { 0x8980, 0x89FC },
-    { 0x8A40, 0x8A7E },
-    { 0x8A80, 0x8AFC },
-    { 0x8B40, 0x8B7E },
-    { 0x8B80, 0x8BFC },
-    { 0x8C40, 0x8C7E },
-    { 0x8C80, 0x8CFC },
-    { 0x8D40, 0x8D7E },
-    { 0x8D80, 0x8DFC },
-    { 0x8E40, 0x8E7E },
-    { 0x8E80, 0x8EFC },
-    { 0x8F40, 0x8F7E },
-    { 0x8F80, 0x8FFC },
-    { 0x9040, 0x907E },
-    { 0x9080, 0x90FC },
-    { 0x9140, 0x917E },
-    { 0x9180, 0x91FC },
-    { 0x9240, 0x927E },
-    { 0x9280, 0x92FC },
-    { 0x9340, 0x937E },
-    { 0x9380, 0x93FC },
-    { 0x9440, 0x947E },
-    { 0x9480, 0x94FC },
-    { 0x9540, 0x957E },
-    { 0x9580, 0x95FC },
-    { 0x9640, 0x967E },
-    { 0x9680, 0x96FC },
-    { 0x9740, 0x977E },
-    { 0x9780, 0x97FC },
-    { 0x9840, 0x9872 },
-    { 0x989F, 0x98FC },
-    { 0x9940, 0x997E },
-    { 0x9980, 0x99FC },
-    { 0x9A40, 0x9A7E },
-    { 0x9A80, 0x9AFC },
-    { 0x9B40, 0x9B7E },
-    { 0x9B80, 0x9BFC },
-    { 0x9C40, 0x9C7E },
-    { 0x9C80, 0x9CFC },
-    { 0x9D40, 0x9D7E },
-    { 0x9D80, 0x9DFC },
-    { 0x9E40, 0x9E7E },
-    { 0x9E80, 0x9EFC },
-    { 0x9F40, 0x9F7E },
-    { 0x9F80, 0x9FFC },
-    { 0xE040, 0xE07E },
-    { 0xE080, 0xE0FC },
-    { 0xE140, 0xE17E },
-    { 0xE180, 0xE1FC },
-    { 0xE240, 0xE27E },
-    { 0xE280, 0xE2FC },
-    { 0xE340, 0xE37E },
-    { 0xE380, 0xE3FC },
-    { 0xE440, 0xE47E },
-    { 0xE480, 0xE4FC },
-    { 0xE540, 0xE57E },
-    { 0xE580, 0xE5FC },
-    { 0xE640, 0xE67E },
-    { 0xE680, 0xE6FC },
-    { 0xE740, 0xE77E },
-    { 0xE780, 0xE7FC },
-    { 0xE840, 0xE87E },
-    { 0xE880, 0xE8FC },
-    { 0xE940, 0xE97E },
-    { 0xE980, 0xE9FC },
-    { 0xEA40, 0xEA7E },
-    { 0xEA80, 0xEAA4 },
-    { 0xED40, 0xED7E },
-    { 0xED80, 0xEDFC },
-    { 0xEE40, 0xEE7E },
-    { 0xEE80, 0xEEEC },
-    { 0xEEEF, 0xEEFC },
-    { 0xFA40, 0xFA7E },
-    { 0xFA80, 0xFAFC },
-    { 0xFB40, 0xFB7E },
-    { 0xFB80, 0xFBFC },
-    { 0xFC40, 0xFC4B },
-};
-
-// generated from http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP936.TXT
-static const CharRange kGBKRanges[] = {
-    { 0x8140, 0x817E },
-    { 0x8180, 0x81FE },
-    { 0x8240, 0x827E },
-    { 0x8280, 0x82FE },
-    { 0x8340, 0x837E },
-    { 0x8380, 0x83FE },
-    { 0x8440, 0x847E },
-    { 0x8480, 0x84FE },
-    { 0x8540, 0x857E },
-    { 0x8580, 0x85FE },
-    { 0x8640, 0x867E },
-    { 0x8680, 0x86FE },
-    { 0x8740, 0x877E },
-    { 0x8780, 0x87FE },
-    { 0x8840, 0x887E },
-    { 0x8880, 0x88FE },
-    { 0x8940, 0x897E },
-    { 0x8980, 0x89FE },
-    { 0x8A40, 0x8A7E },
-    { 0x8A80, 0x8AFE },
-    { 0x8B40, 0x8B7E },
-    { 0x8B80, 0x8BFE },
-    { 0x8C40, 0x8C7E },
-    { 0x8C80, 0x8CFE },
-    { 0x8D40, 0x8D7E },
-    { 0x8D80, 0x8DFE },
-    { 0x8E40, 0x8E7E },
-    { 0x8E80, 0x8EFE },
-    { 0x8F40, 0x8F7E },
-    { 0x8F80, 0x8FFE },
-    { 0x9040, 0x907E },
-    { 0x9080, 0x90FE },
-    { 0x9140, 0x917E },
-    { 0x9180, 0x91FE },
-    { 0x9240, 0x927E },
-    { 0x9280, 0x92FE },
-    { 0x9340, 0x937E },
-    { 0x9380, 0x93FE },
-    { 0x9440, 0x947E },
-    { 0x9480, 0x94FE },
-    { 0x9540, 0x957E },
-    { 0x9580, 0x95FE },
-    { 0x9640, 0x967E },
-    { 0x9680, 0x96FE },
-    { 0x9740, 0x977E },
-    { 0x9780, 0x97FE },
-    { 0x9840, 0x987E },
-    { 0x9880, 0x98FE },
-    { 0x9940, 0x997E },
-    { 0x9980, 0x99FE },
-    { 0x9A40, 0x9A7E },
-    { 0x9A80, 0x9AFE },
-    { 0x9B40, 0x9B7E },
-    { 0x9B80, 0x9BFE },
-    { 0x9C40, 0x9C7E },
-    { 0x9C80, 0x9CFE },
-    { 0x9D40, 0x9D7E },
-    { 0x9D80, 0x9DFE },
-    { 0x9E40, 0x9E7E },
-    { 0x9E80, 0x9EFE },
-    { 0x9F40, 0x9F7E },
-    { 0x9F80, 0x9FFE },
-    { 0xA040, 0xA07E },
-    { 0xA080, 0xA0FE },
-    { 0xA1A1, 0xA1FE },
-    { 0xA2A1, 0xA2AA },
-    { 0xA2B1, 0xA2E2 },
-    { 0xA2E5, 0xA2EE },
-    { 0xA2F1, 0xA2FC },
-    { 0xA3A1, 0xA3FE },
-    { 0xA4A1, 0xA4F3 },
-    { 0xA5A1, 0xA5F6 },
-    { 0xA6A1, 0xA6B8 },
-    { 0xA6C1, 0xA6D8 },
-    { 0xA6E0, 0xA6EB },
-    { 0xA6EE, 0xA6F2 },
-    { 0xA6F4, 0xA6F5 },
-    { 0xA7A1, 0xA7C1 },
-    { 0xA7D1, 0xA7F1 },
-    { 0xA840, 0xA87E },
-    { 0xA880, 0xA895 },
-    { 0xA8A1, 0xA8BB },
-    { 0xA8BD, 0xA8BE },
-    { 0xA8C0, 0xA8C0 },
-    { 0xA8C5, 0xA8E9 },
-    { 0xA940, 0xA957 },
-    { 0xA959, 0xA95A },
-    { 0xA95C, 0xA95C },
-    { 0xA960, 0xA97E },
-    { 0xA980, 0xA988 },
-    { 0xA996, 0xA996 },
-    { 0xA9A4, 0xA9EF },
-    { 0xAA40, 0xAA7E },
-    { 0xAA80, 0xAAA0 },
-    { 0xAB40, 0xAB7E },
-    { 0xAB80, 0xABA0 },
-    { 0xAC40, 0xAC7E },
-    { 0xAC80, 0xACA0 },
-    { 0xAD40, 0xAD7E },
-    { 0xAD80, 0xADA0 },
-    { 0xAE40, 0xAE7E },
-    { 0xAE80, 0xAEA0 },
-    { 0xAF40, 0xAF7E },
-    { 0xAF80, 0xAFA0 },
-    { 0xB040, 0xB07E },
-    { 0xB080, 0xB0FE },
-    { 0xB140, 0xB17E },
-    { 0xB180, 0xB1FE },
-    { 0xB240, 0xB27E },
-    { 0xB280, 0xB2FE },
-    { 0xB340, 0xB37E },
-    { 0xB380, 0xB3FE },
-    { 0xB440, 0xB47E },
-    { 0xB480, 0xB4FE },
-    { 0xB540, 0xB57E },
-    { 0xB580, 0xB5FE },
-    { 0xB640, 0xB67E },
-    { 0xB680, 0xB6FE },
-    { 0xB740, 0xB77E },
-    { 0xB780, 0xB7FE },
-    { 0xB840, 0xB87E },
-    { 0xB880, 0xB8FE },
-    { 0xB940, 0xB97E },
-    { 0xB980, 0xB9FE },
-    { 0xBA40, 0xBA7E },
-    { 0xBA80, 0xBAFE },
-    { 0xBB40, 0xBB7E },
-    { 0xBB80, 0xBBFE },
-    { 0xBC40, 0xBC7E },
-    { 0xBC80, 0xBCFE },
-    { 0xBD40, 0xBD7E },
-    { 0xBD80, 0xBDFE },
-    { 0xBE40, 0xBE7E },
-    { 0xBE80, 0xBEFE },
-    { 0xBF40, 0xBF7E },
-    { 0xBF80, 0xBFFE },
-    { 0xC040, 0xC07E },
-    { 0xC080, 0xC0FE },
-    { 0xC140, 0xC17E },
-    { 0xC180, 0xC1FE },
-    { 0xC240, 0xC27E },
-    { 0xC280, 0xC2FE },
-    { 0xC340, 0xC37E },
-    { 0xC380, 0xC3FE },
-    { 0xC440, 0xC47E },
-    { 0xC480, 0xC4FE },
-    { 0xC540, 0xC57E },
-    { 0xC580, 0xC5FE },
-    { 0xC640, 0xC67E },
-    { 0xC680, 0xC6FE },
-    { 0xC740, 0xC77E },
-    { 0xC780, 0xC7FE },
-    { 0xC840, 0xC87E },
-    { 0xC880, 0xC8FE },
-    { 0xC940, 0xC97E },
-    { 0xC980, 0xC9FE },
-    { 0xCA40, 0xCA7E },
-    { 0xCA80, 0xCAFE },
-    { 0xCB40, 0xCB7E },
-    { 0xCB80, 0xCBFE },
-    { 0xCC40, 0xCC7E },
-    { 0xCC80, 0xCCFE },
-    { 0xCD40, 0xCD7E },
-    { 0xCD80, 0xCDFE },
-    { 0xCE40, 0xCE7E },
-    { 0xCE80, 0xCEFE },
-    { 0xCF40, 0xCF7E },
-    { 0xCF80, 0xCFFE },
-    { 0xD040, 0xD07E },
-    { 0xD080, 0xD0FE },
-    { 0xD140, 0xD17E },
-    { 0xD180, 0xD1FE },
-    { 0xD240, 0xD27E },
-    { 0xD280, 0xD2FE },
-    { 0xD340, 0xD37E },
-    { 0xD380, 0xD3FE },
-    { 0xD440, 0xD47E },
-    { 0xD480, 0xD4FE },
-    { 0xD540, 0xD57E },
-    { 0xD580, 0xD5FE },
-    { 0xD640, 0xD67E },
-    { 0xD680, 0xD6FE },
-    { 0xD740, 0xD77E },
-    { 0xD780, 0xD7F9 },
-    { 0xD840, 0xD87E },
-    { 0xD880, 0xD8FE },
-    { 0xD940, 0xD97E },
-    { 0xD980, 0xD9FE },
-    { 0xDA40, 0xDA7E },
-    { 0xDA80, 0xDAFE },
-    { 0xDB40, 0xDB7E },
-    { 0xDB80, 0xDBFE },
-    { 0xDC40, 0xDC7E },
-    { 0xDC80, 0xDCFE },
-    { 0xDD40, 0xDD7E },
-    { 0xDD80, 0xDDFE },
-    { 0xDE40, 0xDE7E },
-    { 0xDE80, 0xDEFE },
-    { 0xDF40, 0xDF7E },
-    { 0xDF80, 0xDFFE },
-    { 0xE040, 0xE07E },
-    { 0xE080, 0xE0FE },
-    { 0xE140, 0xE17E },
-    { 0xE180, 0xE1FE },
-    { 0xE240, 0xE27E },
-    { 0xE280, 0xE2FE },
-    { 0xE340, 0xE37E },
-    { 0xE380, 0xE3FE },
-    { 0xE440, 0xE47E },
-    { 0xE480, 0xE4FE },
-    { 0xE540, 0xE57E },
-    { 0xE580, 0xE5FE },
-    { 0xE640, 0xE67E },
-    { 0xE680, 0xE6FE },
-    { 0xE740, 0xE77E },
-    { 0xE780, 0xE7FE },
-    { 0xE840, 0xE87E },
-    { 0xE880, 0xE8FE },
-    { 0xE940, 0xE97E },
-    { 0xE980, 0xE9FE },
-    { 0xEA40, 0xEA7E },
-    { 0xEA80, 0xEAFE },
-    { 0xEB40, 0xEB7E },
-    { 0xEB80, 0xEBFE },
-    { 0xEC40, 0xEC7E },
-    { 0xEC80, 0xECFE },
-    { 0xED40, 0xED7E },
-    { 0xED80, 0xEDFE },
-    { 0xEE40, 0xEE7E },
-    { 0xEE80, 0xEEFE },
-    { 0xEF40, 0xEF7E },
-    { 0xEF80, 0xEFFE },
-    { 0xF040, 0xF07E },
-    { 0xF080, 0xF0FE },
-    { 0xF140, 0xF17E },
-    { 0xF180, 0xF1FE },
-    { 0xF240, 0xF27E },
-    { 0xF280, 0xF2FE },
-    { 0xF340, 0xF37E },
-    { 0xF380, 0xF3FE },
-    { 0xF440, 0xF47E },
-    { 0xF480, 0xF4FE },
-    { 0xF540, 0xF57E },
-    { 0xF580, 0xF5FE },
-    { 0xF640, 0xF67E },
-    { 0xF680, 0xF6FE },
-    { 0xF740, 0xF77E },
-    { 0xF780, 0xF7FE },
-    { 0xF840, 0xF87E },
-    { 0xF880, 0xF8A0 },
-    { 0xF940, 0xF97E },
-    { 0xF980, 0xF9A0 },
-    { 0xFA40, 0xFA7E },
-    { 0xFA80, 0xFAA0 },
-    { 0xFB40, 0xFB7E },
-    { 0xFB80, 0xFBA0 },
-    { 0xFC40, 0xFC7E },
-    { 0xFC80, 0xFCA0 },
-    { 0xFD40, 0xFD7E },
-    { 0xFD80, 0xFDA0 },
-    { 0xFE40, 0xFE4F },
-};
-
-// generated from http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP949.TXT
-static const CharRange kEUCKRRanges[] = {
-    { 0x8141, 0x815A },
-    { 0x8161, 0x817A },
-    { 0x8181, 0x81FE },
-    { 0x8241, 0x825A },
-    { 0x8261, 0x827A },
-    { 0x8281, 0x82FE },
-    { 0x8341, 0x835A },
-    { 0x8361, 0x837A },
-    { 0x8381, 0x83FE },
-    { 0x8441, 0x845A },
-    { 0x8461, 0x847A },
-    { 0x8481, 0x84FE },
-    { 0x8541, 0x855A },
-    { 0x8561, 0x857A },
-    { 0x8581, 0x85FE },
-    { 0x8641, 0x865A },
-    { 0x8661, 0x867A },
-    { 0x8681, 0x86FE },
-    { 0x8741, 0x875A },
-    { 0x8761, 0x877A },
-    { 0x8781, 0x87FE },
-    { 0x8841, 0x885A },
-    { 0x8861, 0x887A },
-    { 0x8881, 0x88FE },
-    { 0x8941, 0x895A },
-    { 0x8961, 0x897A },
-    { 0x8981, 0x89FE },
-    { 0x8A41, 0x8A5A },
-    { 0x8A61, 0x8A7A },
-    { 0x8A81, 0x8AFE },
-    { 0x8B41, 0x8B5A },
-    { 0x8B61, 0x8B7A },
-    { 0x8B81, 0x8BFE },
-    { 0x8C41, 0x8C5A },
-    { 0x8C61, 0x8C7A },
-    { 0x8C81, 0x8CFE },
-    { 0x8D41, 0x8D5A },
-    { 0x8D61, 0x8D7A },
-    { 0x8D81, 0x8DFE },
-    { 0x8E41, 0x8E5A },
-    { 0x8E61, 0x8E7A },
-    { 0x8E81, 0x8EFE },
-    { 0x8F41, 0x8F5A },
-    { 0x8F61, 0x8F7A },
-    { 0x8F81, 0x8FFE },
-    { 0x9041, 0x905A },
-    { 0x9061, 0x907A },
-    { 0x9081, 0x90FE },
-    { 0x9141, 0x915A },
-    { 0x9161, 0x917A },
-    { 0x9181, 0x91FE },
-    { 0x9241, 0x925A },
-    { 0x9261, 0x927A },
-    { 0x9281, 0x92FE },
-    { 0x9341, 0x935A },
-    { 0x9361, 0x937A },
-    { 0x9381, 0x93FE },
-    { 0x9441, 0x945A },
-    { 0x9461, 0x947A },
-    { 0x9481, 0x94FE },
-    { 0x9541, 0x955A },
-    { 0x9561, 0x957A },
-    { 0x9581, 0x95FE },
-    { 0x9641, 0x965A },
-    { 0x9661, 0x967A },
-    { 0x9681, 0x96FE },
-    { 0x9741, 0x975A },
-    { 0x9761, 0x977A },
-    { 0x9781, 0x97FE },
-    { 0x9841, 0x985A },
-    { 0x9861, 0x987A },
-    { 0x9881, 0x98FE },
-    { 0x9941, 0x995A },
-    { 0x9961, 0x997A },
-    { 0x9981, 0x99FE },
-    { 0x9A41, 0x9A5A },
-    { 0x9A61, 0x9A7A },
-    { 0x9A81, 0x9AFE },
-    { 0x9B41, 0x9B5A },
-    { 0x9B61, 0x9B7A },
-    { 0x9B81, 0x9BFE },
-    { 0x9C41, 0x9C5A },
-    { 0x9C61, 0x9C7A },
-    { 0x9C81, 0x9CFE },
-    { 0x9D41, 0x9D5A },
-    { 0x9D61, 0x9D7A },
-    { 0x9D81, 0x9DFE },
-    { 0x9E41, 0x9E5A },
-    { 0x9E61, 0x9E7A },
-    { 0x9E81, 0x9EFE },
-    { 0x9F41, 0x9F5A },
-    { 0x9F61, 0x9F7A },
-    { 0x9F81, 0x9FFE },
-    { 0xA041, 0xA05A },
-    { 0xA061, 0xA07A },
-    { 0xA081, 0xA0FE },
-    { 0xA141, 0xA15A },
-    { 0xA161, 0xA17A },
-    { 0xA181, 0xA1FE },
-    { 0xA241, 0xA25A },
-    { 0xA261, 0xA27A },
-    { 0xA281, 0xA2E7 },
-    { 0xA341, 0xA35A },
-    { 0xA361, 0xA37A },
-    { 0xA381, 0xA3FE },
-    { 0xA441, 0xA45A },
-    { 0xA461, 0xA47A },
-    { 0xA481, 0xA4FE },
-    { 0xA541, 0xA55A },
-    { 0xA561, 0xA57A },
-    { 0xA581, 0xA5AA },
-    { 0xA5B0, 0xA5B9 },
-    { 0xA5C1, 0xA5D8 },
-    { 0xA5E1, 0xA5F8 },
-    { 0xA641, 0xA65A },
-    { 0xA661, 0xA67A },
-    { 0xA681, 0xA6E4 },
-    { 0xA741, 0xA75A },
-    { 0xA761, 0xA77A },
-    { 0xA781, 0xA7EF },
-    { 0xA841, 0xA85A },
-    { 0xA861, 0xA87A },
-    { 0xA881, 0xA8A4 },
-    { 0xA8A6, 0xA8A6 },
-    { 0xA8A8, 0xA8AF },
-    { 0xA8B1, 0xA8FE },
-    { 0xA941, 0xA95A },
-    { 0xA961, 0xA97A },
-    { 0xA981, 0xA9FE },
-    { 0xAA41, 0xAA5A },
-    { 0xAA61, 0xAA7A },
-    { 0xAA81, 0xAAF3 },
-    { 0xAB41, 0xAB5A },
-    { 0xAB61, 0xAB7A },
-    { 0xAB81, 0xABF6 },
-    { 0xAC41, 0xAC5A },
-    { 0xAC61, 0xAC7A },
-    { 0xAC81, 0xACC1 },
-    { 0xACD1, 0xACF1 },
-    { 0xAD41, 0xAD5A },
-    { 0xAD61, 0xAD7A },
-    { 0xAD81, 0xADA0 },
-    { 0xAE41, 0xAE5A },
-    { 0xAE61, 0xAE7A },
-    { 0xAE81, 0xAEA0 },
-    { 0xAF41, 0xAF5A },
-    { 0xAF61, 0xAF7A },
-    { 0xAF81, 0xAFA0 },
-    { 0xB041, 0xB05A },
-    { 0xB061, 0xB07A },
-    { 0xB081, 0xB0FE },
-    { 0xB141, 0xB15A },
-    { 0xB161, 0xB17A },
-    { 0xB181, 0xB1FE },
-    { 0xB241, 0xB25A },
-    { 0xB261, 0xB27A },
-    { 0xB281, 0xB2FE },
-    { 0xB341, 0xB35A },
-    { 0xB361, 0xB37A },
-    { 0xB381, 0xB3FE },
-    { 0xB441, 0xB45A },
-    { 0xB461, 0xB47A },
-    { 0xB481, 0xB4FE },
-    { 0xB541, 0xB55A },
-    { 0xB561, 0xB57A },
-    { 0xB581, 0xB5FE },
-    { 0xB641, 0xB65A },
-    { 0xB661, 0xB67A },
-    { 0xB681, 0xB6FE },
-    { 0xB741, 0xB75A },
-    { 0xB761, 0xB77A },
-    { 0xB781, 0xB7FE },
-    { 0xB841, 0xB85A },
-    { 0xB861, 0xB87A },
-    { 0xB881, 0xB8FE },
-    { 0xB941, 0xB95A },
-    { 0xB961, 0xB97A },
-    { 0xB981, 0xB9FE },
-    { 0xBA41, 0xBA5A },
-    { 0xBA61, 0xBA7A },
-    { 0xBA81, 0xBAFE },
-    { 0xBB41, 0xBB5A },
-    { 0xBB61, 0xBB7A },
-    { 0xBB81, 0xBBFE },
-    { 0xBC41, 0xBC5A },
-    { 0xBC61, 0xBC7A },
-    { 0xBC81, 0xBCFE },
-    { 0xBD41, 0xBD5A },
-    { 0xBD61, 0xBD7A },
-    { 0xBD81, 0xBDFE },
-    { 0xBE41, 0xBE5A },
-    { 0xBE61, 0xBE7A },
-    { 0xBE81, 0xBEFE },
-    { 0xBF41, 0xBF5A },
-    { 0xBF61, 0xBF7A },
-    { 0xBF81, 0xBFFE },
-    { 0xC041, 0xC05A },
-    { 0xC061, 0xC07A },
-    { 0xC081, 0xC0FE },
-    { 0xC141, 0xC15A },
-    { 0xC161, 0xC17A },
-    { 0xC181, 0xC1FE },
-    { 0xC241, 0xC25A },
-    { 0xC261, 0xC27A },
-    { 0xC281, 0xC2FE },
-    { 0xC341, 0xC35A },
-    { 0xC361, 0xC37A },
-    { 0xC381, 0xC3FE },
-    { 0xC441, 0xC45A },
-    { 0xC461, 0xC47A },
-    { 0xC481, 0xC4FE },
-    { 0xC541, 0xC55A },
-    { 0xC561, 0xC57A },
-    { 0xC581, 0xC5FE },
-    { 0xC641, 0xC652 },
-    { 0xC6A1, 0xC6FE },
-    { 0xC7A1, 0xC7FE },
-    { 0xC8A1, 0xC8FE },
-    { 0xCAA1, 0xCAFE },
-    { 0xCBA1, 0xCBFE },
-    { 0xCCA1, 0xCCFE },
-    { 0xCDA1, 0xCDFE },
-    { 0xCEA1, 0xCEFE },
-    { 0xCFA1, 0xCFFE },
-    { 0xD0A1, 0xD0FE },
-    { 0xD1A1, 0xD1FE },
-    { 0xD2A1, 0xD2FE },
-    { 0xD3A1, 0xD3FE },
-    { 0xD4A1, 0xD4FE },
-    { 0xD5A1, 0xD5FE },
-    { 0xD6A1, 0xD6FE },
-    { 0xD7A1, 0xD7FE },
-    { 0xD8A1, 0xD8FE },
-    { 0xD9A1, 0xD9FE },
-    { 0xDAA1, 0xDAFE },
-    { 0xDBA1, 0xDBFE },
-    { 0xDCA1, 0xDCFE },
-    { 0xDDA1, 0xDDFE },
-    { 0xDEA1, 0xDEFE },
-    { 0xDFA1, 0xDFFE },
-    { 0xE0A1, 0xE0FE },
-    { 0xE1A1, 0xE1FE },
-    { 0xE2A1, 0xE2FE },
-    { 0xE3A1, 0xE3FE },
-    { 0xE4A1, 0xE4FE },
-    { 0xE5A1, 0xE5FE },
-    { 0xE6A1, 0xE6FE },
-    { 0xE7A1, 0xE7FE },
-    { 0xE8A1, 0xE8FE },
-    { 0xE9A1, 0xE9FE },
-    { 0xEAA1, 0xEAFE },
-    { 0xEBA1, 0xEBFE },
-    { 0xECA1, 0xECFE },
-    { 0xEDA1, 0xEDFE },
-    { 0xEEA1, 0xEEFE },
-    { 0xEFA1, 0xEFFE },
-    { 0xF0A1, 0xF0FE },
-    { 0xF1A1, 0xF1FE },
-    { 0xF2A1, 0xF2FE },
-    { 0xF3A1, 0xF3FE },
-    { 0xF4A1, 0xF4FE },
-    { 0xF5A1, 0xF5FE },
-    { 0xF6A1, 0xF6FE },
-    { 0xF7A1, 0xF7FE },
-    { 0xF8A1, 0xF8FE },
-    { 0xF9A1, 0xF9FE },
-    { 0xFAA1, 0xFAFE },
-    { 0xFBA1, 0xFBFE },
-    { 0xFCA1, 0xFCFE },
-    { 0xFDA1, 0xFDFE },
-};
-
-// generated from http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP950.TXT
-static const CharRange kBig5Ranges[] = {
-    { 0xA140, 0xA17E },
-    { 0xA1A1, 0xA1FE },
-    { 0xA240, 0xA27E },
-    { 0xA2A1, 0xA2FE },
-    { 0xA340, 0xA37E },
-    { 0xA3A1, 0xA3BF },
-    { 0xA3E1, 0xA3E1 },
-    { 0xA440, 0xA47E },
-    { 0xA4A1, 0xA4FE },
-    { 0xA540, 0xA57E },
-    { 0xA5A1, 0xA5FE },
-    { 0xA640, 0xA67E },
-    { 0xA6A1, 0xA6FE },
-    { 0xA740, 0xA77E },
-    { 0xA7A1, 0xA7FE },
-    { 0xA840, 0xA87E },
-    { 0xA8A1, 0xA8FE },
-    { 0xA940, 0xA97E },
-    { 0xA9A1, 0xA9FE },
-    { 0xAA40, 0xAA7E },
-    { 0xAAA1, 0xAAFE },
-    { 0xAB40, 0xAB7E },
-    { 0xABA1, 0xABFE },
-    { 0xAC40, 0xAC7E },
-    { 0xACA1, 0xACFE },
-    { 0xAD40, 0xAD7E },
-    { 0xADA1, 0xADFE },
-    { 0xAE40, 0xAE7E },
-    { 0xAEA1, 0xAEFE },
-    { 0xAF40, 0xAF7E },
-    { 0xAFA1, 0xAFFE },
-    { 0xB040, 0xB07E },
-    { 0xB0A1, 0xB0FE },
-    { 0xB140, 0xB17E },
-    { 0xB1A1, 0xB1FE },
-    { 0xB240, 0xB27E },
-    { 0xB2A1, 0xB2FE },
-    { 0xB340, 0xB37E },
-    { 0xB3A1, 0xB3FE },
-    { 0xB440, 0xB47E },
-    { 0xB4A1, 0xB4FE },
-    { 0xB540, 0xB57E },
-    { 0xB5A1, 0xB5FE },
-    { 0xB640, 0xB67E },
-    { 0xB6A1, 0xB6FE },
-    { 0xB740, 0xB77E },
-    { 0xB7A1, 0xB7FE },
-    { 0xB840, 0xB87E },
-    { 0xB8A1, 0xB8FE },
-    { 0xB940, 0xB97E },
-    { 0xB9A1, 0xB9FE },
-    { 0xBA40, 0xBA7E },
-    { 0xBAA1, 0xBAFE },
-    { 0xBB40, 0xBB7E },
-    { 0xBBA1, 0xBBFE },
-    { 0xBC40, 0xBC7E },
-    { 0xBCA1, 0xBCFE },
-    { 0xBD40, 0xBD7E },
-    { 0xBDA1, 0xBDFE },
-    { 0xBE40, 0xBE7E },
-    { 0xBEA1, 0xBEFE },
-    { 0xBF40, 0xBF7E },
-    { 0xBFA1, 0xBFFE },
-    { 0xC040, 0xC07E },
-    { 0xC0A1, 0xC0FE },
-    { 0xC140, 0xC17E },
-    { 0xC1A1, 0xC1FE },
-    { 0xC240, 0xC27E },
-    { 0xC2A1, 0xC2FE },
-    { 0xC340, 0xC37E },
-    { 0xC3A1, 0xC3FE },
-    { 0xC440, 0xC47E },
-    { 0xC4A1, 0xC4FE },
-    { 0xC540, 0xC57E },
-    { 0xC5A1, 0xC5FE },
-    { 0xC640, 0xC67E },
-    { 0xC940, 0xC97E },
-    { 0xC9A1, 0xC9FE },
-    { 0xCA40, 0xCA7E },
-    { 0xCAA1, 0xCAFE },
-    { 0xCB40, 0xCB7E },
-    { 0xCBA1, 0xCBFE },
-    { 0xCC40, 0xCC7E },
-    { 0xCCA1, 0xCCFE },
-    { 0xCD40, 0xCD7E },
-    { 0xCDA1, 0xCDFE },
-    { 0xCE40, 0xCE7E },
-    { 0xCEA1, 0xCEFE },
-    { 0xCF40, 0xCF7E },
-    { 0xCFA1, 0xCFFE },
-    { 0xD040, 0xD07E },
-    { 0xD0A1, 0xD0FE },
-    { 0xD140, 0xD17E },
-    { 0xD1A1, 0xD1FE },
-    { 0xD240, 0xD27E },
-    { 0xD2A1, 0xD2FE },
-    { 0xD340, 0xD37E },
-    { 0xD3A1, 0xD3FE },
-    { 0xD440, 0xD47E },
-    { 0xD4A1, 0xD4FE },
-    { 0xD540, 0xD57E },
-    { 0xD5A1, 0xD5FE },
-    { 0xD640, 0xD67E },
-    { 0xD6A1, 0xD6FE },
-    { 0xD740, 0xD77E },
-    { 0xD7A1, 0xD7FE },
-    { 0xD840, 0xD87E },
-    { 0xD8A1, 0xD8FE },
-    { 0xD940, 0xD97E },
-    { 0xD9A1, 0xD9FE },
-    { 0xDA40, 0xDA7E },
-    { 0xDAA1, 0xDAFE },
-    { 0xDB40, 0xDB7E },
-    { 0xDBA1, 0xDBFE },
-    { 0xDC40, 0xDC7E },
-    { 0xDCA1, 0xDCFE },
-    { 0xDD40, 0xDD7E },
-    { 0xDDA1, 0xDDFE },
-    { 0xDE40, 0xDE7E },
-    { 0xDEA1, 0xDEFE },
-    { 0xDF40, 0xDF7E },
-    { 0xDFA1, 0xDFFE },
-    { 0xE040, 0xE07E },
-    { 0xE0A1, 0xE0FE },
-    { 0xE140, 0xE17E },
-    { 0xE1A1, 0xE1FE },
-    { 0xE240, 0xE27E },
-    { 0xE2A1, 0xE2FE },
-    { 0xE340, 0xE37E },
-    { 0xE3A1, 0xE3FE },
-    { 0xE440, 0xE47E },
-    { 0xE4A1, 0xE4FE },
-    { 0xE540, 0xE57E },
-    { 0xE5A1, 0xE5FE },
-    { 0xE640, 0xE67E },
-    { 0xE6A1, 0xE6FE },
-    { 0xE740, 0xE77E },
-    { 0xE7A1, 0xE7FE },
-    { 0xE840, 0xE87E },
-    { 0xE8A1, 0xE8FE },
-    { 0xE940, 0xE97E },
-    { 0xE9A1, 0xE9FE },
-    { 0xEA40, 0xEA7E },
-    { 0xEAA1, 0xEAFE },
-    { 0xEB40, 0xEB7E },
-    { 0xEBA1, 0xEBFE },
-    { 0xEC40, 0xEC7E },
-    { 0xECA1, 0xECFE },
-    { 0xED40, 0xED7E },
-    { 0xEDA1, 0xEDFE },
-    { 0xEE40, 0xEE7E },
-    { 0xEEA1, 0xEEFE },
-    { 0xEF40, 0xEF7E },
-    { 0xEFA1, 0xEFFE },
-    { 0xF040, 0xF07E },
-    { 0xF0A1, 0xF0FE },
-    { 0xF140, 0xF17E },
-    { 0xF1A1, 0xF1FE },
-    { 0xF240, 0xF27E },
-    { 0xF2A1, 0xF2FE },
-    { 0xF340, 0xF37E },
-    { 0xF3A1, 0xF3FE },
-    { 0xF440, 0xF47E },
-    { 0xF4A1, 0xF4FE },
-    { 0xF540, 0xF57E },
-    { 0xF5A1, 0xF5FE },
-    { 0xF640, 0xF67E },
-    { 0xF6A1, 0xF6FE },
-    { 0xF740, 0xF77E },
-    { 0xF7A1, 0xF7FE },
-    { 0xF840, 0xF87E },
-    { 0xF8A1, 0xF8FE },
-    { 0xF940, 0xF97E },
-    { 0xF9A1, 0xF9FE },
-};
-
-static bool charMatchesEncoding(int ch, const CharRange* encodingRanges, int rangeCount) {
-    // Use binary search to see if the character is contained in the encoding
-    int low = 0;
-    int high = rangeCount;
-
-    while (low < high) {
-        int i = (low + high) / 2;
-        const CharRange* range = &encodingRanges[i];
-        if (ch >= range->first && ch <= range->last)
-            return true;
-        if (ch > range->last)
-            low = i + 1;
-        else
-            high = i;
-    }
-
-    return false;
-}
-
-extern uint32_t findPossibleEncodings(int ch)
-{
-    // ASCII matches everything
-    if (ch < 256) return kEncodingAll;
-
-    int result = kEncodingNone;
-
-    if (charMatchesEncoding(ch, kShiftJISRanges, ARRAY_SIZE(kShiftJISRanges)))
-        result |= kEncodingShiftJIS;
-    if (charMatchesEncoding(ch, kGBKRanges, ARRAY_SIZE(kGBKRanges)))
-        result |= kEncodingGBK;
-    if (charMatchesEncoding(ch, kBig5Ranges, ARRAY_SIZE(kBig5Ranges)))
-        result |= kEncodingBig5;
-    if (charMatchesEncoding(ch, kEUCKRRanges, ARRAY_SIZE(kEUCKRRanges)))
-        result |= kEncodingEUCKR;
-
-    return result;
-}
diff --git a/media/libmedia/autodetect.h b/media/libmedia/autodetect.h
deleted file mode 100644
index 9675db3..0000000
--- a/media/libmedia/autodetect.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AUTODETECT_H
-#define AUTODETECT_H
-
-#include <inttypes.h>
-
-// flags used for native encoding detection
-enum {
-    kEncodingNone               = 0,
-    kEncodingShiftJIS           = (1 << 0),
-    kEncodingGBK                = (1 << 1),
-    kEncodingBig5               = (1 << 2),
-    kEncodingEUCKR              = (1 << 3),
-
-    kEncodingAll                = (kEncodingShiftJIS | kEncodingGBK | kEncodingBig5 | kEncodingEUCKR),
-};
-
-
-// returns a bitfield containing the possible native encodings for the given character
-extern uint32_t findPossibleEncodings(int ch);
-
-#endif // AUTODETECT_H
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 110b94c..1d6bb6f 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -21,6 +21,7 @@
 #include <binder/IServiceManager.h>
 #include <binder/IPCThreadState.h>
 #include <media/mediametadataretriever.h>
+#include <media/IMediaHTTPService.h>
 #include <media/IMediaPlayerService.h>
 #include <utils/Log.h>
 #include <dlfcn.h>
@@ -93,7 +94,9 @@
 }
 
 status_t MediaMetadataRetriever::setDataSource(
-        const char *srcUrl, const KeyedVector<String8, String8> *headers)
+        const sp<IMediaHTTPService> &httpService,
+        const char *srcUrl,
+        const KeyedVector<String8, String8> *headers)
 {
     ALOGV("setDataSource");
     Mutex::Autolock _l(mLock);
@@ -106,7 +109,7 @@
         return UNKNOWN_ERROR;
     }
     ALOGV("data source (%s)", srcUrl);
-    return mRetriever->setDataSource(srcUrl, headers);
+    return mRetriever->setDataSource(httpService, srcUrl, headers);
 }
 
 status_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
@@ -157,7 +160,7 @@
     return mRetriever->extractAlbumArt();
 }
 
-void MediaMetadataRetriever::DeathNotifier::binderDied(const wp<IBinder>& who) {
+void MediaMetadataRetriever::DeathNotifier::binderDied(const wp<IBinder>& who __unused) {
     Mutex::Autolock lock(MediaMetadataRetriever::sServiceLock);
     MediaMetadataRetriever::sService.clear();
     ALOGW("MediaMetadataRetriever server died!");
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 0f6d897..d94c7c5 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -58,7 +58,7 @@
     mVideoWidth = mVideoHeight = 0;
     mLockThreadId = 0;
     mAudioSessionId = AudioSystem::newAudioSessionId();
-    AudioSystem::acquireAudioSessionId(mAudioSessionId);
+    AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
     mSendLevel = 0;
     mRetransmitEndpointValid = false;
 }
@@ -66,7 +66,7 @@
 MediaPlayer::~MediaPlayer()
 {
     ALOGV("destructor");
-    AudioSystem::releaseAudioSessionId(mAudioSessionId);
+    AudioSystem::releaseAudioSessionId(mAudioSessionId, -1);
     disconnect();
     IPCThreadState::self()->flushCommands();
 }
@@ -136,6 +136,7 @@
 }
 
 status_t MediaPlayer::setDataSource(
+        const sp<IMediaHTTPService> &httpService,
         const char *url, const KeyedVector<String8, String8> *headers)
 {
     ALOGV("setDataSource(%s)", url);
@@ -145,7 +146,7 @@
         if (service != 0) {
             sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
             if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
-                (NO_ERROR != player->setDataSource(url, headers))) {
+                (NO_ERROR != player->setDataSource(httpService, url, headers))) {
                 player.clear();
             }
             err = attachNewPlayer(player);
@@ -575,8 +576,8 @@
         return BAD_VALUE;
     }
     if (sessionId != mAudioSessionId) {
-        AudioSystem::acquireAudioSessionId(sessionId);
-        AudioSystem::releaseAudioSessionId(mAudioSessionId);
+        AudioSystem::acquireAudioSessionId(sessionId, -1);
+        AudioSystem::releaseAudioSessionId(mAudioSessionId, -1);
         mAudioSessionId = sessionId;
     }
     return NO_ERROR;
@@ -654,7 +655,7 @@
         return BAD_VALUE;
     }
 
-    memset(&mRetransmitEndpoint, 0, sizeof(&mRetransmitEndpoint));
+    memset(&mRetransmitEndpoint, 0, sizeof(mRetransmitEndpoint));
     mRetransmitEndpoint.sin_family = AF_INET;
     mRetransmitEndpoint.sin_addr   = saddr;
     mRetransmitEndpoint.sin_port   = htons(port);
@@ -776,15 +777,20 @@
     }
 }
 
-/*static*/ status_t MediaPlayer::decode(const char* url, uint32_t *pSampleRate,
-                                           int* pNumChannels, audio_format_t* pFormat,
-                                           const sp<IMemoryHeap>& heap, size_t *pSize)
+/*static*/ status_t MediaPlayer::decode(
+        const sp<IMediaHTTPService> &httpService,
+        const char* url,
+        uint32_t *pSampleRate,
+        int* pNumChannels,
+        audio_format_t* pFormat,
+        const sp<IMemoryHeap>& heap,
+        size_t *pSize)
 {
     ALOGV("decode(%s)", url);
     status_t status;
     const sp<IMediaPlayerService>& service = getMediaPlayerService();
     if (service != 0) {
-        status = service->decode(url, pSampleRate, pNumChannels, pFormat, heap, pSize);
+        status = service->decode(httpService, url, pSampleRate, pNumChannels, pFormat, heap, pSize);
     } else {
         ALOGE("Unable to locate media service");
         status = DEAD_OBJECT;
@@ -832,15 +838,4 @@
     return mPlayer->setNextPlayer(next == NULL ? NULL : next->mPlayer);
 }
 
-status_t MediaPlayer::updateProxyConfig(
-        const char *host, int32_t port, const char *exclusionList) {
-    const sp<IMediaPlayerService>& service = getMediaPlayerService();
-
-    if (service != NULL) {
-        return service->updateProxyConfig(host, port, exclusionList);
-    }
-
-    return INVALID_OPERATION;
-}
-
 }; // namespace android
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 85c9464..caf2dfc 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -45,7 +45,6 @@
     libstagefright_rtsp         \
 
 LOCAL_C_INCLUDES :=                                                 \
-    $(call include-path-for, graphics corecg)                       \
     $(TOP)/frameworks/av/media/libstagefright/include               \
     $(TOP)/frameworks/av/media/libstagefright/rtsp                  \
     $(TOP)/frameworks/av/media/libstagefright/wifi-display          \
diff --git a/media/libmediaplayerservice/HDCP.cpp b/media/libmediaplayerservice/HDCP.cpp
index c2ac1a3..afe3936 100644
--- a/media/libmediaplayerservice/HDCP.cpp
+++ b/media/libmediaplayerservice/HDCP.cpp
@@ -107,11 +107,7 @@
         return NO_INIT;
     }
 
-    // TO-DO:
-    // Only support HDCP_CAPS_ENCRYPT (byte-array to byte-array) for now.
-    // use mHDCPModule->getCaps() when the HDCP libraries get updated.
-    //return mHDCPModule->getCaps();
-    return HDCPModule::HDCP_CAPS_ENCRYPT;
+    return mHDCPModule->getCaps();
 }
 
 status_t HDCP::encrypt(
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index a392b76..200c561 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -44,6 +44,7 @@
 #include <utils/SystemClock.h>
 #include <utils/Vector.h>
 
+#include <media/IMediaHTTPService.h>
 #include <media/IRemoteDisplay.h>
 #include <media/IRemoteDisplayClient.h>
 #include <media/MediaPlayerInterface.h>
@@ -306,11 +307,6 @@
     return new RemoteDisplay(client, iface.string());
 }
 
-status_t MediaPlayerService::updateProxyConfig(
-        const char *host, int32_t port, const char *exclusionList) {
-    return HTTPBase::UpdateProxyConfig(host, port, exclusionList);
-}
-
 status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
 {
     const size_t SIZE = 256;
@@ -590,7 +586,8 @@
     }
 
     if (!p->hardwareOutput()) {
-        mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid());
+        mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
+                mPid);
         static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
     }
 
@@ -622,7 +619,9 @@
 }
 
 status_t MediaPlayerService::Client::setDataSource(
-        const char *url, const KeyedVector<String8, String8> *headers)
+        const sp<IMediaHTTPService> &httpService,
+        const char *url,
+        const KeyedVector<String8, String8> *headers)
 {
     ALOGV("setDataSource(%s)", url);
     if (url == NULL)
@@ -657,7 +656,7 @@
             return NO_INIT;
         }
 
-        setDataSource_post(p, p->setDataSource(url, headers));
+        setDataSource_post(p, p->setDataSource(httpService, url, headers));
         return mStatus;
     }
 }
@@ -1176,9 +1175,14 @@
 }
 #endif
 
-status_t MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels,
-                                       audio_format_t* pFormat,
-                                       const sp<IMemoryHeap>& heap, size_t *pSize)
+status_t MediaPlayerService::decode(
+        const sp<IMediaHTTPService> &httpService,
+        const char* url,
+        uint32_t *pSampleRate,
+        int* pNumChannels,
+        audio_format_t* pFormat,
+        const sp<IMemoryHeap>& heap,
+        size_t *pSize)
 {
     ALOGV("decode(%s)", url);
     sp<MediaPlayerBase> player;
@@ -1206,7 +1210,7 @@
     static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache);
 
     // set data source
-    if (player->setDataSource(url) != NO_ERROR) goto Exit;
+    if (player->setDataSource(httpService, url) != NO_ERROR) goto Exit;
 
     ALOGV("prepare");
     player->prepareAsync();
@@ -1296,13 +1300,14 @@
 
 #undef LOG_TAG
 #define LOG_TAG "AudioSink"
-MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid)
+MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid)
     : mCallback(NULL),
       mCallbackCookie(NULL),
       mCallbackData(NULL),
       mBytesWritten(0),
       mSessionId(sessionId),
       mUid(uid),
+      mPid(pid),
       mFlags(AUDIO_OUTPUT_FLAG_NONE) {
     ALOGV("AudioOutput(%d)", sessionId);
     mStreamType = AUDIO_STREAM_MUSIC;
@@ -1450,7 +1455,7 @@
                 format, bufferCount, mSessionId, flags);
     uint32_t afSampleRate;
     size_t afFrameCount;
-    uint32_t frameCount;
+    size_t frameCount;
 
     // offloading is only supported in callback mode for now.
     // offloadInfo must be present if offload flag is set
@@ -1551,7 +1556,8 @@
                     mSessionId,
                     AudioTrack::TRANSFER_CALLBACK,
                     offloadInfo,
-                    mUid);
+                    mUid,
+                    mPid);
         } else {
             t = new AudioTrack(
                     mStreamType,
@@ -1566,7 +1572,8 @@
                     mSessionId,
                     AudioTrack::TRANSFER_DEFAULT,
                     NULL, // offload info
-                    mUid);
+                    mUid,
+                    mPid);
         }
 
         if ((t == 0) || (t->initCheck() != NO_ERROR)) {
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 9c084e1..448f27a 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -72,7 +72,7 @@
         class CallbackData;
 
      public:
-                                AudioOutput(int sessionId, int uid);
+                                AudioOutput(int sessionId, int uid, int pid);
         virtual                 ~AudioOutput();
 
         virtual bool            ready() const { return mTrack != 0; }
@@ -140,6 +140,7 @@
         float                   mMsecsPerFrame;
         int                     mSessionId;
         int                     mUid;
+        int                     mPid;
         float                   mSendLevel;
         int                     mAuxEffectId;
         static bool             mIsOnEmulator;
@@ -211,12 +212,12 @@
         virtual void            flush() {}
         virtual void            pause() {}
         virtual void            close() {}
-                void            setAudioStreamType(audio_stream_type_t streamType) {}
+                void            setAudioStreamType(audio_stream_type_t streamType __unused) {}
                 // stream type is not used for AudioCache
         virtual audio_stream_type_t getAudioStreamType() const { return AUDIO_STREAM_DEFAULT; }
 
-                void            setVolume(float left, float right) {}
-        virtual status_t        setPlaybackRatePermille(int32_t ratePermille) { return INVALID_OPERATION; }
+                void            setVolume(float left __unused, float right __unused) {}
+        virtual status_t        setPlaybackRatePermille(int32_t ratePermille __unused) { return INVALID_OPERATION; }
                 uint32_t        sampleRate() const { return mSampleRate; }
                 audio_format_t  format() const { return mFormat; }
                 size_t          size() const { return mSize; }
@@ -256,9 +257,15 @@
 
     virtual sp<IMediaPlayer>    create(const sp<IMediaPlayerClient>& client, int audioSessionId);
 
-    virtual status_t            decode(const char* url, uint32_t *pSampleRate, int* pNumChannels,
-                                       audio_format_t* pFormat,
-                                       const sp<IMemoryHeap>& heap, size_t *pSize);
+    virtual status_t            decode(
+            const sp<IMediaHTTPService> &httpService,
+            const char* url,
+            uint32_t *pSampleRate,
+            int* pNumChannels,
+            audio_format_t* pFormat,
+            const sp<IMemoryHeap>& heap,
+            size_t *pSize);
+
     virtual status_t            decode(int fd, int64_t offset, int64_t length,
                                        uint32_t *pSampleRate, int* pNumChannels,
                                        audio_format_t* pFormat,
@@ -272,9 +279,6 @@
             const String8& iface);
     virtual status_t            dump(int fd, const Vector<String16>& args);
 
-    virtual status_t        updateProxyConfig(
-            const char *host, int32_t port, const char *exclusionList);
-
             void                removeClient(wp<Client> client);
 
     // For battery usage tracking purpose
@@ -356,6 +360,7 @@
         sp<MediaPlayerBase>     createPlayer(player_type playerType);
 
         virtual status_t        setDataSource(
+                        const sp<IMediaHTTPService> &httpService,
                         const char *url,
                         const KeyedVector<String8, String8> *headers);
 
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 348957f..c61cf89 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -31,6 +31,7 @@
 #include <binder/MemoryHeapBase.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <media/IMediaHTTPService.h>
 #include <media/MediaMetadataRetrieverInterface.h>
 #include <media/MediaPlayerInterface.h>
 #include <private/media/VideoFrame.h>
@@ -106,7 +107,9 @@
 }
 
 status_t MetadataRetrieverClient::setDataSource(
-        const char *url, const KeyedVector<String8, String8> *headers)
+        const sp<IMediaHTTPService> &httpService,
+        const char *url,
+        const KeyedVector<String8, String8> *headers)
 {
     ALOGV("setDataSource(%s)", url);
     Mutex::Autolock lock(mLock);
@@ -127,7 +130,7 @@
     ALOGV("player type = %d", playerType);
     sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
     if (p == NULL) return NO_INIT;
-    status_t ret = p->setDataSource(url, headers);
+    status_t ret = p->setDataSource(httpService, url, headers);
     if (ret == NO_ERROR) mRetriever = p;
     return ret;
 }
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index f08f933..9d3fbe9 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -30,6 +30,7 @@
 
 namespace android {
 
+struct IMediaHTTPService;
 class IMediaPlayerService;
 class MemoryDealer;
 
@@ -43,7 +44,9 @@
     virtual void                    disconnect();
 
     virtual status_t                setDataSource(
-            const char *url, const KeyedVector<String8, String8> *headers);
+            const sp<IMediaHTTPService> &httpService,
+            const char *url,
+            const KeyedVector<String8, String8> *headers);
 
     virtual status_t                setDataSource(int fd, int64_t offset, int64_t length);
     virtual sp<IMemory>             getFrameAtTime(int64_t timeUs, int option);
diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp
index 0a6aa90..deeddd1 100644
--- a/media/libmediaplayerservice/MidiFile.cpp
+++ b/media/libmediaplayerservice/MidiFile.cpp
@@ -114,7 +114,9 @@
 }
 
 status_t MidiFile::setDataSource(
-        const char* path, const KeyedVector<String8, String8> *) {
+        const sp<IMediaHTTPService> &httpService,
+        const char* path,
+        const KeyedVector<String8, String8> *) {
     ALOGV("MidiFile::setDataSource url=%s", path);
     Mutex::Autolock lock(mMutex);
 
diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h
index 24d59b4..12802ba 100644
--- a/media/libmediaplayerservice/MidiFile.h
+++ b/media/libmediaplayerservice/MidiFile.h
@@ -32,7 +32,9 @@
     virtual status_t    initCheck();
 
     virtual status_t    setDataSource(
-            const char* path, const KeyedVector<String8, String8> *headers);
+            const sp<IMediaHTTPService> &httpService,
+            const char* path,
+            const KeyedVector<String8, String8> *headers);
 
     virtual status_t    setDataSource(int fd, int64_t offset, int64_t length);
     virtual status_t    setVideoSurfaceTexture(
diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.cpp b/media/libmediaplayerservice/MidiMetadataRetriever.cpp
index 465209f..f3cf6ef 100644
--- a/media/libmediaplayerservice/MidiMetadataRetriever.cpp
+++ b/media/libmediaplayerservice/MidiMetadataRetriever.cpp
@@ -22,6 +22,8 @@
 #include "MidiMetadataRetriever.h"
 #include <media/mediametadataretriever.h>
 
+#include <media/IMediaHTTPService.h>
+
 namespace android {
 
 static status_t ERROR_NOT_OPEN = -1;
@@ -36,7 +38,9 @@
 }
 
 status_t MidiMetadataRetriever::setDataSource(
-        const char *url, const KeyedVector<String8, String8> *headers)
+        const sp<IMediaHTTPService> &httpService,
+        const char *url,
+        const KeyedVector<String8, String8> *headers)
 {
     ALOGV("setDataSource: %s", url? url: "NULL pointer");
     Mutex::Autolock lock(mLock);
@@ -44,7 +48,7 @@
     if (mMidiPlayer == 0) {
         mMidiPlayer = new MidiFile();
     }
-    return mMidiPlayer->setDataSource(url, headers);
+    return mMidiPlayer->setDataSource(httpService, url, headers);
 }
 
 status_t MidiMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.h b/media/libmediaplayerservice/MidiMetadataRetriever.h
index 4cee42d..b8214ee 100644
--- a/media/libmediaplayerservice/MidiMetadataRetriever.h
+++ b/media/libmediaplayerservice/MidiMetadataRetriever.h
@@ -32,7 +32,9 @@
                                    ~MidiMetadataRetriever() {}
 
     virtual status_t                setDataSource(
-            const char *url, const KeyedVector<String8, String8> *headers);
+            const sp<IMediaHTTPService> &httpService,
+            const char *url,
+            const KeyedVector<String8, String8> *headers);
 
     virtual status_t                setDataSource(int fd, int64_t offset, int64_t length);
     virtual const char*             extractMetadata(int keyCode);
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index de61d9b..b37aee3 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -54,8 +54,10 @@
 }
 
 status_t StagefrightPlayer::setDataSource(
-        const char *url, const KeyedVector<String8, String8> *headers) {
-    return mPlayer->setDataSource(url, headers);
+        const sp<IMediaHTTPService> &httpService,
+        const char *url,
+        const KeyedVector<String8, String8> *headers) {
+    return mPlayer->setDataSource(httpService, url, headers);
 }
 
 // Warning: The filedescriptor passed into this method will only be valid until
@@ -187,7 +189,7 @@
 }
 
 status_t StagefrightPlayer::getMetadata(
-        const media::Metadata::Filter& ids, Parcel *records) {
+        const media::Metadata::Filter& /* ids */, Parcel *records) {
     using media::Metadata;
 
     uint32_t flags = mPlayer->flags();
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
index 600945e..e6c30ff 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -34,7 +34,9 @@
     virtual status_t setUID(uid_t uid);
 
     virtual status_t setDataSource(
-            const char *url, const KeyedVector<String8, String8> *headers);
+            const sp<IMediaHTTPService> &httpService,
+            const char *url,
+            const KeyedVector<String8, String8> *headers);
 
     virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
 
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 4da74e1..5b7a236 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -25,8 +25,10 @@
 #include <binder/IServiceManager.h>
 
 #include <media/IMediaPlayerService.h>
-#include <media/openmax/OMX_Audio.h>
+#include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/AudioSource.h>
 #include <media/stagefright/AMRWriter.h>
 #include <media/stagefright/AACWriter.h>
@@ -36,13 +38,12 @@
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaCodecSource.h>
 #include <media/stagefright/OMXClient.h>
 #include <media/stagefright/OMXCodec.h>
-#include <media/stagefright/SurfaceMediaSource.h>
 #include <media/MediaProfiles.h>
 #include <camera/ICamera.h>
 #include <camera/CameraParameters.h>
-#include <gui/Surface.h>
 
 #include <utils/Errors.h>
 #include <sys/types.h>
@@ -72,8 +73,7 @@
       mAudioSource(AUDIO_SOURCE_CNT),
       mVideoSource(VIDEO_SOURCE_LIST_END),
       mCaptureTimeLapse(false),
-      mStarted(false),
-      mSurfaceMediaSource(NULL) {
+      mStarted(false) {
 
     ALOGV("Constructor");
     reset();
@@ -82,10 +82,19 @@
 StagefrightRecorder::~StagefrightRecorder() {
     ALOGV("Destructor");
     stop();
+
+    if (mLooper != NULL) {
+        mLooper->stop();
+    }
 }
 
 status_t StagefrightRecorder::init() {
     ALOGV("init");
+
+    mLooper = new ALooper;
+    mLooper->setName("recorder_looper");
+    mLooper->start();
+
     return OK;
 }
 
@@ -94,7 +103,7 @@
 // while encoding GL Frames
 sp<IGraphicBufferProducer> StagefrightRecorder::querySurfaceMediaSource() const {
     ALOGV("Get SurfaceMediaSource");
-    return mSurfaceMediaSource->getBufferQueue();
+    return mGraphicBufferProducer;
 }
 
 status_t StagefrightRecorder::setAudioSource(audio_source_t as) {
@@ -234,7 +243,7 @@
     return OK;
 }
 
-status_t StagefrightRecorder::setOutputFile(const char *path) {
+status_t StagefrightRecorder::setOutputFile(const char * /* path */) {
     ALOGE("setOutputFile(const char*) must not be called");
     // We don't actually support this at all, as the media_server process
     // no longer has permissions to create files.
@@ -681,10 +690,10 @@
             return setParamTimeLapseEnable(timeLapseEnable);
         }
     } else if (key == "time-between-time-lapse-frame-capture") {
-        int64_t timeBetweenTimeLapseFrameCaptureMs;
-        if (safe_strtoi64(value.string(), &timeBetweenTimeLapseFrameCaptureMs)) {
+        int64_t timeBetweenTimeLapseFrameCaptureUs;
+        if (safe_strtoi64(value.string(), &timeBetweenTimeLapseFrameCaptureUs)) {
             return setParamTimeBetweenTimeLapseFrameCapture(
-                    1000LL * timeBetweenTimeLapseFrameCaptureMs);
+                    timeBetweenTimeLapseFrameCaptureUs);
         }
     } else {
         ALOGE("setParameter: failed to find key %s", key.string());
@@ -739,19 +748,15 @@
     return OK;
 }
 
-status_t StagefrightRecorder::prepare() {
-    return OK;
-}
-
-status_t StagefrightRecorder::start() {
-    CHECK_GE(mOutputFd, 0);
+status_t StagefrightRecorder::prepareInternal() {
+    ALOGV("prepare");
+    if (mOutputFd < 0) {
+        ALOGE("Output file descriptor is invalid");
+        return INVALID_OPERATION;
+    }
 
     // Get UID here for permission checking
     mClientUid = IPCThreadState::self()->getCallingUid();
-    if (mWriter != NULL) {
-        ALOGE("File writer is not avaialble");
-        return UNKNOWN_ERROR;
-    }
 
     status_t status = OK;
 
@@ -759,25 +764,25 @@
         case OUTPUT_FORMAT_DEFAULT:
         case OUTPUT_FORMAT_THREE_GPP:
         case OUTPUT_FORMAT_MPEG_4:
-            status = startMPEG4Recording();
+            status = setupMPEG4Recording();
             break;
 
         case OUTPUT_FORMAT_AMR_NB:
         case OUTPUT_FORMAT_AMR_WB:
-            status = startAMRRecording();
+            status = setupAMRRecording();
             break;
 
         case OUTPUT_FORMAT_AAC_ADIF:
         case OUTPUT_FORMAT_AAC_ADTS:
-            status = startAACRecording();
+            status = setupAACRecording();
             break;
 
         case OUTPUT_FORMAT_RTP_AVP:
-            status = startRTPRecording();
+            status = setupRTPRecording();
             break;
 
         case OUTPUT_FORMAT_MPEG2TS:
-            status = startMPEG2TSRecording();
+            status = setupMPEG2TSRecording();
             break;
 
         default:
@@ -786,6 +791,72 @@
             break;
     }
 
+    return status;
+}
+
+status_t StagefrightRecorder::prepare() {
+    if (mVideoSource == VIDEO_SOURCE_SURFACE) {
+        return prepareInternal();
+    }
+    return OK;
+}
+
+status_t StagefrightRecorder::start() {
+    ALOGV("start");
+    if (mOutputFd < 0) {
+        ALOGE("Output file descriptor is invalid");
+        return INVALID_OPERATION;
+    }
+
+    status_t status = OK;
+
+    if (mVideoSource != VIDEO_SOURCE_SURFACE) {
+        status = prepareInternal();
+        if (status != OK) {
+            return status;
+        }
+    }
+
+    if (mWriter == NULL) {
+        ALOGE("File writer is not avaialble");
+        return UNKNOWN_ERROR;
+    }
+
+    switch (mOutputFormat) {
+        case OUTPUT_FORMAT_DEFAULT:
+        case OUTPUT_FORMAT_THREE_GPP:
+        case OUTPUT_FORMAT_MPEG_4:
+        {
+            sp<MetaData> meta = new MetaData;
+            setupMPEG4MetaData(&meta);
+            status = mWriter->start(meta.get());
+            break;
+        }
+
+        case OUTPUT_FORMAT_AMR_NB:
+        case OUTPUT_FORMAT_AMR_WB:
+        case OUTPUT_FORMAT_AAC_ADIF:
+        case OUTPUT_FORMAT_AAC_ADTS:
+        case OUTPUT_FORMAT_RTP_AVP:
+        case OUTPUT_FORMAT_MPEG2TS:
+        {
+            status = mWriter->start();
+            break;
+        }
+
+        default:
+        {
+            ALOGE("Unsupported output file format: %d", mOutputFormat);
+            status = UNKNOWN_ERROR;
+            break;
+        }
+    }
+
+    if (status != OK) {
+        mWriter.clear();
+        mWriter = NULL;
+    }
+
     if ((status == OK) && (!mStarted)) {
         mStarted = true;
 
@@ -817,58 +888,54 @@
         return NULL;
     }
 
-    sp<MetaData> encMeta = new MetaData;
+    sp<AMessage> format = new AMessage;
     const char *mime;
     switch (mAudioEncoder) {
         case AUDIO_ENCODER_AMR_NB:
         case AUDIO_ENCODER_DEFAULT:
-            mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
+            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_NB);
             break;
         case AUDIO_ENCODER_AMR_WB:
-            mime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
+            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_WB);
             break;
         case AUDIO_ENCODER_AAC:
-            mime = MEDIA_MIMETYPE_AUDIO_AAC;
-            encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectLC);
+            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
+            format->setInt32("aac-profile", OMX_AUDIO_AACObjectLC);
             break;
         case AUDIO_ENCODER_HE_AAC:
-            mime = MEDIA_MIMETYPE_AUDIO_AAC;
-            encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectHE);
+            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
+            format->setInt32("aac-profile", OMX_AUDIO_AACObjectHE);
             break;
         case AUDIO_ENCODER_AAC_ELD:
-            mime = MEDIA_MIMETYPE_AUDIO_AAC;
-            encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectELD);
+            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
+            format->setInt32("aac-profile", OMX_AUDIO_AACObjectELD);
             break;
 
         default:
             ALOGE("Unknown audio encoder: %d", mAudioEncoder);
             return NULL;
     }
-    encMeta->setCString(kKeyMIMEType, mime);
 
     int32_t maxInputSize;
     CHECK(audioSource->getFormat()->findInt32(
                 kKeyMaxInputSize, &maxInputSize));
 
-    encMeta->setInt32(kKeyMaxInputSize, maxInputSize);
-    encMeta->setInt32(kKeyChannelCount, mAudioChannels);
-    encMeta->setInt32(kKeySampleRate, mSampleRate);
-    encMeta->setInt32(kKeyBitRate, mAudioBitRate);
+    format->setInt32("max-input-size", maxInputSize);
+    format->setInt32("channel-count", mAudioChannels);
+    format->setInt32("sample-rate", mSampleRate);
+    format->setInt32("bitrate", mAudioBitRate);
     if (mAudioTimeScale > 0) {
-        encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
+        format->setInt32("time-scale", mAudioTimeScale);
     }
 
-    OMXClient client;
-    CHECK_EQ(client.connect(), (status_t)OK);
     sp<MediaSource> audioEncoder =
-        OMXCodec::Create(client.interface(), encMeta,
-                         true /* createEncoder */, audioSource);
+            MediaCodecSource::Create(mLooper, format, audioSource);
     mAudioSourceNode = audioSource;
 
     return audioEncoder;
 }
 
-status_t StagefrightRecorder::startAACRecording() {
+status_t StagefrightRecorder::setupAACRecording() {
     // FIXME:
     // Add support for OUTPUT_FORMAT_AAC_ADIF
     CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_AAC_ADTS);
@@ -879,16 +946,10 @@
     CHECK(mAudioSource != AUDIO_SOURCE_CNT);
 
     mWriter = new AACWriter(mOutputFd);
-    status_t status = startRawAudioRecording();
-    if (status != OK) {
-        mWriter.clear();
-        mWriter = NULL;
-    }
-
-    return status;
+    return setupRawAudioRecording();
 }
 
-status_t StagefrightRecorder::startAMRRecording() {
+status_t StagefrightRecorder::setupAMRRecording() {
     CHECK(mOutputFormat == OUTPUT_FORMAT_AMR_NB ||
           mOutputFormat == OUTPUT_FORMAT_AMR_WB);
 
@@ -908,15 +969,10 @@
     }
 
     mWriter = new AMRWriter(mOutputFd);
-    status_t status = startRawAudioRecording();
-    if (status != OK) {
-        mWriter.clear();
-        mWriter = NULL;
-    }
-    return status;
+    return setupRawAudioRecording();
 }
 
-status_t StagefrightRecorder::startRawAudioRecording() {
+status_t StagefrightRecorder::setupRawAudioRecording() {
     if (mAudioSource >= AUDIO_SOURCE_CNT) {
         ALOGE("Invalid audio source: %d", mAudioSource);
         return BAD_VALUE;
@@ -942,12 +998,11 @@
         mWriter->setMaxFileSize(mMaxFileSizeBytes);
     }
     mWriter->setListener(mListener);
-    mWriter->start();
 
     return OK;
 }
 
-status_t StagefrightRecorder::startRTPRecording() {
+status_t StagefrightRecorder::setupRTPRecording() {
     CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_RTP_AVP);
 
     if ((mAudioSource != AUDIO_SOURCE_CNT
@@ -974,7 +1029,7 @@
             return err;
         }
 
-        err = setupVideoEncoder(mediaSource, mVideoBitRate, &source);
+        err = setupVideoEncoder(mediaSource, &source);
         if (err != OK) {
             return err;
         }
@@ -984,10 +1039,10 @@
     mWriter->addSource(source);
     mWriter->setListener(mListener);
 
-    return mWriter->start();
+    return OK;
 }
 
-status_t StagefrightRecorder::startMPEG2TSRecording() {
+status_t StagefrightRecorder::setupMPEG2TSRecording() {
     CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_MPEG2TS);
 
     sp<MediaWriter> writer = new MPEG2TSWriter(mOutputFd);
@@ -1018,7 +1073,7 @@
         }
 
         sp<MediaSource> encoder;
-        err = setupVideoEncoder(mediaSource, mVideoBitRate, &encoder);
+        err = setupVideoEncoder(mediaSource, &encoder);
 
         if (err != OK) {
             return err;
@@ -1037,7 +1092,7 @@
 
     mWriter = writer;
 
-    return mWriter->start();
+    return OK;
 }
 
 void StagefrightRecorder::clipVideoFrameRate() {
@@ -1278,49 +1333,14 @@
             return err;
         }
         *mediaSource = cameraSource;
-    } else if (mVideoSource == VIDEO_SOURCE_GRALLOC_BUFFER) {
-        // If using GRAlloc buffers, setup surfacemediasource.
-        // Later a handle to that will be passed
-        // to the client side when queried
-        status_t err = setupSurfaceMediaSource();
-        if (err != OK) {
-            return err;
-        }
-        *mediaSource = mSurfaceMediaSource;
+    } else if (mVideoSource == VIDEO_SOURCE_SURFACE) {
+        *mediaSource = NULL;
     } else {
         return INVALID_OPERATION;
     }
     return OK;
 }
 
-// setupSurfaceMediaSource creates a source with the given
-// width and height and framerate.
-// TODO: This could go in a static function inside SurfaceMediaSource
-// similar to that in CameraSource
-status_t StagefrightRecorder::setupSurfaceMediaSource() {
-    status_t err = OK;
-    mSurfaceMediaSource = new SurfaceMediaSource(mVideoWidth, mVideoHeight);
-    if (mSurfaceMediaSource == NULL) {
-        return NO_INIT;
-    }
-
-    if (mFrameRate == -1) {
-        int32_t frameRate = 0;
-        CHECK (mSurfaceMediaSource->getFormat()->findInt32(
-                                        kKeyFrameRate, &frameRate));
-        ALOGI("Frame rate is not explicitly set. Use the current frame "
-             "rate (%d fps)", frameRate);
-        mFrameRate = frameRate;
-    } else {
-        err = mSurfaceMediaSource->setFrameRate(mFrameRate);
-    }
-    CHECK(mFrameRate != -1);
-
-    mIsMetaDataStoredInVideoBuffers =
-        mSurfaceMediaSource->isMetaDataStoredInVideoBuffers();
-    return err;
-}
-
 status_t StagefrightRecorder::setupCameraSource(
         sp<CameraSource> *cameraSource) {
     status_t err = OK;
@@ -1384,25 +1404,22 @@
 
 status_t StagefrightRecorder::setupVideoEncoder(
         sp<MediaSource> cameraSource,
-        int32_t videoBitRate,
         sp<MediaSource> *source) {
     source->clear();
 
-    sp<MetaData> enc_meta = new MetaData;
-    enc_meta->setInt32(kKeyBitRate, videoBitRate);
-    enc_meta->setInt32(kKeyFrameRate, mFrameRate);
+    sp<AMessage> format = new AMessage();
 
     switch (mVideoEncoder) {
         case VIDEO_ENCODER_H263:
-            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
+            format->setString("mime", MEDIA_MIMETYPE_VIDEO_H263);
             break;
 
         case VIDEO_ENCODER_MPEG_4_SP:
-            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+            format->setString("mime", MEDIA_MIMETYPE_VIDEO_MPEG4);
             break;
 
         case VIDEO_ENCODER_H264:
-            enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+            format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
             break;
 
         default:
@@ -1410,59 +1427,80 @@
             break;
     }
 
-    sp<MetaData> meta = cameraSource->getFormat();
+    if (cameraSource != NULL) {
+        sp<MetaData> meta = cameraSource->getFormat();
 
-    int32_t width, height, stride, sliceHeight, colorFormat;
-    CHECK(meta->findInt32(kKeyWidth, &width));
-    CHECK(meta->findInt32(kKeyHeight, &height));
-    CHECK(meta->findInt32(kKeyStride, &stride));
-    CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
-    CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
+        int32_t width, height, stride, sliceHeight, colorFormat;
+        CHECK(meta->findInt32(kKeyWidth, &width));
+        CHECK(meta->findInt32(kKeyHeight, &height));
+        CHECK(meta->findInt32(kKeyStride, &stride));
+        CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
+        CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
 
-    enc_meta->setInt32(kKeyWidth, width);
-    enc_meta->setInt32(kKeyHeight, height);
-    enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec);
-    enc_meta->setInt32(kKeyStride, stride);
-    enc_meta->setInt32(kKeySliceHeight, sliceHeight);
-    enc_meta->setInt32(kKeyColorFormat, colorFormat);
+        format->setInt32("width", width);
+        format->setInt32("height", height);
+        format->setInt32("stride", stride);
+        format->setInt32("slice-height", sliceHeight);
+        format->setInt32("color-format", colorFormat);
+    } else {
+        format->setInt32("width", mVideoWidth);
+        format->setInt32("height", mVideoHeight);
+        format->setInt32("stride", mVideoWidth);
+        format->setInt32("slice-height", mVideoWidth);
+        format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
+
+        // set up time lapse/slow motion for surface source
+        if (mCaptureTimeLapse) {
+            if (mTimeBetweenTimeLapseFrameCaptureUs <= 0) {
+                ALOGE("Invalid mTimeBetweenTimeLapseFrameCaptureUs value: %lld",
+                    mTimeBetweenTimeLapseFrameCaptureUs);
+                return BAD_VALUE;
+            }
+            format->setInt64("time-lapse",
+                    mTimeBetweenTimeLapseFrameCaptureUs);
+        }
+    }
+
+    format->setInt32("bitrate", mVideoBitRate);
+    format->setInt32("frame-rate", mFrameRate);
+    format->setInt32("i-frame-interval", mIFramesIntervalSec);
+
     if (mVideoTimeScale > 0) {
-        enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
+        format->setInt32("time-scale", mVideoTimeScale);
     }
     if (mVideoEncoderProfile != -1) {
-        enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
+        format->setInt32("profile", mVideoEncoderProfile);
     }
     if (mVideoEncoderLevel != -1) {
-        enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel);
+        format->setInt32("level", mVideoEncoderLevel);
     }
 
-    OMXClient client;
-    CHECK_EQ(client.connect(), (status_t)OK);
-
-    uint32_t encoder_flags = 0;
+    uint32_t flags = 0;
     if (mIsMetaDataStoredInVideoBuffers) {
-        encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers;
+        flags |= MediaCodecSource::FLAG_USE_METADATA_INPUT;
     }
 
-    // Do not wait for all the input buffers to become available.
-    // This give timelapse video recording faster response in
-    // receiving output from video encoder component.
-    if (mCaptureTimeLapse) {
-        encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime;
+    if (cameraSource == NULL) {
+        flags |= MediaCodecSource::FLAG_USE_SURFACE_INPUT;
     }
 
-    sp<MediaSource> encoder = OMXCodec::Create(
-            client.interface(), enc_meta,
-            true /* createEncoder */, cameraSource,
-            NULL, encoder_flags);
+    sp<MediaCodecSource> encoder =
+            MediaCodecSource::Create(mLooper, format, cameraSource, flags);
     if (encoder == NULL) {
         ALOGW("Failed to create the encoder");
         // When the encoder fails to be created, we need
         // release the camera source due to the camera's lock
         // and unlock mechanism.
-        cameraSource->stop();
+        if (cameraSource != NULL) {
+            cameraSource->stop();
+        }
         return UNKNOWN_ERROR;
     }
 
+    if (cameraSource == NULL) {
+        mGraphicBufferProducer = encoder->getGraphicBufferProducer();
+    }
+
     *source = encoder;
 
     return OK;
@@ -1496,16 +1534,12 @@
     return OK;
 }
 
-status_t StagefrightRecorder::setupMPEG4Recording(
-        int outputFd,
-        int32_t videoWidth, int32_t videoHeight,
-        int32_t videoBitRate,
-        int32_t *totalBitRate,
-        sp<MediaWriter> *mediaWriter) {
-    mediaWriter->clear();
-    *totalBitRate = 0;
+status_t StagefrightRecorder::setupMPEG4Recording() {
+    mWriter.clear();
+    mTotalBitRate = 0;
+
     status_t err = OK;
-    sp<MediaWriter> writer = new MPEG4Writer(outputFd);
+    sp<MediaWriter> writer = new MPEG4Writer(mOutputFd);
 
     if (mVideoSource < VIDEO_SOURCE_LIST_END) {
 
@@ -1516,13 +1550,13 @@
         }
 
         sp<MediaSource> encoder;
-        err = setupVideoEncoder(mediaSource, videoBitRate, &encoder);
+        err = setupVideoEncoder(mediaSource, &encoder);
         if (err != OK) {
             return err;
         }
 
         writer->addSource(encoder);
-        *totalBitRate += videoBitRate;
+        mTotalBitRate += mVideoBitRate;
     }
 
     // Audio source is added at the end if it exists.
@@ -1531,7 +1565,7 @@
     if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_CNT)) {
         err = setupAudioEncoder(writer);
         if (err != OK) return err;
-        *totalBitRate += mAudioBitRate;
+        mTotalBitRate += mAudioBitRate;
     }
 
     if (mInterleaveDurationUs > 0) {
@@ -1549,22 +1583,28 @@
         writer->setMaxFileSize(mMaxFileSizeBytes);
     }
 
-    mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId);
+    if (mVideoSource == VIDEO_SOURCE_DEFAULT
+            || mVideoSource == VIDEO_SOURCE_CAMERA) {
+        mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId);
+    } else if (mVideoSource == VIDEO_SOURCE_SURFACE) {
+        // surface source doesn't need large initial delay
+        mStartTimeOffsetMs = 200;
+    }
     if (mStartTimeOffsetMs > 0) {
         reinterpret_cast<MPEG4Writer *>(writer.get())->
             setStartTimeOffsetMs(mStartTimeOffsetMs);
     }
 
     writer->setListener(mListener);
-    *mediaWriter = writer;
+    mWriter = writer;
     return OK;
 }
 
-void StagefrightRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
-        sp<MetaData> *meta) {
+void StagefrightRecorder::setupMPEG4MetaData(sp<MetaData> *meta) {
+    int64_t startTimeUs = systemTime() / 1000;
     (*meta)->setInt64(kKeyTime, startTimeUs);
     (*meta)->setInt32(kKeyFileType, mOutputFormat);
-    (*meta)->setInt32(kKeyBitRate, totalBitRate);
+    (*meta)->setInt32(kKeyBitRate, mTotalBitRate);
     (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
     if (mMovieTimeScale > 0) {
         (*meta)->setInt32(kKeyTimeScale, mMovieTimeScale);
@@ -1577,27 +1617,6 @@
     }
 }
 
-status_t StagefrightRecorder::startMPEG4Recording() {
-    int32_t totalBitRate;
-    status_t err = setupMPEG4Recording(
-            mOutputFd, mVideoWidth, mVideoHeight,
-            mVideoBitRate, &totalBitRate, &mWriter);
-    if (err != OK) {
-        return err;
-    }
-
-    int64_t startTimeUs = systemTime() / 1000;
-    sp<MetaData> meta = new MetaData;
-    setupMPEG4MetaData(startTimeUs, totalBitRate, &meta);
-
-    err = mWriter->start(meta.get());
-    if (err != OK) {
-        return err;
-    }
-
-    return OK;
-}
-
 status_t StagefrightRecorder::pause() {
     ALOGV("pause");
     if (mWriter == NULL) {
@@ -1637,6 +1656,8 @@
         mWriter.clear();
     }
 
+    mGraphicBufferProducer.clear();
+
     if (mOutputFd >= 0) {
         ::close(mOutputFd);
         mOutputFd = -1;
@@ -1656,7 +1677,6 @@
         addBatteryData(params);
     }
 
-
     return err;
 }
 
@@ -1708,6 +1728,7 @@
     mRotationDegrees = 0;
     mLatitudex10000 = -3600000;
     mLongitudex10000 = -3600000;
+    mTotalBitRate = 0;
 
     mOutputFd = -1;
 
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 31f09e0..377d168 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -37,6 +37,7 @@
 class MediaProfiles;
 class IGraphicBufferProducer;
 class SurfaceMediaSource;
+class ALooper;
 
 struct StagefrightRecorder : public MediaRecorderBase {
     StagefrightRecorder();
@@ -106,6 +107,7 @@
     int32_t mLatitudex10000;
     int32_t mLongitudex10000;
     int32_t mStartTimeOffsetMs;
+    int32_t mTotalBitRate;
 
     bool mCaptureTimeLapse;
     int64_t mTimeBetweenTimeLapseFrameCaptureUs;
@@ -122,22 +124,17 @@
     // An <IGraphicBufferProducer> pointer
     // will be sent to the client side using which the
     // frame buffers will be queued and dequeued
-    sp<SurfaceMediaSource> mSurfaceMediaSource;
+    sp<IGraphicBufferProducer> mGraphicBufferProducer;
+    sp<ALooper> mLooper;
 
-    status_t setupMPEG4Recording(
-        int outputFd,
-        int32_t videoWidth, int32_t videoHeight,
-        int32_t videoBitRate,
-        int32_t *totalBitRate,
-        sp<MediaWriter> *mediaWriter);
-    void setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate,
-        sp<MetaData> *meta);
-    status_t startMPEG4Recording();
-    status_t startAMRRecording();
-    status_t startAACRecording();
-    status_t startRawAudioRecording();
-    status_t startRTPRecording();
-    status_t startMPEG2TSRecording();
+    status_t prepareInternal();
+    status_t setupMPEG4Recording();
+    void setupMPEG4MetaData(sp<MetaData> *meta);
+    status_t setupAMRRecording();
+    status_t setupAACRecording();
+    status_t setupRawAudioRecording();
+    status_t setupRTPRecording();
+    status_t setupMPEG2TSRecording();
     sp<MediaSource> createAudioSource();
     status_t checkVideoEncoderCapabilities(
             bool *supportsCameraSourceMetaDataMode);
@@ -147,14 +144,8 @@
     // depending on the videosource type
     status_t setupMediaSource(sp<MediaSource> *mediaSource);
     status_t setupCameraSource(sp<CameraSource> *cameraSource);
-    // setup the surfacemediasource for the encoder
-    status_t setupSurfaceMediaSource();
-
     status_t setupAudioEncoder(const sp<MediaWriter>& writer);
-    status_t setupVideoEncoder(
-            sp<MediaSource> cameraSource,
-            int32_t videoBitRate,
-            sp<MediaSource> *source);
+    status_t setupVideoEncoder(sp<MediaSource> cameraSource, sp<MediaSource> *source);
 
     // Encoding parameter handling utilities
     status_t setParameter(const String8 &key, const String8 &value);
diff --git a/media/libmediaplayerservice/TestPlayerStub.cpp b/media/libmediaplayerservice/TestPlayerStub.cpp
index 5d9728a..5795773 100644
--- a/media/libmediaplayerservice/TestPlayerStub.cpp
+++ b/media/libmediaplayerservice/TestPlayerStub.cpp
@@ -113,7 +113,9 @@
 // Create the test player.
 // Call setDataSource on the test player with the url in param.
 status_t TestPlayerStub::setDataSource(
-        const char *url, const KeyedVector<String8, String8> *headers) {
+        const sp<IMediaHTTPService> &httpService,
+        const char *url,
+        const KeyedVector<String8, String8> *headers) {
     if (!isTestUrl(url) || NULL != mHandle) {
         return INVALID_OPERATION;
     }
@@ -162,7 +164,7 @@
     }
 
     mPlayer = (*mNewPlayer)();
-    return mPlayer->setDataSource(mContentUrl, headers);
+    return mPlayer->setDataSource(httpService, mContentUrl, headers);
 }
 
 // Internal cleanup.
diff --git a/media/libmediaplayerservice/TestPlayerStub.h b/media/libmediaplayerservice/TestPlayerStub.h
index a3802eb..55bf2c8 100644
--- a/media/libmediaplayerservice/TestPlayerStub.h
+++ b/media/libmediaplayerservice/TestPlayerStub.h
@@ -66,7 +66,9 @@
 
     // @param url Should be a test url. See class comment.
     virtual status_t setDataSource(
-            const char* url, const KeyedVector<String8, String8> *headers);
+            const sp<IMediaHTTPService> &httpService,
+            const char* url,
+            const KeyedVector<String8, String8> *headers);
 
     // Test player for a file descriptor source is not supported.
     virtual status_t setDataSource(int, int64_t, int64_t)  {
diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk
index f946c1c..f97ba57 100644
--- a/media/libmediaplayerservice/nuplayer/Android.mk
+++ b/media/libmediaplayerservice/nuplayer/Android.mk
@@ -11,7 +11,6 @@
         NuPlayerStreamListener.cpp      \
         RTSPSource.cpp                  \
         StreamingSource.cpp             \
-        mp4/MP4Source.cpp               \
 
 LOCAL_C_INCLUDES := \
 	$(TOP)/frameworks/av/media/libstagefright/httplive            \
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index b04e7a6..06aac33 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -33,17 +33,16 @@
 
 NuPlayer::GenericSource::GenericSource(
         const sp<AMessage> &notify,
+        const sp<IMediaHTTPService> &httpService,
         const char *url,
-        const KeyedVector<String8, String8> *headers,
-        bool uidValid,
-        uid_t uid)
+        const KeyedVector<String8, String8> *headers)
     : Source(notify),
       mDurationUs(0ll),
       mAudioIsVorbis(false) {
     DataSource::RegisterDefaultSniffers();
 
     sp<DataSource> dataSource =
-        DataSource::CreateFromURI(url, headers);
+        DataSource::CreateFromURI(httpService, url, headers);
     CHECK(dataSource != NULL);
 
     initFromDataSource(dataSource);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 2da680c..20d597e 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -33,10 +33,9 @@
 struct NuPlayer::GenericSource : public NuPlayer::Source {
     GenericSource(
             const sp<AMessage> &notify,
+            const sp<IMediaHTTPService> &httpService,
             const char *url,
-            const KeyedVector<String8, String8> *headers,
-            bool uidValid = false,
-            uid_t uid = 0);
+            const KeyedVector<String8, String8> *headers);
 
     GenericSource(
             const sp<AMessage> &notify,
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index f1782cc..cbedf5c 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -24,6 +24,7 @@
 #include "LiveDataSource.h"
 #include "LiveSession.h"
 
+#include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -34,13 +35,12 @@
 
 NuPlayer::HTTPLiveSource::HTTPLiveSource(
         const sp<AMessage> &notify,
+        const sp<IMediaHTTPService> &httpService,
         const char *url,
-        const KeyedVector<String8, String8> *headers,
-        bool uidValid, uid_t uid)
+        const KeyedVector<String8, String8> *headers)
     : Source(notify),
+      mHTTPService(httpService),
       mURL(url),
-      mUIDValid(uidValid),
-      mUID(uid),
       mFlags(0),
       mFinalResult(OK),
       mOffset(0),
@@ -79,8 +79,7 @@
     mLiveSession = new LiveSession(
             notify,
             (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
-            mUIDValid,
-            mUID);
+            mHTTPService);
 
     mLiveLooper->registerHandler(mLiveSession);
 
@@ -140,7 +139,7 @@
     // LiveSession::selectTrack returns BAD_VALUE when selecting the currently
     // selected track, or unselecting a non-selected track. In this case it's an
     // no-op so we return OK.
-    return (err == OK || err == BAD_VALUE) ? OK : err;
+    return (err == OK || err == BAD_VALUE) ? (status_t)OK : err;
 }
 
 status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) {
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index bcc3f8b..4d7251f 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -28,10 +28,9 @@
 struct NuPlayer::HTTPLiveSource : public NuPlayer::Source {
     HTTPLiveSource(
             const sp<AMessage> &notify,
+            const sp<IMediaHTTPService> &httpService,
             const char *url,
-            const KeyedVector<String8, String8> *headers,
-            bool uidValid = false,
-            uid_t uid = 0);
+            const KeyedVector<String8, String8> *headers);
 
     virtual void prepareAsync();
     virtual void start();
@@ -61,10 +60,9 @@
         kWhatFetchSubtitleData,
     };
 
+    sp<IMediaHTTPService> mHTTPService;
     AString mURL;
     KeyedVector<String8, String8> mExtraHeaders;
-    bool mUIDValid;
-    uid_t mUID;
     uint32_t mFlags;
     status_t mFinalResult;
     off64_t mOffset;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 25d55a3..d8d939a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -28,18 +28,13 @@
 #include "RTSPSource.h"
 #include "StreamingSource.h"
 #include "GenericSource.h"
-#include "mp4/MP4Source.h"
 
 #include "ATSParser.h"
 
-#include "SoftwareRenderer.h"
-
-#include <cutils/properties.h> // for property_get
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/ACodec.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
@@ -148,7 +143,6 @@
     : mUIDValid(false),
       mSourceFlags(0),
       mVideoIsAVC(false),
-      mNeedsSwRenderer(false),
       mAudioEOS(false),
       mVideoEOS(false),
       mScanSourcesPending(false),
@@ -183,14 +177,7 @@
 
     sp<AMessage> notify = new AMessage(kWhatSourceNotify, id());
 
-    char prop[PROPERTY_VALUE_MAX];
-    if (property_get("media.stagefright.use-mp4source", prop, NULL)
-            && (!strcmp(prop, "1") || !strcasecmp(prop, "true"))) {
-        msg->setObject("source", new MP4Source(notify, source));
-    } else {
-        msg->setObject("source", new StreamingSource(notify, source));
-    }
-
+    msg->setObject("source", new StreamingSource(notify, source));
     msg->post();
 }
 
@@ -212,7 +199,9 @@
 }
 
 void NuPlayer::setDataSourceAsync(
-        const char *url, const KeyedVector<String8, String8> *headers) {
+        const sp<IMediaHTTPService> &httpService,
+        const char *url,
+        const KeyedVector<String8, String8> *headers) {
     sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
     size_t len = strlen(url);
 
@@ -220,16 +209,18 @@
 
     sp<Source> source;
     if (IsHTTPLiveURL(url)) {
-        source = new HTTPLiveSource(notify, url, headers, mUIDValid, mUID);
+        source = new HTTPLiveSource(notify, httpService, url, headers);
     } else if (!strncasecmp(url, "rtsp://", 7)) {
-        source = new RTSPSource(notify, url, headers, mUIDValid, mUID);
+        source = new RTSPSource(
+                notify, httpService, url, headers, mUIDValid, mUID);
     } else if ((!strncasecmp(url, "http://", 7)
                 || !strncasecmp(url, "https://", 8))
                     && ((len >= 4 && !strcasecmp(".sdp", &url[len - 4]))
                     || strstr(url, ".sdp?"))) {
-        source = new RTSPSource(notify, url, headers, mUIDValid, mUID, true);
+        source = new RTSPSource(
+                notify, httpService, url, headers, mUIDValid, mUID, true);
     } else {
-        source = new GenericSource(notify, url, headers, mUIDValid, mUID);
+        source = new GenericSource(notify, httpService, url, headers);
     }
 
     msg->setObject("source", source);
@@ -447,7 +438,6 @@
             ALOGV("kWhatStart");
 
             mVideoIsAVC = false;
-            mNeedsSwRenderer = false;
             mAudioEOS = false;
             mVideoEOS = false;
             mSkipRenderingAudioUntilMediaTimeUs = -1;
@@ -538,24 +528,21 @@
         {
             bool audio = msg->what() == kWhatAudioNotify;
 
-            sp<AMessage> codecRequest;
-            CHECK(msg->findMessage("codec-request", &codecRequest));
-
             int32_t what;
-            CHECK(codecRequest->findInt32("what", &what));
+            CHECK(msg->findInt32("what", &what));
 
-            if (what == ACodec::kWhatFillThisBuffer) {
+            if (what == Decoder::kWhatFillThisBuffer) {
                 status_t err = feedDecoderInputData(
-                        audio, codecRequest);
+                        audio, msg);
 
                 if (err == -EWOULDBLOCK) {
                     if (mSource->feedMoreTSData() == OK) {
                         msg->post(10000ll);
                     }
                 }
-            } else if (what == ACodec::kWhatEOS) {
+            } else if (what == Decoder::kWhatEOS) {
                 int32_t err;
-                CHECK(codecRequest->findInt32("err", &err));
+                CHECK(msg->findInt32("err", &err));
 
                 if (err == ERROR_END_OF_STREAM) {
                     ALOGV("got %s decoder EOS", audio ? "audio" : "video");
@@ -566,7 +553,7 @@
                 }
 
                 mRenderer->queueEOS(audio, err);
-            } else if (what == ACodec::kWhatFlushCompleted) {
+            } else if (what == Decoder::kWhatFlushCompleted) {
                 bool needShutdown;
 
                 if (audio) {
@@ -595,14 +582,17 @@
                 }
 
                 finishFlushIfPossible();
-            } else if (what == ACodec::kWhatOutputFormatChanged) {
+            } else if (what == Decoder::kWhatOutputFormatChanged) {
+                sp<AMessage> format;
+                CHECK(msg->findMessage("format", &format));
+
                 if (audio) {
                     int32_t numChannels;
-                    CHECK(codecRequest->findInt32(
+                    CHECK(format->findInt32(
                                 "channel-count", &numChannels));
 
                     int32_t sampleRate;
-                    CHECK(codecRequest->findInt32("sample-rate", &sampleRate));
+                    CHECK(format->findInt32("sample-rate", &sampleRate));
 
                     ALOGV("Audio output format changed to %d Hz, %d channels",
                          sampleRate, numChannels);
@@ -626,7 +616,7 @@
                     }
 
                     int32_t channelMask;
-                    if (!codecRequest->findInt32("channel-mask", &channelMask)) {
+                    if (!format->findInt32("channel-mask", &channelMask)) {
                         channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
                     }
 
@@ -647,11 +637,11 @@
                     // video
 
                     int32_t width, height;
-                    CHECK(codecRequest->findInt32("width", &width));
-                    CHECK(codecRequest->findInt32("height", &height));
+                    CHECK(format->findInt32("width", &width));
+                    CHECK(format->findInt32("height", &height));
 
                     int32_t cropLeft, cropTop, cropRight, cropBottom;
-                    CHECK(codecRequest->findRect(
+                    CHECK(format->findRect(
                                 "crop",
                                 &cropLeft, &cropTop, &cropRight, &cropBottom));
 
@@ -684,22 +674,8 @@
 
                     notifyListener(
                             MEDIA_SET_VIDEO_SIZE, displayWidth, displayHeight);
-
-                    if (mNeedsSwRenderer && mNativeWindow != NULL) {
-                        int32_t colorFormat;
-                        CHECK(codecRequest->findInt32("color-format", &colorFormat));
-
-                        sp<MetaData> meta = new MetaData;
-                        meta->setInt32(kKeyWidth, width);
-                        meta->setInt32(kKeyHeight, height);
-                        meta->setRect(kKeyCropRect, cropLeft, cropTop, cropRight, cropBottom);
-                        meta->setInt32(kKeyColorFormat, colorFormat);
-
-                        mRenderer->setSoftRenderer(
-                                new SoftwareRenderer(mNativeWindow->getNativeWindow(), meta));
-                    }
                 }
-            } else if (what == ACodec::kWhatShutdownCompleted) {
+            } else if (what == Decoder::kWhatShutdownCompleted) {
                 ALOGV("%s shutdown completed", audio ? "audio" : "video");
                 if (audio) {
                     mAudioDecoder.clear();
@@ -714,22 +690,15 @@
                 }
 
                 finishFlushIfPossible();
-            } else if (what == ACodec::kWhatError) {
+            } else if (what == Decoder::kWhatError) {
                 ALOGE("Received error from %s decoder, aborting playback.",
                      audio ? "audio" : "video");
 
                 mRenderer->queueEOS(audio, UNKNOWN_ERROR);
-            } else if (what == ACodec::kWhatDrainThisBuffer) {
-                renderBuffer(audio, codecRequest);
-            } else if (what == ACodec::kWhatComponentAllocated) {
-                if (!audio) {
-                    AString name;
-                    CHECK(codecRequest->findString("componentName", &name));
-                    mNeedsSwRenderer = name.startsWith("OMX.google.");
-                }
-            } else if (what != ACodec::kWhatComponentConfigured
-                    && what != ACodec::kWhatBuffersAllocated) {
-                ALOGV("Unhandled codec notification %d '%c%c%c%c'.",
+            } else if (what == Decoder::kWhatDrainThisBuffer) {
+                renderBuffer(audio, msg);
+            } else {
+                ALOGV("Unhandled decoder notification %d '%c%c%c%c'.",
                       what,
                       what >> 24,
                       (what >> 16) & 0xff,
@@ -930,8 +899,7 @@
 
     *decoder = audio ? new Decoder(notify) :
                        new Decoder(notify, mNativeWindow);
-    looper()->registerHandler(*decoder);
-
+    (*decoder)->init();
     (*decoder)->configure(format);
 
     return OK;
@@ -1531,7 +1499,7 @@
     notify->post();
 }
 
-void NuPlayer::Source::onMessageReceived(const sp<AMessage> &msg) {
+void NuPlayer::Source::onMessageReceived(const sp<AMessage> & /* msg */) {
     TRESPASS();
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 590e1f2..f1d3d55 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -24,7 +24,6 @@
 
 namespace android {
 
-struct ACodec;
 struct MetaData;
 struct NuPlayerDriver;
 
@@ -38,7 +37,9 @@
     void setDataSourceAsync(const sp<IStreamSource> &source);
 
     void setDataSourceAsync(
-            const char *url, const KeyedVector<String8, String8> *headers);
+            const sp<IMediaHTTPService> &httpService,
+            const char *url,
+            const KeyedVector<String8, String8> *headers);
 
     void setDataSourceAsync(int fd, int64_t offset, int64_t length);
 
@@ -116,7 +117,6 @@
     sp<MediaPlayerBase::AudioSink> mAudioSink;
     sp<Decoder> mVideoDecoder;
     bool mVideoIsAVC;
-    bool mNeedsSwRenderer;
     sp<Decoder> mAudioDecoder;
     sp<Renderer> mRenderer;
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 2423fd5..469c9ca 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -17,14 +17,17 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "NuPlayerDecoder"
 #include <utils/Log.h>
+#include <inttypes.h>
 
 #include "NuPlayerDecoder.h"
 
+#include <media/ICrypto.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/ACodec.h>
+#include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
 
 namespace android {
 
@@ -32,70 +35,404 @@
         const sp<AMessage> &notify,
         const sp<NativeWindowWrapper> &nativeWindow)
     : mNotify(notify),
-      mNativeWindow(nativeWindow) {
+      mNativeWindow(nativeWindow),
+      mBufferGeneration(0),
+      mComponentName("decoder") {
+    // Every decoder has its own looper because MediaCodec operations
+    // are blocking, but NuPlayer needs asynchronous operations.
+    mDecoderLooper = new ALooper;
+    mDecoderLooper->setName("NuPlayerDecoder");
+    mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
+
+    mCodecLooper = new ALooper;
+    mCodecLooper->setName("NuPlayerDecoder-MC");
+    mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
 }
 
 NuPlayer::Decoder::~Decoder() {
 }
 
-void NuPlayer::Decoder::configure(const sp<AMessage> &format) {
+void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
     CHECK(mCodec == NULL);
 
+    ++mBufferGeneration;
+
     AString mime;
     CHECK(format->findString("mime", &mime));
 
-    sp<AMessage> notifyMsg =
-        new AMessage(kWhatCodecNotify, id());
-
-    mCSDIndex = 0;
-    for (size_t i = 0;; ++i) {
-        sp<ABuffer> csd;
-        if (!format->findBuffer(StringPrintf("csd-%d", i).c_str(), &csd)) {
-            break;
-        }
-
-        mCSD.push(csd);
+    sp<Surface> surface = NULL;
+    if (mNativeWindow != NULL) {
+        surface = mNativeWindow->getSurfaceTextureClient();
     }
 
+    mComponentName = mime;
+    mComponentName.append(" decoder");
+    ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), surface.get());
+
+    mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */);
+    if (mCodec == NULL) {
+        ALOGE("Failed to create %s decoder", mime.c_str());
+        handleError(UNKNOWN_ERROR);
+        return;
+    }
+
+    mCodec->getName(&mComponentName);
+
     if (mNativeWindow != NULL) {
-        format->setObject("native-window", mNativeWindow);
+        // disconnect from surface as MediaCodec will reconnect
+        CHECK_EQ((int)NO_ERROR,
+                native_window_api_disconnect(
+                        surface.get(),
+                        NATIVE_WINDOW_API_MEDIA));
+    }
+    status_t err = mCodec->configure(
+            format, surface, NULL /* crypto */, 0 /* flags */);
+    if (err != OK) {
+        ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err);
+        handleError(err);
+        return;
+    }
+    // the following should work in configured state
+    CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat));
+    CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat));
+
+    err = mCodec->start();
+    if (err != OK) {
+        ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err);
+        handleError(err);
+        return;
     }
 
-    // Current video decoders do not return from OMX_FillThisBuffer
-    // quickly, violating the OpenMAX specs, until that is remedied
-    // we need to invest in an extra looper to free the main event
-    // queue.
-    bool needDedicatedLooper = !strncasecmp(mime.c_str(), "video/", 6);
+    // the following should work after start
+    CHECK_EQ((status_t)OK, mCodec->getInputBuffers(&mInputBuffers));
+    CHECK_EQ((status_t)OK, mCodec->getOutputBuffers(&mOutputBuffers));
+    ALOGV("[%s] got %zu input and %zu output buffers",
+            mComponentName.c_str(),
+            mInputBuffers.size(),
+            mOutputBuffers.size());
 
-    mFormat = format;
-    mCodec = new ACodec;
+    requestCodecNotification();
+}
 
-    if (needDedicatedLooper && mCodecLooper == NULL) {
-        mCodecLooper = new ALooper;
-        mCodecLooper->setName("NuPlayerDecoder");
-        mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
+void NuPlayer::Decoder::requestCodecNotification() {
+    if (mCodec != NULL) {
+        sp<AMessage> reply = new AMessage(kWhatCodecNotify, id());
+        reply->setInt32("generation", mBufferGeneration);
+        mCodec->requestActivityNotification(reply);
+    }
+}
+
+bool NuPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) {
+    int32_t generation;
+    CHECK(msg->findInt32("generation", &generation));
+    return generation != mBufferGeneration;
+}
+
+void NuPlayer::Decoder::init() {
+    mDecoderLooper->registerHandler(this);
+}
+
+void NuPlayer::Decoder::configure(const sp<AMessage> &format) {
+    sp<AMessage> msg = new AMessage(kWhatConfigure, id());
+    msg->setMessage("format", format);
+    msg->post();
+}
+
+void NuPlayer::Decoder::handleError(int32_t err)
+{
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatError);
+    notify->setInt32("err", err);
+    notify->post();
+}
+
+bool NuPlayer::Decoder::handleAnInputBuffer() {
+    size_t bufferIx = -1;
+    status_t res = mCodec->dequeueInputBuffer(&bufferIx);
+    ALOGV("[%s] dequeued input: %d",
+            mComponentName.c_str(), res == OK ? (int)bufferIx : res);
+    if (res != OK) {
+        if (res != -EAGAIN) {
+            handleError(res);
+        }
+        return false;
     }
 
-    (needDedicatedLooper ? mCodecLooper : looper())->registerHandler(mCodec);
+    CHECK_LT(bufferIx, mInputBuffers.size());
 
-    mCodec->setNotificationMessage(notifyMsg);
-    mCodec->initiateSetup(format);
+    sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, id());
+    reply->setSize("buffer-ix", bufferIx);
+    reply->setInt32("generation", mBufferGeneration);
+
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatFillThisBuffer);
+    notify->setBuffer("buffer", mInputBuffers[bufferIx]);
+    notify->setMessage("reply", reply);
+    notify->post();
+    return true;
+}
+
+void android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) {
+    size_t bufferIx;
+    CHECK(msg->findSize("buffer-ix", &bufferIx));
+    CHECK_LT(bufferIx, mInputBuffers.size());
+    sp<ABuffer> codecBuffer = mInputBuffers[bufferIx];
+
+    sp<ABuffer> buffer;
+    bool hasBuffer = msg->findBuffer("buffer", &buffer);
+    if (buffer == NULL /* includes !hasBuffer */) {
+        int32_t streamErr = ERROR_END_OF_STREAM;
+        CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
+
+        if (streamErr == OK) {
+            /* buffers are returned to hold on to */
+            return;
+        }
+
+        // attempt to queue EOS
+        status_t err = mCodec->queueInputBuffer(
+                bufferIx,
+                0,
+                0,
+                0,
+                MediaCodec::BUFFER_FLAG_EOS);
+        if (streamErr == ERROR_END_OF_STREAM && err != OK) {
+            streamErr = err;
+            // err will not be ERROR_END_OF_STREAM
+        }
+
+        if (streamErr != ERROR_END_OF_STREAM) {
+            handleError(streamErr);
+        }
+    } else {
+        int64_t timeUs = 0;
+        uint32_t flags = 0;
+        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
+
+        int32_t eos;
+        // we do not expect CODECCONFIG or SYNCFRAME for decoder
+        if (buffer->meta()->findInt32("eos", &eos) && eos) {
+            flags |= MediaCodec::BUFFER_FLAG_EOS;
+        }
+
+        // copy into codec buffer
+        if (buffer != codecBuffer) {
+            CHECK_LE(buffer->size(), codecBuffer->capacity());
+            codecBuffer->setRange(0, buffer->size());
+            memcpy(codecBuffer->data(), buffer->data(), buffer->size());
+        }
+
+        status_t err = mCodec->queueInputBuffer(
+                        bufferIx,
+                        codecBuffer->offset(),
+                        codecBuffer->size(),
+                        timeUs,
+                        flags);
+        if (err != OK) {
+            ALOGE("Failed to queue input buffer for %s (err=%d)",
+                    mComponentName.c_str(), err);
+            handleError(err);
+        }
+    }
+}
+
+bool NuPlayer::Decoder::handleAnOutputBuffer() {
+    size_t bufferIx = -1;
+    size_t offset;
+    size_t size;
+    int64_t timeUs;
+    uint32_t flags;
+    status_t res = mCodec->dequeueOutputBuffer(
+            &bufferIx, &offset, &size, &timeUs, &flags);
+
+    if (res != OK) {
+        ALOGV("[%s] dequeued output: %d", mComponentName.c_str(), res);
+    } else {
+        ALOGV("[%s] dequeued output: %d (time=%lld flags=%" PRIu32 ")",
+                mComponentName.c_str(), (int)bufferIx, timeUs, flags);
+    }
+
+    if (res == INFO_OUTPUT_BUFFERS_CHANGED) {
+        res = mCodec->getOutputBuffers(&mOutputBuffers);
+        if (res != OK) {
+            ALOGE("Failed to get output buffers for %s after INFO event (err=%d)",
+                    mComponentName.c_str(), res);
+            handleError(res);
+            return false;
+        }
+        // NuPlayer ignores this
+        return true;
+    } else if (res == INFO_FORMAT_CHANGED) {
+        sp<AMessage> format = new AMessage();
+        res = mCodec->getOutputFormat(&format);
+        if (res != OK) {
+            ALOGE("Failed to get output format for %s after INFO event (err=%d)",
+                    mComponentName.c_str(), res);
+            handleError(res);
+            return false;
+        }
+
+        sp<AMessage> notify = mNotify->dup();
+        notify->setInt32("what", kWhatOutputFormatChanged);
+        notify->setMessage("format", format);
+        notify->post();
+        return true;
+    } else if (res == INFO_DISCONTINUITY) {
+        // nothing to do
+        return true;
+    } else if (res != OK) {
+        if (res != -EAGAIN) {
+            handleError(res);
+        }
+        return false;
+    }
+
+    CHECK_LT(bufferIx, mOutputBuffers.size());
+    sp<ABuffer> buffer = mOutputBuffers[bufferIx];
+    buffer->setRange(offset, size);
+    buffer->meta()->clear();
+    buffer->meta()->setInt64("timeUs", timeUs);
+    if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+        buffer->meta()->setInt32("eos", true);
+    }
+    // we do not expect CODECCONFIG or SYNCFRAME for decoder
+
+    sp<AMessage> reply = new AMessage(kWhatRenderBuffer, id());
+    reply->setSize("buffer-ix", bufferIx);
+    reply->setInt32("generation", mBufferGeneration);
+
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatDrainThisBuffer);
+    notify->setBuffer("buffer", buffer);
+    notify->setMessage("reply", reply);
+    notify->post();
+
+    // FIXME: This should be handled after rendering is complete,
+    // but Renderer needs it now
+    if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+        ALOGV("queueing eos [%s]", mComponentName.c_str());
+        sp<AMessage> notify = mNotify->dup();
+        notify->setInt32("what", kWhatEOS);
+        notify->setInt32("err", ERROR_END_OF_STREAM);
+        notify->post();
+    }
+    return true;
+}
+
+void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) {
+    status_t err;
+    int32_t render;
+    size_t bufferIx;
+    CHECK(msg->findSize("buffer-ix", &bufferIx));
+    if (msg->findInt32("render", &render) && render) {
+        err = mCodec->renderOutputBufferAndRelease(bufferIx);
+    } else {
+        err = mCodec->releaseOutputBuffer(bufferIx);
+    }
+    if (err != OK) {
+        ALOGE("failed to release output buffer for %s (err=%d)",
+                mComponentName.c_str(), err);
+        handleError(err);
+    }
+}
+
+void NuPlayer::Decoder::onFlush() {
+    status_t err = OK;
+    if (mCodec != NULL) {
+        err = mCodec->flush();
+        ++mBufferGeneration;
+    }
+
+    if (err != OK) {
+        ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err);
+        handleError(err);
+        return;
+    }
+
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatFlushCompleted);
+    notify->post();
+}
+
+void NuPlayer::Decoder::onShutdown() {
+    status_t err = OK;
+    if (mCodec != NULL) {
+        err = mCodec->release();
+        mCodec = NULL;
+        ++mBufferGeneration;
+
+        if (mNativeWindow != NULL) {
+            // reconnect to surface as MediaCodec disconnected from it
+            CHECK_EQ((int)NO_ERROR,
+                    native_window_api_connect(
+                            mNativeWindow->getNativeWindow().get(),
+                            NATIVE_WINDOW_API_MEDIA));
+        }
+        mComponentName = "decoder";
+    }
+
+    if (err != OK) {
+        ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err);
+        handleError(err);
+        return;
+    }
+
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatShutdownCompleted);
+    notify->post();
 }
 
 void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
+    ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str());
+
     switch (msg->what()) {
+        case kWhatConfigure:
+        {
+            sp<AMessage> format;
+            CHECK(msg->findMessage("format", &format));
+            onConfigure(format);
+            break;
+        }
+
         case kWhatCodecNotify:
         {
-            int32_t what;
-            CHECK(msg->findInt32("what", &what));
+            if (!isStaleReply(msg)) {
+                while (handleAnInputBuffer()) {
+                }
 
-            if (what == ACodec::kWhatFillThisBuffer) {
-                onFillThisBuffer(msg);
-            } else {
-                sp<AMessage> notify = mNotify->dup();
-                notify->setMessage("codec-request", msg);
-                notify->post();
+                while (handleAnOutputBuffer()) {
+                }
             }
+
+            requestCodecNotification();
+            break;
+        }
+
+        case kWhatInputBufferFilled:
+        {
+            if (!isStaleReply(msg)) {
+                onInputBufferFilled(msg);
+            }
+            break;
+        }
+
+        case kWhatRenderBuffer:
+        {
+            if (!isStaleReply(msg)) {
+                onRenderBuffer(msg);
+            }
+            break;
+        }
+
+        case kWhatFlush:
+        {
+            onFlush();
+            break;
+        }
+
+        case kWhatShutdown:
+        {
+            onShutdown();
             break;
         }
 
@@ -105,47 +442,16 @@
     }
 }
 
-void NuPlayer::Decoder::onFillThisBuffer(const sp<AMessage> &msg) {
-    sp<AMessage> reply;
-    CHECK(msg->findMessage("reply", &reply));
-
-#if 0
-    sp<ABuffer> outBuffer;
-    CHECK(msg->findBuffer("buffer", &outBuffer));
-#else
-    sp<ABuffer> outBuffer;
-#endif
-
-    if (mCSDIndex < mCSD.size()) {
-        outBuffer = mCSD.editItemAt(mCSDIndex++);
-        outBuffer->meta()->setInt64("timeUs", 0);
-
-        reply->setBuffer("buffer", outBuffer);
-        reply->post();
-        return;
-    }
-
-    sp<AMessage> notify = mNotify->dup();
-    notify->setMessage("codec-request", msg);
-    notify->post();
-}
-
 void NuPlayer::Decoder::signalFlush() {
-    if (mCodec != NULL) {
-        mCodec->signalFlush();
-    }
+    (new AMessage(kWhatFlush, id()))->post();
 }
 
 void NuPlayer::Decoder::signalResume() {
-    if (mCodec != NULL) {
-        mCodec->signalResume();
-    }
+    // nothing to do
 }
 
 void NuPlayer::Decoder::initiateShutdown() {
-    if (mCodec != NULL) {
-        mCodec->initiateShutdown();
-    }
+    (new AMessage(kWhatShutdown, id()))->post();
 }
 
 bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const {
@@ -163,14 +469,16 @@
         const char * keys[] = { "channel-count", "sample-rate", "is-adts" };
         for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
             int32_t oldVal, newVal;
-            if (!mFormat->findInt32(keys[i], &oldVal) || !targetFormat->findInt32(keys[i], &newVal)
-                    || oldVal != newVal) {
+            if (!mOutputFormat->findInt32(keys[i], &oldVal) ||
+                    !targetFormat->findInt32(keys[i], &newVal) ||
+                    oldVal != newVal) {
                 return false;
             }
         }
 
         sp<ABuffer> oldBuf, newBuf;
-        if (mFormat->findBuffer("csd-0", &oldBuf) && targetFormat->findBuffer("csd-0", &newBuf)) {
+        if (mOutputFormat->findBuffer("csd-0", &oldBuf) &&
+                targetFormat->findBuffer("csd-0", &newBuf)) {
             if (oldBuf->size() != newBuf->size()) {
                 return false;
             }
@@ -181,7 +489,7 @@
 }
 
 bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const {
-    if (mFormat == NULL) {
+    if (mOutputFormat == NULL) {
         return false;
     }
 
@@ -190,7 +498,7 @@
     }
 
     AString oldMime, newMime;
-    if (!mFormat->findString("mime", &oldMime)
+    if (!mOutputFormat->findString("mime", &oldMime)
             || !targetFormat->findString("mime", &newMime)
             || !(oldMime == newMime)) {
         return false;
@@ -201,7 +509,10 @@
     if (audio) {
         seamless = supportsSeamlessAudioFormatChange(targetFormat);
     } else {
-        seamless = mCodec != NULL && mCodec->isConfiguredForAdaptivePlayback();
+        int32_t isAdaptive;
+        seamless = (mCodec != NULL &&
+                mInputFormat->findInt32("adaptive-playback", &isAdaptive) &&
+                isAdaptive);
     }
 
     ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str());
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 78ea74a..94243fc 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -25,12 +25,14 @@
 namespace android {
 
 struct ABuffer;
+struct MediaCodec;
 
 struct NuPlayer::Decoder : public AHandler {
     Decoder(const sp<AMessage> &notify,
             const sp<NativeWindowWrapper> &nativeWindow = NULL);
 
     void configure(const sp<AMessage> &format);
+    void init();
 
     void signalFlush();
     void signalResume();
@@ -38,7 +40,18 @@
 
     bool supportsSeamlessFormatChange(const sp<AMessage> &to) const;
 
+    enum {
+        kWhatFillThisBuffer      = 'flTB',
+        kWhatDrainThisBuffer     = 'drTB',
+        kWhatOutputFormatChanged = 'fmtC',
+        kWhatFlushCompleted      = 'flsC',
+        kWhatShutdownCompleted   = 'shDC',
+        kWhatEOS                 = 'eos ',
+        kWhatError               = 'err ',
+    };
+
 protected:
+
     virtual ~Decoder();
 
     virtual void onMessageReceived(const sp<AMessage> &msg);
@@ -46,21 +59,40 @@
 private:
     enum {
         kWhatCodecNotify        = 'cdcN',
+        kWhatConfigure          = 'conf',
+        kWhatInputBufferFilled  = 'inpF',
+        kWhatRenderBuffer       = 'rndr',
+        kWhatFlush              = 'flus',
+        kWhatShutdown           = 'shuD',
     };
 
     sp<AMessage> mNotify;
     sp<NativeWindowWrapper> mNativeWindow;
 
-    sp<AMessage> mFormat;
-    sp<ACodec> mCodec;
+    sp<AMessage> mInputFormat;
+    sp<AMessage> mOutputFormat;
+    sp<MediaCodec> mCodec;
     sp<ALooper> mCodecLooper;
+    sp<ALooper> mDecoderLooper;
 
-    Vector<sp<ABuffer> > mCSD;
-    size_t mCSDIndex;
+    Vector<sp<ABuffer> > mInputBuffers;
+    Vector<sp<ABuffer> > mOutputBuffers;
 
-    sp<AMessage> makeFormat(const sp<MetaData> &meta);
+    void handleError(int32_t err);
+    bool handleAnInputBuffer();
+    bool handleAnOutputBuffer();
 
-    void onFillThisBuffer(const sp<AMessage> &msg);
+    void requestCodecNotification();
+    bool isStaleReply(const sp<AMessage> &msg);
+
+    void onConfigure(const sp<AMessage> &format);
+    void onFlush();
+    void onInputBufferFilled(const sp<AMessage> &msg);
+    void onRenderBuffer(const sp<AMessage> &msg);
+    void onShutdown();
+
+    int32_t mBufferGeneration;
+    AString mComponentName;
 
     bool supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const;
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 239296e..e4850f0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -71,7 +71,9 @@
 }
 
 status_t NuPlayerDriver::setDataSource(
-        const char *url, const KeyedVector<String8, String8> *headers) {
+        const sp<IMediaHTTPService> &httpService,
+        const char *url,
+        const KeyedVector<String8, String8> *headers) {
     Mutex::Autolock autoLock(mLock);
 
     if (mState != STATE_IDLE) {
@@ -80,7 +82,7 @@
 
     mState = STATE_SET_DATASOURCE_PENDING;
 
-    mPlayer->setDataSourceAsync(url, headers);
+    mPlayer->setDataSourceAsync(httpService, url, headers);
 
     while (mState == STATE_SET_DATASOURCE_PENDING) {
         mCondition.wait(mLock);
@@ -365,7 +367,7 @@
     return OK;
 }
 
-status_t NuPlayerDriver::setLooping(int loop) {
+status_t NuPlayerDriver::setLooping(int /* loop */) {
     return INVALID_OPERATION;
 }
 
@@ -421,16 +423,17 @@
     mPlayer->setAudioSink(audioSink);
 }
 
-status_t NuPlayerDriver::setParameter(int key, const Parcel &request) {
+status_t NuPlayerDriver::setParameter(
+        int /* key */, const Parcel & /* request */) {
     return INVALID_OPERATION;
 }
 
-status_t NuPlayerDriver::getParameter(int key, Parcel *reply) {
+status_t NuPlayerDriver::getParameter(int /* key */, Parcel * /* reply */) {
     return INVALID_OPERATION;
 }
 
 status_t NuPlayerDriver::getMetadata(
-        const media::Metadata::Filter& ids, Parcel *records) {
+        const media::Metadata::Filter& /* ids */, Parcel *records) {
     Mutex::Autolock autoLock(mLock);
 
     using media::Metadata;
@@ -494,7 +497,8 @@
     mNumFramesDropped = numFramesDropped;
 }
 
-status_t NuPlayerDriver::dump(int fd, const Vector<String16> &args) const {
+status_t NuPlayerDriver::dump(
+        int fd, const Vector<String16> & /* args */) const {
     Mutex::Autolock autoLock(mLock);
 
     FILE *out = fdopen(dup(fd), "w");
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 99f72a6..0148fb1 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -31,7 +31,9 @@
     virtual status_t setUID(uid_t uid);
 
     virtual status_t setDataSource(
-            const char *url, const KeyedVector<String8, String8> *headers);
+            const sp<IMediaHTTPService> &httpService,
+            const char *url,
+            const KeyedVector<String8, String8> *headers);
 
     virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index bf5271e..a070c1a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -20,8 +20,6 @@
 
 #include "NuPlayerRenderer.h"
 
-#include "SoftwareRenderer.h"
-
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -36,7 +34,6 @@
         const sp<AMessage> &notify,
         uint32_t flags)
     : mAudioSink(sink),
-      mSoftRenderer(NULL),
       mNotify(notify),
       mFlags(flags),
       mNumFramesWritten(0),
@@ -60,12 +57,6 @@
 }
 
 NuPlayer::Renderer::~Renderer() {
-    delete mSoftRenderer;
-}
-
-void NuPlayer::Renderer::setSoftRenderer(SoftwareRenderer *softRenderer) {
-    delete mSoftRenderer;
-    mSoftRenderer = softRenderer;
 }
 
 void NuPlayer::Renderer::queueBuffer(
@@ -425,9 +416,6 @@
         ALOGV("rendering video at media time %.2f secs",
                 (mFlags & FLAG_REAL_TIME ? realTimeUs :
                 (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6);
-        if (mSoftRenderer != NULL) {
-            mSoftRenderer->render(entry->mBuffer->data(), entry->mBuffer->size(), NULL);
-        }
     }
 
     entry->mNotifyConsumed->setInt32("render", !tooLate);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 9124e03..94a05ea 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -23,7 +23,6 @@
 namespace android {
 
 struct ABuffer;
-class SoftwareRenderer;
 
 struct NuPlayer::Renderer : public AHandler {
     enum Flags {
@@ -57,8 +56,6 @@
         kWhatMediaRenderingStart = 'mdrd',
     };
 
-    void setSoftRenderer(SoftwareRenderer *softRenderer);
-
 protected:
     virtual ~Renderer();
 
@@ -86,7 +83,6 @@
     static const int64_t kMinPositionUpdateDelayUs;
 
     sp<MediaPlayerBase::AudioSink> mAudioSink;
-    SoftwareRenderer *mSoftRenderer;
     sp<AMessage> mNotify;
     uint32_t mFlags;
     List<QueueEntry> mAudioQueue;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index e50533a..11279fc 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -68,19 +68,19 @@
     virtual status_t dequeueAccessUnit(
             bool audio, sp<ABuffer> *accessUnit) = 0;
 
-    virtual status_t getDuration(int64_t *durationUs) {
+    virtual status_t getDuration(int64_t * /* durationUs */) {
         return INVALID_OPERATION;
     }
 
-    virtual status_t getTrackInfo(Parcel* reply) const {
+    virtual status_t getTrackInfo(Parcel* /* reply */) const {
         return INVALID_OPERATION;
     }
 
-    virtual status_t selectTrack(size_t trackIndex, bool select) {
+    virtual status_t selectTrack(size_t /* trackIndex */, bool /* select */) {
         return INVALID_OPERATION;
     }
 
-    virtual status_t seekTo(int64_t seekTimeUs) {
+    virtual status_t seekTo(int64_t /* seekTimeUs */) {
         return INVALID_OPERATION;
     }
 
@@ -93,7 +93,7 @@
 
     virtual void onMessageReceived(const sp<AMessage> &msg);
 
-    virtual sp<MetaData> getFormatMeta(bool audio) { return NULL; }
+    virtual sp<MetaData> getFormatMeta(bool /* audio */) { return NULL; }
 
     sp<AMessage> dupNotify() const { return mNotify->dup(); }
 
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 18cf6d1..94800ba 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -24,6 +24,7 @@
 #include "MyHandler.h"
 #include "SDPLoader.h"
 
+#include <media/IMediaHTTPService.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 
@@ -33,12 +34,14 @@
 
 NuPlayer::RTSPSource::RTSPSource(
         const sp<AMessage> &notify,
+        const sp<IMediaHTTPService> &httpService,
         const char *url,
         const KeyedVector<String8, String8> *headers,
         bool uidValid,
         uid_t uid,
         bool isSDP)
     : Source(notify),
+      mHTTPService(httpService),
       mURL(url),
       mUIDValid(uidValid),
       mUID(uid),
@@ -92,7 +95,7 @@
     if (mIsSDP) {
         mSDPLoader = new SDPLoader(notify,
                 (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0,
-                mUIDValid, mUID);
+                mHTTPService);
 
         mSDPLoader->load(
                 mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders);
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index 8cf34a0..3718bf9 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -34,6 +34,7 @@
 struct NuPlayer::RTSPSource : public NuPlayer::Source {
     RTSPSource(
             const sp<AMessage> &notify,
+            const sp<IMediaHTTPService> &httpService,
             const char *url,
             const KeyedVector<String8, String8> *headers,
             bool uidValid = false,
@@ -88,6 +89,7 @@
         bool mNPTMappingValid;
     };
 
+    sp<IMediaHTTPService> mHTTPService;
     AString mURL;
     KeyedVector<String8, String8> mExtraHeaders;
     bool mUIDValid;
diff --git a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
deleted file mode 100644
index 2aae4dd..0000000
--- a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "MP4Source.h"
-
-#include "FragmentedMP4Parser.h"
-#include "../NuPlayerStreamListener.h"
-
-#include <media/IStreamSource.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-struct StreamSource : public FragmentedMP4Parser::Source {
-    StreamSource(const sp<IStreamSource> &source)
-        : mListener(new NuPlayer::NuPlayerStreamListener(source, 0)),
-          mPosition(0) {
-        mListener->start();
-    }
-
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
-        if (offset < mPosition) {
-            return -EPIPE;
-        }
-
-        while (offset > mPosition) {
-            char buffer[1024];
-            off64_t skipBytes = offset - mPosition;
-            if (skipBytes > sizeof(buffer)) {
-                skipBytes = sizeof(buffer);
-            }
-
-            sp<AMessage> extra;
-            ssize_t n;
-            for (;;) {
-                n = mListener->read(buffer, skipBytes, &extra);
-
-                if (n == -EWOULDBLOCK) {
-                    usleep(10000);
-                    continue;
-                }
-
-                break;
-            }
-
-            ALOGV("skipped %ld bytes at offset %lld", n, mPosition);
-
-            if (n < 0) {
-                return n;
-            }
-
-            mPosition += n;
-        }
-
-        sp<AMessage> extra;
-        size_t total = 0;
-        while (total < size) {
-            ssize_t n = mListener->read(
-                    (uint8_t *)data + total, size - total, &extra);
-
-            if (n == -EWOULDBLOCK) {
-                usleep(10000);
-                continue;
-            } else if (n == 0) {
-                break;
-            } else if (n < 0) {
-                mPosition += total;
-                return n;
-            }
-
-            total += n;
-        }
-
-        ALOGV("read %ld bytes at offset %lld", total, mPosition);
-
-        mPosition += total;
-
-        return total;
-    }
-
-    bool isSeekable() {
-        return false;
-    }
-
-private:
-    sp<NuPlayer::NuPlayerStreamListener> mListener;
-    off64_t mPosition;
-
-    DISALLOW_EVIL_CONSTRUCTORS(StreamSource);
-};
-
-MP4Source::MP4Source(
-        const sp<AMessage> &notify, const sp<IStreamSource> &source)
-    : Source(notify),
-      mSource(source),
-      mLooper(new ALooper),
-      mParser(new FragmentedMP4Parser),
-      mEOS(false) {
-    mLooper->registerHandler(mParser);
-}
-
-MP4Source::~MP4Source() {
-}
-
-void MP4Source::prepareAsync() {
-    notifyVideoSizeChanged(0, 0);
-    notifyFlagsChanged(0);
-    notifyPrepared();
-}
-
-void MP4Source::start() {
-    mLooper->start(false /* runOnCallingThread */);
-    mParser->start(new StreamSource(mSource));
-}
-
-status_t MP4Source::feedMoreTSData() {
-    return mEOS ? ERROR_END_OF_STREAM : (status_t)OK;
-}
-
-sp<AMessage> MP4Source::getFormat(bool audio) {
-    return mParser->getFormat(audio);
-}
-
-status_t MP4Source::dequeueAccessUnit(
-        bool audio, sp<ABuffer> *accessUnit) {
-    return mParser->dequeueAccessUnit(audio, accessUnit);
-}
-
-}  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h
deleted file mode 100644
index a6ef622..0000000
--- a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MP4_SOURCE_H
-#define MP4_SOURCE_H
-
-#include "NuPlayerSource.h"
-
-namespace android {
-
-struct FragmentedMP4Parser;
-
-struct MP4Source : public NuPlayer::Source {
-    MP4Source(const sp<AMessage> &notify, const sp<IStreamSource> &source);
-
-    virtual void prepareAsync();
-    virtual void start();
-
-    virtual status_t feedMoreTSData();
-
-    virtual sp<AMessage> getFormat(bool audio);
-
-    virtual status_t dequeueAccessUnit(
-            bool audio, sp<ABuffer> *accessUnit);
-
-protected:
-    virtual ~MP4Source();
-
-private:
-    sp<IStreamSource> mSource;
-    sp<ALooper> mLooper;
-    sp<FragmentedMP4Parser> mParser;
-    bool mEOS;
-
-    DISALLOW_EVIL_CONSTRUCTORS(MP4Source);
-};
-
-}  // namespace android
-
-#endif // MP4_SOURCE_H
diff --git a/media/libnbaio/Android.mk b/media/libnbaio/Android.mk
index 69c75b8..9707c4a 100644
--- a/media/libnbaio/Android.mk
+++ b/media/libnbaio/Android.mk
@@ -31,9 +31,8 @@
     libcommon_time_client \
     libcutils \
     libutils \
-    liblog \
-    libmedia
-# This dependency on libmedia is for SingleStateQueueInstantiations.
-# Consider a separate a library for SingleStateQueueInstantiations.
+    liblog
+
+LOCAL_STATIC_LIBRARIES += libinstantssq
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libnbaio/AudioBufferProviderSource.cpp b/media/libnbaio/AudioBufferProviderSource.cpp
index 74a6fdb..551f516 100644
--- a/media/libnbaio/AudioBufferProviderSource.cpp
+++ b/media/libnbaio/AudioBufferProviderSource.cpp
@@ -24,11 +24,11 @@
 namespace android {
 
 AudioBufferProviderSource::AudioBufferProviderSource(AudioBufferProvider *provider,
-                                                     NBAIO_Format format) :
+                                                     const NBAIO_Format& format) :
     NBAIO_Source(format), mProvider(provider), mConsumed(0)
 {
     ALOG_ASSERT(provider != NULL);
-    ALOG_ASSERT(format != Format_Invalid);
+    ALOG_ASSERT(Format_isValid(format));
 }
 
 AudioBufferProviderSource::~AudioBufferProviderSource()
@@ -68,7 +68,7 @@
     }
     // count could be zero, either because count was zero on entry or
     // available is zero, but both are unlikely so don't check for that
-    memcpy(buffer, (char *) mBuffer.raw + (mConsumed << mBitShift), count << mBitShift);
+    memcpy(buffer, (char *) mBuffer.raw + (mConsumed * mFrameSize), count * mFrameSize);
     if (CC_UNLIKELY((mConsumed += count) >= mBuffer.frameCount)) {
         mProvider->releaseBuffer(&mBuffer);
         mBuffer.raw = NULL;
@@ -120,7 +120,7 @@
             count = available;
         }
         if (CC_LIKELY(count > 0)) {
-            char* readTgt = (char *) mBuffer.raw + (mConsumed << mBitShift);
+            char* readTgt = (char *) mBuffer.raw + (mConsumed * mFrameSize);
             ssize_t ret = via(user, readTgt, count, readPTS);
             if (CC_UNLIKELY(ret <= 0)) {
                 if (CC_LIKELY(accumulator > 0)) {
diff --git a/media/libnbaio/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp
index 05273f6..80bf61a 100644
--- a/media/libnbaio/AudioStreamInSource.cpp
+++ b/media/libnbaio/AudioStreamInSource.cpp
@@ -40,16 +40,14 @@
 ssize_t AudioStreamInSource::negotiate(const NBAIO_Format offers[], size_t numOffers,
                                       NBAIO_Format counterOffers[], size_t& numCounterOffers)
 {
-    if (mFormat == Format_Invalid) {
+    if (!Format_isValid(mFormat)) {
         mStreamBufferSizeBytes = mStream->common.get_buffer_size(&mStream->common);
         audio_format_t streamFormat = mStream->common.get_format(&mStream->common);
-        if (streamFormat == AUDIO_FORMAT_PCM_16_BIT) {
-            uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common);
-            audio_channel_mask_t channelMask =
-                    (audio_channel_mask_t) mStream->common.get_channels(&mStream->common);
-            mFormat = Format_from_SR_C(sampleRate, popcount(channelMask));
-            mBitShift = Format_frameBitShift(mFormat);
-        }
+        uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common);
+        audio_channel_mask_t channelMask =
+                (audio_channel_mask_t) mStream->common.get_channels(&mStream->common);
+        mFormat = Format_from_SR_C(sampleRate, popcount(channelMask), streamFormat);
+        mFrameSize = Format_frameSize(mFormat);
     }
     return NBAIO_Source::negotiate(offers, numOffers, counterOffers, numCounterOffers);
 }
@@ -67,12 +65,12 @@
 
 ssize_t AudioStreamInSource::read(void *buffer, size_t count)
 {
-    if (CC_UNLIKELY(mFormat == Format_Invalid)) {
+    if (CC_UNLIKELY(!Format_isValid(mFormat))) {
         return NEGOTIATE;
     }
-    ssize_t bytesRead = mStream->read(mStream, buffer, count << mBitShift);
+    ssize_t bytesRead = mStream->read(mStream, buffer, count * mFrameSize);
     if (bytesRead > 0) {
-        size_t framesRead = bytesRead >> mBitShift;
+        size_t framesRead = bytesRead / mFrameSize;
         mFramesRead += framesRead;
         return framesRead;
     } else {
diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp
index e4341d7..c28d34d 100644
--- a/media/libnbaio/AudioStreamOutSink.cpp
+++ b/media/libnbaio/AudioStreamOutSink.cpp
@@ -37,16 +37,14 @@
 ssize_t AudioStreamOutSink::negotiate(const NBAIO_Format offers[], size_t numOffers,
                                       NBAIO_Format counterOffers[], size_t& numCounterOffers)
 {
-    if (mFormat == Format_Invalid) {
+    if (!Format_isValid(mFormat)) {
         mStreamBufferSizeBytes = mStream->common.get_buffer_size(&mStream->common);
         audio_format_t streamFormat = mStream->common.get_format(&mStream->common);
-        if (streamFormat == AUDIO_FORMAT_PCM_16_BIT) {
-            uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common);
-            audio_channel_mask_t channelMask =
-                    (audio_channel_mask_t) mStream->common.get_channels(&mStream->common);
-            mFormat = Format_from_SR_C(sampleRate, popcount(channelMask));
-            mBitShift = Format_frameBitShift(mFormat);
-        }
+        uint32_t sampleRate = mStream->common.get_sample_rate(&mStream->common);
+        audio_channel_mask_t channelMask =
+                (audio_channel_mask_t) mStream->common.get_channels(&mStream->common);
+        mFormat = Format_from_SR_C(sampleRate, popcount(channelMask), streamFormat);
+        mFrameSize = Format_frameSize(mFormat);
     }
     return NBAIO_Sink::negotiate(offers, numOffers, counterOffers, numCounterOffers);
 }
@@ -56,10 +54,10 @@
     if (!mNegotiated) {
         return NEGOTIATE;
     }
-    ALOG_ASSERT(mFormat != Format_Invalid);
-    ssize_t ret = mStream->write(mStream, buffer, count << mBitShift);
+    ALOG_ASSERT(Format_isValid(mFormat));
+    ssize_t ret = mStream->write(mStream, buffer, count * mFrameSize);
     if (ret > 0) {
-        ret >>= mBitShift;
+        ret /= mFrameSize;
         mFramesWritten += ret;
     } else {
         // FIXME verify HAL implementations are returning the correct error codes e.g. WOULD_BLOCK
diff --git a/media/libnbaio/MonoPipe.cpp b/media/libnbaio/MonoPipe.cpp
index 3c61b60..9c8461c 100644
--- a/media/libnbaio/MonoPipe.cpp
+++ b/media/libnbaio/MonoPipe.cpp
@@ -30,7 +30,7 @@
 
 namespace android {
 
-MonoPipe::MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock) :
+MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock) :
         NBAIO_Sink(format),
         mUpdateSeq(0),
         mReqFrames(reqFrames),
@@ -115,11 +115,11 @@
             part1 = written;
         }
         if (CC_LIKELY(part1 > 0)) {
-            memcpy((char *) mBuffer + (rear << mBitShift), buffer, part1 << mBitShift);
+            memcpy((char *) mBuffer + (rear * mFrameSize), buffer, part1 * mFrameSize);
             if (CC_UNLIKELY(rear + part1 == mMaxFrames)) {
                 size_t part2 = written - part1;
                 if (CC_LIKELY(part2 > 0)) {
-                    memcpy(mBuffer, (char *) buffer + (part1 << mBitShift), part2 << mBitShift);
+                    memcpy(mBuffer, (char *) buffer + (part1 * mFrameSize), part2 * mFrameSize);
                 }
             }
             android_atomic_release_store(written + mRear, &mRear);
@@ -129,7 +129,7 @@
             break;
         }
         count -= written;
-        buffer = (char *) buffer + (written << mBitShift);
+        buffer = (char *) buffer + (written * mFrameSize);
         // Simulate blocking I/O by sleeping at different rates, depending on a throttle.
         // The throttle tries to keep the mean pipe depth near the setpoint, with a slight jitter.
         uint32_t ns;
diff --git a/media/libnbaio/MonoPipeReader.cpp b/media/libnbaio/MonoPipeReader.cpp
index 851341a..de82229 100644
--- a/media/libnbaio/MonoPipeReader.cpp
+++ b/media/libnbaio/MonoPipeReader.cpp
@@ -73,11 +73,11 @@
         part1 = red;
     }
     if (CC_LIKELY(part1 > 0)) {
-        memcpy(buffer, (char *) mPipe->mBuffer + (front << mBitShift), part1 << mBitShift);
+        memcpy(buffer, (char *) mPipe->mBuffer + (front * mFrameSize), part1 * mFrameSize);
         if (CC_UNLIKELY(front + part1 == mPipe->mMaxFrames)) {
             size_t part2 = red - part1;
             if (CC_LIKELY(part2 > 0)) {
-                memcpy((char *) buffer + (part1 << mBitShift), mPipe->mBuffer, part2 << mBitShift);
+                memcpy((char *) buffer + (part1 * mFrameSize), mPipe->mBuffer, part2 * mFrameSize);
             }
         }
         mPipe->updateFrontAndNRPTS(red + mPipe->mFront, nextReadPTS);
diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp
index e0d2c21..ff3284c 100644
--- a/media/libnbaio/NBAIO.cpp
+++ b/media/libnbaio/NBAIO.cpp
@@ -22,119 +22,42 @@
 
 namespace android {
 
-size_t Format_frameSize(NBAIO_Format format)
+size_t Format_frameSize(const NBAIO_Format& format)
 {
-    return Format_channelCount(format) * sizeof(short);
+    return format.mFrameSize;
 }
 
-size_t Format_frameBitShift(NBAIO_Format format)
+const NBAIO_Format Format_Invalid = { 0, 0, AUDIO_FORMAT_INVALID, 0 };
+
+unsigned Format_sampleRate(const NBAIO_Format& format)
 {
-    // sizeof(short) == 2, so frame size == 1 << channels
-    return Format_channelCount(format);
+    if (!Format_isValid(format)) {
+        return 0;
+    }
+    return format.mSampleRate;
 }
 
-enum {
-    Format_SR_8000,
-    Format_SR_11025,
-    Format_SR_16000,
-    Format_SR_22050,
-    Format_SR_24000,
-    Format_SR_32000,
-    Format_SR_44100,
-    Format_SR_48000,
-    Format_SR_Mask = 7
-};
-
-enum {
-    Format_C_1 = 0x08,
-    Format_C_2 = 0x10,
-    Format_C_Mask = 0x18
-};
-
-unsigned Format_sampleRate(NBAIO_Format format)
+unsigned Format_channelCount(const NBAIO_Format& format)
 {
-    if (format == Format_Invalid) {
+    if (!Format_isValid(format)) {
         return 0;
     }
-    switch (format & Format_SR_Mask) {
-    case Format_SR_8000:
-        return 8000;
-    case Format_SR_11025:
-        return 11025;
-    case Format_SR_16000:
-        return 16000;
-    case Format_SR_22050:
-        return 22050;
-    case Format_SR_24000:
-        return 24000;
-    case Format_SR_32000:
-        return 32000;
-    case Format_SR_44100:
-        return 44100;
-    case Format_SR_48000:
-        return 48000;
-    default:
-        return 0;
-    }
+    return format.mChannelCount;
 }
 
-unsigned Format_channelCount(NBAIO_Format format)
+NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount,
+        audio_format_t format)
 {
-    if (format == Format_Invalid) {
-        return 0;
-    }
-    switch (format & Format_C_Mask) {
-    case Format_C_1:
-        return 1;
-    case Format_C_2:
-        return 2;
-    default:
-        return 0;
-    }
-}
-
-NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount)
-{
-    NBAIO_Format format;
-    switch (sampleRate) {
-    case 8000:
-        format = Format_SR_8000;
-        break;
-    case 11025:
-        format = Format_SR_11025;
-        break;
-    case 16000:
-        format = Format_SR_16000;
-        break;
-    case 22050:
-        format = Format_SR_22050;
-        break;
-    case 24000:
-        format = Format_SR_24000;
-        break;
-    case 32000:
-        format = Format_SR_32000;
-        break;
-    case 44100:
-        format = Format_SR_44100;
-        break;
-    case 48000:
-        format = Format_SR_48000;
-        break;
-    default:
+    if (sampleRate == 0 || channelCount == 0 || !audio_is_valid_format(format)) {
         return Format_Invalid;
     }
-    switch (channelCount) {
-    case 1:
-        format |= Format_C_1;
-        break;
-    case 2:
-        format |= Format_C_2;
-        break;
-    default:
-        return Format_Invalid;
-    }
-    return format;
+    NBAIO_Format ret;
+    ret.mSampleRate = sampleRate;
+    ret.mChannelCount = channelCount;
+    ret.mFormat = format;
+    ret.mFrameSize = audio_is_linear_pcm(format) ?
+            channelCount * audio_bytes_per_sample(format) : sizeof(uint8_t);
+    return ret;
 }
 
 // This is a default implementation; it is expected that subclasses will optimize this.
@@ -216,9 +139,9 @@
 {
     ALOGV("negotiate offers=%p numOffers=%u countersOffers=%p numCounterOffers=%u",
             offers, numOffers, counterOffers, numCounterOffers);
-    if (mFormat != Format_Invalid) {
+    if (Format_isValid(mFormat)) {
         for (size_t i = 0; i < numOffers; ++i) {
-            if (offers[i] == mFormat) {
+            if (Format_isEqual(offers[i], mFormat)) {
                 mNegotiated = true;
                 return i;
             }
@@ -233,4 +156,17 @@
     return (ssize_t) NEGOTIATE;
 }
 
+bool Format_isValid(const NBAIO_Format& format)
+{
+    return format.mSampleRate != 0 && format.mChannelCount != 0 &&
+            format.mFormat != AUDIO_FORMAT_INVALID && format.mFrameSize != 0;
+}
+
+bool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2)
+{
+    return format1.mSampleRate == format2.mSampleRate &&
+            format1.mChannelCount == format2.mChannelCount && format1.mFormat == format2.mFormat &&
+            format1.mFrameSize == format2.mFrameSize;
+}
+
 }   // namespace android
diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp
index d74a7a6..96738a7 100644
--- a/media/libnbaio/NBLog.cpp
+++ b/media/libnbaio/NBLog.cpp
@@ -26,6 +26,7 @@
 #include <cutils/atomic.h>
 #include <media/nbaio/NBLog.h>
 #include <utils/Log.h>
+#include <utils/String8.h>
 
 namespace android {
 
@@ -337,25 +338,25 @@
         }
         i -= length + 3;
     }
-    if (i > 0) {
-        lost += i;
-        if (fd >= 0) {
-            fdprintf(fd, "%*swarning: lost %zu bytes worth of events\n", indent, "", lost);
-        } else {
-            ALOGI("%*swarning: lost %u bytes worth of events\n", indent, "", lost);
-        }
+    mFd = fd;
+    mIndent = indent;
+    String8 timestamp, body;
+    lost += i;
+    if (lost > 0) {
+        body.appendFormat("warning: lost %u bytes worth of events", lost);
+        // TODO timestamp empty here, only other choice to wait for the first timestamp event in the
+        //      log to push it out.  Consider keeping the timestamp/body between calls to readAt().
+        dumpLine(timestamp, body);
     }
     size_t width = 1;
     while (maxSec >= 10) {
         ++width;
         maxSec /= 10;
     }
-    char prefix[32];
     if (maxSec >= 0) {
-        snprintf(prefix, sizeof(prefix), "[%*s] ", width + 4, "");
-    } else {
-        prefix[0] = '\0';
+        timestamp.appendFormat("[%*s]", width + 4, "");
     }
+    bool deferredTimestamp = false;
     while (i < avail) {
         event = (Event) copy[i];
         length = copy[i + 1];
@@ -363,11 +364,8 @@
         size_t advance = length + 3;
         switch (event) {
         case EVENT_STRING:
-            if (fd >= 0) {
-                fdprintf(fd, "%*s%s%.*s\n", indent, "", prefix, length, (const char *) data);
-            } else {
-                ALOGI("%*s%s%.*s", indent, "", prefix, length, (const char *) data);
-            } break;
+            body.appendFormat("%.*s", length, (const char *) data);
+            break;
         case EVENT_TIMESTAMP: {
             // already checked that length == sizeof(struct timespec);
             memcpy(&ts, data, sizeof(struct timespec));
@@ -400,48 +398,56 @@
                 prevNsec = tsNext.tv_nsec;
             }
             size_t n = (j - i) / (sizeof(struct timespec) + 3);
+            if (deferredTimestamp) {
+                dumpLine(timestamp, body);
+                deferredTimestamp = false;
+            }
+            timestamp.clear();
             if (n >= kSquashTimestamp) {
-                if (fd >= 0) {
-                    fdprintf(fd, "%*s[%d.%03d to .%.03d by .%.03d to .%.03d]\n", indent, "",
-                            (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000),
-                            (int) ((ts.tv_nsec + deltaTotal) / 1000000),
-                            (int) (deltaMin / 1000000), (int) (deltaMax / 1000000));
-                } else {
-                    ALOGI("%*s[%d.%03d to .%.03d by .%.03d to .%.03d]\n", indent, "",
-                            (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000),
-                            (int) ((ts.tv_nsec + deltaTotal) / 1000000),
-                            (int) (deltaMin / 1000000), (int) (deltaMax / 1000000));
-                }
+                timestamp.appendFormat("[%d.%03d to .%.03d by .%.03d to .%.03d]",
+                        (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000),
+                        (int) ((ts.tv_nsec + deltaTotal) / 1000000),
+                        (int) (deltaMin / 1000000), (int) (deltaMax / 1000000));
                 i = j;
                 advance = 0;
                 break;
             }
-            if (fd >= 0) {
-                fdprintf(fd, "%*s[%d.%03d]\n", indent, "", (int) ts.tv_sec,
-                        (int) (ts.tv_nsec / 1000000));
-            } else {
-                ALOGI("%*s[%d.%03d]", indent, "", (int) ts.tv_sec,
-                        (int) (ts.tv_nsec / 1000000));
-            }
+            timestamp.appendFormat("[%d.%03d]", (int) ts.tv_sec,
+                    (int) (ts.tv_nsec / 1000000));
+            deferredTimestamp = true;
             } break;
         case EVENT_RESERVED:
         default:
-            if (fd >= 0) {
-                fdprintf(fd, "%*s%swarning: unknown event %d\n", indent, "", prefix, event);
-            } else {
-                ALOGI("%*s%swarning: unknown event %d", indent, "", prefix, event);
-            }
+            body.appendFormat("warning: unknown event %d", event);
             break;
         }
         i += advance;
+
+        if (!body.isEmpty()) {
+            dumpLine(timestamp, body);
+            deferredTimestamp = false;
+        }
+    }
+    if (deferredTimestamp) {
+        dumpLine(timestamp, body);
     }
     // FIXME it would be more efficient to put a char mCopy[256] as a member variable of the dumper
     delete[] copy;
 }
 
+void NBLog::Reader::dumpLine(const String8& timestamp, String8& body)
+{
+    if (mFd >= 0) {
+        fdprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string());
+    } else {
+        ALOGI("%.*s%s %s", mIndent, "", timestamp.string(), body.string());
+    }
+    body.clear();
+}
+
 bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const
 {
-    return iMemory.get() == mIMemory.get();
+    return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
 }
 
 }   // namespace android
diff --git a/media/libnbaio/Pipe.cpp b/media/libnbaio/Pipe.cpp
index 1c21f9c..28a034c 100644
--- a/media/libnbaio/Pipe.cpp
+++ b/media/libnbaio/Pipe.cpp
@@ -25,7 +25,7 @@
 
 namespace android {
 
-Pipe::Pipe(size_t maxFrames, NBAIO_Format format) :
+Pipe::Pipe(size_t maxFrames, const NBAIO_Format& format) :
         NBAIO_Sink(format),
         mMaxFrames(roundup(maxFrames)),
         mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
@@ -52,13 +52,13 @@
     if (CC_LIKELY(written > count)) {
         written = count;
     }
-    memcpy((char *) mBuffer + (rear << mBitShift), buffer, written << mBitShift);
+    memcpy((char *) mBuffer + (rear * mFrameSize), buffer, written * mFrameSize);
     if (CC_UNLIKELY(rear + written == mMaxFrames)) {
         if (CC_UNLIKELY((count -= written) > rear)) {
             count = rear;
         }
         if (CC_LIKELY(count > 0)) {
-            memcpy(mBuffer, (char *) buffer + (written << mBitShift), count << mBitShift);
+            memcpy(mBuffer, (char *) buffer + (written * mFrameSize), count * mFrameSize);
             written += count;
         }
     }
diff --git a/media/libnbaio/PipeReader.cpp b/media/libnbaio/PipeReader.cpp
index d786b84..c8e4953 100644
--- a/media/libnbaio/PipeReader.cpp
+++ b/media/libnbaio/PipeReader.cpp
@@ -59,7 +59,7 @@
     return avail;
 }
 
-ssize_t PipeReader::read(void *buffer, size_t count, int64_t readPTS)
+ssize_t PipeReader::read(void *buffer, size_t count, int64_t readPTS __unused)
 {
     ssize_t avail = availableToRead();
     if (CC_UNLIKELY(avail <= 0)) {
@@ -76,14 +76,14 @@
         red = count;
     }
     // In particular, an overrun during the memcpy will result in reading corrupt data
-    memcpy(buffer, (char *) mPipe.mBuffer + (front << mBitShift), red << mBitShift);
+    memcpy(buffer, (char *) mPipe.mBuffer + (front * mFrameSize), red * mFrameSize);
     // We could re-read the rear pointer here to detect the corruption, but why bother?
     if (CC_UNLIKELY(front + red == mPipe.mMaxFrames)) {
         if (CC_UNLIKELY((count -= red) > front)) {
             count = front;
         }
         if (CC_LIKELY(count > 0)) {
-            memcpy((char *) buffer + (red << mBitShift), mPipe.mBuffer, count << mBitShift);
+            memcpy((char *) buffer + (red * mFrameSize), mPipe.mBuffer, count * mFrameSize);
             red += count;
         }
     }
diff --git a/media/libnbaio/SourceAudioBufferProvider.cpp b/media/libnbaio/SourceAudioBufferProvider.cpp
index 062fa0f..e21ef48 100644
--- a/media/libnbaio/SourceAudioBufferProvider.cpp
+++ b/media/libnbaio/SourceAudioBufferProvider.cpp
@@ -24,7 +24,7 @@
 
 SourceAudioBufferProvider::SourceAudioBufferProvider(const sp<NBAIO_Source>& source) :
     mSource(source),
-    // mFrameBitShiftFormat below
+    // mFrameSize below
     mAllocated(NULL), mSize(0), mOffset(0), mRemaining(0), mGetCount(0), mFramesReleased(0)
 {
     ALOG_ASSERT(source != 0);
@@ -37,7 +37,7 @@
     numCounterOffers = 0;
     index = source->negotiate(counterOffers, 1, NULL, numCounterOffers);
     ALOG_ASSERT(index == 0);
-    mFrameBitShift = Format_frameBitShift(source->format());
+    mFrameSize = Format_frameSize(source->format());
 }
 
 SourceAudioBufferProvider::~SourceAudioBufferProvider()
@@ -54,14 +54,14 @@
         if (mRemaining < buffer->frameCount) {
             buffer->frameCount = mRemaining;
         }
-        buffer->raw = (char *) mAllocated + (mOffset << mFrameBitShift);
+        buffer->raw = (char *) mAllocated + (mOffset * mFrameSize);
         mGetCount = buffer->frameCount;
         return OK;
     }
     // do we need to reallocate?
     if (buffer->frameCount > mSize) {
         free(mAllocated);
-        mAllocated = malloc(buffer->frameCount << mFrameBitShift);
+        mAllocated = malloc(buffer->frameCount * mFrameSize);
         mSize = buffer->frameCount;
     }
     // read from source
@@ -84,7 +84,7 @@
 void SourceAudioBufferProvider::releaseBuffer(Buffer *buffer)
 {
     ALOG_ASSERT((buffer != NULL) &&
-            (buffer->raw == (char *) mAllocated + (mOffset << mFrameBitShift)) &&
+            (buffer->raw == (char *) mAllocated + (mOffset * mFrameSize)) &&
             (buffer->frameCount <= mGetCount) &&
             (mGetCount <= mRemaining) &&
             (mOffset + mRemaining <= mSize));
diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
index 4d1072f..196f6ee 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/libstagefright/AACExtractor.cpp
@@ -219,7 +219,7 @@
     return new AACSource(mDataSource, mMeta, mOffsetVector, mFrameDurationUs);
 }
 
-sp<MetaData> AACExtractor::getTrackMetaData(size_t index, uint32_t flags) {
+sp<MetaData> AACExtractor::getTrackMetaData(size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -252,7 +252,7 @@
     }
 }
 
-status_t AACSource::start(MetaData *params) {
+status_t AACSource::start(MetaData * /* params */) {
     CHECK(!mStarted);
 
     if (mOffsetVector.empty()) {
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index c9bcaba..deee8e7 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -111,7 +111,7 @@
     return OK;
 }
 
-status_t AACWriter::start(MetaData *params) {
+status_t AACWriter::start(MetaData * /* params */) {
     if (mInitCheck != OK) {
         return mInitCheck;
     }
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 6dcedca..e9e96d1 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -365,7 +365,6 @@
       mIsEncoder(false),
       mUseMetadataOnEncoderOutput(false),
       mShutdownInProgress(false),
-      mIsConfiguredForAdaptivePlayback(false),
       mEncoderDelay(0),
       mEncoderPadding(0),
       mChannelMaskPresent(false),
@@ -374,7 +373,10 @@
       mStoreMetaDataInOutputBuffers(false),
       mMetaDataBuffersToSubmit(0),
       mRepeatFrameDelayUs(-1ll),
-      mMaxPtsGapUs(-1l) {
+      mMaxPtsGapUs(-1ll),
+      mTimePerCaptureUs(-1ll),
+      mTimePerFrameUs(-1ll),
+      mCreateInputBuffersSuspended(false) {
     mUninitializedState = new UninitializedState(this);
     mLoadedState = new LoadedState(this);
     mLoadedToIdleState = new LoadedToIdleState(this);
@@ -640,18 +642,33 @@
         return err;
     }
 
-    // XXX: Is this the right logic to use?  It's not clear to me what the OMX
-    // buffer counts refer to - how do they account for the renderer holding on
-    // to buffers?
-    if (def.nBufferCountActual < def.nBufferCountMin + *minUndequeuedBuffers) {
-        OMX_U32 newBufferCount = def.nBufferCountMin + *minUndequeuedBuffers;
+    // FIXME: assume that surface is controlled by app (native window
+    // returns the number for the case when surface is not controlled by app)
+    (*minUndequeuedBuffers)++;
+
+
+    // Use conservative allocation while also trying to reduce starvation
+    //
+    // 1. allocate at least nBufferCountMin + minUndequeuedBuffers - that is the
+    //    minimum needed for the consumer to be able to work
+    // 2. try to allocate two (2) additional buffers to reduce starvation from
+    //    the consumer
+    for (OMX_U32 extraBuffers = 2; /* condition inside loop */; extraBuffers--) {
+        OMX_U32 newBufferCount =
+            def.nBufferCountMin + *minUndequeuedBuffers + extraBuffers;
         def.nBufferCountActual = newBufferCount;
         err = mOMX->setParameter(
                 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
 
-        if (err != OK) {
-            ALOGE("[%s] setting nBufferCountActual to %lu failed: %d",
-                    mComponentName.c_str(), newBufferCount, err);
+        if (err == OK) {
+            *minUndequeuedBuffers += extraBuffers;
+            break;
+        }
+
+        ALOGW("[%s] setting nBufferCountActual to %lu failed: %d",
+                mComponentName.c_str(), newBufferCount, err);
+        /* exit condition */
+        if (extraBuffers == 0) {
             return err;
         }
     }
@@ -676,6 +693,7 @@
             &bufferCount, &bufferSize, &minUndequeuedBuffers);
     if (err != 0)
         return err;
+    mNumUndequeuedBuffers = minUndequeuedBuffers;
 
     ALOGV("[%s] Allocating %lu buffers from a native window of size %lu on "
          "output port",
@@ -741,6 +759,7 @@
             &bufferCount, &bufferSize, &minUndequeuedBuffers);
     if (err != 0)
         return err;
+    mNumUndequeuedBuffers = minUndequeuedBuffers;
 
     ALOGV("[%s] Allocating %lu meta buffers on output port",
          mComponentName.c_str(), bufferCount);
@@ -961,6 +980,8 @@
             "audio_decoder.aac", "audio_encoder.aac" },
         { MEDIA_MIMETYPE_AUDIO_VORBIS,
             "audio_decoder.vorbis", "audio_encoder.vorbis" },
+        { MEDIA_MIMETYPE_AUDIO_OPUS,
+            "audio_decoder.opus", "audio_encoder.opus" },
         { MEDIA_MIMETYPE_AUDIO_G711_MLAW,
             "audio_decoder.g711mlaw", "audio_encoder.g711mlaw" },
         { MEDIA_MIMETYPE_AUDIO_G711_ALAW,
@@ -1036,6 +1057,9 @@
         encoder = false;
     }
 
+    sp<AMessage> inputFormat = new AMessage();
+    sp<AMessage> outputFormat = new AMessage();
+
     mIsEncoder = encoder;
 
     status_t err = setComponentRole(encoder /* isEncoder */, mime);
@@ -1118,7 +1142,17 @@
         }
 
         if (!msg->findInt64("max-pts-gap-to-encoder", &mMaxPtsGapUs)) {
-            mMaxPtsGapUs = -1l;
+            mMaxPtsGapUs = -1ll;
+        }
+
+        if (!msg->findInt64("time-lapse", &mTimePerCaptureUs)) {
+            mTimePerCaptureUs = -1ll;
+        }
+
+        if (!msg->findInt32(
+                    "create-input-buffers-suspended",
+                    (int32_t*)&mCreateInputBuffersSuspended)) {
+            mCreateInputBuffersSuspended = false;
         }
     }
 
@@ -1127,7 +1161,9 @@
     int32_t haveNativeWindow = msg->findObject("native-window", &obj) &&
             obj != NULL;
     mStoreMetaDataInOutputBuffers = false;
-    mIsConfiguredForAdaptivePlayback = false;
+    if (video && !encoder) {
+        inputFormat->setInt32("adaptive-playback", false);
+    }
     if (!encoder && video && haveNativeWindow) {
         err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexOutput, OMX_TRUE);
         if (err != OK) {
@@ -1164,7 +1200,7 @@
             if (canDoAdaptivePlayback &&
                 msg->findInt32("max-width", &maxWidth) &&
                 msg->findInt32("max-height", &maxHeight)) {
-                ALOGV("[%s] prepareForAdaptivePlayback(%ldx%ld)",
+                ALOGV("[%s] prepareForAdaptivePlayback(%dx%d)",
                       mComponentName.c_str(), maxWidth, maxHeight);
 
                 err = mOMX->prepareForAdaptivePlayback(
@@ -1172,14 +1208,19 @@
                 ALOGW_IF(err != OK,
                         "[%s] prepareForAdaptivePlayback failed w/ err %d",
                         mComponentName.c_str(), err);
-                mIsConfiguredForAdaptivePlayback = (err == OK);
+
+                if (err == OK) {
+                    inputFormat->setInt32("max-width", maxWidth);
+                    inputFormat->setInt32("max-height", maxHeight);
+                    inputFormat->setInt32("adaptive-playback", true);
+                }
             }
             // allow failure
             err = OK;
         } else {
             ALOGV("[%s] storeMetaDataInBuffers succeeded", mComponentName.c_str());
             mStoreMetaDataInOutputBuffers = true;
-            mIsConfiguredForAdaptivePlayback = true;
+            inputFormat->setInt32("adaptive-playback", true);
         }
 
         int32_t push;
@@ -1319,6 +1360,11 @@
         err = setMinBufferSize(kPortIndexInput, 8192);  // XXX
     }
 
+    CHECK_EQ(getPortFormat(kPortIndexInput, inputFormat), (status_t)OK);
+    CHECK_EQ(getPortFormat(kPortIndexOutput, outputFormat), (status_t)OK);
+    mInputFormat = inputFormat;
+    mOutputFormat = outputFormat;
+
     return err;
 }
 
@@ -1909,6 +1955,7 @@
             return INVALID_OPERATION;
         }
         frameRate = (float)tmp;
+        mTimePerFrameUs = (int64_t) (1000000.0f / frameRate);
     }
 
     video_def->xFramerate = (OMX_U32)(frameRate * 65536.0f);
@@ -2482,19 +2529,7 @@
         return;
     }
 
-    int minUndequeuedBufs = 0;
-    status_t err = mNativeWindow->query(
-            mNativeWindow.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-            &minUndequeuedBufs);
-
-    if (err != OK) {
-        ALOGE("[%s] NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)",
-                mComponentName.c_str(), strerror(-err), -err);
-
-        minUndequeuedBufs = 0;
-    }
-
-    while (countBuffersOwnedByNativeWindow() > (size_t)minUndequeuedBufs
+    while (countBuffersOwnedByNativeWindow() > mNumUndequeuedBuffers
             && dequeueBufferFromNativeWindow() != NULL) {
         // these buffers will be submitted as regular buffers; account for this
         if (mStoreMetaDataInOutputBuffers && mMetaDataBuffersToSubmit > 0) {
@@ -2540,79 +2575,78 @@
     }
 }
 
-void ACodec::sendFormatChange(const sp<AMessage> &reply) {
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatOutputFormatChanged);
-
+status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify) {
+    // TODO: catch errors an return them instead of using CHECK
     OMX_PARAM_PORTDEFINITIONTYPE def;
     InitOMXParams(&def);
-    def.nPortIndex = kPortIndexOutput;
+    def.nPortIndex = portIndex;
 
     CHECK_EQ(mOMX->getParameter(
                 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)),
              (status_t)OK);
 
-    CHECK_EQ((int)def.eDir, (int)OMX_DirOutput);
+    CHECK_EQ((int)def.eDir,
+            (int)(portIndex == kPortIndexOutput ? OMX_DirOutput : OMX_DirInput));
 
     switch (def.eDomain) {
         case OMX_PortDomainVideo:
         {
             OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
+            switch ((int)videoDef->eCompressionFormat) {
+                case OMX_VIDEO_CodingUnused:
+                {
+                    CHECK(mIsEncoder ^ (portIndex == kPortIndexOutput));
+                    notify->setString("mime", MEDIA_MIMETYPE_VIDEO_RAW);
 
-            AString mime;
-            if (!mIsEncoder) {
-                notify->setString("mime", MEDIA_MIMETYPE_VIDEO_RAW);
-            } else if (GetMimeTypeForVideoCoding(
+                    notify->setInt32("stride", videoDef->nStride);
+                    notify->setInt32("slice-height", videoDef->nSliceHeight);
+                    notify->setInt32("color-format", videoDef->eColorFormat);
+
+                    OMX_CONFIG_RECTTYPE rect;
+                    InitOMXParams(&rect);
+                    rect.nPortIndex = kPortIndexOutput;
+
+                    if (mOMX->getConfig(
+                                mNode, OMX_IndexConfigCommonOutputCrop,
+                                &rect, sizeof(rect)) != OK) {
+                        rect.nLeft = 0;
+                        rect.nTop = 0;
+                        rect.nWidth = videoDef->nFrameWidth;
+                        rect.nHeight = videoDef->nFrameHeight;
+                    }
+
+                    CHECK_GE(rect.nLeft, 0);
+                    CHECK_GE(rect.nTop, 0);
+                    CHECK_GE(rect.nWidth, 0u);
+                    CHECK_GE(rect.nHeight, 0u);
+                    CHECK_LE(rect.nLeft + rect.nWidth - 1, videoDef->nFrameWidth);
+                    CHECK_LE(rect.nTop + rect.nHeight - 1, videoDef->nFrameHeight);
+
+                    notify->setRect(
+                            "crop",
+                            rect.nLeft,
+                            rect.nTop,
+                            rect.nLeft + rect.nWidth - 1,
+                            rect.nTop + rect.nHeight - 1);
+
+                    break;
+                }
+                default:
+                {
+                    CHECK(mIsEncoder ^ (portIndex == kPortIndexInput));
+                    AString mime;
+                    if (GetMimeTypeForVideoCoding(
                         videoDef->eCompressionFormat, &mime) != OK) {
-                notify->setString("mime", "application/octet-stream");
-            } else {
-                notify->setString("mime", mime.c_str());
+                        notify->setString("mime", "application/octet-stream");
+                    } else {
+                        notify->setString("mime", mime.c_str());
+                    }
+                    break;
+                }
             }
 
             notify->setInt32("width", videoDef->nFrameWidth);
             notify->setInt32("height", videoDef->nFrameHeight);
-
-            if (!mIsEncoder) {
-                notify->setInt32("stride", videoDef->nStride);
-                notify->setInt32("slice-height", videoDef->nSliceHeight);
-                notify->setInt32("color-format", videoDef->eColorFormat);
-
-                OMX_CONFIG_RECTTYPE rect;
-                InitOMXParams(&rect);
-                rect.nPortIndex = kPortIndexOutput;
-
-                if (mOMX->getConfig(
-                            mNode, OMX_IndexConfigCommonOutputCrop,
-                            &rect, sizeof(rect)) != OK) {
-                    rect.nLeft = 0;
-                    rect.nTop = 0;
-                    rect.nWidth = videoDef->nFrameWidth;
-                    rect.nHeight = videoDef->nFrameHeight;
-                }
-
-                CHECK_GE(rect.nLeft, 0);
-                CHECK_GE(rect.nTop, 0);
-                CHECK_GE(rect.nWidth, 0u);
-                CHECK_GE(rect.nHeight, 0u);
-                CHECK_LE(rect.nLeft + rect.nWidth - 1, videoDef->nFrameWidth);
-                CHECK_LE(rect.nTop + rect.nHeight - 1, videoDef->nFrameHeight);
-
-                notify->setRect(
-                        "crop",
-                        rect.nLeft,
-                        rect.nTop,
-                        rect.nLeft + rect.nWidth - 1,
-                        rect.nTop + rect.nHeight - 1);
-
-                if (mNativeWindow != NULL) {
-                    reply->setRect(
-                            "crop",
-                            rect.nLeft,
-                            rect.nTop,
-                            rect.nLeft + rect.nWidth,
-                            rect.nTop + rect.nHeight);
-                }
-            }
             break;
         }
 
@@ -2625,7 +2659,7 @@
                 {
                     OMX_AUDIO_PARAM_PCMMODETYPE params;
                     InitOMXParams(&params);
-                    params.nPortIndex = kPortIndexOutput;
+                    params.nPortIndex = portIndex;
 
                     CHECK_EQ(mOMX->getParameter(
                                 mNode, OMX_IndexParamAudioPcm,
@@ -2645,20 +2679,6 @@
                     notify->setString("mime", MEDIA_MIMETYPE_AUDIO_RAW);
                     notify->setInt32("channel-count", params.nChannels);
                     notify->setInt32("sample-rate", params.nSamplingRate);
-                    if (mEncoderDelay + mEncoderPadding) {
-                        size_t frameSize = params.nChannels * sizeof(int16_t);
-                        if (mSkipCutBuffer != NULL) {
-                            size_t prevbufsize = mSkipCutBuffer->size();
-                            if (prevbufsize != 0) {
-                                ALOGW("Replacing SkipCutBuffer holding %d "
-                                      "bytes",
-                                      prevbufsize);
-                            }
-                        }
-                        mSkipCutBuffer = new SkipCutBuffer(
-                                mEncoderDelay * frameSize,
-                                mEncoderPadding * frameSize);
-                    }
 
                     if (mChannelMaskPresent) {
                         notify->setInt32("channel-mask", mChannelMask);
@@ -2670,7 +2690,7 @@
                 {
                     OMX_AUDIO_PARAM_AACPROFILETYPE params;
                     InitOMXParams(&params);
-                    params.nPortIndex = kPortIndexOutput;
+                    params.nPortIndex = portIndex;
 
                     CHECK_EQ(mOMX->getParameter(
                                 mNode, OMX_IndexParamAudioAac,
@@ -2687,7 +2707,7 @@
                 {
                     OMX_AUDIO_PARAM_AMRTYPE params;
                     InitOMXParams(&params);
-                    params.nPortIndex = kPortIndexOutput;
+                    params.nPortIndex = portIndex;
 
                     CHECK_EQ(mOMX->getParameter(
                                 mNode, OMX_IndexParamAudioAmr,
@@ -2713,7 +2733,7 @@
                 {
                     OMX_AUDIO_PARAM_FLACTYPE params;
                     InitOMXParams(&params);
-                    params.nPortIndex = kPortIndexOutput;
+                    params.nPortIndex = portIndex;
 
                     CHECK_EQ(mOMX->getParameter(
                                 mNode, OMX_IndexParamAudioFlac,
@@ -2726,11 +2746,45 @@
                     break;
                 }
 
+                case OMX_AUDIO_CodingMP3:
+                {
+                    OMX_AUDIO_PARAM_MP3TYPE params;
+                    InitOMXParams(&params);
+                    params.nPortIndex = portIndex;
+
+                    CHECK_EQ(mOMX->getParameter(
+                                mNode, OMX_IndexParamAudioMp3,
+                                &params, sizeof(params)),
+                             (status_t)OK);
+
+                    notify->setString("mime", MEDIA_MIMETYPE_AUDIO_MPEG);
+                    notify->setInt32("channel-count", params.nChannels);
+                    notify->setInt32("sample-rate", params.nSampleRate);
+                    break;
+                }
+
+                case OMX_AUDIO_CodingVORBIS:
+                {
+                    OMX_AUDIO_PARAM_VORBISTYPE params;
+                    InitOMXParams(&params);
+                    params.nPortIndex = portIndex;
+
+                    CHECK_EQ(mOMX->getParameter(
+                                mNode, OMX_IndexParamAudioVorbis,
+                                &params, sizeof(params)),
+                             (status_t)OK);
+
+                    notify->setString("mime", MEDIA_MIMETYPE_AUDIO_VORBIS);
+                    notify->setInt32("channel-count", params.nChannels);
+                    notify->setInt32("sample-rate", params.nSampleRate);
+                    break;
+                }
+
                 case OMX_AUDIO_CodingAndroidAC3:
                 {
                     OMX_AUDIO_PARAM_ANDROID_AC3TYPE params;
                     InitOMXParams(&params);
-                    params.nPortIndex = kPortIndexOutput;
+                    params.nPortIndex = portIndex;
 
                     CHECK_EQ((status_t)OK, mOMX->getParameter(
                             mNode,
@@ -2745,6 +2799,7 @@
                 }
 
                 default:
+                    ALOGE("UNKNOWN AUDIO CODING: %d\n", audioDef->eEncoding);
                     TRESPASS();
             }
             break;
@@ -2754,6 +2809,43 @@
             TRESPASS();
     }
 
+    return OK;
+}
+
+void ACodec::sendFormatChange(const sp<AMessage> &reply) {
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatOutputFormatChanged);
+
+    CHECK_EQ(getPortFormat(kPortIndexOutput, notify), (status_t)OK);
+
+    AString mime;
+    CHECK(notify->findString("mime", &mime));
+
+    int32_t left, top, right, bottom;
+    if (mime == MEDIA_MIMETYPE_VIDEO_RAW &&
+        mNativeWindow != NULL &&
+        notify->findRect("crop", &left, &top, &right, &bottom)) {
+        // notify renderer of the crop change
+        // NOTE: native window uses extended right-bottom coordinate
+        reply->setRect("crop", left, top, right + 1, bottom + 1);
+    } else if (mime == MEDIA_MIMETYPE_AUDIO_RAW &&
+               (mEncoderDelay || mEncoderPadding)) {
+        int32_t channelCount;
+        CHECK(notify->findInt32("channel-count", &channelCount));
+        size_t frameSize = channelCount * sizeof(int16_t);
+        if (mSkipCutBuffer != NULL) {
+            size_t prevbufsize = mSkipCutBuffer->size();
+            if (prevbufsize != 0) {
+                ALOGW("Replacing SkipCutBuffer holding %d "
+                      "bytes",
+                      prevbufsize);
+            }
+        }
+        mSkipCutBuffer = new SkipCutBuffer(
+                mEncoderDelay * frameSize,
+                mEncoderPadding * frameSize);
+    }
+
     notify->post();
 
     mSentFormat = true;
@@ -2960,7 +3052,8 @@
       mCodec(codec) {
 }
 
-ACodec::BaseState::PortMode ACodec::BaseState::getPortMode(OMX_U32 portIndex) {
+ACodec::BaseState::PortMode ACodec::BaseState::getPortMode(
+        OMX_U32 /* portIndex */) {
     return KEEP_BUFFERS;
 }
 
@@ -3369,8 +3462,8 @@
         size_t rangeOffset, size_t rangeLength,
         OMX_U32 flags,
         int64_t timeUs,
-        void *platformPrivate,
-        void *dataPtr) {
+        void * /* platformPrivate */,
+        void * /* dataPtr */) {
     ALOGV("[%s] onOMXFillBufferDone %p time %lld us, flags = 0x%08lx",
          mCodec->mComponentName.c_str(), bufferID, timeUs, flags);
 
@@ -3422,7 +3515,7 @@
             sp<AMessage> reply =
                 new AMessage(kWhatOutputBufferDrained, mCodec->id());
 
-            if (!mCodec->mSentFormat) {
+            if (!mCodec->mSentFormat && rangeLength > 0) {
                 mCodec->sendFormatChange(reply);
             }
 
@@ -3782,7 +3875,8 @@
     mCodec->mDequeueCounter = 0;
     mCodec->mMetaDataBuffersToSubmit = 0;
     mCodec->mRepeatFrameDelayUs = -1ll;
-    mCodec->mIsConfiguredForAdaptivePlayback = false;
+    mCodec->mInputFormat.clear();
+    mCodec->mOutputFormat.clear();
 
     if (mCodec->mShutdownInProgress) {
         bool keepComponentAllocated = mCodec->mKeepComponentAllocated;
@@ -3896,6 +3990,8 @@
     {
         sp<AMessage> notify = mCodec->mNotify->dup();
         notify->setInt32("what", ACodec::kWhatComponentConfigured);
+        notify->setMessage("input-format", mCodec->mInputFormat);
+        notify->setMessage("output-format", mCodec->mOutputFormat);
         notify->post();
     }
 
@@ -3903,7 +3999,7 @@
 }
 
 void ACodec::LoadedState::onCreateInputSurface(
-        const sp<AMessage> &msg) {
+        const sp<AMessage> & /* msg */) {
     ALOGV("onCreateInputSurface");
 
     sp<AMessage> notify = mCodec->mNotify->dup();
@@ -3931,7 +4027,7 @@
         }
     }
 
-    if (err == OK && mCodec->mMaxPtsGapUs > 0l) {
+    if (err == OK && mCodec->mMaxPtsGapUs > 0ll) {
         err = mCodec->mOMX->setInternalOption(
                 mCodec->mNode,
                 kPortIndexInput,
@@ -3941,6 +4037,41 @@
 
         if (err != OK) {
             ALOGE("[%s] Unable to configure max timestamp gap (err %d)",
+                    mCodec->mComponentName.c_str(),
+                    err);
+        }
+    }
+
+    if (err == OK && mCodec->mTimePerCaptureUs > 0ll
+            && mCodec->mTimePerFrameUs > 0ll) {
+        int64_t timeLapse[2];
+        timeLapse[0] = mCodec->mTimePerFrameUs;
+        timeLapse[1] = mCodec->mTimePerCaptureUs;
+        err = mCodec->mOMX->setInternalOption(
+                mCodec->mNode,
+                kPortIndexInput,
+                IOMX::INTERNAL_OPTION_TIME_LAPSE,
+                &timeLapse[0],
+                sizeof(timeLapse));
+
+        if (err != OK) {
+            ALOGE("[%s] Unable to configure time lapse (err %d)",
+                    mCodec->mComponentName.c_str(),
+                    err);
+        }
+    }
+
+    if (err == OK && mCodec->mCreateInputBuffersSuspended) {
+        bool suspend = true;
+        err = mCodec->mOMX->setInternalOption(
+                mCodec->mNode,
+                kPortIndexInput,
+                IOMX::INTERNAL_OPTION_SUSPEND,
+                &suspend,
+                sizeof(suspend));
+
+        if (err != OK) {
+            ALOGE("[%s] Unable to configure option to suspend (err %d)",
                   mCodec->mComponentName.c_str(),
                   err);
         }
@@ -4003,6 +4134,7 @@
 
 bool ACodec::LoadedToIdleState::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
+        case kWhatSetParameters:
         case kWhatShutdown:
         {
             mCodec->deferMessage(msg);
@@ -4069,6 +4201,7 @@
 
 bool ACodec::IdleToExecutingState::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
+        case kWhatSetParameters:
         case kWhatShutdown:
         {
             mCodec->deferMessage(msg);
@@ -4129,7 +4262,7 @@
 }
 
 ACodec::BaseState::PortMode ACodec::ExecutingState::getPortMode(
-        OMX_U32 portIndex) {
+        OMX_U32 /* portIndex */) {
     return RESUBMIT_BUFFERS;
 }
 
@@ -4338,6 +4471,22 @@
         }
     }
 
+    int64_t skipFramesBeforeUs;
+    if (params->findInt64("skip-frames-before", &skipFramesBeforeUs)) {
+        status_t err =
+            mOMX->setInternalOption(
+                     mNode,
+                     kPortIndexInput,
+                     IOMX::INTERNAL_OPTION_START_TIME,
+                     &skipFramesBeforeUs,
+                     sizeof(skipFramesBeforeUs));
+
+        if (err != OK) {
+            ALOGE("Failed to set parameter 'skip-frames-before' (err %d)", err);
+            return err;
+        }
+    }
+
     int32_t dropInputFrames;
     if (params->findInt32("drop-input-frames", &dropInputFrames)) {
         bool suspend = dropInputFrames != 0;
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 03dcbf9..3f592ed 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -189,7 +189,7 @@
             mOffsetTable, mOffsetTableLength);
 }
 
-sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) {
+sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -221,7 +221,7 @@
     }
 }
 
-status_t AMRSource::start(MetaData *params) {
+status_t AMRSource::start(MetaData * /* params */) {
     CHECK(!mStarted);
 
     mOffset = mIsWide ? 9 : 6;
@@ -258,7 +258,7 @@
         int64_t seekFrame = seekTimeUs / 20000ll;  // 20ms per frame.
         mCurrentTimeUs = seekFrame * 20000ll;
 
-        int index = seekFrame / 50;
+        size_t index = seekFrame < 0 ? 0 : seekFrame / 50;
         if (index >= mOffsetTableLength) {
             index = mOffsetTableLength - 1;
         }
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 3fe247a..653ca36 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -105,7 +105,7 @@
     return OK;
 }
 
-status_t AMRWriter::start(MetaData *params) {
+status_t AMRWriter::start(MetaData * /* params */) {
     if (mInitCheck != OK) {
         return mInitCheck;
     }
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 4f17ea5..a9b0c73 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -15,6 +15,7 @@
         CameraSource.cpp                  \
         CameraSourceTimeLapse.cpp         \
         DataSource.cpp                    \
+        DataURISource.cpp                 \
         DRMExtractor.cpp                  \
         ESDS.cpp                          \
         FileSource.cpp                    \
@@ -30,8 +31,10 @@
         MediaBufferGroup.cpp              \
         MediaCodec.cpp                    \
         MediaCodecList.cpp                \
+        MediaCodecSource.cpp              \
         MediaDefs.cpp                     \
         MediaExtractor.cpp                \
+        http/MediaHTTP.cpp                \
         MediaMuxer.cpp                    \
         MediaSource.cpp                   \
         MetaData.cpp                      \
@@ -55,8 +58,6 @@
         WVMExtractor.cpp                  \
         XINGSeeker.cpp                    \
         avc_utils.cpp                     \
-        mp4/FragmentedMP4Parser.cpp       \
-        mp4/TrackFragment.cpp             \
 
 LOCAL_C_INCLUDES:= \
         $(TOP)/frameworks/av/include/media/stagefright/timedtext \
@@ -80,6 +81,7 @@
         libicuuc \
         liblog \
         libmedia \
+        libopus \
         libsonivox \
         libssl \
         libstagefright_omx \
@@ -95,6 +97,7 @@
         libstagefright_color_conversion \
         libstagefright_aacenc \
         libstagefright_matroska \
+        libstagefright_webm \
         libstagefright_timedtext \
         libvpx \
         libwebm \
@@ -103,13 +106,6 @@
         libFLAC \
         libmedia_helper
 
-LOCAL_SRC_FILES += \
-        chromium_http_stub.cpp
-LOCAL_CPPFLAGS += -DCHROMIUM_AVAILABLE=1
-
-LOCAL_SHARED_LIBRARIES += libstlport
-include external/stlport/libstlport.mk
-
 LOCAL_SHARED_LIBRARIES += \
         libstagefright_enc_common \
         libstagefright_avc_common \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 05ee34e..8623100 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -410,7 +410,7 @@
 
 // static
 size_t AudioPlayer::AudioSinkCallback(
-        MediaPlayerBase::AudioSink *audioSink,
+        MediaPlayerBase::AudioSink * /* audioSink */,
         void *buffer, size_t size, void *cookie,
         MediaPlayerBase::AudioSink::cb_event_t event) {
     AudioPlayer *me = (AudioPlayer *)cookie;
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index f0d1a14..d0e0e8e 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -65,10 +65,10 @@
     if (status == OK) {
         // make sure that the AudioRecord callback never returns more than the maximum
         // buffer size
-        int frameCount = kMaxBufferSize / sizeof(int16_t) / channelCount;
+        uint32_t frameCount = kMaxBufferSize / sizeof(int16_t) / channelCount;
 
         // make sure that the AudioRecord total buffer size is large enough
-        int bufCount = 2;
+        size_t bufCount = 2;
         while ((bufCount * frameCount) < minFrameCount) {
             bufCount++;
         }
@@ -76,10 +76,10 @@
         mRecord = new AudioRecord(
                     inputSource, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
                     audio_channel_in_mask_from_count(channelCount),
-                    bufCount * frameCount,
+                    (size_t) (bufCount * frameCount),
                     AudioRecordCallbackFunction,
                     this,
-                    frameCount);
+                    frameCount /*notificationFrames*/);
         mInitCheck = mRecord->initCheck();
     } else {
         mInitCheck = status;
@@ -208,7 +208,7 @@
 }
 
 status_t AudioSource::read(
-        MediaBuffer **out, const ReadOptions *options) {
+        MediaBuffer **out, const ReadOptions * /* options */) {
     Mutex::Autolock autoLock(mLock);
     *out = NULL;
 
@@ -278,7 +278,7 @@
 
     // Drop retrieved and previously lost audio data.
     if (mNumFramesReceived == 0 && timeUs < mStartTimeUs) {
-        mRecord->getInputFramesLost();
+        (void) mRecord->getInputFramesLost();
         ALOGV("Drop audio data at %lld/%lld us", timeUs, mStartTimeUs);
         return OK;
     }
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 29c007a..4bad14b 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -35,6 +35,8 @@
 
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <media/IMediaHTTPConnection.h>
+#include <media/IMediaHTTPService.h>
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -45,6 +47,7 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaHTTP.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/OMXCodec.h>
@@ -83,7 +86,7 @@
 protected:
     virtual ~AwesomeEvent() {}
 
-    virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
+    virtual void fire(TimedEventQueue * /* queue */, int64_t /* now_us */) {
         (mPlayer->*mMethod)();
     }
 
@@ -277,15 +280,20 @@
 }
 
 status_t AwesomePlayer::setDataSource(
-        const char *uri, const KeyedVector<String8, String8> *headers) {
+        const sp<IMediaHTTPService> &httpService,
+        const char *uri,
+        const KeyedVector<String8, String8> *headers) {
     Mutex::Autolock autoLock(mLock);
-    return setDataSource_l(uri, headers);
+    return setDataSource_l(httpService, uri, headers);
 }
 
 status_t AwesomePlayer::setDataSource_l(
-        const char *uri, const KeyedVector<String8, String8> *headers) {
+        const sp<IMediaHTTPService> &httpService,
+        const char *uri,
+        const KeyedVector<String8, String8> *headers) {
     reset_l();
 
+    mHTTPService = httpService;
     mUri = uri;
 
     if (headers) {
@@ -582,6 +590,7 @@
     mSeekNotificationSent = true;
     mSeekTimeUs = 0;
 
+    mHTTPService.clear();
     mUri.setTo("");
     mUriHeaders.clear();
 
@@ -1483,7 +1492,7 @@
     CHECK(source != NULL);
 
     if (mTextDriver == NULL) {
-        mTextDriver = new TimedTextDriver(mListener);
+        mTextDriver = new TimedTextDriver(mListener, mHTTPService);
     }
 
     mTextDriver->addInBandTextSource(trackIndex, source);
@@ -2193,15 +2202,14 @@
     if (!strncasecmp("http://", mUri.string(), 7)
             || !strncasecmp("https://", mUri.string(), 8)
             || isWidevineStreaming) {
-        mConnectingDataSource = HTTPBase::Create(
-                (mFlags & INCOGNITO)
-                    ? HTTPBase::kFlagIncognito
-                    : 0);
-
-        if (mUIDValid) {
-            mConnectingDataSource->setUID(mUID);
+        if (mHTTPService == NULL) {
+            ALOGE("Attempt to play media from http URI without HTTP service.");
+            return UNKNOWN_ERROR;
         }
 
+        sp<IMediaHTTPConnection> conn = mHTTPService->makeHTTPConnection();
+        mConnectingDataSource = new MediaHTTP(conn);
+
         String8 cacheConfig;
         bool disconnectAtHighwatermark;
         NuCachedSource2::RemoveCacheSpecificHeaders(
@@ -2209,6 +2217,10 @@
 
         mLock.unlock();
         status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
+        // force connection at this point, to avoid a race condition between getMIMEType and the
+        // caching datasource constructed below, which could result in multiple requests to the
+        // server, and/or failed connections.
+        String8 contentType = mConnectingDataSource->getMIMEType();
         mLock.lock();
 
         if (err != OK) {
@@ -2239,8 +2251,6 @@
 
         mConnectingDataSource.clear();
 
-        String8 contentType = dataSource->getMIMEType();
-
         if (strncasecmp(contentType.string(), "audio/", 6)) {
             // We're not doing this for streams that appear to be audio-only
             // streams to ensure that even low bandwidth streams start
@@ -2317,7 +2327,8 @@
             }
         }
     } else {
-        dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
+        dataSource = DataSource::CreateFromURI(
+                mHTTPService, mUri.string(), &mUriHeaders);
     }
 
     if (dataSource == NULL) {
@@ -2759,7 +2770,7 @@
         {
             Mutex::Autolock autoLock(mLock);
             if (mTextDriver == NULL) {
-                mTextDriver = new TimedTextDriver(mListener);
+                mTextDriver = new TimedTextDriver(mListener, mHTTPService);
             }
             // String values written in Parcel are UTF-16 values.
             String8 uri(request.readString16());
@@ -2771,7 +2782,7 @@
         {
             Mutex::Autolock autoLock(mLock);
             if (mTextDriver == NULL) {
-                mTextDriver = new TimedTextDriver(mListener);
+                mTextDriver = new TimedTextDriver(mListener, mHTTPService);
             }
             int fd         = request.readFileDescriptor();
             off64_t offset = request.readInt64();
@@ -2804,7 +2815,8 @@
     return mCachedSource != NULL || mWVMExtractor != NULL;
 }
 
-status_t AwesomePlayer::dump(int fd, const Vector<String16> &args) const {
+status_t AwesomePlayer::dump(
+        int fd, const Vector<String16> & /* args */) const {
     Mutex::Autolock autoLock(mStatsLock);
 
     FILE *out = fdopen(dup(fd), "w");
@@ -2900,6 +2912,8 @@
     // get current position so we can start recreated stream from here
     getPosition(&mAudioTearDownPosition);
 
+    sp<IMediaHTTPService> savedHTTPService = mHTTPService;
+
     // Reset and recreate
     reset_l();
 
@@ -2909,7 +2923,7 @@
         mFileSource = fileSource;
         err = setDataSource_l(fileSource);
     } else {
-        err = setDataSource_l(uri, &uriHeaders);
+        err = setDataSource_l(savedHTTPService, uri, &uriHeaders);
     }
 
     mFlags |= PREPARING;
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 3017fe7..b31e9e8 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -31,6 +31,12 @@
 #include <utils/String8.h>
 #include <cutils/properties.h>
 
+#if LOG_NDEBUG
+#define UNUSED_UNLESS_VERBOSE(x) (void)(x)
+#else
+#define UNUSED_UNLESS_VERBOSE(x)
+#endif
+
 namespace android {
 
 static const int64_t CAMERA_SOURCE_TIMEOUT_NS = 3000000000LL;
@@ -63,11 +69,14 @@
 }
 
 void CameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) {
+    UNUSED_UNLESS_VERBOSE(msgType);
+    UNUSED_UNLESS_VERBOSE(ext1);
+    UNUSED_UNLESS_VERBOSE(ext2);
     ALOGV("notify(%d, %d, %d)", msgType, ext1, ext2);
 }
 
 void CameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr,
-                                    camera_frame_metadata_t *metadata) {
+                                    camera_frame_metadata_t * /* metadata */) {
     ALOGV("postData(%d, ptr:%p, size:%d)",
          msgType, dataPtr->pointer(), dataPtr->size());
 
@@ -577,14 +586,15 @@
     }
 }
 
-void CameraSource::startCameraRecording() {
+status_t CameraSource::startCameraRecording() {
     ALOGV("startCameraRecording");
     // Reset the identity to the current thread because media server owns the
     // camera and recording is started by the applications. The applications
     // will connect to the camera in ICameraRecordingProxy::startRecording.
     int64_t token = IPCThreadState::self()->clearCallingIdentity();
+    status_t err;
     if (mNumInputBuffers > 0) {
-        status_t err = mCamera->sendCommand(
+        err = mCamera->sendCommand(
             CAMERA_CMD_SET_VIDEO_BUFFER_COUNT, mNumInputBuffers, 0);
 
         // This could happen for CameraHAL1 clients; thus the failure is
@@ -595,17 +605,25 @@
         }
     }
 
+    err = OK;
     if (mCameraFlags & FLAGS_HOT_CAMERA) {
         mCamera->unlock();
         mCamera.clear();
-        CHECK_EQ((status_t)OK,
-            mCameraRecordingProxy->startRecording(new ProxyListener(this)));
+        if ((err = mCameraRecordingProxy->startRecording(
+                new ProxyListener(this))) != OK) {
+            ALOGE("Failed to start recording, received error: %s (%d)",
+                    strerror(-err), err);
+        }
     } else {
         mCamera->setListener(new CameraSourceListener(this));
         mCamera->startRecording();
-        CHECK(mCamera->recordingEnabled());
+        if (!mCamera->recordingEnabled()) {
+            err = -EINVAL;
+            ALOGE("Failed to start recording");
+        }
     }
     IPCThreadState::self()->restoreCallingIdentity(token);
+    return err;
 }
 
 status_t CameraSource::start(MetaData *meta) {
@@ -637,10 +655,12 @@
         }
     }
 
-    startCameraRecording();
+    status_t err;
+    if ((err = startCameraRecording()) == OK) {
+        mStarted = true;
+    }
 
-    mStarted = true;
-    return OK;
+    return err;
 }
 
 void CameraSource::stopCameraRecording() {
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 5772316..60cdf66 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -85,7 +85,8 @@
     mVideoWidth = videoSize.width;
     mVideoHeight = videoSize.height;
 
-    if (!trySettingVideoSize(videoSize.width, videoSize.height)) {
+    if (OK == mInitCheck && !trySettingVideoSize(videoSize.width, videoSize.height)) {
+        releaseCamera();
         mInitCheck = NO_INIT;
     }
 
@@ -231,7 +232,7 @@
     return newMemory;
 }
 
-bool CameraSourceTimeLapse::skipCurrentFrame(int64_t timestampUs) {
+bool CameraSourceTimeLapse::skipCurrentFrame(int64_t /* timestampUs */) {
     ALOGV("skipCurrentFrame");
     if (mSkipCurrentFrame) {
         mSkipCurrentFrame = false;
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 97987e2..6e0f37a 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -16,10 +16,6 @@
 
 #include "include/AMRExtractor.h"
 
-#if CHROMIUM_AVAILABLE
-#include "include/chromium_http_stub.h"
-#endif
-
 #include "include/AACExtractor.h"
 #include "include/DRMExtractor.h"
 #include "include/FLACExtractor.h"
@@ -35,10 +31,14 @@
 
 #include "matroska/MatroskaExtractor.h"
 
+#include <media/IMediaHTTPConnection.h>
+#include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataURISource.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaHTTP.h>
 #include <utils/String8.h>
 
 #include <cutils/properties.h>
@@ -180,7 +180,9 @@
 
 // static
 sp<DataSource> DataSource::CreateFromURI(
-        const char *uri, const KeyedVector<String8, String8> *headers) {
+        const sp<IMediaHTTPService> &httpService,
+        const char *uri,
+        const KeyedVector<String8, String8> *headers) {
     bool isWidevine = !strncasecmp("widevine://", uri, 11);
 
     sp<DataSource> source;
@@ -189,7 +191,7 @@
     } else if (!strncasecmp("http://", uri, 7)
             || !strncasecmp("https://", uri, 8)
             || isWidevine) {
-        sp<HTTPBase> httpSource = HTTPBase::Create();
+        sp<HTTPBase> httpSource = new MediaHTTP(httpService->makeHTTPConnection());
 
         String8 tmp;
         if (isWidevine) {
@@ -220,11 +222,8 @@
             // in the widevine:// case.
             source = httpSource;
         }
-
-# if CHROMIUM_AVAILABLE
     } else if (!strncasecmp("data:", uri, 5)) {
-        source = createDataUriSource(uri);
-#endif
+        source = DataURISource::Create(uri);
     } else {
         // Assume it's a filename.
         source = new FileSource(uri);
diff --git a/media/libstagefright/DataURISource.cpp b/media/libstagefright/DataURISource.cpp
new file mode 100644
index 0000000..377bc85
--- /dev/null
+++ b/media/libstagefright/DataURISource.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/stagefright/DataURISource.h>
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
+
+namespace android {
+
+// static
+sp<DataURISource> DataURISource::Create(const char *uri) {
+    if (strncasecmp("data:", uri, 5)) {
+        return NULL;
+    }
+
+    char *commaPos = strrchr(uri, ',');
+
+    if (commaPos == NULL) {
+        return NULL;
+    }
+
+    sp<ABuffer> buffer;
+
+    AString tmp(&uri[5], commaPos - &uri[5]);
+
+    if (tmp.endsWith(";base64")) {
+        AString encoded(commaPos + 1);
+
+        // Strip CR and LF...
+        for (size_t i = encoded.size(); i-- > 0;) {
+            if (encoded.c_str()[i] == '\r' || encoded.c_str()[i] == '\n') {
+                encoded.erase(i, 1);
+            }
+        }
+
+        buffer = decodeBase64(encoded);
+
+        if (buffer == NULL) {
+            ALOGE("Malformed base64 encoded content found.");
+            return NULL;
+        }
+    } else {
+#if 0
+        size_t dataLen = strlen(uri) - tmp.size() - 6;
+        buffer = new ABuffer(dataLen);
+        memcpy(buffer->data(), commaPos + 1, dataLen);
+
+        // unescape
+#else
+        // MediaPlayer doesn't care for this right now as we don't
+        // play any text-based media.
+        return NULL;
+#endif
+    }
+
+    // We don't really care about charset or mime type.
+
+    return new DataURISource(buffer);
+}
+
+DataURISource::DataURISource(const sp<ABuffer> &buffer)
+    : mBuffer(buffer) {
+}
+
+DataURISource::~DataURISource() {
+}
+
+status_t DataURISource::initCheck() const {
+    return OK;
+}
+
+ssize_t DataURISource::readAt(off64_t offset, void *data, size_t size) {
+    if (offset >= mBuffer->size()) {
+        return 0;
+    }
+
+    size_t copy = mBuffer->size() - offset;
+    if (copy > size) {
+        copy = size;
+    }
+
+    memcpy(data, mBuffer->data() + offset, copy);
+
+    return copy;
+}
+
+status_t DataURISource::getSize(off64_t *size) {
+    *size = mBuffer->size();
+
+    return OK;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp
index 098fcf9..fa7251c 100644
--- a/media/libstagefright/FLACExtractor.cpp
+++ b/media/libstagefright/FLACExtractor.cpp
@@ -208,55 +208,55 @@
 // with the same parameter list, but discard redundant information.
 
 FLAC__StreamDecoderReadStatus FLACParser::read_callback(
-        const FLAC__StreamDecoder *decoder, FLAC__byte buffer[],
+        const FLAC__StreamDecoder * /* decoder */, FLAC__byte buffer[],
         size_t *bytes, void *client_data)
 {
     return ((FLACParser *) client_data)->readCallback(buffer, bytes);
 }
 
 FLAC__StreamDecoderSeekStatus FLACParser::seek_callback(
-        const FLAC__StreamDecoder *decoder,
+        const FLAC__StreamDecoder * /* decoder */,
         FLAC__uint64 absolute_byte_offset, void *client_data)
 {
     return ((FLACParser *) client_data)->seekCallback(absolute_byte_offset);
 }
 
 FLAC__StreamDecoderTellStatus FLACParser::tell_callback(
-        const FLAC__StreamDecoder *decoder,
+        const FLAC__StreamDecoder * /* decoder */,
         FLAC__uint64 *absolute_byte_offset, void *client_data)
 {
     return ((FLACParser *) client_data)->tellCallback(absolute_byte_offset);
 }
 
 FLAC__StreamDecoderLengthStatus FLACParser::length_callback(
-        const FLAC__StreamDecoder *decoder,
+        const FLAC__StreamDecoder * /* decoder */,
         FLAC__uint64 *stream_length, void *client_data)
 {
     return ((FLACParser *) client_data)->lengthCallback(stream_length);
 }
 
 FLAC__bool FLACParser::eof_callback(
-        const FLAC__StreamDecoder *decoder, void *client_data)
+        const FLAC__StreamDecoder * /* decoder */, void *client_data)
 {
     return ((FLACParser *) client_data)->eofCallback();
 }
 
 FLAC__StreamDecoderWriteStatus FLACParser::write_callback(
-        const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame,
+        const FLAC__StreamDecoder * /* decoder */, const FLAC__Frame *frame,
         const FLAC__int32 * const buffer[], void *client_data)
 {
     return ((FLACParser *) client_data)->writeCallback(frame, buffer);
 }
 
 void FLACParser::metadata_callback(
-        const FLAC__StreamDecoder *decoder,
+        const FLAC__StreamDecoder * /* decoder */,
         const FLAC__StreamMetadata *metadata, void *client_data)
 {
     ((FLACParser *) client_data)->metadataCallback(metadata);
 }
 
 void FLACParser::error_callback(
-        const FLAC__StreamDecoder *decoder,
+        const FLAC__StreamDecoder * /* decoder */,
         FLAC__StreamDecoderErrorStatus status, void *client_data)
 {
     ((FLACParser *) client_data)->errorCallback(status);
@@ -380,15 +380,21 @@
 // Copy samples from FLAC native 32-bit non-interleaved to 16-bit interleaved.
 // These are candidates for optimization if needed.
 
-static void copyMono8(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
-{
+static void copyMono8(
+        short *dst,
+        const int *const *src,
+        unsigned nSamples,
+        unsigned /* nChannels */) {
     for (unsigned i = 0; i < nSamples; ++i) {
         *dst++ = src[0][i] << 8;
     }
 }
 
-static void copyStereo8(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
-{
+static void copyStereo8(
+        short *dst,
+        const int *const *src,
+        unsigned nSamples,
+        unsigned /* nChannels */) {
     for (unsigned i = 0; i < nSamples; ++i) {
         *dst++ = src[0][i] << 8;
         *dst++ = src[1][i] << 8;
@@ -404,15 +410,21 @@
     }
 }
 
-static void copyMono16(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
-{
+static void copyMono16(
+        short *dst,
+        const int *const *src,
+        unsigned nSamples,
+        unsigned /* nChannels */) {
     for (unsigned i = 0; i < nSamples; ++i) {
         *dst++ = src[0][i];
     }
 }
 
-static void copyStereo16(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
-{
+static void copyStereo16(
+        short *dst,
+        const int *const *src,
+        unsigned nSamples,
+        unsigned /* nChannels */) {
     for (unsigned i = 0; i < nSamples; ++i) {
         *dst++ = src[0][i];
         *dst++ = src[1][i];
@@ -430,15 +442,21 @@
 
 // 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger
 
-static void copyMono24(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
-{
+static void copyMono24(
+        short *dst,
+        const int *const *src,
+        unsigned nSamples,
+        unsigned /* nChannels */) {
     for (unsigned i = 0; i < nSamples; ++i) {
         *dst++ = src[0][i] >> 8;
     }
 }
 
-static void copyStereo24(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
-{
+static void copyStereo24(
+        short *dst,
+        const int *const *src,
+        unsigned nSamples,
+        unsigned /* nChannels */) {
     for (unsigned i = 0; i < nSamples; ++i) {
         *dst++ = src[0][i] >> 8;
         *dst++ = src[1][i] >> 8;
@@ -454,8 +472,11 @@
     }
 }
 
-static void copyTrespass(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
-{
+static void copyTrespass(
+        short * /* dst */,
+        const int *const * /* src */,
+        unsigned /* nSamples */,
+        unsigned /* nChannels */) {
     TRESPASS();
 }
 
@@ -700,7 +721,7 @@
     }
 }
 
-status_t FLACSource::start(MetaData *params)
+status_t FLACSource::start(MetaData * /* params */)
 {
     ALOGV("FLACSource::start");
 
@@ -792,8 +813,7 @@
 }
 
 sp<MetaData> FLACExtractor::getTrackMetaData(
-        size_t index, uint32_t flags)
-{
+        size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index > 0) {
         return NULL;
     }
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
index 5fa4b6f..ca68c3d 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libstagefright/HTTPBase.cpp
@@ -20,10 +20,6 @@
 
 #include "include/HTTPBase.h"
 
-#if CHROMIUM_AVAILABLE
-#include "include/chromium_http_stub.h"
-#endif
-
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
 
@@ -40,34 +36,7 @@
       mTotalTransferBytes(0),
       mPrevBandwidthMeasureTimeUs(0),
       mPrevEstimatedBandWidthKbps(0),
-      mBandWidthCollectFreqMs(5000),
-      mUIDValid(false),
-      mUID(0) {
-}
-
-// static
-sp<HTTPBase> HTTPBase::Create(uint32_t flags) {
-#if CHROMIUM_AVAILABLE
-        HTTPBase *dataSource = createChromiumHTTPDataSource(flags);
-        if (dataSource) {
-           return dataSource;
-        }
-#endif
-    {
-        TRESPASS();
-
-        return NULL;
-    }
-}
-
-// static
-status_t HTTPBase::UpdateProxyConfig(
-        const char *host, int32_t port, const char *exclusionList) {
-#if CHROMIUM_AVAILABLE
-    return UpdateChromiumHTTPDataSourceProxyConfig(host, port, exclusionList);
-#else
-    return INVALID_OPERATION;
-#endif
+      mBandWidthCollectFreqMs(5000) {
 }
 
 void HTTPBase::addBandwidthMeasurement(
@@ -135,21 +104,6 @@
     return OK;
 }
 
-void HTTPBase::setUID(uid_t uid) {
-    mUIDValid = true;
-    mUID = uid;
-}
-
-bool HTTPBase::getUID(uid_t *uid) const {
-    if (!mUIDValid) {
-        return false;
-    }
-
-    *uid = mUID;
-
-    return true;
-}
-
 // static
 void HTTPBase::RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag) {
     int res = qtaguid_tagSocket(sockfd, kTag, uid);
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 380dab4..4a63152 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -398,7 +398,8 @@
             mSeeker);
 }
 
-sp<MetaData> MP3Extractor::getTrackMetaData(size_t index, uint32_t flags) {
+sp<MetaData> MP3Extractor::getTrackMetaData(
+        size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index c9ed5bb..78c12e1 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -555,7 +555,7 @@
     return OK;
 }
 
-status_t MPEG2TSWriter::start(MetaData *param) {
+status_t MPEG2TSWriter::start(MetaData * /* param */) {
     CHECK(!mStarted);
 
     mStarted = true;
@@ -596,7 +596,8 @@
     return !mStarted || (mNumSourcesDone == mSources.size() ? true : false);
 }
 
-status_t MPEG2TSWriter::dump(int fd, const Vector<String16> &args) {
+status_t MPEG2TSWriter::dump(
+        int /* fd */, const Vector<String16> & /* args */) {
     return OK;
 }
 
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 6a33ce6..2a3fa04 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -488,12 +488,12 @@
             break;
         }
         uint32_t chunk_type = ntohl(hdr[1]);
-        if (chunk_type == FOURCC('s', 'i', 'd', 'x')) {
-            // parse the sidx box too
-            continue;
-        } else if (chunk_type == FOURCC('m', 'o', 'o', 'f')) {
+        if (chunk_type == FOURCC('m', 'o', 'o', 'f')) {
             // store the offset of the first segment
             mMoofOffset = offset;
+        } else if (chunk_type != FOURCC('m', 'd', 'a', 't')) {
+            // keep parsing until we get to the data
+            continue;
         }
         break;
     }
@@ -571,7 +571,8 @@
     return size;
 }
 
-status_t MPEG4Extractor::parseDrmSINF(off64_t *offset, off64_t data_offset) {
+status_t MPEG4Extractor::parseDrmSINF(
+        off64_t * /* offset */, off64_t data_offset) {
     uint8_t updateIdTag;
     if (mDataSource->readAt(data_offset, &updateIdTag, 1) < 1) {
         return ERROR_IO;
@@ -912,6 +913,8 @@
 
         case FOURCC('e', 'l', 's', 't'):
         {
+            *offset += chunk_size;
+
             // See 14496-12 8.6.6
             uint8_t version;
             if (mDataSource->readAt(data_offset, &version, 1) < 1) {
@@ -974,12 +977,13 @@
                     mLastTrack->meta->setInt32(kKeyEncoderPadding, paddingsamples);
                 }
             }
-            *offset += chunk_size;
             break;
         }
 
         case FOURCC('f', 'r', 'm', 'a'):
         {
+            *offset += chunk_size;
+
             uint32_t original_fourcc;
             if (mDataSource->readAt(data_offset, &original_fourcc, 4) < 4) {
                 return ERROR_IO;
@@ -993,12 +997,13 @@
                 mLastTrack->meta->setInt32(kKeyChannelCount, num_channels);
                 mLastTrack->meta->setInt32(kKeySampleRate, sample_rate);
             }
-            *offset += chunk_size;
             break;
         }
 
         case FOURCC('t', 'e', 'n', 'c'):
         {
+            *offset += chunk_size;
+
             if (chunk_size < 32) {
                 return ERROR_MALFORMED;
             }
@@ -1043,23 +1048,25 @@
             mLastTrack->meta->setInt32(kKeyCryptoMode, defaultAlgorithmId);
             mLastTrack->meta->setInt32(kKeyCryptoDefaultIVSize, defaultIVSize);
             mLastTrack->meta->setData(kKeyCryptoKey, 'tenc', defaultKeyId, 16);
-            *offset += chunk_size;
             break;
         }
 
         case FOURCC('t', 'k', 'h', 'd'):
         {
+            *offset += chunk_size;
+
             status_t err;
             if ((err = parseTrackHeader(data_offset, chunk_data_size)) != OK) {
                 return err;
             }
 
-            *offset += chunk_size;
             break;
         }
 
         case FOURCC('p', 's', 's', 'h'):
         {
+            *offset += chunk_size;
+
             PsshInfo pssh;
 
             if (mDataSource->readAt(data_offset + 4, &pssh.uuid, 16) < 16) {
@@ -1085,12 +1092,13 @@
             }
             mPssh.push_back(pssh);
 
-            *offset += chunk_size;
             break;
         }
 
         case FOURCC('m', 'd', 'h', 'd'):
         {
+            *offset += chunk_size;
+
             if (chunk_data_size < 4) {
                 return ERROR_MALFORMED;
             }
@@ -1171,7 +1179,6 @@
             mLastTrack->meta->setCString(
                     kKeyMediaLanguage, lang_code);
 
-            *offset += chunk_size;
             break;
         }
 
@@ -1338,11 +1345,12 @@
                 mLastTrack->sampleTable->setChunkOffsetParams(
                         chunk_type, data_offset, chunk_data_size);
 
+            *offset += chunk_size;
+
             if (err != OK) {
                 return err;
             }
 
-            *offset += chunk_size;
             break;
         }
 
@@ -1352,11 +1360,12 @@
                 mLastTrack->sampleTable->setSampleToChunkParams(
                         data_offset, chunk_data_size);
 
+            *offset += chunk_size;
+
             if (err != OK) {
                 return err;
             }
 
-            *offset += chunk_size;
             break;
         }
 
@@ -1367,6 +1376,8 @@
                 mLastTrack->sampleTable->setSampleSizeParams(
                         chunk_type, data_offset, chunk_data_size);
 
+            *offset += chunk_size;
+
             if (err != OK) {
                 return err;
             }
@@ -1407,7 +1418,6 @@
                 }
                 mLastTrack->meta->setInt32(kKeyMaxInputSize, max_size);
             }
-            *offset += chunk_size;
 
             // NOTE: setting another piece of metadata invalidates any pointers (such as the
             // mimetype) previously obtained, so don't cache them.
@@ -1431,6 +1441,8 @@
 
         case FOURCC('s', 't', 't', 's'):
         {
+            *offset += chunk_size;
+
             status_t err =
                 mLastTrack->sampleTable->setTimeToSampleParams(
                         data_offset, chunk_data_size);
@@ -1439,12 +1451,13 @@
                 return err;
             }
 
-            *offset += chunk_size;
             break;
         }
 
         case FOURCC('c', 't', 't', 's'):
         {
+            *offset += chunk_size;
+
             status_t err =
                 mLastTrack->sampleTable->setCompositionTimeToSampleParams(
                         data_offset, chunk_data_size);
@@ -1453,12 +1466,13 @@
                 return err;
             }
 
-            *offset += chunk_size;
             break;
         }
 
         case FOURCC('s', 't', 's', 's'):
         {
+            *offset += chunk_size;
+
             status_t err =
                 mLastTrack->sampleTable->setSyncSampleParams(
                         data_offset, chunk_data_size);
@@ -1467,13 +1481,14 @@
                 return err;
             }
 
-            *offset += chunk_size;
             break;
         }
 
         // @xyz
         case FOURCC('\xA9', 'x', 'y', 'z'):
         {
+            *offset += chunk_size;
+
             // Best case the total data length inside "@xyz" box
             // would be 8, for instance "@xyz" + "\x00\x04\x15\xc7" + "0+0/",
             // where "\x00\x04" is the text string length with value = 4,
@@ -1502,12 +1517,13 @@
 
             buffer[location_length] = '\0';
             mFileMetaData->setCString(kKeyLocation, buffer);
-            *offset += chunk_size;
             break;
         }
 
         case FOURCC('e', 's', 'd', 's'):
         {
+            *offset += chunk_size;
+
             if (chunk_data_size < 4) {
                 return ERROR_MALFORMED;
             }
@@ -1545,12 +1561,13 @@
                 }
             }
 
-            *offset += chunk_size;
             break;
         }
 
         case FOURCC('a', 'v', 'c', 'C'):
         {
+            *offset += chunk_size;
+
             sp<ABuffer> buffer = new ABuffer(chunk_data_size);
 
             if (mDataSource->readAt(
@@ -1561,12 +1578,12 @@
             mLastTrack->meta->setData(
                     kKeyAVCC, kTypeAVCC, buffer->data(), chunk_data_size);
 
-            *offset += chunk_size;
             break;
         }
 
         case FOURCC('d', '2', '6', '3'):
         {
+            *offset += chunk_size;
             /*
              * d263 contains a fixed 7 bytes part:
              *   vendor - 4 bytes
@@ -1592,7 +1609,6 @@
 
             mLastTrack->meta->setData(kKeyD263, kTypeD263, buffer, chunk_data_size);
 
-            *offset += chunk_size;
             break;
         }
 
@@ -1600,11 +1616,13 @@
         {
             uint8_t buffer[4];
             if (chunk_data_size < (off64_t)sizeof(buffer)) {
+                *offset += chunk_size;
                 return ERROR_MALFORMED;
             }
 
             if (mDataSource->readAt(
                         data_offset, buffer, 4) < 4) {
+                *offset += chunk_size;
                 return ERROR_IO;
             }
 
@@ -1638,6 +1656,8 @@
         case FOURCC('n', 'a', 'm', 'e'):
         case FOURCC('d', 'a', 't', 'a'):
         {
+            *offset += chunk_size;
+
             if (mPath.size() == 6 && underMetaDataPath(mPath)) {
                 status_t err = parseITunesMetaData(data_offset, chunk_data_size);
 
@@ -1646,12 +1666,13 @@
                 }
             }
 
-            *offset += chunk_size;
             break;
         }
 
         case FOURCC('m', 'v', 'h', 'd'):
         {
+            *offset += chunk_size;
+
             if (chunk_data_size < 24) {
                 return ERROR_MALFORMED;
             }
@@ -1679,7 +1700,6 @@
 
             mFileMetaData->setCString(kKeyDate, s.string());
 
-            *offset += chunk_size;
             break;
         }
 
@@ -1700,6 +1720,8 @@
 
         case FOURCC('h', 'd', 'l', 'r'):
         {
+            *offset += chunk_size;
+
             uint32_t buffer;
             if (mDataSource->readAt(
                         data_offset + 8, &buffer, 4) < 4) {
@@ -1714,7 +1736,6 @@
                 mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP);
             }
 
-            *offset += chunk_size;
             break;
         }
 
@@ -1739,6 +1760,8 @@
                 delete[] buffer;
                 buffer = NULL;
 
+                // advance read pointer so we don't end up reading this again
+                *offset += chunk_size;
                 return ERROR_IO;
             }
 
@@ -1753,6 +1776,8 @@
 
         case FOURCC('c', 'o', 'v', 'r'):
         {
+            *offset += chunk_size;
+
             if (mFileMetaData != NULL) {
                 ALOGV("chunk_data_size = %lld and data_offset = %lld",
                         chunk_data_size, data_offset);
@@ -1767,7 +1792,6 @@
                     buffer->data() + kSkipBytesOfDataBox, chunk_data_size - kSkipBytesOfDataBox);
             }
 
-            *offset += chunk_size;
             break;
         }
 
@@ -1778,25 +1802,27 @@
         case FOURCC('a', 'l', 'b', 'm'):
         case FOURCC('y', 'r', 'r', 'c'):
         {
+            *offset += chunk_size;
+
             status_t err = parse3GPPMetaData(data_offset, chunk_data_size, depth);
 
             if (err != OK) {
                 return err;
             }
 
-            *offset += chunk_size;
             break;
         }
 
         case FOURCC('I', 'D', '3', '2'):
         {
+            *offset += chunk_size;
+
             if (chunk_data_size < 6) {
                 return ERROR_MALFORMED;
             }
 
             parseID3v2MetaData(data_offset + 6);
 
-            *offset += chunk_size;
             break;
         }
 
@@ -1920,9 +1946,10 @@
             ALOGW("sub-sidx boxes not supported yet");
         }
         bool sap = d3 & 0x80000000;
-        bool saptype = d3 >> 28;
-        if (!sap || saptype > 2) {
-            ALOGW("not a stream access point, or unsupported type");
+        uint32_t saptype = (d3 >> 28) & 7;
+        if (!sap || (saptype != 1 && saptype != 2)) {
+            // type 1 and 2 are sync samples
+            ALOGW("not a stream access point, or unsupported type: %08x", d3);
         }
         total_duration += d2;
         offset += 12;
@@ -2441,6 +2468,58 @@
     return OK;
 }
 
+typedef enum {
+    //AOT_NONE             = -1,
+    //AOT_NULL_OBJECT      = 0,
+    //AOT_AAC_MAIN         = 1, /**< Main profile                              */
+    AOT_AAC_LC           = 2,   /**< Low Complexity object                     */
+    //AOT_AAC_SSR          = 3,
+    //AOT_AAC_LTP          = 4,
+    AOT_SBR              = 5,
+    //AOT_AAC_SCAL         = 6,
+    //AOT_TWIN_VQ          = 7,
+    //AOT_CELP             = 8,
+    //AOT_HVXC             = 9,
+    //AOT_RSVD_10          = 10, /**< (reserved)                                */
+    //AOT_RSVD_11          = 11, /**< (reserved)                                */
+    //AOT_TTSI             = 12, /**< TTSI Object                               */
+    //AOT_MAIN_SYNTH       = 13, /**< Main Synthetic object                     */
+    //AOT_WAV_TAB_SYNTH    = 14, /**< Wavetable Synthesis object                */
+    //AOT_GEN_MIDI         = 15, /**< General MIDI object                       */
+    //AOT_ALG_SYNTH_AUD_FX = 16, /**< Algorithmic Synthesis and Audio FX object */
+    AOT_ER_AAC_LC        = 17,   /**< Error Resilient(ER) AAC Low Complexity    */
+    //AOT_RSVD_18          = 18, /**< (reserved)                                */
+    //AOT_ER_AAC_LTP       = 19, /**< Error Resilient(ER) AAC LTP object        */
+    AOT_ER_AAC_SCAL      = 20,   /**< Error Resilient(ER) AAC Scalable object   */
+    //AOT_ER_TWIN_VQ       = 21, /**< Error Resilient(ER) TwinVQ object         */
+    AOT_ER_BSAC          = 22,   /**< Error Resilient(ER) BSAC object           */
+    AOT_ER_AAC_LD        = 23,   /**< Error Resilient(ER) AAC LowDelay object   */
+    //AOT_ER_CELP          = 24, /**< Error Resilient(ER) CELP object           */
+    //AOT_ER_HVXC          = 25, /**< Error Resilient(ER) HVXC object           */
+    //AOT_ER_HILN          = 26, /**< Error Resilient(ER) HILN object           */
+    //AOT_ER_PARA          = 27, /**< Error Resilient(ER) Parametric object     */
+    //AOT_RSVD_28          = 28, /**< might become SSC                          */
+    AOT_PS               = 29,   /**< PS, Parametric Stereo (includes SBR)      */
+    //AOT_MPEGS            = 30, /**< MPEG Surround                             */
+
+    AOT_ESCAPE           = 31,   /**< Signal AOT uses more than 5 bits          */
+
+    //AOT_MP3ONMP4_L1      = 32, /**< MPEG-Layer1 in mp4                        */
+    //AOT_MP3ONMP4_L2      = 33, /**< MPEG-Layer2 in mp4                        */
+    //AOT_MP3ONMP4_L3      = 34, /**< MPEG-Layer3 in mp4                        */
+    //AOT_RSVD_35          = 35, /**< might become DST                          */
+    //AOT_RSVD_36          = 36, /**< might become ALS                          */
+    //AOT_AAC_SLS          = 37, /**< AAC + SLS                                 */
+    //AOT_SLS              = 38, /**< SLS                                       */
+    //AOT_ER_AAC_ELD       = 39, /**< AAC Enhanced Low Delay                    */
+
+    //AOT_USAC             = 42, /**< USAC                                      */
+    //AOT_SAOC             = 43, /**< SAOC                                      */
+    //AOT_LD_MPEGS         = 44, /**< Low Delay MPEG Surround                   */
+
+    //AOT_RSVD50           = 50,  /**< Interim AOT for Rsvd50                   */
+} AUDIO_OBJECT_TYPE;
+
 status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
         const void *esds_data, size_t esds_size) {
     ESDS esds(esds_data, esds_size);
@@ -2523,7 +2602,7 @@
         sampleRate = kSamplingRate[freqIndex];
     }
 
-    if (objectType == 5 || objectType == 29) { // SBR specific config per 14496-3 table 1.13
+    if (objectType == AOT_SBR || objectType == AOT_PS) {//SBR specific config per 14496-3 table 1.13
         uint32_t extFreqIndex = br.getBits(4);
         int32_t extSampleRate;
         if (extFreqIndex == 15) {
@@ -2541,6 +2620,111 @@
         //      mLastTrack->meta->setInt32(kKeyExtSampleRate, extSampleRate);
     }
 
+    switch (numChannels) {
+        // values defined in 14496-3_2009 amendment-4 Table 1.19 - Channel Configuration
+        case 0:
+        case 1:// FC
+        case 2:// FL FR
+        case 3:// FC, FL FR
+        case 4:// FC, FL FR, RC
+        case 5:// FC, FL FR, SL SR
+        case 6:// FC, FL FR, SL SR, LFE
+            //numChannels already contains the right value
+            break;
+        case 11:// FC, FL FR, SL SR, RC, LFE
+            numChannels = 7;
+            break;
+        case 7: // FC, FCL FCR, FL FR, SL SR, LFE
+        case 12:// FC, FL  FR,  SL SR, RL RR, LFE
+        case 14:// FC, FL  FR,  SL SR, LFE, FHL FHR
+            numChannels = 8;
+            break;
+        default:
+            return ERROR_UNSUPPORTED;
+    }
+
+    {
+        if (objectType == AOT_SBR || objectType == AOT_PS) {
+            const int32_t extensionSamplingFrequency = br.getBits(4);
+            objectType = br.getBits(5);
+
+            if (objectType == AOT_ESCAPE) {
+                objectType = 32 + br.getBits(6);
+            }
+        }
+        if (objectType == AOT_AAC_LC || objectType == AOT_ER_AAC_LC ||
+                objectType == AOT_ER_AAC_LD || objectType == AOT_ER_AAC_SCAL ||
+                objectType == AOT_ER_BSAC) {
+            const int32_t frameLengthFlag = br.getBits(1);
+
+            const int32_t dependsOnCoreCoder = br.getBits(1);
+
+            if (dependsOnCoreCoder ) {
+                const int32_t coreCoderDelay = br.getBits(14);
+            }
+
+            const int32_t extensionFlag = br.getBits(1);
+
+            if (numChannels == 0 ) {
+                int32_t channelsEffectiveNum = 0;
+                int32_t channelsNum = 0;
+                const int32_t ElementInstanceTag = br.getBits(4);
+                const int32_t Profile = br.getBits(2);
+                const int32_t SamplingFrequencyIndex = br.getBits(4);
+                const int32_t NumFrontChannelElements = br.getBits(4);
+                const int32_t NumSideChannelElements = br.getBits(4);
+                const int32_t NumBackChannelElements = br.getBits(4);
+                const int32_t NumLfeChannelElements = br.getBits(2);
+                const int32_t NumAssocDataElements = br.getBits(3);
+                const int32_t NumValidCcElements = br.getBits(4);
+
+                const int32_t MonoMixdownPresent = br.getBits(1);
+                if (MonoMixdownPresent != 0) {
+                    const int32_t MonoMixdownElementNumber = br.getBits(4);
+                }
+
+                const int32_t StereoMixdownPresent = br.getBits(1);
+                if (StereoMixdownPresent != 0) {
+                    const int32_t StereoMixdownElementNumber = br.getBits(4);
+                }
+
+                const int32_t MatrixMixdownIndexPresent = br.getBits(1);
+                if (MatrixMixdownIndexPresent != 0) {
+                    const int32_t MatrixMixdownIndex = br.getBits(2);
+                    const int32_t PseudoSurroundEnable = br.getBits(1);
+                }
+
+                int i;
+                for (i=0; i < NumFrontChannelElements; i++) {
+                    const int32_t FrontElementIsCpe = br.getBits(1);
+                    const int32_t FrontElementTagSelect = br.getBits(4);
+                    channelsNum += FrontElementIsCpe ? 2 : 1;
+                }
+
+                for (i=0; i < NumSideChannelElements; i++) {
+                    const int32_t SideElementIsCpe = br.getBits(1);
+                    const int32_t SideElementTagSelect = br.getBits(4);
+                    channelsNum += SideElementIsCpe ? 2 : 1;
+                }
+
+                for (i=0; i < NumBackChannelElements; i++) {
+                    const int32_t BackElementIsCpe = br.getBits(1);
+                    const int32_t BackElementTagSelect = br.getBits(4);
+                    channelsNum += BackElementIsCpe ? 2 : 1;
+                }
+                channelsEffectiveNum = channelsNum;
+
+                for (i=0; i < NumLfeChannelElements; i++) {
+                    const int32_t LfeElementTagSelect = br.getBits(4);
+                    channelsNum += 1;
+                }
+                ALOGV("mpeg4 audio channelsNum = %d", channelsNum);
+                ALOGV("mpeg4 audio channelsEffectiveNum = %d", channelsEffectiveNum);
+                numChannels = channelsNum;
+            }
+        }
+    }
+
     if (numChannels == 0) {
         return ERROR_UNSUPPORTED;
     }
@@ -2741,9 +2925,20 @@
                 }
             }
             if (chunk_type == FOURCC('m', 'o', 'o', 'f')) {
-                // *offset points to the mdat box following this moof
-                parseChunk(offset); // doesn't actually parse it, just updates offset
-                mNextMoofOffset = *offset;
+                // *offset points to the box following this moof. Find the next moof from there.
+
+                while (true) {
+                    if (mDataSource->readAt(*offset, hdr, 8) < 8) {
+                        return ERROR_END_OF_STREAM;
+                    }
+                    chunk_size = ntohl(hdr[0]);
+                    chunk_type = ntohl(hdr[1]);
+                    if (chunk_type == FOURCC('m', 'o', 'o', 'f')) {
+                        mNextMoofOffset = *offset;
+                        break;
+                    }
+                    *offset += chunk_size;
+                }
             }
             break;
         }
@@ -2802,7 +2997,8 @@
     return OK;
 }
 
-status_t MPEG4Source::parseSampleAuxiliaryInformationSizes(off64_t offset, off64_t size) {
+status_t MPEG4Source::parseSampleAuxiliaryInformationSizes(
+        off64_t offset, off64_t /* size */) {
     ALOGV("parseSampleAuxiliaryInformationSizes");
     // 14496-12 8.7.12
     uint8_t version;
@@ -2864,7 +3060,8 @@
     return OK;
 }
 
-status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(off64_t offset, off64_t size) {
+status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(
+        off64_t offset, off64_t /* size */) {
     ALOGV("parseSampleAuxiliaryInformationOffsets");
     // 14496-12 8.7.13
     uint8_t version;
@@ -3546,7 +3743,7 @@
                 const SidxEntry *se = &mSegments[i];
                 if (totalTime + se->mDurationUs > seekTimeUs) {
                     // The requested time is somewhere in this segment
-                    if ((mode == ReadOptions::SEEK_NEXT_SYNC) ||
+                    if ((mode == ReadOptions::SEEK_NEXT_SYNC && seekTimeUs > totalTime) ||
                         (mode == ReadOptions::SEEK_CLOSEST_SYNC &&
                         (seekTimeUs - totalTime) > (totalTime + se->mDurationUs - seekTimeUs))) {
                         // requested next sync, or closest sync and it was closer to the end of
@@ -3559,11 +3756,19 @@
                 totalTime += se->mDurationUs;
                 totalOffset += se->mSize;
             }
-        mCurrentMoofOffset = totalOffset;
-        mCurrentSamples.clear();
-        mCurrentSampleIndex = 0;
-        parseChunk(&totalOffset);
-        mCurrentTime = totalTime * mTimescale / 1000000ll;
+            mCurrentMoofOffset = totalOffset;
+            mCurrentSamples.clear();
+            mCurrentSampleIndex = 0;
+            parseChunk(&totalOffset);
+            mCurrentTime = totalTime * mTimescale / 1000000ll;
+        } else {
+            // without sidx boxes, we can only seek to 0
+            mCurrentMoofOffset = mFirstMoofOffset;
+            mCurrentSamples.clear();
+            mCurrentSampleIndex = 0;
+            off64_t tmp = mCurrentMoofOffset;
+            parseChunk(&tmp);
+            mCurrentTime = 0;
         }
 
         if (mBuffer != NULL) {
@@ -3575,7 +3780,7 @@
     }
 
     off64_t offset = 0;
-    size_t size;
+    size_t size = 0;
     uint32_t cts = 0;
     bool isSyncSample = false;
     bool newBuffer = false;
@@ -3583,16 +3788,18 @@
         newBuffer = true;
 
         if (mCurrentSampleIndex >= mCurrentSamples.size()) {
-            // move to next fragment
-            Sample lastSample = mCurrentSamples[mCurrentSamples.size() - 1];
-            off64_t nextMoof = mNextMoofOffset; // lastSample.offset + lastSample.size;
+            // move to next fragment if there is one
+            if (mNextMoofOffset <= mCurrentMoofOffset) {
+                return ERROR_END_OF_STREAM;
+            }
+            off64_t nextMoof = mNextMoofOffset;
             mCurrentMoofOffset = nextMoof;
             mCurrentSamples.clear();
             mCurrentSampleIndex = 0;
             parseChunk(&nextMoof);
-                if (mCurrentSampleIndex >= mCurrentSamples.size()) {
-                    return ERROR_END_OF_STREAM;
-                }
+            if (mCurrentSampleIndex >= mCurrentSamples.size()) {
+                return ERROR_END_OF_STREAM;
+            }
         }
 
         const Sample *smpl = &mCurrentSamples[mCurrentSampleIndex];
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index e7d3cc2..24e53b3 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -41,10 +41,18 @@
 
 #include "include/ESDS.h"
 
+#define WARN_UNLESS(condition, message, ...) \
+( (CONDITION(condition)) ? false : ({ \
+    ALOGW("Condition %s failed "  message, #condition, ##__VA_ARGS__); \
+    true; \
+}))
+
 namespace android {
 
 static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024;
-static const int64_t kMax32BitFileSize = 0x007fffffffLL;
+static const int64_t kMax32BitFileSize = 0x00ffffffffLL; // 2^32-1 : max FAT32
+                                                         // filesystem file size
+                                                         // used by most SD cards
 static const uint8_t kNalUnitTypeSeqParamSet = 0x07;
 static const uint8_t kNalUnitTypePicParamSet = 0x08;
 static const int64_t kInitialDelayTimeUs     = 700000LL;
@@ -407,7 +415,7 @@
 }
 
 status_t MPEG4Writer::Track::dump(
-        int fd, const Vector<String16>& args) const {
+        int fd, const Vector<String16>& /* args */) const {
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
@@ -861,11 +869,11 @@
     // Fix up the size of the 'mdat' chunk.
     if (mUse32BitOffset) {
         lseek64(mFd, mMdatOffset, SEEK_SET);
-        int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset));
+        uint32_t size = htonl(static_cast<uint32_t>(mOffset - mMdatOffset));
         ::write(mFd, &size, 4);
     } else {
         lseek64(mFd, mMdatOffset + 8, SEEK_SET);
-        int64_t size = mOffset - mMdatOffset;
+        uint64_t size = mOffset - mMdatOffset;
         size = hton64(size);
         ::write(mFd, &size, 8);
     }
@@ -973,13 +981,16 @@
     if (param && param->findInt32(kKeyFileType, &fileType) &&
         fileType != OUTPUT_FORMAT_MPEG_4) {
         writeFourcc("3gp4");
-    } else {
+        writeInt32(0);
         writeFourcc("isom");
+        writeFourcc("3gp4");
+    } else {
+        writeFourcc("mp42");
+        writeInt32(0);
+        writeFourcc("isom");
+        writeFourcc("mp42");
     }
 
-    writeInt32(0);
-    writeFourcc("isom");
-    writeFourcc("3gp4");
     endBox();
 }
 
@@ -1761,7 +1772,7 @@
 }
 
 status_t MPEG4Writer::Track::stop() {
-    ALOGD("Stopping %s track", mIsAudio? "Audio": "Video");
+    ALOGD("%s track stopping", mIsAudio? "Audio": "Video");
     if (!mStarted) {
         ALOGE("Stop() called but track is not started");
         return ERROR_END_OF_STREAM;
@@ -1772,19 +1783,14 @@
     }
     mDone = true;
 
+    ALOGD("%s track source stopping", mIsAudio? "Audio": "Video");
+    mSource->stop();
+    ALOGD("%s track source stopped", mIsAudio? "Audio": "Video");
+
     void *dummy;
     pthread_join(mThread, &dummy);
-
     status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
 
-    ALOGD("Stopping %s track source", mIsAudio? "Audio": "Video");
-    {
-        status_t status = mSource->stop();
-        if (err == OK && status != OK && status != ERROR_END_OF_STREAM) {
-            err = status;
-        }
-    }
-
     ALOGD("%s track stopped", mIsAudio? "Audio": "Video");
     return err;
 }
@@ -2098,6 +2104,7 @@
 
     status_t err = OK;
     MediaBuffer *buffer;
+    const char *trackName = mIsAudio ? "Audio" : "Video";
     while (!mDone && (err = mSource->read(&buffer)) == OK) {
         if (buffer->range_length() == 0) {
             buffer->release();
@@ -2193,15 +2200,27 @@
 
         if (mResumed) {
             int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
-            CHECK_GE(durExcludingEarlierPausesUs, 0ll);
+            if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) {
+                copy->release();
+                return ERROR_MALFORMED;
+            }
+
             int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
-            CHECK_GE(pausedDurationUs, lastDurationUs);
+            if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) {
+                copy->release();
+                return ERROR_MALFORMED;
+            }
+
             previousPausedDurationUs += pausedDurationUs - lastDurationUs;
             mResumed = false;
         }
 
         timestampUs -= previousPausedDurationUs;
-        CHECK_GE(timestampUs, 0ll);
+        if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
+            copy->release();
+            return ERROR_MALFORMED;
+        }
+
         if (!mIsAudio) {
             /*
              * Composition time: timestampUs
@@ -2213,7 +2232,11 @@
             decodingTimeUs -= previousPausedDurationUs;
             cttsOffsetTimeUs =
                     timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
-            CHECK_GE(cttsOffsetTimeUs, 0ll);
+            if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) {
+                copy->release();
+                return ERROR_MALFORMED;
+            }
+
             timestampUs = decodingTimeUs;
             ALOGV("decoding time: %lld and ctts offset time: %lld",
                 timestampUs, cttsOffsetTimeUs);
@@ -2221,7 +2244,11 @@
             // Update ctts box table if necessary
             currCttsOffsetTimeTicks =
                     (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
-            CHECK_LE(currCttsOffsetTimeTicks, 0x0FFFFFFFFLL);
+            if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) {
+                copy->release();
+                return ERROR_MALFORMED;
+            }
+
             if (mStszTableEntries->count() == 0) {
                 // Force the first ctts table entry to have one single entry
                 // so that we can do adjustment for the initial track start
@@ -2259,9 +2286,13 @@
             }
         }
 
-        CHECK_GE(timestampUs, 0ll);
+        if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
+            copy->release();
+            return ERROR_MALFORMED;
+        }
+
         ALOGV("%s media time stamp: %lld and previous paused duration %lld",
-                mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs);
+                trackName, timestampUs, previousPausedDurationUs);
         if (timestampUs > mTrackDurationUs) {
             mTrackDurationUs = timestampUs;
         }
@@ -2276,10 +2307,27 @@
                 (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
         if (currDurationTicks < 0ll) {
             ALOGE("timestampUs %lld < lastTimestampUs %lld for %s track",
-                timestampUs, lastTimestampUs, mIsAudio? "Audio": "Video");
+                timestampUs, lastTimestampUs, trackName);
+            copy->release();
             return UNKNOWN_ERROR;
         }
 
+        // if the duration is different for this sample, see if it is close enough to the previous
+        // duration that we can fudge it and use the same value, to avoid filling the stts table
+        // with lots of near-identical entries.
+        // "close enough" here means that the current duration needs to be adjusted by less
+        // than 0.1 milliseconds
+        if (lastDurationTicks && (currDurationTicks != lastDurationTicks)) {
+            int64_t deltaUs = ((lastDurationTicks - currDurationTicks) * 1000000LL
+                    + (mTimeScale / 2)) / mTimeScale;
+            if (deltaUs > -100 && deltaUs < 100) {
+                // use previous ticks, and adjust timestamp as if it was actually that number
+                // of ticks
+                currDurationTicks = lastDurationTicks;
+                timestampUs += deltaUs;
+            }
+        }
+
         mStszTableEntries->add(htonl(sampleSize));
         if (mStszTableEntries->count() > 2) {
 
@@ -2300,7 +2348,7 @@
             previousSampleSize = sampleSize;
         }
         ALOGV("%s timestampUs/lastTimestampUs: %lld/%lld",
-                mIsAudio? "Audio": "Video", timestampUs, lastTimestampUs);
+                trackName, timestampUs, lastTimestampUs);
         lastDurationUs = timestampUs - lastTimestampUs;
         lastDurationTicks = currDurationTicks;
         lastTimestampUs = timestampUs;
@@ -2405,7 +2453,7 @@
     sendTrackSummary(hasMultipleTracks);
 
     ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
-            count, nZeroLengthFrames, mStszTableEntries->count(), mIsAudio? "audio": "video");
+            count, nZeroLengthFrames, mStszTableEntries->count(), trackName);
     if (mIsAudio) {
         ALOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs());
     }
diff --git a/media/libstagefright/MediaAdapter.cpp b/media/libstagefright/MediaAdapter.cpp
index 2484212..d680e0c 100644
--- a/media/libstagefright/MediaAdapter.cpp
+++ b/media/libstagefright/MediaAdapter.cpp
@@ -36,7 +36,7 @@
     CHECK(mCurrentMediaBuffer == NULL);
 }
 
-status_t MediaAdapter::start(MetaData *params) {
+status_t MediaAdapter::start(MetaData * /* params */) {
     Mutex::Autolock autoLock(mAdapterLock);
     if (!mStarted) {
         mStarted = true;
@@ -75,7 +75,7 @@
 }
 
 status_t MediaAdapter::read(
-            MediaBuffer **buffer, const ReadOptions *options) {
+            MediaBuffer **buffer, const ReadOptions * /* options */) {
     Mutex::Autolock autoLock(mAdapterLock);
     if (!mStarted) {
         ALOGV("Read before even started!");
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index c4c47b3..e0419ca 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -115,7 +115,7 @@
         if (codecIdx >= 0) {
             Vector<AString> types;
             if (mcl->getSupportedTypes(codecIdx, &types) == OK) {
-                for (int i = 0; i < types.size(); i++) {
+                for (size_t i = 0; i < types.size(); i++) {
                     if (types[i].startsWith("video/")) {
                         needDedicatedLooper = true;
                         break;
@@ -352,6 +352,20 @@
     return OK;
 }
 
+status_t MediaCodec::getInputFormat(sp<AMessage> *format) const {
+    sp<AMessage> msg = new AMessage(kWhatGetInputFormat, id());
+
+    sp<AMessage> response;
+    status_t err;
+    if ((err = PostAndAwaitResponse(msg, &response)) != OK) {
+        return err;
+    }
+
+    CHECK(response->findMessage("format", format));
+
+    return OK;
+}
+
 status_t MediaCodec::getName(AString *name) const {
     sp<AMessage> msg = new AMessage(kWhatGetName, id());
 
@@ -642,6 +656,9 @@
                     // reset input surface flag
                     mHaveInputSurface = false;
 
+                    CHECK(msg->findMessage("input-format", &mInputFormat));
+                    CHECK(msg->findMessage("output-format", &mOutputFormat));
+
                     (new AMessage)->postReply(mReplyID);
                     break;
                 }
@@ -1330,14 +1347,19 @@
             break;
         }
 
+        case kWhatGetInputFormat:
         case kWhatGetOutputFormat:
         {
+            sp<AMessage> format =
+                (msg->what() == kWhatGetOutputFormat ? mOutputFormat : mInputFormat);
+
             uint32_t replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
-            if ((mState != STARTED && mState != FLUSHING)
+            if ((mState != CONFIGURED && mState != STARTING &&
+                 mState != STARTED && mState != FLUSHING)
                     || (mFlags & kFlagStickyError)
-                    || mOutputFormat == NULL) {
+                    || format == NULL) {
                 sp<AMessage> response = new AMessage;
                 response->setInt32("err", INVALID_OPERATION);
 
@@ -1346,7 +1368,7 @@
             }
 
             sp<AMessage> response = new AMessage;
-            response->setMessage("format", mOutputFormat);
+            response->setMessage("format", format);
             response->postReply(replyID);
             break;
         }
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
new file mode 100644
index 0000000..924173c
--- /dev/null
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -0,0 +1,881 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaCodecSource"
+#define DEBUG_DRIFT_TIME 0
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
+#include <media/ICrypto.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaCodecSource.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+static void ReleaseMediaBufferReference(const sp<ABuffer> &accessUnit) {
+    void *mbuf;
+    if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf)
+            && mbuf != NULL) {
+        ALOGV("releasing mbuf %p", mbuf);
+
+        accessUnit->meta()->setPointer("mediaBuffer", NULL);
+
+        static_cast<MediaBuffer *>(mbuf)->release();
+        mbuf = NULL;
+    }
+}
+
+struct MediaCodecSource::Puller : public AHandler {
+    Puller(const sp<MediaSource> &source);
+
+    status_t start(const sp<MetaData> &meta, const sp<AMessage> &notify);
+    void stopAsync();
+
+    void pause();
+    void resume();
+
+protected:
+    virtual void onMessageReceived(const sp<AMessage> &msg);
+    virtual ~Puller();
+
+private:
+    enum {
+        kWhatStart = 'msta',
+        kWhatStop,
+        kWhatPull,
+        kWhatPause,
+        kWhatResume,
+    };
+
+    sp<MediaSource> mSource;
+    sp<AMessage> mNotify;
+    sp<ALooper> mLooper;
+    int32_t mPullGeneration;
+    bool mIsAudio;
+    bool mPaused;
+    bool mReachedEOS;
+
+    status_t postSynchronouslyAndReturnError(const sp<AMessage> &msg);
+    void schedulePull();
+    void handleEOS();
+
+    DISALLOW_EVIL_CONSTRUCTORS(Puller);
+};
+
+MediaCodecSource::Puller::Puller(const sp<MediaSource> &source)
+    : mSource(source),
+      mLooper(new ALooper()),
+      mPullGeneration(0),
+      mIsAudio(false),
+      mPaused(false),
+      mReachedEOS(false) {
+    sp<MetaData> meta = source->getFormat();
+    const char *mime;
+    CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+    mIsAudio = !strncasecmp(mime, "audio/", 6);
+
+    mLooper->setName("pull_looper");
+}
+
+MediaCodecSource::Puller::~Puller() {
+    mLooper->unregisterHandler(id());
+    mLooper->stop();
+}
+
+status_t MediaCodecSource::Puller::postSynchronouslyAndReturnError(
+        const sp<AMessage> &msg) {
+    sp<AMessage> response;
+    status_t err = msg->postAndAwaitResponse(&response);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (!response->findInt32("err", &err)) {
+        err = OK;
+    }
+
+    return err;
+}
+
+status_t MediaCodecSource::Puller::start(const sp<MetaData> &meta,
+        const sp<AMessage> &notify) {
+    ALOGV("puller (%s) start", mIsAudio ? "audio" : "video");
+    mLooper->start(
+            false /* runOnCallingThread */,
+            false /* canCallJava */,
+            PRIORITY_AUDIO);
+    mLooper->registerHandler(this);
+    mNotify = notify;
+
+    sp<AMessage> msg = new AMessage(kWhatStart, id());
+    msg->setObject("meta", meta);
+    return postSynchronouslyAndReturnError(msg);
+}
+
+void MediaCodecSource::Puller::stopAsync() {
+    ALOGV("puller (%s) stopAsync", mIsAudio ? "audio" : "video");
+    (new AMessage(kWhatStop, id()))->post();
+}
+
+void MediaCodecSource::Puller::pause() {
+    (new AMessage(kWhatPause, id()))->post();
+}
+
+void MediaCodecSource::Puller::resume() {
+    (new AMessage(kWhatResume, id()))->post();
+}
+
+void MediaCodecSource::Puller::schedulePull() {
+    sp<AMessage> msg = new AMessage(kWhatPull, id());
+    msg->setInt32("generation", mPullGeneration);
+    msg->post();
+}
+
+void MediaCodecSource::Puller::handleEOS() {
+    if (!mReachedEOS) {
+        ALOGV("puller (%s) posting EOS", mIsAudio ? "audio" : "video");
+        mReachedEOS = true;
+        sp<AMessage> notify = mNotify->dup();
+        notify->setPointer("accessUnit", NULL);
+        notify->post();
+    }
+}
+
+void MediaCodecSource::Puller::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatStart:
+        {
+            sp<RefBase> obj;
+            CHECK(msg->findObject("meta", &obj));
+
+            mReachedEOS = false;
+
+            status_t err = mSource->start(static_cast<MetaData *>(obj.get()));
+
+            if (err == OK) {
+                schedulePull();
+            }
+
+            sp<AMessage> response = new AMessage;
+            response->setInt32("err", err);
+
+            uint32_t replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+            response->postReply(replyID);
+            break;
+        }
+
+        case kWhatStop:
+        {
+            ALOGV("source (%s) stopping", mIsAudio ? "audio" : "video");
+            mSource->stop();
+            ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video");
+            ++mPullGeneration;
+
+            handleEOS();
+            break;
+        }
+
+        case kWhatPull:
+        {
+            int32_t generation;
+            CHECK(msg->findInt32("generation", &generation));
+
+            if (generation != mPullGeneration) {
+                break;
+            }
+
+            MediaBuffer *mbuf;
+            status_t err = mSource->read(&mbuf);
+
+            if (mPaused) {
+                if (err == OK) {
+                    mbuf->release();
+                    mbuf = NULL;
+                }
+
+                msg->post();
+                break;
+            }
+
+            if (err != OK) {
+                if (err == ERROR_END_OF_STREAM) {
+                    ALOGV("stream ended, mbuf %p", mbuf);
+                } else {
+                    ALOGE("error %d reading stream.", err);
+                }
+                handleEOS();
+            } else {
+                sp<AMessage> notify = mNotify->dup();
+
+                notify->setPointer("accessUnit", mbuf);
+                notify->post();
+
+                msg->post();
+            }
+            break;
+        }
+
+        case kWhatPause:
+        {
+            mPaused = true;
+            break;
+        }
+
+        case kWhatResume:
+        {
+            mPaused = false;
+            break;
+        }
+
+        default:
+            TRESPASS();
+    }
+}
+
+// static
+sp<MediaCodecSource> MediaCodecSource::Create(
+        const sp<ALooper> &looper,
+        const sp<AMessage> &format,
+        const sp<MediaSource> &source,
+        uint32_t flags) {
+    sp<MediaCodecSource> mediaSource =
+            new MediaCodecSource(looper, format, source, flags);
+
+    if (mediaSource->init() == OK) {
+        return mediaSource;
+    }
+    return NULL;
+}
+
+status_t MediaCodecSource::start(MetaData* params) {
+    sp<AMessage> msg = new AMessage(kWhatStart, mReflector->id());
+    msg->setObject("meta", params);
+    return postSynchronouslyAndReturnError(msg);
+}
+
+status_t MediaCodecSource::stop() {
+    sp<AMessage> msg = new AMessage(kWhatStop, mReflector->id());
+    return postSynchronouslyAndReturnError(msg);
+}
+
+status_t MediaCodecSource::pause() {
+    (new AMessage(kWhatPause, mReflector->id()))->post();
+    return OK;
+}
+
+sp<IGraphicBufferProducer> MediaCodecSource::getGraphicBufferProducer() {
+    CHECK(mFlags & FLAG_USE_SURFACE_INPUT);
+    return mGraphicBufferProducer;
+}
+
+status_t MediaCodecSource::read(
+        MediaBuffer** buffer, const ReadOptions* /* options */) {
+    Mutex::Autolock autolock(mOutputBufferLock);
+
+    *buffer = NULL;
+    while (mOutputBufferQueue.size() == 0 && !mEncodedReachedEOS) {
+        mOutputBufferCond.wait(mOutputBufferLock);
+    }
+    if (!mEncodedReachedEOS) {
+        *buffer = *mOutputBufferQueue.begin();
+        mOutputBufferQueue.erase(mOutputBufferQueue.begin());
+        return OK;
+    }
+    return mErrorCode;
+}
+
+void MediaCodecSource::signalBufferReturned(MediaBuffer *buffer) {
+    buffer->setObserver(0);
+    buffer->release();
+}
+
+MediaCodecSource::MediaCodecSource(
+        const sp<ALooper> &looper,
+        const sp<AMessage> &outputFormat,
+        const sp<MediaSource> &source,
+        uint32_t flags)
+    : mLooper(looper),
+      mOutputFormat(outputFormat),
+      mMeta(new MetaData),
+      mFlags(flags),
+      mIsVideo(false),
+      mStarted(false),
+      mStopping(false),
+      mDoMoreWorkPending(false),
+      mPullerReachedEOS(false),
+      mFirstSampleTimeUs(-1ll),
+      mEncodedReachedEOS(false),
+      mErrorCode(OK) {
+    CHECK(mLooper != NULL);
+
+    AString mime;
+    CHECK(mOutputFormat->findString("mime", &mime));
+
+    if (!strncasecmp("video/", mime.c_str(), 6)) {
+        mIsVideo = true;
+    }
+
+    if (!(mFlags & FLAG_USE_SURFACE_INPUT)) {
+        mPuller = new Puller(source);
+    }
+}
+
+MediaCodecSource::~MediaCodecSource() {
+    releaseEncoder();
+
+    mCodecLooper->stop();
+    mLooper->unregisterHandler(mReflector->id());
+}
+
+status_t MediaCodecSource::init() {
+    status_t err = initEncoder();
+
+    if (err != OK) {
+        releaseEncoder();
+    }
+
+    return err;
+}
+
+status_t MediaCodecSource::initEncoder() {
+    mReflector = new AHandlerReflector<MediaCodecSource>(this);
+    mLooper->registerHandler(mReflector);
+
+    mCodecLooper = new ALooper;
+    mCodecLooper->setName("codec_looper");
+    mCodecLooper->start();
+
+    if (mFlags & FLAG_USE_METADATA_INPUT) {
+        mOutputFormat->setInt32("store-metadata-in-buffers", 1);
+    }
+
+    if (mFlags & FLAG_USE_SURFACE_INPUT) {
+        mOutputFormat->setInt32("create-input-buffers-suspended", 1);
+    }
+
+    AString outputMIME;
+    CHECK(mOutputFormat->findString("mime", &outputMIME));
+
+    mEncoder = MediaCodec::CreateByType(
+            mCodecLooper, outputMIME.c_str(), true /* encoder */);
+
+    if (mEncoder == NULL) {
+        return NO_INIT;
+    }
+
+    ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str());
+
+    status_t err = mEncoder->configure(
+                mOutputFormat,
+                NULL /* nativeWindow */,
+                NULL /* crypto */,
+                MediaCodec::CONFIGURE_FLAG_ENCODE);
+
+    if (err != OK) {
+        return err;
+    }
+
+    mEncoder->getOutputFormat(&mOutputFormat);
+    convertMessageToMetaData(mOutputFormat, mMeta);
+
+    if (mFlags & FLAG_USE_SURFACE_INPUT) {
+        CHECK(mIsVideo);
+
+        err = mEncoder->createInputSurface(&mGraphicBufferProducer);
+
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    err = mEncoder->start();
+
+    if (err != OK) {
+        return err;
+    }
+
+    err = mEncoder->getInputBuffers(&mEncoderInputBuffers);
+
+    if (err != OK) {
+        return err;
+    }
+
+    err = mEncoder->getOutputBuffers(&mEncoderOutputBuffers);
+
+    if (err != OK) {
+        return err;
+    }
+
+    mEncodedReachedEOS = false;
+    mErrorCode = OK;
+
+    return OK;
+}
+
+void MediaCodecSource::releaseEncoder() {
+    if (mEncoder == NULL) {
+        return;
+    }
+
+    mEncoder->release();
+    mEncoder.clear();
+
+    while (!mInputBufferQueue.empty()) {
+        MediaBuffer *mbuf = *mInputBufferQueue.begin();
+        mInputBufferQueue.erase(mInputBufferQueue.begin());
+        if (mbuf != NULL) {
+            mbuf->release();
+        }
+    }
+
+    for (size_t i = 0; i < mEncoderInputBuffers.size(); ++i) {
+        sp<ABuffer> accessUnit = mEncoderInputBuffers.itemAt(i);
+        ReleaseMediaBufferReference(accessUnit);
+    }
+
+    mEncoderInputBuffers.clear();
+    mEncoderOutputBuffers.clear();
+}
+
+bool MediaCodecSource::reachedEOS() {
+    return mEncodedReachedEOS && ((mPuller == NULL) || mPullerReachedEOS);
+}
+
+status_t MediaCodecSource::postSynchronouslyAndReturnError(
+        const sp<AMessage> &msg) {
+    sp<AMessage> response;
+    status_t err = msg->postAndAwaitResponse(&response);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (!response->findInt32("err", &err)) {
+        err = OK;
+    }
+
+    return err;
+}
+
+void MediaCodecSource::signalEOS(status_t err) {
+    if (!mEncodedReachedEOS) {
+        ALOGI("encoder (%s) reached EOS", mIsVideo ? "video" : "audio");
+        {
+            Mutex::Autolock autoLock(mOutputBufferLock);
+            // release all unread media buffers
+            for (List<MediaBuffer*>::iterator it = mOutputBufferQueue.begin();
+                    it != mOutputBufferQueue.end(); it++) {
+                (*it)->release();
+            }
+            mOutputBufferQueue.clear();
+            mEncodedReachedEOS = true;
+            mErrorCode = err;
+            mOutputBufferCond.signal();
+        }
+
+        releaseEncoder();
+    }
+    if (mStopping && reachedEOS()) {
+        ALOGI("MediaCodecSource (%s) fully stopped",
+                mIsVideo ? "video" : "audio");
+        // posting reply to everyone that's waiting
+        List<uint32_t>::iterator it;
+        for (it = mStopReplyIDQueue.begin();
+                it != mStopReplyIDQueue.end(); it++) {
+            (new AMessage)->postReply(*it);
+        }
+        mStopReplyIDQueue.clear();
+        mStopping = false;
+    }
+}
+
+void MediaCodecSource::suspend() {
+    CHECK(mFlags & FLAG_USE_SURFACE_INPUT);
+    if (mEncoder != NULL) {
+        sp<AMessage> params = new AMessage;
+        params->setInt32("drop-input-frames", true);
+        mEncoder->setParameters(params);
+    }
+}
+
+void MediaCodecSource::resume(int64_t skipFramesBeforeUs) {
+    CHECK(mFlags & FLAG_USE_SURFACE_INPUT);
+    if (mEncoder != NULL) {
+        sp<AMessage> params = new AMessage;
+        params->setInt32("drop-input-frames", false);
+        if (skipFramesBeforeUs > 0) {
+            params->setInt64("skip-frames-before", skipFramesBeforeUs);
+        }
+        mEncoder->setParameters(params);
+    }
+}
+
+void MediaCodecSource::scheduleDoMoreWork() {
+    if (mDoMoreWorkPending) {
+        return;
+    }
+
+    mDoMoreWorkPending = true;
+
+    if (mEncoderActivityNotify == NULL) {
+        mEncoderActivityNotify = new AMessage(
+                kWhatEncoderActivity, mReflector->id());
+    }
+    mEncoder->requestActivityNotification(mEncoderActivityNotify);
+}
+
+status_t MediaCodecSource::feedEncoderInputBuffers() {
+    while (!mInputBufferQueue.empty()
+            && !mAvailEncoderInputIndices.empty()) {
+        MediaBuffer* mbuf = *mInputBufferQueue.begin();
+        mInputBufferQueue.erase(mInputBufferQueue.begin());
+
+        size_t bufferIndex = *mAvailEncoderInputIndices.begin();
+        mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin());
+
+        int64_t timeUs = 0ll;
+        uint32_t flags = 0;
+        size_t size = 0;
+
+        if (mbuf != NULL) {
+            CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
+
+            // push decoding time for video, or drift time for audio
+            if (mIsVideo) {
+                mDecodingTimeQueue.push_back(timeUs);
+            } else {
+#if DEBUG_DRIFT_TIME
+                if (mFirstSampleTimeUs < 0ll) {
+                    mFirstSampleTimeUs = timeUs;
+                }
+
+                int64_t driftTimeUs = 0;
+                if (mbuf->meta_data()->findInt64(kKeyDriftTime, &driftTimeUs)
+                        && driftTimeUs) {
+                    driftTimeUs = timeUs - mFirstSampleTimeUs - driftTimeUs;
+                }
+                mDriftTimeQueue.push_back(driftTimeUs);
+#endif // DEBUG_DRIFT_TIME
+            }
+
+            size = mbuf->size();
+
+            memcpy(mEncoderInputBuffers.itemAt(bufferIndex)->data(),
+                   mbuf->data(), size);
+
+            if (mIsVideo) {
+                // video encoder will release MediaBuffer when done
+                // with underlying data.
+                mEncoderInputBuffers.itemAt(bufferIndex)->meta()
+                        ->setPointer("mediaBuffer", mbuf);
+            } else {
+                mbuf->release();
+            }
+        } else {
+            flags = MediaCodec::BUFFER_FLAG_EOS;
+        }
+
+        status_t err = mEncoder->queueInputBuffer(
+                bufferIndex, 0, size, timeUs, flags);
+
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    return OK;
+}
+
+status_t MediaCodecSource::doMoreWork() {
+    status_t err;
+
+    if (!(mFlags & FLAG_USE_SURFACE_INPUT)) {
+        for (;;) {
+            size_t bufferIndex;
+            err = mEncoder->dequeueInputBuffer(&bufferIndex);
+
+            if (err != OK) {
+                break;
+            }
+
+            mAvailEncoderInputIndices.push_back(bufferIndex);
+        }
+
+        feedEncoderInputBuffers();
+    }
+
+    for (;;) {
+        size_t bufferIndex;
+        size_t offset;
+        size_t size;
+        int64_t timeUs;
+        uint32_t flags;
+        native_handle_t* handle = NULL;
+        err = mEncoder->dequeueOutputBuffer(
+                &bufferIndex, &offset, &size, &timeUs, &flags);
+
+        if (err != OK) {
+            if (err == INFO_FORMAT_CHANGED) {
+                continue;
+            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
+                mEncoder->getOutputBuffers(&mEncoderOutputBuffers);
+                continue;
+            }
+
+            if (err == -EAGAIN) {
+                err = OK;
+            }
+            break;
+        }
+        if (!(flags & MediaCodec::BUFFER_FLAG_EOS)) {
+            sp<ABuffer> outbuf = mEncoderOutputBuffers.itemAt(bufferIndex);
+
+            MediaBuffer *mbuf = new MediaBuffer(outbuf->size());
+            memcpy(mbuf->data(), outbuf->data(), outbuf->size());
+
+            if (!(flags & MediaCodec::BUFFER_FLAG_CODECCONFIG)) {
+                if (mIsVideo) {
+                    int64_t decodingTimeUs;
+                    if (mFlags & FLAG_USE_SURFACE_INPUT) {
+                        // GraphicBufferSource is supposed to discard samples
+                        // queued before start, and offset timeUs by start time
+                        CHECK_GE(timeUs, 0ll);
+                        // TODO:
+                        // Decoding time for surface source is unavailable,
+                        // use presentation time for now. May need to move
+                        // this logic into MediaCodec.
+                        decodingTimeUs = timeUs;
+                    } else {
+                        CHECK(!mDecodingTimeQueue.empty());
+                        decodingTimeUs = *(mDecodingTimeQueue.begin());
+                        mDecodingTimeQueue.erase(mDecodingTimeQueue.begin());
+                    }
+                    mbuf->meta_data()->setInt64(kKeyDecodingTime, decodingTimeUs);
+
+                    ALOGV("[video] time %lld us (%.2f secs), dts/pts diff %lld",
+                            timeUs, timeUs / 1E6, decodingTimeUs - timeUs);
+                } else {
+                    int64_t driftTimeUs = 0;
+#if DEBUG_DRIFT_TIME
+                    CHECK(!mDriftTimeQueue.empty());
+                    driftTimeUs = *(mDriftTimeQueue.begin());
+                    mDriftTimeQueue.erase(mDriftTimeQueue.begin());
+                    mbuf->meta_data()->setInt64(kKeyDriftTime, driftTimeUs);
+#endif // DEBUG_DRIFT_TIME
+                    ALOGV("[audio] time %lld us (%.2f secs), drift %lld",
+                            timeUs, timeUs / 1E6, driftTimeUs);
+                }
+                mbuf->meta_data()->setInt64(kKeyTime, timeUs);
+            } else {
+                mbuf->meta_data()->setInt32(kKeyIsCodecConfig, true);
+            }
+            if (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME) {
+                mbuf->meta_data()->setInt32(kKeyIsSyncFrame, true);
+            }
+            mbuf->setObserver(this);
+            mbuf->add_ref();
+
+            {
+                Mutex::Autolock autoLock(mOutputBufferLock);
+                mOutputBufferQueue.push_back(mbuf);
+                mOutputBufferCond.signal();
+            }
+        }
+
+        mEncoder->releaseOutputBuffer(bufferIndex);
+
+        if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+            err = ERROR_END_OF_STREAM;
+            break;
+        }
+    }
+
+    return err;
+}
+
+status_t MediaCodecSource::onStart(MetaData *params) {
+    if (mStopping) {
+        ALOGE("Failed to start while we're stopping");
+        return INVALID_OPERATION;
+    }
+
+    if (mStarted) {
+        ALOGI("MediaCodecSource (%s) resuming", mIsVideo ? "video" : "audio");
+        if (mFlags & FLAG_USE_SURFACE_INPUT) {
+            resume();
+        } else {
+            CHECK(mPuller != NULL);
+            mPuller->resume();
+        }
+        return OK;
+    }
+
+    ALOGI("MediaCodecSource (%s) starting", mIsVideo ? "video" : "audio");
+
+    status_t err = OK;
+
+    if (mFlags & FLAG_USE_SURFACE_INPUT) {
+        int64_t startTimeUs;
+        if (!params || !params->findInt64(kKeyTime, &startTimeUs)) {
+            startTimeUs = -1ll;
+        }
+        resume(startTimeUs);
+        scheduleDoMoreWork();
+    } else {
+        CHECK(mPuller != NULL);
+        sp<AMessage> notify = new AMessage(
+                kWhatPullerNotify, mReflector->id());
+        err = mPuller->start(params, notify);
+        if (err != OK) {
+            mPullerReachedEOS = true;
+            return err;
+        }
+    }
+
+    ALOGI("MediaCodecSource (%s) started", mIsVideo ? "video" : "audio");
+
+    mStarted = true;
+    return OK;
+}
+
+void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+    case kWhatPullerNotify:
+    {
+        MediaBuffer *mbuf;
+        CHECK(msg->findPointer("accessUnit", (void**)&mbuf));
+
+        if (mbuf == NULL) {
+            ALOGI("puller (%s) reached EOS",
+                    mIsVideo ? "video" : "audio");
+            mPullerReachedEOS = true;
+        }
+
+        if (mEncoder == NULL) {
+            ALOGV("got msg '%s' after encoder shutdown.",
+                  msg->debugString().c_str());
+
+            if (mbuf != NULL) {
+                mbuf->release();
+            } else {
+                signalEOS();
+            }
+            break;
+        }
+
+        mInputBufferQueue.push_back(mbuf);
+
+        feedEncoderInputBuffers();
+        scheduleDoMoreWork();
+
+        break;
+    }
+    case kWhatEncoderActivity:
+    {
+        mDoMoreWorkPending = false;
+
+        if (mEncoder == NULL) {
+            break;
+        }
+
+        status_t err = doMoreWork();
+
+        if (err == OK) {
+            scheduleDoMoreWork();
+        } else {
+            // reached EOS, or error
+            signalEOS(err);
+        }
+
+        break;
+    }
+    case kWhatStart:
+    {
+        uint32_t replyID;
+        CHECK(msg->senderAwaitsResponse(&replyID));
+
+        sp<RefBase> obj;
+        CHECK(msg->findObject("meta", &obj));
+        MetaData *params = static_cast<MetaData *>(obj.get());
+
+        sp<AMessage> response = new AMessage;
+        response->setInt32("err", onStart(params));
+        response->postReply(replyID);
+        break;
+    }
+    case kWhatStop:
+    {
+        ALOGI("MediaCodecSource (%s) stopping", mIsVideo ? "video" : "audio");
+
+        uint32_t replyID;
+        CHECK(msg->senderAwaitsResponse(&replyID));
+
+        if (reachedEOS()) {
+            // if we already reached EOS, reply and return now
+            ALOGI("MediaCodecSource (%s) already stopped",
+                    mIsVideo ? "video" : "audio");
+            (new AMessage)->postReply(replyID);
+            break;
+        }
+
+        mStopReplyIDQueue.push_back(replyID);
+        if (mStopping) {
+            // nothing to do if we're already stopping, reply will be posted
+            // to all when we're stopped.
+            break;
+        }
+
+        mStopping = true;
+
+        // if using surface, signal source EOS and wait for EOS to come back.
+        // otherwise, release encoder and post EOS if haven't done already
+        if (mFlags & FLAG_USE_SURFACE_INPUT) {
+            mEncoder->signalEndOfInputStream();
+        } else {
+            CHECK(mPuller != NULL);
+            mPuller->stopAsync();
+            signalEOS();
+        }
+        break;
+    }
+    case kWhatPause:
+    {
+        if (mFlags && FLAG_USE_SURFACE_INPUT) {
+            suspend();
+        } else {
+            CHECK(mPuller != NULL);
+            mPuller->pause();
+        }
+        break;
+    }
+    default:
+        TRESPASS();
+    }
+}
+
+} // namespace android
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 340cba7..c670bb4 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -36,6 +36,7 @@
 const char *MEDIA_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
 const char *MEDIA_MIMETYPE_AUDIO_QCELP = "audio/qcelp";
 const char *MEDIA_MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
+const char *MEDIA_MIMETYPE_AUDIO_OPUS = "audio/opus";
 const char *MEDIA_MIMETYPE_AUDIO_G711_ALAW = "audio/g711-alaw";
 const char *MEDIA_MIMETYPE_AUDIO_G711_MLAW = "audio/g711-mlaw";
 const char *MEDIA_MIMETYPE_AUDIO_RAW = "audio/raw";
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index d87e910..90335ee 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -16,6 +16,9 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MediaMuxer"
+
+#include "webm/WebmWriter.h"
+
 #include <utils/Log.h>
 
 #include <media/stagefright/MediaMuxer.h>
@@ -36,19 +39,30 @@
 namespace android {
 
 MediaMuxer::MediaMuxer(const char *path, OutputFormat format)
-    : mState(UNINITIALIZED) {
+    : mFormat(format),
+      mState(UNINITIALIZED) {
     if (format == OUTPUT_FORMAT_MPEG_4) {
         mWriter = new MPEG4Writer(path);
+    } else if (format == OUTPUT_FORMAT_WEBM) {
+        mWriter = new WebmWriter(path);
+    }
+
+    if (mWriter != NULL) {
         mFileMeta = new MetaData;
         mState = INITIALIZED;
     }
-
 }
 
 MediaMuxer::MediaMuxer(int fd, OutputFormat format)
-    : mState(UNINITIALIZED) {
+    : mFormat(format),
+      mState(UNINITIALIZED) {
     if (format == OUTPUT_FORMAT_MPEG_4) {
         mWriter = new MPEG4Writer(fd);
+    } else if (format == OUTPUT_FORMAT_WEBM) {
+        mWriter = new WebmWriter(fd);
+    }
+
+    if (mWriter != NULL) {
         mFileMeta = new MetaData;
         mState = INITIALIZED;
     }
@@ -109,8 +123,13 @@
         ALOGE("setLocation() must be called before start().");
         return INVALID_OPERATION;
     }
+    if (mFormat != OUTPUT_FORMAT_MPEG_4) {
+        ALOGE("setLocation() is only supported for .mp4 output.");
+        return INVALID_OPERATION;
+    }
+
     ALOGV("Setting location: latitude = %d, longitude = %d", latitude, longitude);
-    return mWriter->setGeoData(latitude, longitude);
+    return static_cast<MPEG4Writer*>(mWriter.get())->setGeoData(latitude, longitude);
 }
 
 status_t MediaMuxer::start() {
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 05e599b..72ea32d 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -213,7 +213,14 @@
 
     mLooper->setName("NuCachedSource2");
     mLooper->registerHandler(mReflector);
-    mLooper->start();
+
+    // Since it may not be obvious why our looper thread needs to be
+    // able to call into java since it doesn't appear to do so at all...
+    // IMediaHTTPConnection may be (and most likely is) implemented in JAVA
+    // and a local JAVA IBinder will call directly into JNI methods.
+    // So whenever we call DataSource::readAt it may end up in a call to
+    // IMediaHTTPConnection::readAt and therefore call back into JAVA.
+    mLooper->start(false /* runOnCallingThread */, true /* canCallJava */);
 
     Mutex::Autolock autoLock(mLock);
     (new AMessage(kWhatFetchMore, mReflector->id()))->post();
@@ -326,7 +333,7 @@
             mNumRetriesLeft = 0;
         }
 
-        ALOGE("source returned error %ld, %d retries left", n, mNumRetriesLeft);
+        ALOGE("source returned error %d, %d retries left", n, mNumRetriesLeft);
         mCache->releasePage(page);
     } else if (n == 0) {
         ALOGI("ERROR_END_OF_STREAM");
@@ -641,7 +648,7 @@
     ssize_t lowwaterMarkKb, highwaterMarkKb;
     int keepAliveSecs;
 
-    if (sscanf(s, "%ld/%ld/%d",
+    if (sscanf(s, "%d/%d/%d",
                &lowwaterMarkKb, &highwaterMarkKb, &keepAliveSecs) != 3) {
         ALOGE("Failed to parse cache parameters from '%s'.", s);
         return;
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 7bc7da2..64f56e9 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -58,7 +58,9 @@
 }
 
 status_t NuMediaExtractor::setDataSource(
-        const char *path, const KeyedVector<String8, String8> *headers) {
+        const sp<IMediaHTTPService> &httpService,
+        const char *path,
+        const KeyedVector<String8, String8> *headers) {
     Mutex::Autolock autoLock(mLock);
 
     if (mImpl != NULL) {
@@ -66,7 +68,7 @@
     }
 
     sp<DataSource> dataSource =
-        DataSource::CreateFromURI(path, headers);
+        DataSource::CreateFromURI(httpService, path, headers);
 
     if (dataSource == NULL) {
         return -ENOENT;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 625922f..545ca9d 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -94,6 +94,7 @@
 
 #define CODEC_LOGI(x, ...) ALOGI("[%s] "x, mComponentName, ##__VA_ARGS__)
 #define CODEC_LOGV(x, ...) ALOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
+#define CODEC_LOGW(x, ...) ALOGW("[%s] "x, mComponentName, ##__VA_ARGS__)
 #define CODEC_LOGE(x, ...) ALOGE("[%s] "x, mComponentName, ##__VA_ARGS__)
 
 struct OMXCodecObserver : public BnOMXObserver {
@@ -489,6 +490,13 @@
 
             CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size));
             addCodecSpecificData(data, size);
+        } else if (meta->findData(kKeyOpusHeader, &type, &data, &size)) {
+            addCodecSpecificData(data, size);
+
+            CHECK(meta->findData(kKeyOpusCodecDelay, &type, &data, &size));
+            addCodecSpecificData(data, size);
+            CHECK(meta->findData(kKeyOpusSeekPreRoll, &type, &data, &size));
+            addCodecSpecificData(data, size);
         }
     }
 
@@ -1387,6 +1395,8 @@
             "audio_decoder.aac", "audio_encoder.aac" },
         { MEDIA_MIMETYPE_AUDIO_VORBIS,
             "audio_decoder.vorbis", "audio_encoder.vorbis" },
+        { MEDIA_MIMETYPE_AUDIO_OPUS,
+            "audio_decoder.opus", "audio_encoder.opus" },
         { MEDIA_MIMETYPE_AUDIO_G711_MLAW,
             "audio_decoder.g711mlaw", "audio_encoder.g711mlaw" },
         { MEDIA_MIMETYPE_AUDIO_G711_ALAW,
@@ -1794,21 +1804,40 @@
                 strerror(-err), -err);
         return err;
     }
+    // FIXME: assume that surface is controlled by app (native window
+    // returns the number for the case when surface is not controlled by app)
+    minUndequeuedBufs++;
 
-    // XXX: Is this the right logic to use?  It's not clear to me what the OMX
-    // buffer counts refer to - how do they account for the renderer holding on
-    // to buffers?
-    if (def.nBufferCountActual < def.nBufferCountMin + minUndequeuedBufs) {
-        OMX_U32 newBufferCount = def.nBufferCountMin + minUndequeuedBufs;
+    // Use conservative allocation while also trying to reduce starvation
+    //
+    // 1. allocate at least nBufferCountMin + minUndequeuedBuffers - that is the
+    //    minimum needed for the consumer to be able to work
+    // 2. try to allocate two (2) additional buffers to reduce starvation from
+    //    the consumer
+    CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d",
+            def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs);
+
+    for (OMX_U32 extraBuffers = 2; /* condition inside loop */; extraBuffers--) {
+        OMX_U32 newBufferCount =
+            def.nBufferCountMin + minUndequeuedBufs + extraBuffers;
         def.nBufferCountActual = newBufferCount;
         err = mOMX->setParameter(
                 mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
-        if (err != OK) {
-            CODEC_LOGE("setting nBufferCountActual to %lu failed: %d",
-                    newBufferCount, err);
+
+        if (err == OK) {
+            minUndequeuedBufs += extraBuffers;
+            break;
+        }
+
+        CODEC_LOGW("setting nBufferCountActual to %lu failed: %d",
+                newBufferCount, err);
+        /* exit condition */
+        if (extraBuffers == 0) {
             return err;
         }
     }
+    CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d",
+            def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs);
 
     err = native_window_set_buffer_count(
             mNativeWindow.get(), def.nBufferCountActual);
@@ -4125,6 +4154,7 @@
         "OMX_AUDIO_CodingMP3",
         "OMX_AUDIO_CodingSBC",
         "OMX_AUDIO_CodingVORBIS",
+        "OMX_AUDIO_CodingOPUS",
         "OMX_AUDIO_CodingWMA",
         "OMX_AUDIO_CodingRA",
         "OMX_AUDIO_CodingMIDI",
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 5e79e78..f3eeb03 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -151,7 +151,7 @@
     return mExtractor->mImpl->getFormat();
 }
 
-status_t OggSource::start(MetaData *params) {
+status_t OggSource::start(MetaData * /* params */) {
     if (mStarted) {
         return INVALID_OPERATION;
     }
@@ -381,7 +381,7 @@
     ssize_t n;
     if ((n = mSource->readAt(offset, header, sizeof(header)))
             < (ssize_t)sizeof(header)) {
-        ALOGV("failed to read %d bytes at offset 0x%016llx, got %ld bytes",
+        ALOGV("failed to read %zu bytes at offset 0x%016llx, got %d bytes",
              sizeof(header), offset, n);
 
         if (n < 0) {
@@ -505,7 +505,7 @@
                     packetSize);
 
             if (n < (ssize_t)packetSize) {
-                ALOGV("failed to read %d bytes at 0x%016llx, got %ld bytes",
+                ALOGV("failed to read %zu bytes at 0x%016llx, got %d bytes",
                      packetSize, dataOffset, n);
                 return ERROR_IO;
             }
@@ -546,7 +546,7 @@
                 buffer = NULL;
             }
 
-            ALOGV("readPage returned %ld", n);
+            ALOGV("readPage returned %d", n);
 
             return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
         }
@@ -998,7 +998,7 @@
 }
 
 sp<MetaData> OggExtractor::getTrackMetaData(
-        size_t index, uint32_t flags) {
+        size_t index, uint32_t /* flags */) {
     if (index >= 1) {
         return NULL;
     }
diff --git a/media/libstagefright/SkipCutBuffer.cpp b/media/libstagefright/SkipCutBuffer.cpp
index 773854f..e2e6d79 100644
--- a/media/libstagefright/SkipCutBuffer.cpp
+++ b/media/libstagefright/SkipCutBuffer.cpp
@@ -25,7 +25,7 @@
 namespace android {
 
 SkipCutBuffer::SkipCutBuffer(int32_t skip, int32_t cut) {
-    mFrontPadding = skip;
+    mFrontPadding = mSkip = skip;
     mBackPadding = cut;
     mWriteHead = 0;
     mReadHead = 0;
@@ -94,6 +94,7 @@
 
 void SkipCutBuffer::clear() {
     mWriteHead = mReadHead = 0;
+    mFrontPadding = mSkip;
 }
 
 void SkipCutBuffer::write(const char *src, size_t num) {
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index af8186c..fe20835 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -24,6 +24,7 @@
 
 #include <media/stagefright/StagefrightMediaScanner.h>
 
+#include <media/IMediaHTTPService.h>
 #include <media/mediametadataretriever.h>
 #include <private/media/VideoFrame.h>
 
@@ -117,7 +118,7 @@
 }
 
 MediaScanResult StagefrightMediaScanner::processFileInternal(
-        const char *path, const char *mimeType,
+        const char *path, const char * /* mimeType */,
         MediaScannerClient &client) {
     const char *extension = strrchr(path, '.');
 
@@ -147,7 +148,7 @@
     status_t status;
     if (fd < 0) {
         // couldn't open it locally, maybe the media server can?
-        status = mRetriever->setDataSource(path);
+        status = mRetriever->setDataSource(NULL /* httpService */, path);
     } else {
         status = mRetriever->setDataSource(fd, 0, 0x7ffffffffffffffL);
         close(fd);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index fcd9a85..9475d05 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -21,6 +21,7 @@
 
 #include "include/StagefrightMetadataRetriever.h"
 
+#include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/ColorConverter.h>
 #include <media/stagefright/DataSource.h>
@@ -51,7 +52,9 @@
 }
 
 status_t StagefrightMetadataRetriever::setDataSource(
-        const char *uri, const KeyedVector<String8, String8> *headers) {
+        const sp<IMediaHTTPService> &httpService,
+        const char *uri,
+        const KeyedVector<String8, String8> *headers) {
     ALOGV("setDataSource(%s)", uri);
 
     mParsedMetaData = false;
@@ -59,7 +62,7 @@
     delete mAlbumArt;
     mAlbumArt = NULL;
 
-    mSource = DataSource::CreateFromURI(uri, headers);
+    mSource = DataSource::CreateFromURI(httpService, uri, headers);
 
     if (mSource == NULL) {
         ALOGE("Unable to create data source for '%s'.", uri);
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 6b934d4..e7cc46d 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -99,8 +99,11 @@
     dump(result, "", buffer, 1024);
 }
 
-void SurfaceMediaSource::dump(String8& result, const char* prefix,
-        char* buffer, size_t SIZE) const
+void SurfaceMediaSource::dump(
+        String8& result,
+        const char* /* prefix */,
+        char* buffer,
+        size_t /* SIZE */) const
 {
     Mutex::Autolock lock(mMutex);
 
@@ -202,6 +205,9 @@
         return OK;
     }
 
+    mStarted = false;
+    mFrameAvailableCondition.signal();
+
     while (mNumPendingBuffers > 0) {
         ALOGI("Still waiting for %d buffers to be returned.",
                 mNumPendingBuffers);
@@ -215,8 +221,6 @@
         mMediaBuffersAvailableCondition.wait(mMutex);
     }
 
-    mStarted = false;
-    mFrameAvailableCondition.signal();
     mMediaBuffersAvailableCondition.signal();
 
     return mBufferQueue->consumerDisconnect();
@@ -269,9 +273,8 @@
             bufferHandle, (*buffer)->range_length(), (*buffer)->range_offset());
 }
 
-status_t SurfaceMediaSource::read( MediaBuffer **buffer,
-                                    const ReadOptions *options)
-{
+status_t SurfaceMediaSource::read(
+        MediaBuffer **buffer, const ReadOptions * /* options */) {
     ALOGV("read");
     Mutex::Autolock lock(mMutex);
 
@@ -474,4 +477,8 @@
     }
 }
 
+void SurfaceMediaSource::onSidebandStreamChanged() {
+    ALOG_ASSERT(false, "SurfaceMediaSource can't consume sideband streams");
+}
+
 } // end of namespace android
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 0afac69..3d2eb1f 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -376,8 +376,8 @@
     mPowerManager.clear();
 }
 
-void TimedEventQueue::PMDeathRecipient::binderDied(const wp<IBinder>& who)
-{
+void TimedEventQueue::PMDeathRecipient::binderDied(
+        const wp<IBinder>& /* who */) {
     mQueue->clearPowerManager();
 }
 
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 216a329..4ff805f 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -251,6 +251,13 @@
         buffer->meta()->setInt32("csd", true);
         buffer->meta()->setInt64("timeUs", 0);
         msg->setBuffer("csd-1", buffer);
+    } else if (meta->findData(kKeyOpusHeader, &type, &data, &size)) {
+        sp<ABuffer> buffer = new ABuffer(size);
+        memcpy(buffer->data(), data, size);
+
+        buffer->meta()->setInt32("csd", true);
+        buffer->meta()->setInt64("timeUs", 0);
+        msg->setBuffer("csd-0", buffer);
     }
 
     *format = msg;
@@ -452,6 +459,11 @@
         }
     }
 
+    int32_t timeScale;
+    if (msg->findInt32("time-scale", &timeScale)) {
+        meta->setInt32(kKeyTimeScale, timeScale);
+    }
+
     // XXX TODO add whatever other keys there are
 
 #if 0
@@ -523,6 +535,7 @@
     { MEDIA_MIMETYPE_AUDIO_AMR_WB,      AUDIO_FORMAT_AMR_WB },
     { MEDIA_MIMETYPE_AUDIO_AAC,         AUDIO_FORMAT_AAC },
     { MEDIA_MIMETYPE_AUDIO_VORBIS,      AUDIO_FORMAT_VORBIS },
+    { MEDIA_MIMETYPE_AUDIO_OPUS,        AUDIO_FORMAT_OPUS},
     { 0, AUDIO_FORMAT_INVALID }
 };
 
diff --git a/media/libstagefright/VBRISeeker.cpp b/media/libstagefright/VBRISeeker.cpp
index a245f2c..af858b9 100644
--- a/media/libstagefright/VBRISeeker.cpp
+++ b/media/libstagefright/VBRISeeker.cpp
@@ -119,7 +119,7 @@
 
         seeker->mSegments.push(numBytes);
 
-        ALOGV("entry #%d: %d offset 0x%08lx", i, numBytes, offset);
+        ALOGV("entry #%d: %u offset 0x%016llx", i, numBytes, offset);
         offset += numBytes;
     }
 
@@ -160,7 +160,7 @@
         *pos += mSegments.itemAt(segmentIndex++);
     }
 
-    ALOGV("getOffsetForTime %lld us => 0x%08lx", *timeUs, *pos);
+    ALOGV("getOffsetForTime %lld us => 0x%016llx", *timeUs, *pos);
 
     *timeUs = nowUs;
 
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 22af6fb..fe9058b 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -127,7 +127,7 @@
 }
 
 sp<MetaData> WAVExtractor::getTrackMetaData(
-        size_t index, uint32_t flags) {
+        size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index > 0) {
         return NULL;
     }
@@ -358,7 +358,7 @@
     }
 }
 
-status_t WAVSource::start(MetaData *params) {
+status_t WAVSource::start(MetaData * /* params */) {
     ALOGV("WAVSource::start");
 
     CHECK(!mStarted);
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index b822868..38a1f6b 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -40,6 +40,25 @@
     return x + (1u << numZeroes) - 1;
 }
 
+signed parseSE(ABitReader *br) {
+    unsigned codeNum = parseUE(br);
+
+    return (codeNum & 1) ? (codeNum + 1) / 2 : -(codeNum / 2);
+}
+
+static void skipScalingList(ABitReader *br, size_t sizeOfScalingList) {
+    size_t lastScale = 8;
+    size_t nextScale = 8;
+    for (size_t j = 0; j < sizeOfScalingList; ++j) {
+        if (nextScale != 0) {
+            signed delta_scale = parseSE(br);
+            nextScale = (lastScale + delta_scale + 256) % 256;
+        }
+
+        lastScale = (nextScale == 0) ? lastScale : nextScale;
+    }
+}
+
 // Determine video dimensions from the sequence parameterset.
 void FindAVCDimensions(
         const sp<ABuffer> &seqParamSet,
@@ -63,7 +82,24 @@
         parseUE(&br);  // bit_depth_luma_minus8
         parseUE(&br);  // bit_depth_chroma_minus8
         br.skipBits(1);  // qpprime_y_zero_transform_bypass_flag
-        CHECK_EQ(br.getBits(1), 0u);  // seq_scaling_matrix_present_flag
+
+        if (br.getBits(1)) {  // seq_scaling_matrix_present_flag
+            for (size_t i = 0; i < 8; ++i) {
+                if (br.getBits(1)) {  // seq_scaling_list_present_flag[i]
+
+                    // WARNING: the code below has not ever been exercised...
+                    // need a real-world example.
+
+                    if (i < 6) {
+                        // ScalingList4x4[i],16,...
+                        skipScalingList(&br, 16);
+                    } else {
+                        // ScalingList8x8[i-6],64,...
+                        skipScalingList(&br, 64);
+                    }
+                }
+            }
+        }
     }
 
     parseUE(&br);  // log2_max_frame_num_minus4
@@ -251,9 +287,7 @@
     return OK;
 }
 
-static sp<ABuffer> FindNAL(
-        const uint8_t *data, size_t size, unsigned nalType,
-        size_t *stopOffset) {
+static sp<ABuffer> FindNAL(const uint8_t *data, size_t size, unsigned nalType) {
     const uint8_t *nalStart;
     size_t nalSize;
     while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
@@ -293,7 +327,7 @@
     const uint8_t *data = accessUnit->data();
     size_t size = accessUnit->size();
 
-    sp<ABuffer> seqParamSet = FindNAL(data, size, 7, NULL);
+    sp<ABuffer> seqParamSet = FindNAL(data, size, 7);
     if (seqParamSet == NULL) {
         return NULL;
     }
@@ -303,8 +337,7 @@
     FindAVCDimensions(
             seqParamSet, &width, &height, &sarWidth, &sarHeight);
 
-    size_t stopOffset;
-    sp<ABuffer> picParamSet = FindNAL(data, size, 8, &stopOffset);
+    sp<ABuffer> picParamSet = FindNAL(data, size, 8);
     CHECK(picParamSet != NULL);
 
     size_t csdSize =
diff --git a/media/libstagefright/chromium_http/Android.mk b/media/libstagefright/chromium_http/Android.mk
deleted file mode 100644
index f191a4b..0000000
--- a/media/libstagefright/chromium_http/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-ifneq ($(TARGET_BUILD_PDK), true)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:=       \
-        DataUriSource.cpp \
-        ChromiumHTTPDataSource.cpp \
-        support.cpp \
-        chromium_http_stub.cpp
-
-LOCAL_C_INCLUDES:= \
-        $(TOP)/frameworks/av/media/libstagefright \
-        $(TOP)/frameworks/native/include/media/openmax \
-        external/chromium \
-        external/chromium/android
-
-LOCAL_CFLAGS += -Wno-multichar
-
-LOCAL_SHARED_LIBRARIES += \
-        libstlport \
-        libchromium_net \
-        libutils \
-        libbinder \
-        libcutils \
-        liblog \
-        libstagefright_foundation \
-        libstagefright \
-        libdrmframework
-
-include external/stlport/libstlport.mk
-
-LOCAL_MODULE:= libstagefright_chromium_http
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_32_BIT_ONLY := true
-
-include $(BUILD_SHARED_LIBRARY)
-endif
diff --git a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
deleted file mode 100644
index 7e5c280..0000000
--- a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * 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_NDEBUG 0
-#define LOG_TAG "ChromiumHTTPDataSource"
-#include <media/stagefright/foundation/ADebug.h>
-
-#include "include/ChromiumHTTPDataSource.h"
-
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/MediaErrors.h>
-
-#include "support.h"
-
-#include <cutils/properties.h> // for property_get
-
-namespace android {
-
-ChromiumHTTPDataSource::ChromiumHTTPDataSource(uint32_t flags)
-    : mFlags(flags),
-      mState(DISCONNECTED),
-      mDelegate(new SfDelegate),
-      mCurrentOffset(0),
-      mIOResult(OK),
-      mContentSize(-1),
-      mDecryptHandle(NULL),
-      mDrmManagerClient(NULL) {
-    mDelegate->setOwner(this);
-}
-
-ChromiumHTTPDataSource::~ChromiumHTTPDataSource() {
-    disconnect();
-
-    delete mDelegate;
-    mDelegate = NULL;
-
-    clearDRMState_l();
-
-    if (mDrmManagerClient != NULL) {
-        delete mDrmManagerClient;
-        mDrmManagerClient = NULL;
-    }
-}
-
-status_t ChromiumHTTPDataSource::connect(
-        const char *uri,
-        const KeyedVector<String8, String8> *headers,
-        off64_t offset) {
-    Mutex::Autolock autoLock(mLock);
-
-    uid_t uid;
-    if (getUID(&uid)) {
-        mDelegate->setUID(uid);
-    }
-
-#if defined(LOG_NDEBUG) && !LOG_NDEBUG
-    LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, "connect on behalf of uid %d", uid);
-#endif
-
-    return connect_l(uri, headers, offset);
-}
-
-status_t ChromiumHTTPDataSource::connect_l(
-        const char *uri,
-        const KeyedVector<String8, String8> *headers,
-        off64_t offset) {
-    if (mState != DISCONNECTED) {
-        disconnect_l();
-    }
-
-#if defined(LOG_NDEBUG) && !LOG_NDEBUG
-    LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG,
-                "connect to <URL suppressed> @%lld", offset);
-#endif
-
-    mURI = uri;
-    mContentType = String8("application/octet-stream");
-
-    if (headers != NULL) {
-        mHeaders = *headers;
-    } else {
-        mHeaders.clear();
-    }
-
-    mState = CONNECTING;
-    mContentSize = -1;
-    mCurrentOffset = offset;
-
-    mDelegate->initiateConnection(mURI.c_str(), &mHeaders, offset);
-
-    while (mState == CONNECTING || mState == DISCONNECTING) {
-        mCondition.wait(mLock);
-    }
-
-    return mState == CONNECTED ? OK : mIOResult;
-}
-
-void ChromiumHTTPDataSource::onRedirect(const char *url) {
-    Mutex::Autolock autoLock(mLock);
-    mURI = url;
-}
-
-void ChromiumHTTPDataSource::onConnectionEstablished(
-        int64_t contentSize, const char *contentType) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mState != CONNECTING) {
-        // We may have initiated disconnection.
-        CHECK_EQ(mState, DISCONNECTING);
-        return;
-    }
-
-    mState = CONNECTED;
-    mContentSize = (contentSize < 0) ? -1 : contentSize + mCurrentOffset;
-    mContentType = String8(contentType);
-    mCondition.broadcast();
-}
-
-void ChromiumHTTPDataSource::onConnectionFailed(status_t err) {
-    Mutex::Autolock autoLock(mLock);
-    mState = DISCONNECTED;
-    mCondition.broadcast();
-
-    // mURI.clear();
-
-    mIOResult = err;
-}
-
-void ChromiumHTTPDataSource::disconnect() {
-    Mutex::Autolock autoLock(mLock);
-    disconnect_l();
-}
-
-void ChromiumHTTPDataSource::disconnect_l() {
-    if (mState == DISCONNECTED) {
-        return;
-    }
-
-    mState = DISCONNECTING;
-    mIOResult = -EINTR;
-
-    mDelegate->initiateDisconnect();
-
-    while (mState == DISCONNECTING) {
-        mCondition.wait(mLock);
-    }
-
-    CHECK_EQ((int)mState, (int)DISCONNECTED);
-}
-
-status_t ChromiumHTTPDataSource::initCheck() const {
-    Mutex::Autolock autoLock(mLock);
-
-    return mState == CONNECTED ? OK : NO_INIT;
-}
-
-ssize_t ChromiumHTTPDataSource::readAt(off64_t offset, void *data, size_t size) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mState != CONNECTED) {
-        return INVALID_OPERATION;
-    }
-
-#if 0
-    char value[PROPERTY_VALUE_MAX];
-    if (property_get("media.stagefright.disable-net", value, 0)
-            && (!strcasecmp(value, "true") || !strcmp(value, "1"))) {
-        LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Simulating that the network is down.");
-        disconnect_l();
-        return ERROR_IO;
-    }
-#endif
-
-    if (offset != mCurrentOffset) {
-        AString tmp = mURI;
-        KeyedVector<String8, String8> tmpHeaders = mHeaders;
-
-        disconnect_l();
-
-        status_t err = connect_l(tmp.c_str(), &tmpHeaders, offset);
-
-        if (err != OK) {
-            return err;
-        }
-    }
-
-    mState = READING;
-
-    int64_t startTimeUs = ALooper::GetNowUs();
-
-    mDelegate->initiateRead(data, size);
-
-    while (mState == READING) {
-        mCondition.wait(mLock);
-    }
-
-    if (mIOResult < OK) {
-        return mIOResult;
-    }
-
-    if (mState == CONNECTED) {
-        int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
-
-        // The read operation was successful, mIOResult contains
-        // the number of bytes read.
-        addBandwidthMeasurement(mIOResult, delayUs);
-
-        mCurrentOffset += mIOResult;
-        return mIOResult;
-    }
-
-    return ERROR_IO;
-}
-
-void ChromiumHTTPDataSource::onReadCompleted(ssize_t size) {
-    Mutex::Autolock autoLock(mLock);
-
-    mIOResult = size;
-
-    if (mState == READING) {
-        mState = CONNECTED;
-        mCondition.broadcast();
-    }
-}
-
-status_t ChromiumHTTPDataSource::getSize(off64_t *size) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mContentSize < 0) {
-        return ERROR_UNSUPPORTED;
-    }
-
-    *size = mContentSize;
-
-    return OK;
-}
-
-uint32_t ChromiumHTTPDataSource::flags() {
-    return kWantsPrefetching | kIsHTTPBasedSource;
-}
-
-// static
-void ChromiumHTTPDataSource::InitiateRead(
-        ChromiumHTTPDataSource *me, void *data, size_t size) {
-    me->initiateRead(data, size);
-}
-
-void ChromiumHTTPDataSource::initiateRead(void *data, size_t size) {
-    mDelegate->initiateRead(data, size);
-}
-
-void ChromiumHTTPDataSource::onDisconnectComplete() {
-    Mutex::Autolock autoLock(mLock);
-    CHECK_EQ((int)mState, (int)DISCONNECTING);
-
-    mState = DISCONNECTED;
-    // mURI.clear();
-    mIOResult = -ENOTCONN;
-
-    mCondition.broadcast();
-}
-
-sp<DecryptHandle> ChromiumHTTPDataSource::DrmInitialization(const char* mime) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mDrmManagerClient == NULL) {
-        mDrmManagerClient = new DrmManagerClient();
-    }
-
-    if (mDrmManagerClient == NULL) {
-        return NULL;
-    }
-
-    if (mDecryptHandle == NULL) {
-        /* Note if redirect occurs, mUri is the redirect uri instead of the
-         * original one
-         */
-        mDecryptHandle = mDrmManagerClient->openDecryptSession(
-                String8(mURI.c_str()), mime);
-    }
-
-    if (mDecryptHandle == NULL) {
-        delete mDrmManagerClient;
-        mDrmManagerClient = NULL;
-    }
-
-    return mDecryptHandle;
-}
-
-void ChromiumHTTPDataSource::getDrmInfo(
-        sp<DecryptHandle> &handle, DrmManagerClient **client) {
-    Mutex::Autolock autoLock(mLock);
-
-    handle = mDecryptHandle;
-    *client = mDrmManagerClient;
-}
-
-String8 ChromiumHTTPDataSource::getUri() {
-    Mutex::Autolock autoLock(mLock);
-
-    return String8(mURI.c_str());
-}
-
-String8 ChromiumHTTPDataSource::getMIMEType() const {
-    Mutex::Autolock autoLock(mLock);
-
-    return mContentType;
-}
-
-void ChromiumHTTPDataSource::clearDRMState_l() {
-    if (mDecryptHandle != NULL) {
-        // To release mDecryptHandle
-        CHECK(mDrmManagerClient);
-        mDrmManagerClient->closeDecryptSession(mDecryptHandle);
-        mDecryptHandle = NULL;
-    }
-}
-
-status_t ChromiumHTTPDataSource::reconnectAtOffset(off64_t offset) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mURI.empty()) {
-        return INVALID_OPERATION;
-    }
-
-    LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Reconnecting...");
-    status_t err = connect_l(mURI.c_str(), &mHeaders, offset);
-    if (err != OK) {
-        LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Reconnect failed w/ err 0x%08x", err);
-    }
-
-    return err;
-}
-
-// static
-status_t ChromiumHTTPDataSource::UpdateProxyConfig(
-        const char *host, int32_t port, const char *exclusionList) {
-    return SfDelegate::UpdateProxyConfig(host, port, exclusionList);
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/chromium_http/DataUriSource.cpp b/media/libstagefright/chromium_http/DataUriSource.cpp
deleted file mode 100644
index ecf3fa1..0000000
--- a/media/libstagefright/chromium_http/DataUriSource.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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 <include/DataUriSource.h>
-
-#include <net/base/data_url.h>
-#include <googleurl/src/gurl.h>
-
-
-namespace android {
-
-DataUriSource::DataUriSource(const char *uri) :
-    mDataUri(uri),
-    mInited(NO_INIT) {
-
-    // Copy1: const char *uri -> String8 mDataUri.
-    std::string mimeTypeStr, unusedCharsetStr, dataStr;
-    // Copy2: String8 mDataUri -> std::string
-    const bool ret = net::DataURL::Parse(
-            GURL(std::string(mDataUri.string())),
-            &mimeTypeStr, &unusedCharsetStr, &dataStr);
-    // Copy3: std::string dataStr -> AString mData
-    mData.setTo(dataStr.data(), dataStr.length());
-    mInited = ret ? OK : UNKNOWN_ERROR;
-
-    // The chromium data url implementation defaults to using "text/plain"
-    // if no mime type is specified. We prefer to leave this unspecified
-    // instead, since the mime type is sniffed in most cases.
-    if (mimeTypeStr != "text/plain") {
-        mMimeType = mimeTypeStr.c_str();
-    }
-}
-
-ssize_t DataUriSource::readAt(off64_t offset, void *out, size_t size) {
-    if (mInited != OK) {
-        return mInited;
-    }
-
-    const off64_t length = mData.size();
-    if (offset >= length) {
-        return UNKNOWN_ERROR;
-    }
-
-    const char *dataBuf = mData.c_str();
-    const size_t bytesToCopy =
-            offset + size >= length ? (length - offset) : size;
-
-    if (bytesToCopy > 0) {
-        memcpy(out, dataBuf + offset, bytesToCopy);
-    }
-
-    return bytesToCopy;
-}
-
-}  // namespace android
diff --git a/media/libstagefright/chromium_http/chromium_http_stub.cpp b/media/libstagefright/chromium_http/chromium_http_stub.cpp
deleted file mode 100644
index 289f6de..0000000
--- a/media/libstagefright/chromium_http/chromium_http_stub.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <dlfcn.h>
-
-#include <include/chromium_http_stub.h>
-#include <include/ChromiumHTTPDataSource.h>
-#include <include/DataUriSource.h>
-
-namespace android {
-
-HTTPBase *createChromiumHTTPDataSource(uint32_t flags) {
-    return new ChromiumHTTPDataSource(flags);
-}
-
-status_t UpdateChromiumHTTPDataSourceProxyConfig(
-        const char *host, int32_t port, const char *exclusionList) {
-    return ChromiumHTTPDataSource::UpdateProxyConfig(host, port, exclusionList);
-}
-
-DataSource *createDataUriSource(const char *uri) {
-    return new DataUriSource(uri);
-}
-
-}
diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp
deleted file mode 100644
index d4e82ee..0000000
--- a/media/libstagefright/chromium_http/support.cpp
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
- * 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_NDEBUG 0
-#define LOG_TAG "ChromiumHTTPDataSourceSupport"
-#include <utils/Log.h>
-
-#include <media/stagefright/foundation/AString.h>
-
-#include "support.h"
-
-#include "android/net/android_network_library_impl.h"
-#include "base/logging.h"
-#include "base/threading/thread.h"
-#include "net/base/cert_verifier.h"
-#include "net/base/cookie_monster.h"
-#include "net/base/host_resolver.h"
-#include "net/base/ssl_config_service.h"
-#include "net/http/http_auth_handler_factory.h"
-#include "net/http/http_cache.h"
-#include "net/proxy/proxy_config_service_android.h"
-
-#include "include/ChromiumHTTPDataSource.h"
-
-#include <cutils/log.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/Utils.h>
-#include <string>
-
-#include <utils/Errors.h>
-#include <binder/IInterface.h>
-#include <binder/IServiceManager.h>
-
-namespace android {
-
-// must be kept in sync with interface defined in IAudioService.aidl
-class IAudioService : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(AudioService);
-
-    virtual int verifyX509CertChain(
-            const std::vector<std::string>& cert_chain,
-            const std::string& hostname,
-            const std::string& auth_type) = 0;
-};
-
-class BpAudioService : public BpInterface<IAudioService>
-{
-public:
-    BpAudioService(const sp<IBinder>& impl)
-        : BpInterface<IAudioService>(impl)
-    {
-    }
-
-    virtual int verifyX509CertChain(
-            const std::vector<std::string>& cert_chain,
-            const std::string& hostname,
-            const std::string& auth_type)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IAudioService::getInterfaceDescriptor());
-
-        // The vector of std::string we get isn't really a vector of strings,
-        // but rather a vector of binary certificate data. If we try to pass
-        // it to Java language code as a string, it ends up mangled on the other
-        // side, so send them as bytes instead.
-        // Since we can't send an array of byte arrays, send a single array,
-        // which will be split out by the recipient.
-
-        int numcerts = cert_chain.size();
-        data.writeInt32(numcerts);
-        size_t total = 0;
-        for (int i = 0; i < numcerts; i++) {
-            total += cert_chain[i].size();
-        }
-        size_t bytesize = total + numcerts * 4;
-        uint8_t *bytes = (uint8_t*) malloc(bytesize);
-        if (!bytes) {
-            return 5; // SSL_INVALID
-        }
-        ALOGV("%d certs: %d -> %d", numcerts, total, bytesize);
-
-        int offset = 0;
-        for (int i = 0; i < numcerts; i++) {
-            int32_t certsize = cert_chain[i].size();
-            // store this in a known order, which just happens to match the default
-            // byte order of a java ByteBuffer
-            int32_t bigsize = htonl(certsize);
-            ALOGV("cert %d, size %d", i, certsize);
-            memcpy(bytes + offset, &bigsize, sizeof(bigsize));
-            offset += sizeof(bigsize);
-            memcpy(bytes + offset, cert_chain[i].data(), certsize);
-            offset += certsize;
-        }
-        data.writeByteArray(bytesize, bytes);
-        free(bytes);
-        data.writeString16(String16(hostname.c_str()));
-        data.writeString16(String16(auth_type.c_str()));
-
-        int32_t result;
-        if (remote()->transact(IBinder::FIRST_CALL_TRANSACTION, data, &reply) != NO_ERROR
-                || reply.readExceptionCode() < 0 || reply.readInt32(&result) != NO_ERROR) {
-            return 5; // SSL_INVALID;
-        }
-        return result;
-    }
-
-};
-
-IMPLEMENT_META_INTERFACE(AudioService, "android.media.IAudioService");
-
-
-static Mutex gNetworkThreadLock;
-static base::Thread *gNetworkThread = NULL;
-static scoped_refptr<SfRequestContext> gReqContext;
-static scoped_ptr<net::NetworkChangeNotifier> gNetworkChangeNotifier;
-
-bool logMessageHandler(
-        int severity,
-        const char* file,
-        int line,
-        size_t message_start,
-        const std::string& str) {
-    int androidSeverity = ANDROID_LOG_VERBOSE;
-    switch(severity) {
-    case logging::LOG_FATAL:
-        androidSeverity = ANDROID_LOG_FATAL;
-        break;
-    case logging::LOG_ERROR_REPORT:
-    case logging::LOG_ERROR:
-        androidSeverity = ANDROID_LOG_ERROR;
-        break;
-    case logging::LOG_WARNING:
-        androidSeverity = ANDROID_LOG_WARN;
-        break;
-    default:
-        androidSeverity = ANDROID_LOG_VERBOSE;
-        break;
-    }
-    android_printLog(androidSeverity, "chromium-libstagefright",
-                    "%s:%d: %s", file, line, str.c_str());
-    return false;
-}
-
-struct AutoPrioritySaver {
-    AutoPrioritySaver()
-        : mTID(androidGetTid()),
-          mPrevPriority(androidGetThreadPriority(mTID)) {
-        androidSetThreadPriority(mTID, ANDROID_PRIORITY_NORMAL);
-    }
-
-    ~AutoPrioritySaver() {
-        androidSetThreadPriority(mTID, mPrevPriority);
-    }
-
-private:
-    pid_t mTID;
-    int mPrevPriority;
-
-    DISALLOW_EVIL_CONSTRUCTORS(AutoPrioritySaver);
-};
-
-static void InitializeNetworkThreadIfNecessary() {
-    Mutex::Autolock autoLock(gNetworkThreadLock);
-
-    if (gNetworkThread == NULL) {
-        // Make sure any threads spawned by the chromium framework are
-        // running at normal priority instead of inheriting this thread's.
-        AutoPrioritySaver saver;
-
-        gNetworkThread = new base::Thread("network");
-        base::Thread::Options options;
-        options.message_loop_type = MessageLoop::TYPE_IO;
-        CHECK(gNetworkThread->StartWithOptions(options));
-
-        gReqContext = new SfRequestContext;
-
-        gNetworkChangeNotifier.reset(net::NetworkChangeNotifier::Create());
-
-        net::AndroidNetworkLibrary::RegisterSharedInstance(
-                new SfNetworkLibrary);
-        logging::SetLogMessageHandler(logMessageHandler);
-    }
-}
-
-static void MY_LOGI(const char *s) {
-    LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "%s", s);
-}
-
-static void MY_LOGV(const char *s) {
-#if !defined(LOG_NDEBUG) || LOG_NDEBUG == 0
-    LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, "%s", s);
-#endif
-}
-
-SfNetLog::SfNetLog()
-    : mNextID(1) {
-}
-
-void SfNetLog::AddEntry(
-        EventType type,
-        const base::TimeTicks &time,
-        const Source &source,
-        EventPhase phase,
-        EventParameters *params) {
-#if 0
-    MY_LOGI(StringPrintf(
-                "AddEntry time=%s type=%s source=%s phase=%s\n",
-                TickCountToString(time).c_str(),
-                EventTypeToString(type),
-                SourceTypeToString(source.type),
-                EventPhaseToString(phase)).c_str());
-#endif
-}
-
-uint32 SfNetLog::NextID() {
-    return mNextID++;
-}
-
-net::NetLog::LogLevel SfNetLog::GetLogLevel() const {
-    return LOG_BASIC;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-SfRequestContext::SfRequestContext() {
-    mUserAgent = MakeUserAgent().c_str();
-
-    set_net_log(new SfNetLog());
-
-    set_host_resolver(
-        net::CreateSystemHostResolver(
-                net::HostResolver::kDefaultParallelism,
-                NULL /* resolver_proc */,
-                net_log()));
-
-    set_ssl_config_service(
-        net::SSLConfigService::CreateSystemSSLConfigService());
-
-    mProxyConfigService = new net::ProxyConfigServiceAndroid;
-
-    set_proxy_service(net::ProxyService::CreateWithoutProxyResolver(
-        mProxyConfigService, net_log()));
-
-    set_http_transaction_factory(new net::HttpCache(
-            host_resolver(),
-            new net::CertVerifier(),
-            dnsrr_resolver(),
-            dns_cert_checker(),
-            proxy_service(),
-            ssl_config_service(),
-            net::HttpAuthHandlerFactory::CreateDefault(host_resolver()),
-            network_delegate(),
-            net_log(),
-            NULL));  // backend_factory
-
-    set_cookie_store(new net::CookieMonster(NULL, NULL));
-}
-
-const std::string &SfRequestContext::GetUserAgent(const GURL &url) const {
-    return mUserAgent;
-}
-
-status_t SfRequestContext::updateProxyConfig(
-        const char *host, int32_t port, const char *exclusionList) {
-    Mutex::Autolock autoLock(mProxyConfigLock);
-
-    if (host == NULL || *host == '\0') {
-        MY_LOGV("updateProxyConfig NULL");
-
-        std::string proxy;
-        std::string exList;
-        mProxyConfigService->UpdateProxySettings(proxy, exList);
-    } else {
-#if !defined(LOG_NDEBUG) || LOG_NDEBUG == 0
-        LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG,
-                "updateProxyConfig %s:%d, exclude '%s'",
-                host, port, exclusionList);
-#endif
-
-        std::string proxy = StringPrintf("%s:%d", host, port).c_str();
-        std::string exList = exclusionList;
-        mProxyConfigService->UpdateProxySettings(proxy, exList);
-    }
-
-    return OK;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-SfNetworkLibrary::SfNetworkLibrary() {}
-
-SfNetworkLibrary::VerifyResult SfNetworkLibrary::VerifyX509CertChain(
-        const std::vector<std::string>& cert_chain,
-        const std::string& hostname,
-        const std::string& auth_type) {
-
-    sp<IBinder> binder =
-        defaultServiceManager()->checkService(String16("audio"));
-    if (binder == 0) {
-        ALOGW("Thread cannot connect to the audio service");
-    } else {
-        sp<IAudioService> service = interface_cast<IAudioService>(binder);
-        int code = service->verifyX509CertChain(cert_chain, hostname, auth_type);
-        ALOGV("verified: %d", code);
-        if (code == -1) {
-            return VERIFY_OK;
-        } else if (code == 2) { // SSL_IDMISMATCH
-            return VERIFY_BAD_HOSTNAME;
-        } else if (code == 3) { // SSL_UNTRUSTED
-            return VERIFY_NO_TRUSTED_ROOT;
-        }
-    }
-    return VERIFY_INVOCATION_ERROR;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-SfDelegate::SfDelegate()
-    : mOwner(NULL),
-      mURLRequest(NULL),
-      mReadBuffer(new net::IOBufferWithSize(8192)),
-      mNumBytesRead(0),
-      mNumBytesTotal(0),
-      mDataDestination(NULL),
-      mAtEOS(false) {
-    InitializeNetworkThreadIfNecessary();
-}
-
-SfDelegate::~SfDelegate() {
-    CHECK(mURLRequest == NULL);
-}
-
-// static
-status_t SfDelegate::UpdateProxyConfig(
-        const char *host, int32_t port, const char *exclusionList) {
-    InitializeNetworkThreadIfNecessary();
-
-    return gReqContext->updateProxyConfig(host, port, exclusionList);
-}
-
-void SfDelegate::setOwner(ChromiumHTTPDataSource *owner) {
-    mOwner = owner;
-}
-
-void SfDelegate::setUID(uid_t uid) {
-    gReqContext->setUID(uid);
-}
-
-bool SfDelegate::getUID(uid_t *uid) const {
-    return gReqContext->getUID(uid);
-}
-
-void SfDelegate::OnReceivedRedirect(
-            net::URLRequest *request, const GURL &new_url, bool *defer_redirect) {
-    MY_LOGV("OnReceivedRedirect");
-    mOwner->onRedirect(new_url.spec().c_str());
-}
-
-void SfDelegate::OnAuthRequired(
-            net::URLRequest *request, net::AuthChallengeInfo *auth_info) {
-    MY_LOGV("OnAuthRequired");
-
-    inherited::OnAuthRequired(request, auth_info);
-}
-
-void SfDelegate::OnCertificateRequested(
-            net::URLRequest *request, net::SSLCertRequestInfo *cert_request_info) {
-    MY_LOGV("OnCertificateRequested");
-
-    inherited::OnCertificateRequested(request, cert_request_info);
-}
-
-void SfDelegate::OnSSLCertificateError(
-            net::URLRequest *request, int cert_error, net::X509Certificate *cert) {
-    fprintf(stderr, "OnSSLCertificateError cert_error=%d\n", cert_error);
-
-    inherited::OnSSLCertificateError(request, cert_error, cert);
-}
-
-void SfDelegate::OnGetCookies(net::URLRequest *request, bool blocked_by_policy) {
-    MY_LOGV("OnGetCookies");
-}
-
-void SfDelegate::OnSetCookie(
-        net::URLRequest *request,
-        const std::string &cookie_line,
-        const net::CookieOptions &options,
-        bool blocked_by_policy) {
-    MY_LOGV("OnSetCookie");
-}
-
-void SfDelegate::OnResponseStarted(net::URLRequest *request) {
-    if (request->status().status() != net::URLRequestStatus::SUCCESS) {
-        MY_LOGI(StringPrintf(
-                    "Request failed with status %d and os_error %d",
-                    request->status().status(),
-                    request->status().os_error()).c_str());
-
-        delete mURLRequest;
-        mURLRequest = NULL;
-
-        mOwner->onConnectionFailed(ERROR_IO);
-        return;
-    } else if (mRangeRequested && request->GetResponseCode() != 206) {
-        MY_LOGI(StringPrintf(
-                    "We requested a content range, but server didn't "
-                    "support that. (responded with %d)",
-                    request->GetResponseCode()).c_str());
-
-        delete mURLRequest;
-        mURLRequest = NULL;
-
-        mOwner->onConnectionFailed(-EPIPE);
-        return;
-    } else if ((request->GetResponseCode() / 100) != 2) {
-        MY_LOGI(StringPrintf(
-                    "Server responded with http status %d",
-                    request->GetResponseCode()).c_str());
-
-        delete mURLRequest;
-        mURLRequest = NULL;
-
-        mOwner->onConnectionFailed(ERROR_IO);
-        return;
-    }
-
-    MY_LOGV("OnResponseStarted");
-
-    std::string headers;
-    request->GetAllResponseHeaders(&headers);
-
-    MY_LOGV(StringPrintf("response headers: %s", headers.c_str()).c_str());
-
-    std::string contentType;
-    request->GetResponseHeaderByName("Content-Type", &contentType);
-
-    mOwner->onConnectionEstablished(
-            request->GetExpectedContentSize(), contentType.c_str());
-}
-
-void SfDelegate::OnReadCompleted(net::URLRequest *request, int bytes_read) {
-    if (bytes_read == -1) {
-        MY_LOGI(StringPrintf(
-                    "OnReadCompleted, read failed, status %d",
-                    request->status().status()).c_str());
-
-        mOwner->onReadCompleted(ERROR_IO);
-        return;
-    }
-
-    MY_LOGV(StringPrintf("OnReadCompleted, read %d bytes", bytes_read).c_str());
-
-    if (bytes_read < 0) {
-        MY_LOGI(StringPrintf(
-                    "Read failed w/ status %d\n",
-                    request->status().status()).c_str());
-
-        mOwner->onReadCompleted(ERROR_IO);
-        return;
-    } else if (bytes_read == 0) {
-        mAtEOS = true;
-        mOwner->onReadCompleted(mNumBytesRead);
-        return;
-    }
-
-    CHECK_GT(bytes_read, 0);
-    CHECK_LE(mNumBytesRead + bytes_read, mNumBytesTotal);
-
-    memcpy((uint8_t *)mDataDestination + mNumBytesRead,
-           mReadBuffer->data(),
-           bytes_read);
-
-    mNumBytesRead += bytes_read;
-
-    readMore(request);
-}
-
-void SfDelegate::readMore(net::URLRequest *request) {
-    while (mNumBytesRead < mNumBytesTotal) {
-        size_t copy = mNumBytesTotal - mNumBytesRead;
-        if (copy > mReadBuffer->size()) {
-            copy = mReadBuffer->size();
-        }
-
-        int n;
-        if (request->Read(mReadBuffer, copy, &n)) {
-            MY_LOGV(StringPrintf("Read %d bytes directly.", n).c_str());
-
-            CHECK_LE((size_t)n, copy);
-
-            memcpy((uint8_t *)mDataDestination + mNumBytesRead,
-                   mReadBuffer->data(),
-                   n);
-
-            mNumBytesRead += n;
-
-            if (n == 0) {
-                mAtEOS = true;
-                break;
-            }
-        } else {
-            MY_LOGV("readMore pending read");
-
-            if (request->status().status() != net::URLRequestStatus::IO_PENDING) {
-                MY_LOGI(StringPrintf(
-                            "Direct read failed w/ status %d\n",
-                            request->status().status()).c_str());
-
-                mOwner->onReadCompleted(ERROR_IO);
-                return;
-            }
-
-            return;
-        }
-    }
-
-    mOwner->onReadCompleted(mNumBytesRead);
-}
-
-void SfDelegate::initiateConnection(
-        const char *uri,
-        const KeyedVector<String8, String8> *headers,
-        off64_t offset) {
-    GURL url(uri);
-
-    MessageLoop *loop = gNetworkThread->message_loop();
-    loop->PostTask(
-            FROM_HERE,
-            NewRunnableFunction(
-                &SfDelegate::OnInitiateConnectionWrapper,
-                this,
-                url,
-                headers,
-                offset));
-
-}
-
-// static
-void SfDelegate::OnInitiateConnectionWrapper(
-        SfDelegate *me, GURL url,
-        const KeyedVector<String8, String8> *headers,
-        off64_t offset) {
-    me->onInitiateConnection(url, headers, offset);
-}
-
-void SfDelegate::onInitiateConnection(
-        const GURL &url,
-        const KeyedVector<String8, String8> *extra,
-        off64_t offset) {
-    CHECK(mURLRequest == NULL);
-
-    mURLRequest = new net::URLRequest(url, this);
-    mAtEOS = false;
-
-    mRangeRequested = false;
-
-    if (offset != 0 || extra != NULL) {
-        net::HttpRequestHeaders headers =
-            mURLRequest->extra_request_headers();
-
-        if (offset != 0) {
-            headers.AddHeaderFromString(
-                    StringPrintf("Range: bytes=%lld-", offset).c_str());
-
-            mRangeRequested = true;
-        }
-
-        if (extra != NULL) {
-            for (size_t i = 0; i < extra->size(); ++i) {
-                AString s;
-                s.append(extra->keyAt(i).string());
-                s.append(": ");
-                s.append(extra->valueAt(i).string());
-
-                headers.AddHeaderFromString(s.c_str());
-            }
-        }
-
-        mURLRequest->SetExtraRequestHeaders(headers);
-    }
-
-    mURLRequest->set_context(gReqContext);
-
-    mURLRequest->Start();
-}
-
-void SfDelegate::initiateDisconnect() {
-    MessageLoop *loop = gNetworkThread->message_loop();
-    loop->PostTask(
-            FROM_HERE,
-            NewRunnableFunction(
-                &SfDelegate::OnInitiateDisconnectWrapper, this));
-}
-
-// static
-void SfDelegate::OnInitiateDisconnectWrapper(SfDelegate *me) {
-    me->onInitiateDisconnect();
-}
-
-void SfDelegate::onInitiateDisconnect() {
-    if (mURLRequest == NULL) {
-        return;
-    }
-
-    mURLRequest->Cancel();
-
-    delete mURLRequest;
-    mURLRequest = NULL;
-
-    mOwner->onDisconnectComplete();
-}
-
-void SfDelegate::initiateRead(void *data, size_t size) {
-    MessageLoop *loop = gNetworkThread->message_loop();
-    loop->PostTask(
-            FROM_HERE,
-            NewRunnableFunction(
-                &SfDelegate::OnInitiateReadWrapper, this, data, size));
-}
-
-// static
-void SfDelegate::OnInitiateReadWrapper(
-        SfDelegate *me, void *data, size_t size) {
-    me->onInitiateRead(data, size);
-}
-
-void SfDelegate::onInitiateRead(void *data, size_t size) {
-    CHECK(mURLRequest != NULL);
-
-    mNumBytesRead = 0;
-    mNumBytesTotal = size;
-    mDataDestination = data;
-
-    if (mAtEOS) {
-        mOwner->onReadCompleted(0);
-        return;
-    }
-
-    readMore(mURLRequest);
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/chromium_http/support.h b/media/libstagefright/chromium_http/support.h
deleted file mode 100644
index 975a1d3..0000000
--- a/media/libstagefright/chromium_http/support.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * 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 SUPPORT_H_
-
-#define SUPPORT_H_
-
-#include <assert.h>
-
-#include "net/base/net_log.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context.h"
-#include "net/base/android_network_library.h"
-#include "net/base/io_buffer.h"
-
-#include <utils/KeyedVector.h>
-#include <utils/Mutex.h>
-#include <utils/String8.h>
-
-namespace net {
-    struct ProxyConfigServiceAndroid;
-};
-
-namespace android {
-
-struct SfNetLog : public net::NetLog {
-    SfNetLog();
-
-    virtual void AddEntry(
-            EventType type,
-            const base::TimeTicks &time,
-            const Source &source,
-            EventPhase phase,
-            EventParameters *params);
-
-    virtual uint32 NextID();
-    virtual LogLevel GetLogLevel() const;
-
-private:
-    uint32 mNextID;
-
-    DISALLOW_EVIL_CONSTRUCTORS(SfNetLog);
-};
-
-struct SfRequestContext : public net::URLRequestContext {
-    SfRequestContext();
-
-    virtual const std::string &GetUserAgent(const GURL &url) const;
-
-    status_t updateProxyConfig(
-            const char *host, int32_t port, const char *exclusionList);
-
-private:
-    Mutex mProxyConfigLock;
-
-    std::string mUserAgent;
-    net::ProxyConfigServiceAndroid *mProxyConfigService;
-
-    DISALLOW_EVIL_CONSTRUCTORS(SfRequestContext);
-};
-
-// This is required for https support, we don't really verify certificates,
-// we accept anything...
-struct SfNetworkLibrary : public net::AndroidNetworkLibrary {
-    SfNetworkLibrary();
-
-    virtual VerifyResult VerifyX509CertChain(
-            const std::vector<std::string>& cert_chain,
-            const std::string& hostname,
-            const std::string& auth_type);
-
-private:
-    DISALLOW_EVIL_CONSTRUCTORS(SfNetworkLibrary);
-};
-
-struct ChromiumHTTPDataSource;
-
-struct SfDelegate : public net::URLRequest::Delegate {
-    SfDelegate();
-    virtual ~SfDelegate();
-
-    void initiateConnection(
-            const char *uri,
-            const KeyedVector<String8, String8> *headers,
-            off64_t offset);
-
-    void initiateDisconnect();
-    void initiateRead(void *data, size_t size);
-
-    void setOwner(ChromiumHTTPDataSource *mOwner);
-
-    // Gets the UID of the calling process
-    bool getUID(uid_t *uid) const;
-
-    void setUID(uid_t uid);
-
-    virtual void OnReceivedRedirect(
-            net::URLRequest *request, const GURL &new_url, bool *defer_redirect);
-
-    virtual void OnAuthRequired(
-            net::URLRequest *request, net::AuthChallengeInfo *auth_info);
-
-    virtual void OnCertificateRequested(
-            net::URLRequest *request, net::SSLCertRequestInfo *cert_request_info);
-
-    virtual void OnSSLCertificateError(
-            net::URLRequest *request, int cert_error, net::X509Certificate *cert);
-
-    virtual void OnGetCookies(net::URLRequest *request, bool blocked_by_policy);
-
-    virtual void OnSetCookie(
-            net::URLRequest *request,
-            const std::string &cookie_line,
-            const net::CookieOptions &options,
-            bool blocked_by_policy);
-
-    virtual void OnResponseStarted(net::URLRequest *request);
-
-    virtual void OnReadCompleted(net::URLRequest *request, int bytes_read);
-
-    static status_t UpdateProxyConfig(
-            const char *host, int32_t port, const char *exclusionList);
-
-private:
-    typedef Delegate inherited;
-
-    ChromiumHTTPDataSource *mOwner;
-
-    net::URLRequest *mURLRequest;
-    scoped_refptr<net::IOBufferWithSize> mReadBuffer;
-
-    size_t mNumBytesRead;
-    size_t mNumBytesTotal;
-    void *mDataDestination;
-
-    bool mRangeRequested;
-    bool mAtEOS;
-
-    void readMore(net::URLRequest *request);
-
-    static void OnInitiateConnectionWrapper(
-            SfDelegate *me,
-            GURL url,
-            const KeyedVector<String8, String8> *headers,
-            off64_t offset);
-
-    static void OnInitiateDisconnectWrapper(SfDelegate *me);
-
-    static void OnInitiateReadWrapper(
-            SfDelegate *me, void *data, size_t size);
-
-    void onInitiateConnection(
-            const GURL &url,
-            const KeyedVector<String8, String8> *headers,
-            off64_t offset);
-
-    void onInitiateDisconnect();
-    void onInitiateRead(void *data, size_t size);
-
-    DISALLOW_EVIL_CONSTRUCTORS(SfDelegate);
-};
-
-}  // namespace android
-
-#endif  // SUPPORT_H_
diff --git a/media/libstagefright/chromium_http_stub.cpp b/media/libstagefright/chromium_http_stub.cpp
deleted file mode 100644
index ed8a878..0000000
--- a/media/libstagefright/chromium_http_stub.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <dlfcn.h>
-
-#include <media/stagefright/DataSource.h>
-
-#include "include/chromium_http_stub.h"
-#include "include/HTTPBase.h"
-
-namespace android {
-
-static bool gFirst = true;
-static void *gHandle;
-static Mutex gLibMutex;
-
-HTTPBase *(*gLib_createChromiumHTTPDataSource)(uint32_t flags);
-DataSource *(*gLib_createDataUriSource)(const char *uri);
-
-status_t (*gLib_UpdateChromiumHTTPDataSourceProxyConfig)(
-        const char *host, int32_t port, const char *exclusionList);
-
-static bool load_libstagefright_chromium_http() {
-    Mutex::Autolock autoLock(gLibMutex);
-    void *sym;
-
-    if (!gFirst) {
-        return (gHandle != NULL);
-    }
-
-    gFirst = false;
-
-    gHandle = dlopen("libstagefright_chromium_http.so", RTLD_NOW);
-    if (gHandle == NULL) {
-        return false;
-    }
-
-    sym = dlsym(gHandle, "createChromiumHTTPDataSource");
-    if (sym == NULL) {
-        gHandle = NULL;
-        return false;
-    }
-    gLib_createChromiumHTTPDataSource = (HTTPBase *(*)(uint32_t))sym;
-
-    sym = dlsym(gHandle, "createDataUriSource");
-    if (sym == NULL) {
-        gHandle = NULL;
-        return false;
-    }
-    gLib_createDataUriSource = (DataSource *(*)(const char *))sym;
-
-    sym = dlsym(gHandle, "UpdateChromiumHTTPDataSourceProxyConfig");
-    if (sym == NULL) {
-        gHandle = NULL;
-        return false;
-    }
-    gLib_UpdateChromiumHTTPDataSourceProxyConfig =
-        (status_t (*)(const char *, int32_t, const char *))sym;
-
-    return true;
-}
-
-HTTPBase *createChromiumHTTPDataSource(uint32_t flags) {
-    if (!load_libstagefright_chromium_http()) {
-        return NULL;
-    }
-
-    return gLib_createChromiumHTTPDataSource(flags);
-}
-
-status_t UpdateChromiumHTTPDataSourceProxyConfig(
-        const char *host, int32_t port, const char *exclusionList) {
-    if (!load_libstagefright_chromium_http()) {
-        return INVALID_OPERATION;
-    }
-
-    return gLib_UpdateChromiumHTTPDataSourceProxyConfig(
-            host, port, exclusionList);
-}
-
-DataSource *createDataUriSource(const char *uri) {
-    if (!load_libstagefright_chromium_http()) {
-        return NULL;
-    }
-
-    return gLib_createDataUriSource(uri);
-}
-
-}
diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk
index ffa64f9..49ff238 100644
--- a/media/libstagefright/codecs/aacdec/Android.mk
+++ b/media/libstagefright/codecs/aacdec/Android.mk
@@ -17,6 +17,8 @@
 
 LOCAL_CFLAGS :=
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_STATIC_LIBRARIES := libFraunhoferAAC
 
 LOCAL_SHARED_LIBRARIES := \
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 1b20cbb..4ac8999 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -30,7 +30,7 @@
 #define DRC_DEFAULT_MOBILE_REF_LEVEL 64  /* 64*-0.25dB = -16 dB below full scale for mobile conf */
 #define DRC_DEFAULT_MOBILE_DRC_CUT   127 /* maximum compression of dynamic range for mobile conf */
 #define DRC_DEFAULT_MOBILE_DRC_BOOST 127 /* maximum compression of dynamic range for mobile conf */
-#define MAX_CHANNEL_COUNT            6  /* maximum number of audio channels that can be decoded */
+#define MAX_CHANNEL_COUNT            8  /* maximum number of audio channels that can be decoded */
 // names of properties that can be used to override the default DRC settings
 #define PROP_DRC_OVERRIDE_REF_LEVEL  "aac_drc_reference_level"
 #define PROP_DRC_OVERRIDE_CUT        "aac_drc_cut"
@@ -58,6 +58,8 @@
       mIsADTS(false),
       mInputBufferCount(0),
       mSignalledError(false),
+      mSawInputEos(false),
+      mSignalledOutputEos(false),
       mAnchorTimeUs(0),
       mNumSamplesOutput(0),
       mOutputPortSettingsChange(NONE) {
@@ -294,8 +296,11 @@
         if (!(property_get("media.aac_51_output_enabled", value, NULL) &&
                 (!strcmp(value, "1") || !strcasecmp(value, "true")))) {
             ALOGI("Downmixing multichannel AAC to stereo");
-            aacDecoder_SetParam(mAACDecoder, AAC_PCM_OUTPUT_CHANNELS, 2);
+            aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, 2);
             mStreamInfo->numChannels = 2;
+            // By default, the decoder creates a 5.1 channel downmix signal
+            // for seven and eight channel input streams. To enable 6.1 and 7.1 channel output
+            // use aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, -1)
         }
     }
 }
@@ -350,115 +355,83 @@
         return;
     }
 
-    while (!inQueue.empty() && !outQueue.empty()) {
-        BufferInfo *inInfo = *inQueue.begin();
-        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+    while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
+        BufferInfo *inInfo = NULL;
+        OMX_BUFFERHEADERTYPE *inHeader = NULL;
+        if (!inQueue.empty()) {
+            inInfo = *inQueue.begin();
+            inHeader = inInfo->mHeader;
+        }
 
         BufferInfo *outInfo = *outQueue.begin();
         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+        outHeader->nFlags = 0;
 
-        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
-            inQueue.erase(inQueue.begin());
-            inInfo->mOwnedByUs = false;
-            notifyEmptyBufferDone(inHeader);
+        if (inHeader) {
+            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+                mSawInputEos = true;
+            }
 
-            if (mDecoderHasData) {
-                // flush out the decoder's delayed data by calling DecodeFrame
-                // one more time, with the AACDEC_FLUSH flag set
-                INT_PCM *outBuffer =
-                        reinterpret_cast<INT_PCM *>(
-                                outHeader->pBuffer + outHeader->nOffset);
+            if (inHeader->nOffset == 0 && inHeader->nFilledLen) {
+                mAnchorTimeUs = inHeader->nTimeStamp;
+                mNumSamplesOutput = 0;
+            }
 
-                AAC_DECODER_ERROR decoderErr =
-                    aacDecoder_DecodeFrame(mAACDecoder,
-                                           outBuffer,
-                                           outHeader->nAllocLen,
-                                           AACDEC_FLUSH);
-                mDecoderHasData = false;
+            if (mIsADTS && inHeader->nFilledLen) {
+                size_t adtsHeaderSize = 0;
+                // skip 30 bits, aac_frame_length follows.
+                // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
 
-                if (decoderErr != AAC_DEC_OK) {
+                const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;
+
+                bool signalError = false;
+                if (inHeader->nFilledLen < 7) {
+                    ALOGE("Audio data too short to contain even the ADTS header. "
+                          "Got %ld bytes.", inHeader->nFilledLen);
+                    hexdump(adtsHeader, inHeader->nFilledLen);
+                    signalError = true;
+                } else {
+                    bool protectionAbsent = (adtsHeader[1] & 1);
+
+                    unsigned aac_frame_length =
+                        ((adtsHeader[3] & 3) << 11)
+                        | (adtsHeader[4] << 3)
+                        | (adtsHeader[5] >> 5);
+
+                    if (inHeader->nFilledLen < aac_frame_length) {
+                        ALOGE("Not enough audio data for the complete frame. "
+                              "Got %ld bytes, frame size according to the ADTS "
+                              "header is %u bytes.",
+                              inHeader->nFilledLen, aac_frame_length);
+                        hexdump(adtsHeader, inHeader->nFilledLen);
+                        signalError = true;
+                    } else {
+                        adtsHeaderSize = (protectionAbsent ? 7 : 9);
+
+                        inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize;
+                        inBufferLength[0] = aac_frame_length - adtsHeaderSize;
+
+                        inHeader->nOffset += adtsHeaderSize;
+                        inHeader->nFilledLen -= adtsHeaderSize;
+                    }
+                }
+
+                if (signalError) {
                     mSignalledError = true;
 
-                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr,
+                    notify(OMX_EventError,
+                           OMX_ErrorStreamCorrupt,
+                           ERROR_MALFORMED,
                            NULL);
 
                     return;
                 }
-
-                outHeader->nFilledLen =
-                        mStreamInfo->frameSize
-                            * sizeof(int16_t)
-                            * mStreamInfo->numChannels;
             } else {
-                // we never submitted any data to the decoder, so there's nothing to flush out
-                outHeader->nFilledLen = 0;
-            }
-
-            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
-
-            outQueue.erase(outQueue.begin());
-            outInfo->mOwnedByUs = false;
-            notifyFillBufferDone(outHeader);
-            return;
-        }
-
-        if (inHeader->nOffset == 0) {
-            mAnchorTimeUs = inHeader->nTimeStamp;
-            mNumSamplesOutput = 0;
-        }
-
-        size_t adtsHeaderSize = 0;
-        if (mIsADTS) {
-            // skip 30 bits, aac_frame_length follows.
-            // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
-
-            const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;
-
-            bool signalError = false;
-            if (inHeader->nFilledLen < 7) {
-                ALOGE("Audio data too short to contain even the ADTS header. "
-                      "Got %ld bytes.", inHeader->nFilledLen);
-                hexdump(adtsHeader, inHeader->nFilledLen);
-                signalError = true;
-            } else {
-                bool protectionAbsent = (adtsHeader[1] & 1);
-
-                unsigned aac_frame_length =
-                    ((adtsHeader[3] & 3) << 11)
-                    | (adtsHeader[4] << 3)
-                    | (adtsHeader[5] >> 5);
-
-                if (inHeader->nFilledLen < aac_frame_length) {
-                    ALOGE("Not enough audio data for the complete frame. "
-                          "Got %ld bytes, frame size according to the ADTS "
-                          "header is %u bytes.",
-                          inHeader->nFilledLen, aac_frame_length);
-                    hexdump(adtsHeader, inHeader->nFilledLen);
-                    signalError = true;
-                } else {
-                    adtsHeaderSize = (protectionAbsent ? 7 : 9);
-
-                    inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize;
-                    inBufferLength[0] = aac_frame_length - adtsHeaderSize;
-
-                    inHeader->nOffset += adtsHeaderSize;
-                    inHeader->nFilledLen -= adtsHeaderSize;
-                }
-            }
-
-            if (signalError) {
-                mSignalledError = true;
-
-                notify(OMX_EventError,
-                       OMX_ErrorStreamCorrupt,
-                       ERROR_MALFORMED,
-                       NULL);
-
-                return;
+                inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
+                inBufferLength[0] = inHeader->nFilledLen;
             }
         } else {
-            inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
-            inBufferLength[0] = inHeader->nFilledLen;
+            inBufferLength[0] = 0;
         }
 
         // Fill and decode
@@ -471,50 +444,66 @@
         int prevNumChannels = mStreamInfo->numChannels;
 
         AAC_DECODER_ERROR decoderErr = AAC_DEC_NOT_ENOUGH_BITS;
-        while (bytesValid[0] > 0 && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
+        while ((bytesValid[0] > 0 || mSawInputEos) && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
+            mDecoderHasData |= (bytesValid[0] > 0);
             aacDecoder_Fill(mAACDecoder,
                             inBuffer,
                             inBufferLength,
                             bytesValid);
-            mDecoderHasData = true;
 
             decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
                                                 outBuffer,
                                                 outHeader->nAllocLen,
                                                 0 /* flags */);
-
             if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
-                ALOGW("Not enough bits, bytesValid %d", bytesValid[0]);
+                if (mSawInputEos && bytesValid[0] <= 0) {
+                    if (mDecoderHasData) {
+                        // flush out the decoder's delayed data by calling DecodeFrame
+                        // one more time, with the AACDEC_FLUSH flag set
+                        decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
+                                                            outBuffer,
+                                                            outHeader->nAllocLen,
+                                                            AACDEC_FLUSH);
+                        mDecoderHasData = false;
+                    }
+                    outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+                    mSignalledOutputEos = true;
+                    break;
+                } else {
+                    ALOGW("Not enough bits, bytesValid %d", bytesValid[0]);
+                }
             }
         }
 
         size_t numOutBytes =
             mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
 
-        if (decoderErr == AAC_DEC_OK) {
-            UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
-            inHeader->nFilledLen -= inBufferUsedLength;
-            inHeader->nOffset += inBufferUsedLength;
-        } else {
-            ALOGW("AAC decoder returned error %d, substituting silence",
-                  decoderErr);
+        if (inHeader) {
+            if (decoderErr == AAC_DEC_OK) {
+                UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
+                inHeader->nFilledLen -= inBufferUsedLength;
+                inHeader->nOffset += inBufferUsedLength;
+            } else {
+                ALOGW("AAC decoder returned error %d, substituting silence",
+                      decoderErr);
 
-            memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes);
+                memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes);
 
-            // Discard input buffer.
-            inHeader->nFilledLen = 0;
+                // Discard input buffer.
+                inHeader->nFilledLen = 0;
 
-            aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
+                aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
 
-            // fall through
-        }
+                // fall through
+            }
 
-        if (inHeader->nFilledLen == 0) {
-            inInfo->mOwnedByUs = false;
-            inQueue.erase(inQueue.begin());
-            inInfo = NULL;
-            notifyEmptyBufferDone(inHeader);
-            inHeader = NULL;
+            if (inHeader->nFilledLen == 0) {
+                inInfo->mOwnedByUs = false;
+                inQueue.erase(inQueue.begin());
+                inInfo = NULL;
+                notifyEmptyBufferDone(inHeader);
+                inHeader = NULL;
+            }
         }
 
         /*
@@ -555,7 +544,6 @@
             // we've previously decoded valid data, in the latter case
             // (decode failed) we'll output a silent frame.
             outHeader->nFilledLen = numOutBytes;
-            outHeader->nFlags = 0;
 
             outHeader->nTimeStamp =
                 mAnchorTimeUs
@@ -582,6 +570,12 @@
         // depend on fragments from the last one decoded.
         // drain all existing data
         drainDecoder();
+        // force decoder loop to drop the first decoded buffer by resetting these state variables,
+        // but only if initialization has already happened.
+        if (mInputBufferCount != 0) {
+            mInputBufferCount = 1;
+            mStreamInfo->sampleRate = 0;
+        }
     }
 }
 
@@ -606,6 +600,8 @@
     mStreamInfo->sampleRate = 0;
 
     mSignalledError = false;
+    mSawInputEos = false;
+    mSignalledOutputEos = false;
     mOutputPortSettingsChange = NONE;
 }
 
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h
index 2d960ab..a7ea1e2 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h
@@ -55,6 +55,8 @@
     bool mDecoderHasData;
     size_t mInputBufferCount;
     bool mSignalledError;
+    bool mSawInputEos;
+    bool mSignalledOutputEos;
     int64_t mAnchorTimeUs;
     int64_t mNumSamplesOutput;
 
diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk
index 35348de..04dc487 100644
--- a/media/libstagefright/codecs/aacenc/Android.mk
+++ b/media/libstagefright/codecs/aacenc/Android.mk
@@ -82,6 +82,8 @@
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV7
 endif
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_STATIC_LIBRARY)
 
 ################################################################################
@@ -106,6 +108,8 @@
 
   LOCAL_CFLAGS :=
 
+  LOCAL_CFLAGS += -Werror
+
   LOCAL_STATIC_LIBRARIES := libFraunhoferAAC
 
   LOCAL_SHARED_LIBRARIES := \
@@ -129,6 +133,8 @@
 
   LOCAL_CFLAGS := -DOSCL_IMPORT_REF=
 
+  LOCAL_CFLAGS += -Werror
+
   LOCAL_STATIC_LIBRARIES := \
           libstagefright_aacenc
 
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
index ff2b503..9a91579 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
@@ -338,7 +338,7 @@
     return OK;
 }
 
-void SoftAACEncoder2::onQueueFilled(OMX_U32 portIndex) {
+void SoftAACEncoder2::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError) {
         return;
     }
diff --git a/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c b/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c
index cc01927..1d029fc 100644
--- a/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c
+++ b/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c
@@ -24,6 +24,8 @@
 #include "basic_op.h"
 #include "oper_32b.h"
 
+#define UNUSED(x) (void)(x)
+
 /*****************************************************************************
  *                                                                           *
  *  Function L_Extract()                                                     *
@@ -243,6 +245,8 @@
 Word32 rsqrt(Word32 value,     /*!< Operand to square root (0.0 ... 1) */
              Word32 accuracy)  /*!< Number of valid bits that will be calculated */
 {
+    UNUSED(accuracy);
+
     Word32 root = 0;
 	Word32 scale;
 
diff --git a/media/libstagefright/codecs/aacenc/src/aacenc.c b/media/libstagefright/codecs/aacenc/src/aacenc.c
index d1c8621..40db92c 100644
--- a/media/libstagefright/codecs/aacenc/src/aacenc.c
+++ b/media/libstagefright/codecs/aacenc/src/aacenc.c
@@ -27,6 +27,8 @@
 #include "cmnMemory.h"
 #include "memalign.h"
 
+#define UNUSED(x) (void)(x)
+
 /**
 * Init the audio codec module and return codec handle
 * \param phCodec [OUT] Return the video codec handle
@@ -46,6 +48,8 @@
 	VO_MEM_OPERATOR *pMemOP;
 	int interMem;
 
+        UNUSED(vType);
+
 	interMem = 0;
 	error = 0;
 
@@ -471,6 +475,10 @@
 */
 VO_U32 VO_API voAACEncGetParam(VO_HANDLE hCodec, VO_S32 uParamID, VO_PTR pData)
 {
+        UNUSED(hCodec);
+        UNUSED(uParamID);
+        UNUSED(pData);
+
 	return VO_ERR_NONE;
 }
 
diff --git a/media/libstagefright/codecs/aacenc/src/adj_thr.c b/media/libstagefright/codecs/aacenc/src/adj_thr.c
index ccfe883..471631c 100644
--- a/media/libstagefright/codecs/aacenc/src/adj_thr.c
+++ b/media/libstagefright/codecs/aacenc/src/adj_thr.c
@@ -72,7 +72,7 @@
                           const Word16 nChannels)
 {
   Word16 ch, sfb, sfbGrp;
-  Word32 *pthrExp, *psfbThre;
+  Word32 *pthrExp = NULL, *psfbThre;
   for (ch=0; ch<nChannels; ch++) {
     PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
 	 for(sfbGrp = 0; sfbGrp < psyOutChan->sfbCnt; sfbGrp+= psyOutChan->sfbPerGroup)
diff --git a/media/libstagefright/codecs/aacenc/src/bitenc.c b/media/libstagefright/codecs/aacenc/src/bitenc.c
index fcc12dd..d1fd647 100644
--- a/media/libstagefright/codecs/aacenc/src/bitenc.c
+++ b/media/libstagefright/codecs/aacenc/src/bitenc.c
@@ -26,6 +26,7 @@
 #include "qc_data.h"
 #include "interface.h"
 
+#define UNUSED(x) (void)(x)
 
 static const  Word16 globalGainOffset = 100;
 static const  Word16 icsReservedBit   = 0;
@@ -585,6 +586,8 @@
   Word16 elementUsedBits;
   Word16 frameBits=0;
 
+  UNUSED(ancBytes);
+
   /*   struct bitbuffer bsWriteCopy; */
   bitMarkUp = GetBitsAvail(hBitStream);
   if(qcOut->qcElement.adtsUsed)  /*  write adts header*/
diff --git a/media/libstagefright/codecs/aacenc/src/dyn_bits.c b/media/libstagefright/codecs/aacenc/src/dyn_bits.c
index 7769188..4d763d0 100644
--- a/media/libstagefright/codecs/aacenc/src/dyn_bits.c
+++ b/media/libstagefright/codecs/aacenc/src/dyn_bits.c
@@ -25,7 +25,6 @@
 #include "bit_cnt.h"
 #include "psy_const.h"
 
-
 /*****************************************************************************
 *
 * function name: buildBitLookUp
@@ -226,7 +225,7 @@
   }
 
   while (TRUE) {
-    Word16 maxMergeGain, maxNdx, maxNdxNext, maxNdxLast;
+    Word16 maxMergeGain, maxNdx = 0, maxNdxNext, maxNdxLast;
 
     maxMergeGain = findMaxMerge(mergeGainLookUp, sectionInfo, maxSfb, &maxNdx);
 
diff --git a/media/libstagefright/codecs/aacenc/src/psy_main.c b/media/libstagefright/codecs/aacenc/src/psy_main.c
index 4e9218c..6f0679c 100644
--- a/media/libstagefright/codecs/aacenc/src/psy_main.c
+++ b/media/libstagefright/codecs/aacenc/src/psy_main.c
@@ -38,6 +38,8 @@
 #include "tns_func.h"
 #include "memalign.h"
 
+#define UNUSED(x) (void)(x)
+
 /*                                    long       start       short       stop */
 static Word16 blockType2windowShape[] = {KBD_WINDOW,SINE_WINDOW,SINE_WINDOW,KBD_WINDOW};
 
@@ -170,7 +172,9 @@
 *****************************************************************************/
 Word16 PsyOutDelete(PSY_OUT *hPsyOut, VO_MEM_OPERATOR *pMemOP)
 {
-  hPsyOut=NULL;
+  UNUSED(hPsyOut);
+  UNUSED(pMemOP);
+
   return 0;
 }
 
diff --git a/media/libstagefright/codecs/aacenc/src/qc_main.c b/media/libstagefright/codecs/aacenc/src/qc_main.c
index 48ff300..e5d78aa 100644
--- a/media/libstagefright/codecs/aacenc/src/qc_main.c
+++ b/media/libstagefright/codecs/aacenc/src/qc_main.c
@@ -33,6 +33,7 @@
 #include "channel_map.h"
 #include "memalign.h"
 
+#define UNUSED(x) (void)(x)
 
 typedef enum{
   FRAME_LEN_BYTES_MODULO =  1,
@@ -204,11 +205,8 @@
 **********************************************************************************/
 void QCDelete(QC_STATE *hQC, VO_MEM_OPERATOR *pMemOP)
 {
-
-  /*
-     nothing to do
-  */
-  hQC=NULL;
+  UNUSED(hQC);
+  UNUSED(pMemOP);
 }
 
 /*********************************************************************************
diff --git a/media/libstagefright/codecs/aacenc/src/tns.c b/media/libstagefright/codecs/aacenc/src/tns.c
index 455a864..5172612 100644
--- a/media/libstagefright/codecs/aacenc/src/tns.c
+++ b/media/libstagefright/codecs/aacenc/src/tns.c
@@ -30,6 +30,8 @@
 #include "psy_configuration.h"
 #include "tns_func.h"
 
+#define UNUSED(x) (void)(x)
+
 #define TNS_MODIFY_BEGIN         2600  /* Hz */
 #define RATIO_PATCH_LOWER_BORDER 380   /* Hz */
 #define TNS_GAIN_THRESH			 141   /* 1.41*100 */
@@ -643,6 +645,8 @@
   Word32 i;
   Word32 tnsOrderPlus1 = tnsOrder + 1;
 
+  UNUSED(window);
+
   assert(tnsOrder <= TNS_MAX_ORDER);      /* remove asserts later? (btg) */
 
   for(i=0;i<tnsOrder;i++) {
diff --git a/media/libstagefright/codecs/amrnb/common/Android.mk b/media/libstagefright/codecs/amrnb/common/Android.mk
index 30ce29c..a2b3c8f 100644
--- a/media/libstagefright/codecs/amrnb/common/Android.mk
+++ b/media/libstagefright/codecs/amrnb/common/Android.mk
@@ -69,6 +69,8 @@
 LOCAL_CFLAGS := \
         -DOSCL_UNUSED_ARG= -DOSCL_IMPORT_REF= -DOSCL_EXPORT_REF=
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE := libstagefright_amrnb_common
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk
index 8d6c6f8..b067456 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.mk
+++ b/media/libstagefright/codecs/amrnb/dec/Android.mk
@@ -47,6 +47,8 @@
 LOCAL_CFLAGS := \
         -DOSCL_UNUSED_ARG= -DOSCL_IMPORT_REF=
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE := libstagefright_amrnbdec
 
 include $(BUILD_STATIC_LIBRARY)
@@ -68,6 +70,8 @@
 
 LOCAL_CFLAGS := -DOSCL_IMPORT_REF=
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_amrnbdec libstagefright_amrwbdec
 
diff --git a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
index 3320688..d1b0f76 100644
--- a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
@@ -274,7 +274,7 @@
     return frameSize;
 }
 
-void SoftAMR::onQueueFilled(OMX_U32 portIndex) {
+void SoftAMR::onQueueFilled(OMX_U32 /* portIndex */) {
     List<BufferInfo *> &inQueue = getPortQueue(0);
     List<BufferInfo *> &outQueue = getPortQueue(1);
 
@@ -428,7 +428,7 @@
     }
 }
 
-void SoftAMR::onPortFlushCompleted(OMX_U32 portIndex) {
+void SoftAMR::onPortFlushCompleted(OMX_U32 /* portIndex */) {
 }
 
 void SoftAMR::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk
index f4e467a..afc0b89 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.mk
+++ b/media/libstagefright/codecs/amrnb/enc/Android.mk
@@ -69,6 +69,8 @@
 LOCAL_CFLAGS := \
         -DOSCL_UNUSED_ARG=
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE := libstagefright_amrnbenc
 
 include $(BUILD_STATIC_LIBRARY)
@@ -88,6 +90,8 @@
         $(LOCAL_PATH)/../common/include \
         $(LOCAL_PATH)/../common
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_amrnbenc
 
diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
index 50b739c..9489457 100644
--- a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
@@ -270,7 +270,7 @@
     }
 }
 
-void SoftAMRNBEncoder::onQueueFilled(OMX_U32 portIndex) {
+void SoftAMRNBEncoder::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError) {
         return;
     }
diff --git a/media/libstagefright/codecs/amrwb/Android.mk b/media/libstagefright/codecs/amrwb/Android.mk
index 677107f..efdf988 100644
--- a/media/libstagefright/codecs/amrwb/Android.mk
+++ b/media/libstagefright/codecs/amrwb/Android.mk
@@ -50,6 +50,8 @@
 LOCAL_CFLAGS := \
         -DOSCL_UNUSED_ARG= -DOSCL_IMPORT_REF=
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE := libstagefright_amrwbdec
 
 include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk
index c5b8e0c..64fe8d1 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/Android.mk
@@ -112,6 +112,8 @@
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV7
 endif
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_STATIC_LIBRARY)
 
 ################################################################################
@@ -126,6 +128,8 @@
 	frameworks/av/media/libstagefright/codecs/common/include \
 	frameworks/native/include/media/openmax
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_amrwbenc
 
diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
index 9ccb49c..91a512d 100644
--- a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
+++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
@@ -317,7 +317,7 @@
     }
 }
 
-void SoftAMRWBEncoder::onQueueFilled(OMX_U32 portIndex) {
+void SoftAMRWBEncoder::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError) {
         return;
     }
diff --git a/media/libstagefright/codecs/amrwbenc/src/autocorr.c b/media/libstagefright/codecs/amrwbenc/src/autocorr.c
index 8c477ca..0b2ea89 100644
--- a/media/libstagefright/codecs/amrwbenc/src/autocorr.c
+++ b/media/libstagefright/codecs/amrwbenc/src/autocorr.c
@@ -28,6 +28,8 @@
 #include "acelp.h"
 #include "ham_wind.tab"
 
+#define UNUSED(x) (void)(x)
+
 void Autocorr(
 		Word16 x[],                           /* (i)    : Input signal                      */
 		Word16 m,                             /* (i)    : LPC order                         */
@@ -40,6 +42,8 @@
 	Word32 L_sum, L_sum1, L_tmp, F_LEN;
 	Word16 *p1,*p2,*p3;
 	const Word16 *p4;
+        UNUSED(m);
+
 	/* Windowing of signal */
 	p1 = x;
 	p4 = vo_window;
diff --git a/media/libstagefright/codecs/amrwbenc/src/convolve.c b/media/libstagefright/codecs/amrwbenc/src/convolve.c
index acba532..4c1f7d4 100644
--- a/media/libstagefright/codecs/amrwbenc/src/convolve.c
+++ b/media/libstagefright/codecs/amrwbenc/src/convolve.c
@@ -25,6 +25,8 @@
 #include "typedef.h"
 #include "basic_op.h"
 
+#define UNUSED(x) (void)(x)
+
 void Convolve (
 		Word16 x[],        /* (i)     : input vector                           */
 		Word16 h[],        /* (i)     : impulse response                       */
@@ -35,6 +37,8 @@
 	Word32  i, n;
 	Word16 *tmpH,*tmpX;
 	Word32 s;
+        UNUSED(L);
+
 	for (n = 0; n < 64;)
 	{
 		tmpH = h+n;
diff --git a/media/libstagefright/codecs/amrwbenc/src/pitch_f4.c b/media/libstagefright/codecs/amrwbenc/src/pitch_f4.c
index 0d66c31..b66b55e 100644
--- a/media/libstagefright/codecs/amrwbenc/src/pitch_f4.c
+++ b/media/libstagefright/codecs/amrwbenc/src/pitch_f4.c
@@ -31,6 +31,8 @@
 #define UP_SAMP      4
 #define L_INTERPOL1  4
 
+#define UNUSED(x) (void)(x)
+
 /* Local functions */
 
 #ifdef ASM_OPT
@@ -171,6 +173,7 @@
 	Word32 corr, exp_corr, norm, exp, scale;
 	Word16 exp_norm, excf[L_SUBFR], tmp;
 	Word32 L_tmp, L_tmp1, L_tmp2;
+        UNUSED(L_subfr);
 
 	/* compute the filtered excitation for the first delay t_min */
 	k = -t_min;
diff --git a/media/libstagefright/codecs/amrwbenc/src/syn_filt.c b/media/libstagefright/codecs/amrwbenc/src/syn_filt.c
index 1bda05a..961aadc 100644
--- a/media/libstagefright/codecs/amrwbenc/src/syn_filt.c
+++ b/media/libstagefright/codecs/amrwbenc/src/syn_filt.c
@@ -26,6 +26,8 @@
 #include "math_op.h"
 #include "cnst.h"
 
+#define UNUSED(x) (void)(x)
+
 void Syn_filt(
 		Word16 a[],                           /* (i) Q12 : a[m+1] prediction coefficients           */
 		Word16 x[],                           /* (i)     : input signal                             */
@@ -95,6 +97,8 @@
 	Word32 i,a0;
 	Word32 L_tmp, L_tmp1;
 	Word16 *p1, *p2, *p3;
+        UNUSED(m);
+
 	a0 = a[0] >> (4 + Qnew);          /* input / 16 and >>Qnew */
 	/* Do the filtering. */
 	for (i = 0; i < lg; i++)
diff --git a/media/libstagefright/codecs/amrwbenc/src/voAMRWBEnc.c b/media/libstagefright/codecs/amrwbenc/src/voAMRWBEnc.c
index ea9da52..df7b9b3 100644
--- a/media/libstagefright/codecs/amrwbenc/src/voAMRWBEnc.c
+++ b/media/libstagefright/codecs/amrwbenc/src/voAMRWBEnc.c
@@ -39,6 +39,8 @@
 #include "mem_align.h"
 #include "cmnMemory.h"
 
+#define UNUSED(x) (void)(x)
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -1602,6 +1604,8 @@
 	VO_MEM_OPERATOR voMemoprator;
 #endif
 	VO_MEM_OPERATOR *pMemOP;
+        UNUSED(vType);
+
 	int interMem = 0;
 
 	if(pUserData == NULL || pUserData->memflag != VO_IMF_USERMEMOPERATOR || pUserData->memData == NULL )
diff --git a/media/libstagefright/codecs/avc/common/Android.mk b/media/libstagefright/codecs/avc/common/Android.mk
index 22dee15..844ef0a 100644
--- a/media/libstagefright/codecs/avc/common/Android.mk
+++ b/media/libstagefright/codecs/avc/common/Android.mk
@@ -16,4 +16,6 @@
 	$(LOCAL_PATH)/src \
  	$(LOCAL_PATH)/include
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/avc/enc/Android.mk b/media/libstagefright/codecs/avc/enc/Android.mk
index d4381e4..c2e7b81 100644
--- a/media/libstagefright/codecs/avc/enc/Android.mk
+++ b/media/libstagefright/codecs/avc/enc/Android.mk
@@ -31,6 +31,8 @@
 LOCAL_CFLAGS := \
     -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_STATIC_LIBRARY)
 
 ################################################################################
@@ -71,4 +73,6 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_32_BIT_ONLY := true
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp
index 1d398fb..a15b040 100644
--- a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp
+++ b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp
@@ -34,6 +34,12 @@
 
 #include "SoftAVCEncoder.h"
 
+#if LOG_NDEBUG
+#define UNUSED_UNLESS_VERBOSE(x) (void)(x)
+#else
+#define UNUSED_UNLESS_VERBOSE(x)
+#endif
+
 namespace android {
 
 template<class T>
@@ -136,14 +142,14 @@
 }
 
 static void* MallocWrapper(
-        void *userData, int32_t size, int32_t attrs) {
+        void * /* userData */, int32_t size, int32_t /* attrs */) {
     void *ptr = malloc(size);
     if (ptr)
         memset(ptr, 0, size);
     return ptr;
 }
 
-static void FreeWrapper(void *userData, void* ptr) {
+static void FreeWrapper(void * /* userData */, void* ptr) {
     free(ptr);
 }
 
@@ -217,7 +223,7 @@
     mHandle->CBAVC_Free = FreeWrapper;
 
     CHECK(mEncParams != NULL);
-    memset(mEncParams, 0, sizeof(mEncParams));
+    memset(mEncParams, 0, sizeof(*mEncParams));
     mEncParams->rate_control = AVC_ON;
     mEncParams->initQP = 0;
     mEncParams->init_CBP_removal_delay = 1600;
@@ -722,7 +728,7 @@
     }
 }
 
-void SoftAVCEncoder::onQueueFilled(OMX_U32 portIndex) {
+void SoftAVCEncoder::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError || mSawInputEOS) {
         return;
     }
@@ -795,7 +801,7 @@
             }
         }
 
-        buffer_handle_t srcBuffer; // for MetaDataMode only
+        buffer_handle_t srcBuffer = NULL; // for MetaDataMode only
 
         // Get next input video frame
         if (mReadyForNextFrame) {
@@ -964,6 +970,7 @@
 }
 
 void SoftAVCEncoder::signalBufferReturned(MediaBuffer *buffer) {
+    UNUSED_UNLESS_VERBOSE(buffer);
     ALOGV("signalBufferReturned: %p", buffer);
 }
 
diff --git a/media/libstagefright/codecs/common/Android.mk b/media/libstagefright/codecs/common/Android.mk
index a33cb92..b0010ff 100644
--- a/media/libstagefright/codecs/common/Android.mk
+++ b/media/libstagefright/codecs/common/Android.mk
@@ -14,6 +14,8 @@
 LOCAL_C_INCLUDES := \
 	$(LOCAL_PATH)/include
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
 
 
diff --git a/media/libstagefright/codecs/common/cmnMemory.c b/media/libstagefright/codecs/common/cmnMemory.c
index aa52bd9..5bb6cc4 100644
--- a/media/libstagefright/codecs/common/cmnMemory.c
+++ b/media/libstagefright/codecs/common/cmnMemory.c
@@ -26,8 +26,12 @@
 
 //VO_MEM_OPERATOR		g_memOP;
 
+#define UNUSED(x) (void)(x)
+
 VO_U32 cmnMemAlloc (VO_S32 uID,  VO_MEM_INFO * pMemInfo)
 {
+        UNUSED(uID);
+
 	if (!pMemInfo)
 		return VO_ERR_INVALID_ARG;
 
@@ -37,34 +41,48 @@
 
 VO_U32 cmnMemFree (VO_S32 uID, VO_PTR pMem)
 {
+        UNUSED(uID);
+
 	free (pMem);
 	return 0;
 }
 
 VO_U32	cmnMemSet (VO_S32 uID, VO_PTR pBuff, VO_U8 uValue, VO_U32 uSize)
 {
+        UNUSED(uID);
+
 	memset (pBuff, uValue, uSize);
 	return 0;
 }
 
 VO_U32	cmnMemCopy (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize)
 {
+        UNUSED(uID);
+
 	memcpy (pDest, pSource, uSize);
 	return 0;
 }
 
 VO_U32	cmnMemCheck (VO_S32 uID, VO_PTR pBuffer, VO_U32 uSize)
 {
+        UNUSED(uID);
+        UNUSED(pBuffer);
+        UNUSED(uSize);
+
 	return 0;
 }
 
 VO_S32 cmnMemCompare (VO_S32 uID, VO_PTR pBuffer1, VO_PTR pBuffer2, VO_U32 uSize)
 {
+        UNUSED(uID);
+
 	return memcmp(pBuffer1, pBuffer2, uSize);
 }
 
 VO_U32	cmnMemMove (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize)
 {
+        UNUSED(uID);
+
 	memmove (pDest, pSource, uSize);
 	return 0;
 }
diff --git a/media/libstagefright/codecs/flac/enc/Android.mk b/media/libstagefright/codecs/flac/enc/Android.mk
index f01d605..59a11de 100644
--- a/media/libstagefright/codecs/flac/enc/Android.mk
+++ b/media/libstagefright/codecs/flac/enc/Android.mk
@@ -9,6 +9,8 @@
         frameworks/native/include/media/openmax \
         external/flac/include
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_SHARED_LIBRARIES := \
         libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
index e64fe72..40661e7 100644
--- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
+++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
@@ -27,6 +27,12 @@
 #define FLAC_COMPRESSION_LEVEL_DEFAULT 5
 #define FLAC_COMPRESSION_LEVEL_MAX     8
 
+#if LOG_NDEBUG
+#define UNUSED_UNLESS_VERBOSE(x) (void)(x)
+#else
+#define UNUSED_UNLESS_VERBOSE(x)
+#endif
+
 namespace android {
 
 template<class T>
@@ -257,7 +263,7 @@
 }
 
 void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) {
-
+    UNUSED_UNLESS_VERBOSE(portIndex);
     ALOGV("SoftFlacEncoder::onQueueFilled(portIndex=%ld)", portIndex);
 
     if (mSignalledError) {
@@ -343,10 +349,11 @@
     }
 }
 
-
 FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable(
             const FLAC__byte buffer[],
-            size_t bytes, unsigned samples, unsigned current_frame) {
+            size_t bytes, unsigned samples,
+            unsigned current_frame) {
+    UNUSED_UNLESS_VERBOSE(current_frame);
     ALOGV("SoftFlacEncoder::onEncodedFlacAvailable(bytes=%d, samples=%d, curr_frame=%d)",
             bytes, samples, current_frame);
 
@@ -444,8 +451,12 @@
 
 // static
 FLAC__StreamEncoderWriteStatus SoftFlacEncoder::flacEncoderWriteCallback(
-            const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[],
-            size_t bytes, unsigned samples, unsigned current_frame, void *client_data) {
+            const FLAC__StreamEncoder * /* encoder */,
+            const FLAC__byte buffer[],
+            size_t bytes,
+            unsigned samples,
+            unsigned current_frame,
+            void *client_data) {
     return ((SoftFlacEncoder*) client_data)->onEncodedFlacAvailable(
             buffer, bytes, samples, current_frame);
 }
diff --git a/media/libstagefright/codecs/g711/dec/Android.mk b/media/libstagefright/codecs/g711/dec/Android.mk
index 4c80da6..a0112e1 100644
--- a/media/libstagefright/codecs/g711/dec/Android.mk
+++ b/media/libstagefright/codecs/g711/dec/Android.mk
@@ -14,4 +14,6 @@
 LOCAL_MODULE := libstagefright_soft_g711dec
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.cpp b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
index bcdd3c7..160ada0 100644
--- a/media/libstagefright/codecs/g711/dec/SoftG711.cpp
+++ b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
@@ -182,7 +182,7 @@
     }
 }
 
-void SoftG711::onQueueFilled(OMX_U32 portIndex) {
+void SoftG711::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError) {
         return;
     }
diff --git a/media/libstagefright/codecs/gsm/dec/Android.mk b/media/libstagefright/codecs/gsm/dec/Android.mk
index 71613d2..30868d5 100644
--- a/media/libstagefright/codecs/gsm/dec/Android.mk
+++ b/media/libstagefright/codecs/gsm/dec/Android.mk
@@ -9,6 +9,8 @@
         frameworks/native/include/media/openmax \
         external/libgsm/inc
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_SHARED_LIBRARIES := \
         libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
diff --git a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
index 00e0c85..18f7d29 100644
--- a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
+++ b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
@@ -172,7 +172,7 @@
     }
 }
 
-void SoftGSM::onQueueFilled(OMX_U32 portIndex) {
+void SoftGSM::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError) {
         return;
     }
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.mk b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
index a3d5779..1d232c6 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
@@ -46,6 +46,8 @@
 
 LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF=
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_STATIC_LIBRARY)
 
 ################################################################################
@@ -72,4 +74,6 @@
 LOCAL_MODULE := libstagefright_soft_mpeg4dec
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
index fb2a430..0d1ab71 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -91,7 +91,7 @@
     return OK;
 }
 
-void SoftMPEG4::onQueueFilled(OMX_U32 portIndex) {
+void SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError || mOutputPortSettingsChange != NONE) {
         return;
     }
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.mk b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
index 83a2dd2..c9006d9 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
@@ -33,6 +33,8 @@
     $(TOP)/frameworks/av/media/libstagefright/include \
     $(TOP)/frameworks/native/include/media/openmax
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_STATIC_LIBRARY)
 
 ################################################################################
@@ -72,4 +74,6 @@
 LOCAL_MODULE := libstagefright_soft_mpeg4enc
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
index e02af90..2c73e57 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
@@ -620,7 +620,7 @@
     }
 }
 
-void SoftMPEG4Encoder::onQueueFilled(OMX_U32 portIndex) {
+void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError || mSawInputEOS) {
         return;
     }
@@ -677,7 +677,7 @@
             mSawInputEOS = true;
         }
 
-        buffer_handle_t srcBuffer; // for MetaDataMode only
+        buffer_handle_t srcBuffer = NULL; // for MetaDataMode only
         if (inHeader->nFilledLen > 0) {
             uint8_t *inputData = NULL;
             if (mStoreMetaDataInBuffers) {
diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk
index 135c715..8284490 100644
--- a/media/libstagefright/codecs/mp3dec/Android.mk
+++ b/media/libstagefright/codecs/mp3dec/Android.mk
@@ -50,6 +50,8 @@
 LOCAL_CFLAGS := \
         -DOSCL_UNUSED_ARG=
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE := libstagefright_mp3dec
 
 LOCAL_ARM_MODE := arm
@@ -69,6 +71,8 @@
         $(LOCAL_PATH)/src \
         $(LOCAL_PATH)/include
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_SHARED_LIBRARIES := \
         libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index 7c382fb..5396022 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -49,6 +49,8 @@
       mNumChannels(2),
       mSamplingRate(44100),
       mSignalledError(false),
+      mSawInputEos(false),
+      mSignalledOutputEos(false),
       mOutputPortSettingsChange(NONE) {
     initPorts();
     initDecoder();
@@ -144,6 +146,23 @@
             return OMX_ErrorNone;
         }
 
+        case OMX_IndexParamAudioMp3:
+        {
+            OMX_AUDIO_PARAM_MP3TYPE *mp3Params =
+                (OMX_AUDIO_PARAM_MP3TYPE *)params;
+
+            if (mp3Params->nPortIndex > 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            mp3Params->nChannels = mNumChannels;
+            mp3Params->nBitRate = 0 /* unknown */;
+            mp3Params->nSampleRate = mSamplingRate;
+            // other fields are encoder-only
+
+            return OMX_ErrorNone;
+        }
+
         default:
             return SimpleSoftOMXComponent::internalGetParameter(index, params);
     }
@@ -186,7 +205,7 @@
     }
 }
 
-void SoftMP3::onQueueFilled(OMX_U32 portIndex) {
+void SoftMP3::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError || mOutputPortSettingsChange != NONE) {
         return;
     }
@@ -194,48 +213,36 @@
     List<BufferInfo *> &inQueue = getPortQueue(0);
     List<BufferInfo *> &outQueue = getPortQueue(1);
 
-    while (!inQueue.empty() && !outQueue.empty()) {
-        BufferInfo *inInfo = *inQueue.begin();
-        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+    while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
+        BufferInfo *inInfo = NULL;
+        OMX_BUFFERHEADERTYPE *inHeader = NULL;
+        if (!inQueue.empty()) {
+            inInfo = *inQueue.begin();
+            inHeader = inInfo->mHeader;
+        }
 
         BufferInfo *outInfo = *outQueue.begin();
         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+        outHeader->nFlags = 0;
 
-        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
-            inQueue.erase(inQueue.begin());
-            inInfo->mOwnedByUs = false;
-            notifyEmptyBufferDone(inHeader);
-
-            if (!mIsFirst) {
-                // pad the end of the stream with 529 samples, since that many samples
-                // were trimmed off the beginning when decoding started
-                outHeader->nFilledLen =
-                    kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);
-
-                memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
-            } else {
-                // Since we never discarded frames from the start, we won't have
-                // to add any padding at the end either.
-                outHeader->nFilledLen = 0;
+        if (inHeader) {
+            if (inHeader->nOffset == 0 && inHeader->nFilledLen) {
+                mAnchorTimeUs = inHeader->nTimeStamp;
+                mNumFramesOutput = 0;
             }
 
-            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+                mSawInputEos = true;
+            }
 
-            outQueue.erase(outQueue.begin());
-            outInfo->mOwnedByUs = false;
-            notifyFillBufferDone(outHeader);
-            return;
+            mConfig->pInputBuffer =
+                inHeader->pBuffer + inHeader->nOffset;
+
+            mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
+        } else {
+            mConfig->pInputBuffer = NULL;
+            mConfig->inputBufferCurrentLength = 0;
         }
-
-        if (inHeader->nOffset == 0) {
-            mAnchorTimeUs = inHeader->nTimeStamp;
-            mNumFramesOutput = 0;
-        }
-
-        mConfig->pInputBuffer =
-            inHeader->pBuffer + inHeader->nOffset;
-
-        mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
         mConfig->inputBufferMaxLength = 0;
         mConfig->inputBufferUsedLength = 0;
 
@@ -262,13 +269,28 @@
                 mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
             }
 
-            // This is recoverable, just ignore the current frame and
-            // play silence instead.
-            memset(outHeader->pBuffer,
-                   0,
-                   mConfig->outputFrameSize * sizeof(int16_t));
+            if (decoderErr == NO_ENOUGH_MAIN_DATA_ERROR && mSawInputEos) {
+                if (!mIsFirst) {
+                    // pad the end of the stream with 529 samples, since that many samples
+                    // were trimmed off the beginning when decoding started
+                    outHeader->nOffset = 0;
+                    outHeader->nFilledLen = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);
 
-            mConfig->inputBufferUsedLength = inHeader->nFilledLen;
+                    memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
+                }
+                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+                mSignalledOutputEos = true;
+            } else {
+                // This is recoverable, just ignore the current frame and
+                // play silence instead.
+                memset(outHeader->pBuffer,
+                       0,
+                       mConfig->outputFrameSize * sizeof(int16_t));
+
+                if (inHeader) {
+                    mConfig->inputBufferUsedLength = inHeader->nFilledLen;
+                }
+            }
         } else if (mConfig->samplingRate != mSamplingRate
                 || mConfig->num_channels != mNumChannels) {
             mSamplingRate = mConfig->samplingRate;
@@ -289,7 +311,7 @@
 
             outHeader->nFilledLen =
                 mConfig->outputFrameSize * sizeof(int16_t) - outHeader->nOffset;
-        } else {
+        } else if (!mSignalledOutputEos) {
             outHeader->nOffset = 0;
             outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t);
         }
@@ -298,23 +320,24 @@
             mAnchorTimeUs
                 + (mNumFramesOutput * 1000000ll) / mConfig->samplingRate;
 
-        outHeader->nFlags = 0;
+        if (inHeader) {
+            CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);
 
-        CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);
+            inHeader->nOffset += mConfig->inputBufferUsedLength;
+            inHeader->nFilledLen -= mConfig->inputBufferUsedLength;
 
-        inHeader->nOffset += mConfig->inputBufferUsedLength;
-        inHeader->nFilledLen -= mConfig->inputBufferUsedLength;
+
+            if (inHeader->nFilledLen == 0) {
+                inInfo->mOwnedByUs = false;
+                inQueue.erase(inQueue.begin());
+                inInfo = NULL;
+                notifyEmptyBufferDone(inHeader);
+                inHeader = NULL;
+            }
+        }
 
         mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;
 
-        if (inHeader->nFilledLen == 0) {
-            inInfo->mOwnedByUs = false;
-            inQueue.erase(inQueue.begin());
-            inInfo = NULL;
-            notifyEmptyBufferDone(inHeader);
-            inHeader = NULL;
-        }
-
         outInfo->mOwnedByUs = false;
         outQueue.erase(outQueue.begin());
         outInfo = NULL;
@@ -329,6 +352,9 @@
         // depend on fragments from the last one decoded.
         pvmp3_InitDecoder(mConfig, mDecoderBuf);
         mIsFirst = true;
+        mSignalledError = false;
+        mSawInputEos = false;
+        mSignalledOutputEos = false;
     }
 }
 
@@ -362,6 +388,8 @@
     pvmp3_InitDecoder(mConfig, mDecoderBuf);
     mIsFirst = true;
     mSignalledError = false;
+    mSawInputEos = false;
+    mSignalledOutputEos = false;
     mOutputPortSettingsChange = NONE;
 }
 
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.h b/media/libstagefright/codecs/mp3dec/SoftMP3.h
index 4af91ea..f9e7b53 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.h
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.h
@@ -61,6 +61,8 @@
 
     bool mIsFirst;
     bool mSignalledError;
+    bool mSawInputEos;
+    bool mSignalledOutputEos;
 
     enum {
         NONE,
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_mpeg2_get_scale_data.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_mpeg2_get_scale_data.cpp
index ee42dc5..499672b 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_mpeg2_get_scale_data.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_mpeg2_get_scale_data.cpp
@@ -139,7 +139,7 @@
     int16 blocknumber = 0;
 
     granuleInfo *gr_info = &(si->ch[ch].gran[gr]);
-    uint32 scalefac_comp, int_scalefac_comp, new_slen[4];
+    uint32 scalefac_comp, int_scalefac_comp, new_slen[4] = { 0,0,0,0 };
 
     scalefac_comp =  gr_info->scalefac_compress;
 
diff --git a/media/libstagefright/codecs/on2/dec/Android.mk b/media/libstagefright/codecs/on2/dec/Android.mk
index 7f2c46d..93ff64c 100644
--- a/media/libstagefright/codecs/on2/dec/Android.mk
+++ b/media/libstagefright/codecs/on2/dec/Android.mk
@@ -20,4 +20,6 @@
 LOCAL_MODULE := libstagefright_soft_vpxdec
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
index 476e986..423a057 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
@@ -85,7 +85,7 @@
     return OK;
 }
 
-void SoftVPX::onQueueFilled(OMX_U32 portIndex) {
+void SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mOutputPortSettingsChange != NONE) {
         return;
     }
diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
index 7ddb13c..a7bde97 100644
--- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
+++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
@@ -98,7 +98,7 @@
     return UNKNOWN_ERROR;
 }
 
-void SoftAVC::onQueueFilled(OMX_U32 portIndex) {
+void SoftAVC::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError || mOutputPortSettingsChange != NONE) {
         return;
     }
diff --git a/media/libstagefright/codecs/on2/h264dec/source/H264SwDecApi.c b/media/libstagefright/codecs/on2/h264dec/source/H264SwDecApi.c
index 2bb4c4d..524a3f0 100644
--- a/media/libstagefright/codecs/on2/h264dec/source/H264SwDecApi.c
+++ b/media/libstagefright/codecs/on2/h264dec/source/H264SwDecApi.c
@@ -42,6 +42,8 @@
 #include "h264bsd_decoder.h"
 #include "h264bsd_util.h"
 
+#define UNUSED(x) (void)(x)
+
 /*------------------------------------------------------------------------------
        Version Information
 ------------------------------------------------------------------------------*/
@@ -73,6 +75,7 @@
 #endif
 
 void H264SwDecTrace(char *string) {
+    UNUSED(string);
 }
 
 void* H264SwDecMalloc(u32 size) {
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_conceal.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_conceal.c
index 493fb9e..7a262ed 100755
--- a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_conceal.c
+++ b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_conceal.c
@@ -267,7 +267,7 @@
     i32 firstPhase[16];
     i32 *pTmp;
     /* neighbours above, below, left and right */
-    i32 a[4], b[4], l[4], r[4];
+    i32 a[4] = { 0,0,0,0 }, b[4], l[4] = { 0,0,0,0 }, r[4];
     u32 A, B, L, R;
 #ifdef H264DEC_OMXDL
     u8 fillBuff[32*21 + 15 + 32];
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_reconstruct.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_reconstruct.c
index c948776..b409a06 100755
--- a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_reconstruct.c
+++ b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_reconstruct.c
@@ -42,6 +42,8 @@
 #include "armVC.h"
 #endif /* H264DEC_OMXDL */
 
+#define UNUSED(x) (void)(x)
+
 /*------------------------------------------------------------------------------
     2. External compiler flags
 --------------------------------------------------------------------------------
@@ -2136,7 +2138,8 @@
   i32 center,
   i32 right)
 {
-
+    UNUSED(left);
+    UNUSED(right);
     ASSERT(ref);
     ASSERT(fill);
 
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_header.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_header.c
index a7c6f64..23401c6 100755
--- a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_header.c
+++ b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_header.c
@@ -47,6 +47,8 @@
 #include "h264bsd_nal_unit.h"
 #include "h264bsd_dpb.h"
 
+#define UNUSED(x) (void)(x)
+
 /*------------------------------------------------------------------------------
     2. External compiler flags
 --------------------------------------------------------------------------------
@@ -1407,6 +1409,7 @@
     u32 tmp, value, i;
     i32 ivalue;
     strmData_t tmpStrmData[1];
+    UNUSED(nalUnitType);
 
 /* Code */
 
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_util.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_util.c
index cc838fd..fb97a28 100755
--- a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_util.c
+++ b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_util.c
@@ -186,7 +186,7 @@
         return(HANTRO_FALSE);
 
     if ( (bits > 8) ||
-         ((h264bsdShowBits32(pStrmData)>>(32-bits)) != (1 << (bits-1))) )
+         ((h264bsdShowBits32(pStrmData)>>(32-bits)) != (1ul << (bits-1))) )
         return(HANTRO_TRUE);
     else
         return(HANTRO_FALSE);
diff --git a/media/libstagefright/codecs/opus/Android.mk b/media/libstagefright/codecs/opus/Android.mk
new file mode 100644
index 0000000..365b179
--- /dev/null
+++ b/media/libstagefright/codecs/opus/Android.mk
@@ -0,0 +1,4 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/media/libstagefright/codecs/opus/dec/Android.mk b/media/libstagefright/codecs/opus/dec/Android.mk
new file mode 100644
index 0000000..2379c5f
--- /dev/null
+++ b/media/libstagefright/codecs/opus/dec/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+        SoftOpus.cpp
+
+LOCAL_C_INCLUDES := \
+        external/libopus/include \
+        frameworks/av/media/libstagefright/include \
+        frameworks/native/include/media/openmax \
+
+LOCAL_SHARED_LIBRARIES := \
+        libopus libstagefright libstagefright_omx \
+        libstagefright_foundation libutils liblog
+
+LOCAL_MODULE := libstagefright_soft_opusdec
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
\ No newline at end of file
diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
new file mode 100644
index 0000000..b8084ae
--- /dev/null
+++ b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoftOpus"
+#include <utils/Log.h>
+
+#include "SoftOpus.h"
+#include <OMX_AudioExt.h>
+#include <OMX_IndexExt.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+
+extern "C" {
+    #include <opus.h>
+    #include <opus_multistream.h>
+}
+
+namespace android {
+
+static const int kRate = 48000;
+
+template<class T>
+static void InitOMXParams(T *params) {
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
+
+SoftOpus::SoftOpus(
+        const char *name,
+        const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData,
+        OMX_COMPONENTTYPE **component)
+    : SimpleSoftOMXComponent(name, callbacks, appData, component),
+      mInputBufferCount(0),
+      mDecoder(NULL),
+      mHeader(NULL),
+      mCodecDelay(0),
+      mSeekPreRoll(0),
+      mAnchorTimeUs(0),
+      mNumFramesOutput(0),
+      mOutputPortSettingsChange(NONE) {
+    initPorts();
+    CHECK_EQ(initDecoder(), (status_t)OK);
+}
+
+SoftOpus::~SoftOpus() {
+    if (mDecoder != NULL) {
+        opus_multistream_decoder_destroy(mDecoder);
+        mDecoder = NULL;
+    }
+    if (mHeader != NULL) {
+        delete mHeader;
+        mHeader = NULL;
+    }
+}
+
+void SoftOpus::initPorts() {
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+
+    def.nPortIndex = 0;
+    def.eDir = OMX_DirInput;
+    def.nBufferCountMin = kNumBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = 960 * 6;
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 1;
+
+    def.format.audio.cMIMEType =
+        const_cast<char *>(MEDIA_MIMETYPE_AUDIO_OPUS);
+
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding =
+        (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidOPUS;
+
+    addPort(def);
+
+    def.nPortIndex = 1;
+    def.eDir = OMX_DirOutput;
+    def.nBufferCountMin = kNumBuffers;
+    def.nBufferCountActual = def.nBufferCountMin;
+    def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t);
+    def.bEnabled = OMX_TRUE;
+    def.bPopulated = OMX_FALSE;
+    def.eDomain = OMX_PortDomainAudio;
+    def.bBuffersContiguous = OMX_FALSE;
+    def.nBufferAlignment = 2;
+
+    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+    def.format.audio.pNativeRender = NULL;
+    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+    addPort(def);
+}
+
+status_t SoftOpus::initDecoder() {
+    return OK;
+}
+
+OMX_ERRORTYPE SoftOpus::internalGetParameter(
+        OMX_INDEXTYPE index, OMX_PTR params) {
+    switch ((int)index) {
+        case OMX_IndexParamAudioAndroidOpus:
+        {
+            OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *opusParams =
+                (OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *)params;
+
+            if (opusParams->nPortIndex != 0) {
+                return OMX_ErrorUndefined;
+            }
+
+            opusParams->nAudioBandWidth = 0;
+            opusParams->nSampleRate = kRate;
+            opusParams->nBitRate = 0;
+
+            if (!isConfigured()) {
+                opusParams->nChannels = 1;
+            } else {
+                opusParams->nChannels = mHeader->channels;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioPcm:
+        {
+            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+            if (pcmParams->nPortIndex != 1) {
+                return OMX_ErrorUndefined;
+            }
+
+            pcmParams->eNumData = OMX_NumericalDataSigned;
+            pcmParams->eEndian = OMX_EndianBig;
+            pcmParams->bInterleaved = OMX_TRUE;
+            pcmParams->nBitPerSample = 16;
+            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+            pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+            pcmParams->nSamplingRate = kRate;
+
+            if (!isConfigured()) {
+                pcmParams->nChannels = 1;
+            } else {
+                pcmParams->nChannels = mHeader->channels;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::internalGetParameter(index, params);
+    }
+}
+
+OMX_ERRORTYPE SoftOpus::internalSetParameter(
+        OMX_INDEXTYPE index, const OMX_PTR params) {
+    switch ((int)index) {
+        case OMX_IndexParamStandardComponentRole:
+        {
+            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+                (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+            if (strncmp((const char *)roleParams->cRole,
+                        "audio_decoder.opus",
+                        OMX_MAX_STRINGNAME_SIZE - 1)) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        case OMX_IndexParamAudioAndroidOpus:
+        {
+            const OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *opusParams =
+                (const OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *)params;
+
+            if (opusParams->nPortIndex != 0) {
+                return OMX_ErrorUndefined;
+            }
+
+            return OMX_ErrorNone;
+        }
+
+        default:
+            return SimpleSoftOMXComponent::internalSetParameter(index, params);
+    }
+}
+
+bool SoftOpus::isConfigured() const {
+    return mInputBufferCount >= 1;
+}
+
+static uint16_t ReadLE16(const uint8_t *data, size_t data_size,
+                         uint32_t read_offset) {
+    if (read_offset + 1 > data_size)
+        return 0;
+    uint16_t val;
+    val = data[read_offset];
+    val |= data[read_offset + 1] << 8;
+    return val;
+}
+
+// Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies
+// mappings for up to 8 channels. This information is part of the Vorbis I
+// Specification:
+// http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
+static const int kMaxChannels = 8;
+
+// Maximum packet size used in Xiph's opusdec.
+static const int kMaxOpusOutputPacketSizeSamples = 960 * 6;
+
+// Default audio output channel layout. Used to initialize |stream_map| in
+// OpusHeader, and passed to opus_multistream_decoder_create() when the header
+// does not contain mapping information. The values are valid only for mono and
+// stereo output: Opus streams with more than 2 channels require a stream map.
+static const int kMaxChannelsWithDefaultLayout = 2;
+static const uint8_t kDefaultOpusChannelLayout[kMaxChannelsWithDefaultLayout] = { 0, 1 };
+
+// Parses Opus Header. Header spec: http://wiki.xiph.org/OggOpus#ID_Header
+static bool ParseOpusHeader(const uint8_t *data, size_t data_size,
+                            OpusHeader* header) {
+    // Size of the Opus header excluding optional mapping information.
+    const size_t kOpusHeaderSize = 19;
+
+    // Offset to the channel count byte in the Opus header.
+    const size_t kOpusHeaderChannelsOffset = 9;
+
+    // Offset to the pre-skip value in the Opus header.
+    const size_t kOpusHeaderSkipSamplesOffset = 10;
+
+    // Offset to the gain value in the Opus header.
+    const size_t kOpusHeaderGainOffset = 16;
+
+    // Offset to the channel mapping byte in the Opus header.
+    const size_t kOpusHeaderChannelMappingOffset = 18;
+
+    // Opus Header contains a stream map. The mapping values are in the header
+    // beyond the always present |kOpusHeaderSize| bytes of data. The mapping
+    // data contains stream count, coupling information, and per channel mapping
+    // values:
+    //   - Byte 0: Number of streams.
+    //   - Byte 1: Number coupled.
+    //   - Byte 2: Starting at byte 2 are |header->channels| uint8 mapping
+    //             values.
+    const size_t kOpusHeaderNumStreamsOffset = kOpusHeaderSize;
+    const size_t kOpusHeaderNumCoupledOffset = kOpusHeaderNumStreamsOffset + 1;
+    const size_t kOpusHeaderStreamMapOffset = kOpusHeaderNumStreamsOffset + 2;
+
+    if (data_size < kOpusHeaderSize) {
+        ALOGV("Header size is too small.");
+        return false;
+    }
+    header->channels = *(data + kOpusHeaderChannelsOffset);
+
+    if (header->channels <= 0 || header->channels > kMaxChannels) {
+        ALOGV("Invalid Header, wrong channel count: %d", header->channels);
+        return false;
+    }
+    header->skip_samples = ReadLE16(data, data_size,
+                                        kOpusHeaderSkipSamplesOffset);
+    header->gain_db = static_cast<int16_t>(
+                              ReadLE16(data, data_size,
+                                       kOpusHeaderGainOffset));
+    header->channel_mapping = *(data + kOpusHeaderChannelMappingOffset);
+    if (!header->channel_mapping) {
+        if (header->channels > kMaxChannelsWithDefaultLayout) {
+            ALOGV("Invalid Header, missing stream map.");
+            return false;
+        }
+        header->num_streams = 1;
+        header->num_coupled = header->channels > 1;
+        header->stream_map[0] = 0;
+        header->stream_map[1] = 1;
+        return true;
+    }
+    if (data_size < kOpusHeaderStreamMapOffset + header->channels) {
+        ALOGV("Invalid stream map; insufficient data for current channel "
+              "count: %d", header->channels);
+        return false;
+    }
+    header->num_streams = *(data + kOpusHeaderNumStreamsOffset);
+    header->num_coupled = *(data + kOpusHeaderNumCoupledOffset);
+    if (header->num_streams + header->num_coupled != header->channels) {
+        ALOGV("Inconsistent channel mapping.");
+        return false;
+    }
+    for (int i = 0; i < header->channels; ++i)
+      header->stream_map[i] = *(data + kOpusHeaderStreamMapOffset + i);
+    return true;
+}
+
+// Convert nanoseconds to number of samples.
+static uint64_t ns_to_samples(uint64_t ns, int kRate) {
+    return static_cast<double>(ns) * kRate / 1000000000;
+}
+
+void SoftOpus::onQueueFilled(OMX_U32 portIndex) {
+    List<BufferInfo *> &inQueue = getPortQueue(0);
+    List<BufferInfo *> &outQueue = getPortQueue(1);
+
+    if (mOutputPortSettingsChange != NONE) {
+        return;
+    }
+
+    if (portIndex == 0 && mInputBufferCount < 3) {
+        BufferInfo *info = *inQueue.begin();
+        OMX_BUFFERHEADERTYPE *header = info->mHeader;
+
+        const uint8_t *data = header->pBuffer + header->nOffset;
+        size_t size = header->nFilledLen;
+
+        if (mInputBufferCount == 0) {
+            CHECK(mHeader == NULL);
+            mHeader = new OpusHeader();
+            memset(mHeader, 0, sizeof(*mHeader));
+            if (!ParseOpusHeader(data, size, mHeader)) {
+                ALOGV("Parsing Opus Header failed.");
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                return;
+            }
+
+            uint8_t channel_mapping[kMaxChannels] = {0};
+            memcpy(&channel_mapping,
+                   kDefaultOpusChannelLayout,
+                   kMaxChannelsWithDefaultLayout);
+
+            int status = OPUS_INVALID_STATE;
+            mDecoder = opus_multistream_decoder_create(kRate,
+                                                       mHeader->channels,
+                                                       mHeader->num_streams,
+                                                       mHeader->num_coupled,
+                                                       channel_mapping,
+                                                       &status);
+            if (!mDecoder || status != OPUS_OK) {
+                ALOGV("opus_multistream_decoder_create failed status=%s",
+                      opus_strerror(status));
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                return;
+            }
+            status =
+                opus_multistream_decoder_ctl(mDecoder,
+                                             OPUS_SET_GAIN(mHeader->gain_db));
+            if (status != OPUS_OK) {
+                ALOGV("Failed to set OPUS header gain; status=%s",
+                      opus_strerror(status));
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                return;
+            }
+        } else if (mInputBufferCount == 1) {
+            mCodecDelay = ns_to_samples(
+                              *(reinterpret_cast<int64_t*>(header->pBuffer +
+                                                           header->nOffset)),
+                              kRate);
+            mSamplesToDiscard = mCodecDelay;
+        } else {
+            mSeekPreRoll = ns_to_samples(
+                               *(reinterpret_cast<int64_t*>(header->pBuffer +
+                                                            header->nOffset)),
+                               kRate);
+            notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+            mOutputPortSettingsChange = AWAITING_DISABLED;
+        }
+
+        inQueue.erase(inQueue.begin());
+        info->mOwnedByUs = false;
+        notifyEmptyBufferDone(header);
+        ++mInputBufferCount;
+        return;
+    }
+
+    while (!inQueue.empty() && !outQueue.empty()) {
+        BufferInfo *inInfo = *inQueue.begin();
+        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+        BufferInfo *outInfo = *outQueue.begin();
+        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+            inQueue.erase(inQueue.begin());
+            inInfo->mOwnedByUs = false;
+            notifyEmptyBufferDone(inHeader);
+
+            outHeader->nFilledLen = 0;
+            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+
+            outQueue.erase(outQueue.begin());
+            outInfo->mOwnedByUs = false;
+            notifyFillBufferDone(outHeader);
+            return;
+        }
+
+        if (inHeader->nOffset == 0) {
+            mAnchorTimeUs = inHeader->nTimeStamp;
+            mNumFramesOutput = 0;
+        }
+
+        // When seeking to zero, |mCodecDelay| samples has to be discarded
+        // instead of |mSeekPreRoll| samples (as we would when seeking to any
+        // other timestamp).
+        if (inHeader->nTimeStamp == 0) {
+            mSamplesToDiscard = mCodecDelay;
+        }
+
+        const uint8_t *data = inHeader->pBuffer + inHeader->nOffset;
+        const uint32_t size = inHeader->nFilledLen;
+
+        int numFrames = opus_multistream_decode(mDecoder,
+                                                data,
+                                                size,
+                                                (int16_t *)outHeader->pBuffer,
+                                                kMaxOpusOutputPacketSizeSamples,
+                                                0);
+        if (numFrames < 0) {
+            ALOGE("opus_multistream_decode returned %d", numFrames);
+            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+            return;
+        }
+
+        outHeader->nOffset = 0;
+        if (mSamplesToDiscard > 0) {
+            if (mSamplesToDiscard > numFrames) {
+                mSamplesToDiscard -= numFrames;
+                numFrames = 0;
+            } else {
+                numFrames -= mSamplesToDiscard;
+                outHeader->nOffset = mSamplesToDiscard * sizeof(int16_t) *
+                                     mHeader->channels;
+                mSamplesToDiscard = 0;
+            }
+        }
+
+        outHeader->nFilledLen = numFrames * sizeof(int16_t) * mHeader->channels;
+        outHeader->nFlags = 0;
+
+        outHeader->nTimeStamp = mAnchorTimeUs +
+                                (mNumFramesOutput * 1000000ll) /
+                                kRate;
+
+        mNumFramesOutput += numFrames;
+
+        inInfo->mOwnedByUs = false;
+        inQueue.erase(inQueue.begin());
+        inInfo = NULL;
+        notifyEmptyBufferDone(inHeader);
+        inHeader = NULL;
+
+        outInfo->mOwnedByUs = false;
+        outQueue.erase(outQueue.begin());
+        outInfo = NULL;
+        notifyFillBufferDone(outHeader);
+        outHeader = NULL;
+
+        ++mInputBufferCount;
+    }
+}
+
+void SoftOpus::onPortFlushCompleted(OMX_U32 portIndex) {
+    if (portIndex == 0 && mDecoder != NULL) {
+        // Make sure that the next buffer output does not still
+        // depend on fragments from the last one decoded.
+        mNumFramesOutput = 0;
+        opus_multistream_decoder_ctl(mDecoder, OPUS_RESET_STATE);
+        mAnchorTimeUs = 0;
+        mSamplesToDiscard = mSeekPreRoll;
+    }
+}
+
+void SoftOpus::onReset() {
+    mInputBufferCount = 0;
+    mNumFramesOutput = 0;
+    if (mDecoder != NULL) {
+        opus_multistream_decoder_destroy(mDecoder);
+        mDecoder = NULL;
+    }
+    if (mHeader != NULL) {
+        delete mHeader;
+        mHeader = NULL;
+    }
+
+    mOutputPortSettingsChange = NONE;
+}
+
+void SoftOpus::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
+    if (portIndex != 1) {
+        return;
+    }
+
+    switch (mOutputPortSettingsChange) {
+        case NONE:
+            break;
+
+        case AWAITING_DISABLED:
+        {
+            CHECK(!enabled);
+            mOutputPortSettingsChange = AWAITING_ENABLED;
+            break;
+        }
+
+        default:
+        {
+            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
+            CHECK(enabled);
+            mOutputPortSettingsChange = NONE;
+            break;
+        }
+    }
+}
+
+}  // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+        const char *name, const OMX_CALLBACKTYPE *callbacks,
+        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+    return new android::SoftOpus(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.h b/media/libstagefright/codecs/opus/dec/SoftOpus.h
new file mode 100644
index 0000000..97f6561
--- /dev/null
+++ b/media/libstagefright/codecs/opus/dec/SoftOpus.h
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+/*
+ * The Opus specification is part of IETF RFC 6716:
+ * http://tools.ietf.org/html/rfc6716
+ */
+
+#ifndef SOFT_OPUS_H_
+
+#define SOFT_OPUS_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+struct OpusMSDecoder;
+
+namespace android {
+
+struct OpusHeader {
+  int channels;
+  int skip_samples;
+  int channel_mapping;
+  int num_streams;
+  int num_coupled;
+  int16_t gain_db;
+  uint8_t stream_map[8];
+};
+
+struct SoftOpus : public SimpleSoftOMXComponent {
+    SoftOpus(const char *name,
+             const OMX_CALLBACKTYPE *callbacks,
+             OMX_PTR appData,
+             OMX_COMPONENTTYPE **component);
+
+protected:
+    virtual ~SoftOpus();
+
+    virtual OMX_ERRORTYPE internalGetParameter(
+            OMX_INDEXTYPE index, OMX_PTR params);
+
+    virtual OMX_ERRORTYPE internalSetParameter(
+            OMX_INDEXTYPE index, const OMX_PTR params);
+
+    virtual void onQueueFilled(OMX_U32 portIndex);
+    virtual void onPortFlushCompleted(OMX_U32 portIndex);
+    virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled);
+    virtual void onReset();
+
+private:
+    enum {
+        kNumBuffers = 4,
+        kMaxNumSamplesPerBuffer = 960 * 6
+    };
+
+    size_t mInputBufferCount;
+
+    OpusMSDecoder *mDecoder;
+    OpusHeader *mHeader;
+
+    int64_t mCodecDelay;
+    int64_t mSeekPreRoll;
+    int64_t mSamplesToDiscard;
+    int64_t mAnchorTimeUs;
+    int64_t mNumFramesOutput;
+
+    enum {
+        NONE,
+        AWAITING_DISABLED,
+        AWAITING_ENABLED
+    } mOutputPortSettingsChange;
+
+    void initPorts();
+    status_t initDecoder();
+    bool isConfigured() const;
+
+    DISALLOW_EVIL_CONSTRUCTORS(SoftOpus);
+};
+
+}  // namespace android
+
+#endif  // SOFT_OPUS_H_
diff --git a/media/libstagefright/codecs/raw/Android.mk b/media/libstagefright/codecs/raw/Android.mk
index fe90a03..87080e7 100644
--- a/media/libstagefright/codecs/raw/Android.mk
+++ b/media/libstagefright/codecs/raw/Android.mk
@@ -8,6 +8,8 @@
         frameworks/av/media/libstagefright/include \
         frameworks/native/include/media/openmax
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_SHARED_LIBRARIES := \
         libstagefright_omx libstagefright_foundation libutils liblog
 
diff --git a/media/libstagefright/codecs/raw/SoftRaw.cpp b/media/libstagefright/codecs/raw/SoftRaw.cpp
index 19d6f13..9d514a6 100644
--- a/media/libstagefright/codecs/raw/SoftRaw.cpp
+++ b/media/libstagefright/codecs/raw/SoftRaw.cpp
@@ -163,7 +163,7 @@
     }
 }
 
-void SoftRaw::onQueueFilled(OMX_U32 portIndex) {
+void SoftRaw::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError) {
         return;
     }
diff --git a/media/libstagefright/codecs/vorbis/dec/Android.mk b/media/libstagefright/codecs/vorbis/dec/Android.mk
index 2232353..217a6d2 100644
--- a/media/libstagefright/codecs/vorbis/dec/Android.mk
+++ b/media/libstagefright/codecs/vorbis/dec/Android.mk
@@ -16,4 +16,6 @@
 LOCAL_MODULE := libstagefright_soft_vorbisdec
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index 51bb958..515e4d3 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -54,6 +54,8 @@
       mAnchorTimeUs(0),
       mNumFramesOutput(0),
       mNumFramesLeftOnPage(-1),
+      mSawInputEos(false),
+      mSignalledOutputEos(false),
       mOutputPortSettingsChange(NONE) {
     initPorts();
     CHECK_EQ(initDecoder(), (status_t)OK);
@@ -290,48 +292,47 @@
         return;
     }
 
-    while (!inQueue.empty() && !outQueue.empty()) {
-        BufferInfo *inInfo = *inQueue.begin();
-        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+    while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
+        BufferInfo *inInfo = NULL;
+        OMX_BUFFERHEADERTYPE *inHeader = NULL;
+        if (!inQueue.empty()) {
+            inInfo = *inQueue.begin();
+            inHeader = inInfo->mHeader;
+        }
 
         BufferInfo *outInfo = *outQueue.begin();
         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
 
-        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
-            inQueue.erase(inQueue.begin());
-            inInfo->mOwnedByUs = false;
-            notifyEmptyBufferDone(inHeader);
+        int32_t numPageSamples = 0;
 
-            outHeader->nFilledLen = 0;
-            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+        if (inHeader) {
+            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+                mSawInputEos = true;
+            }
 
-            outQueue.erase(outQueue.begin());
-            outInfo->mOwnedByUs = false;
-            notifyFillBufferDone(outHeader);
-            return;
+            if (inHeader->nFilledLen || !mSawInputEos) {
+                CHECK_GE(inHeader->nFilledLen, sizeof(numPageSamples));
+                memcpy(&numPageSamples,
+                       inHeader->pBuffer
+                        + inHeader->nOffset + inHeader->nFilledLen - 4,
+                       sizeof(numPageSamples));
+
+                if (inHeader->nOffset == 0) {
+                    mAnchorTimeUs = inHeader->nTimeStamp;
+                    mNumFramesOutput = 0;
+                }
+
+                inHeader->nFilledLen -= sizeof(numPageSamples);;
+            }
         }
 
-        int32_t numPageSamples;
-        CHECK_GE(inHeader->nFilledLen, sizeof(numPageSamples));
-        memcpy(&numPageSamples,
-               inHeader->pBuffer
-                + inHeader->nOffset + inHeader->nFilledLen - 4,
-               sizeof(numPageSamples));
-
         if (numPageSamples >= 0) {
             mNumFramesLeftOnPage = numPageSamples;
         }
 
-        if (inHeader->nOffset == 0) {
-            mAnchorTimeUs = inHeader->nTimeStamp;
-            mNumFramesOutput = 0;
-        }
-
-        inHeader->nFilledLen -= sizeof(numPageSamples);;
-
         ogg_buffer buf;
-        buf.data = inHeader->pBuffer + inHeader->nOffset;
-        buf.size = inHeader->nFilledLen;
+        buf.data = inHeader ? inHeader->pBuffer + inHeader->nOffset : NULL;
+        buf.size = inHeader ? inHeader->nFilledLen : 0;
         buf.refcount = 1;
         buf.ptr.owner = NULL;
 
@@ -351,6 +352,7 @@
 
         int numFrames = 0;
 
+        outHeader->nFlags = 0;
         int err = vorbis_dsp_synthesis(mState, &pack, 1);
         if (err != 0) {
             ALOGW("vorbis_dsp_synthesis returned %d", err);
@@ -370,13 +372,16 @@
                 ALOGV("discarding %d frames at end of page",
                      numFrames - mNumFramesLeftOnPage);
                 numFrames = mNumFramesLeftOnPage;
+                if (mSawInputEos) {
+                    outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+                    mSignalledOutputEos = true;
+                }
             }
             mNumFramesLeftOnPage -= numFrames;
         }
 
         outHeader->nFilledLen = numFrames * sizeof(int16_t) * mVi->channels;
         outHeader->nOffset = 0;
-        outHeader->nFlags = 0;
 
         outHeader->nTimeStamp =
             mAnchorTimeUs
@@ -384,11 +389,13 @@
 
         mNumFramesOutput += numFrames;
 
-        inInfo->mOwnedByUs = false;
-        inQueue.erase(inQueue.begin());
-        inInfo = NULL;
-        notifyEmptyBufferDone(inHeader);
-        inHeader = NULL;
+        if (inHeader) {
+            inInfo->mOwnedByUs = false;
+            inQueue.erase(inQueue.begin());
+            inInfo = NULL;
+            notifyEmptyBufferDone(inHeader);
+            inHeader = NULL;
+        }
 
         outInfo->mOwnedByUs = false;
         outQueue.erase(outQueue.begin());
@@ -425,6 +432,8 @@
         mVi = NULL;
     }
 
+    mSawInputEos = false;
+    mSignalledOutputEos = false;
     mOutputPortSettingsChange = NONE;
 }
 
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
index cb628a0..1d00816 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
@@ -59,6 +59,8 @@
     int64_t mAnchorTimeUs;
     int64_t mNumFramesOutput;
     int32_t mNumFramesLeftOnPage;
+    bool mSawInputEos;
+    bool mSignalledOutputEos;
 
     enum {
         NONE,
diff --git a/media/libstagefright/foundation/ANetworkSession.cpp b/media/libstagefright/foundation/ANetworkSession.cpp
index e629588..08c4a87 100644
--- a/media/libstagefright/foundation/ANetworkSession.cpp
+++ b/media/libstagefright/foundation/ANetworkSession.cpp
@@ -521,7 +521,7 @@
     return err;
 }
 
-void ANetworkSession::Session::dumpFragmentStats(const Fragment &frag) {
+void ANetworkSession::Session::dumpFragmentStats(const Fragment & /* frag */) {
 #if 0
     int64_t nowUs = ALooper::GetNowUs();
     int64_t delayMs = (nowUs - frag.mTimeUs) / 1000ll;
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index ad2dab5..90a6a23 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -24,7 +24,7 @@
         libutils          \
         liblog
 
-LOCAL_CFLAGS += -Wno-multichar
+LOCAL_CFLAGS += -Wno-multichar -Werror
 
 LOCAL_MODULE:= libstagefright_foundation
 
diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp
index d5fb4e0..dcf5bef 100644
--- a/media/libstagefright/foundation/base64.cpp
+++ b/media/libstagefright/foundation/base64.cpp
@@ -33,6 +33,10 @@
 
         if (n >= 2 && s.c_str()[n - 2] == '=') {
             padding = 2;
+
+            if (n >= 3 && s.c_str()[n - 3] == '=') {
+                padding = 3;
+            }
         }
     }
 
@@ -71,7 +75,7 @@
         if (((i + 1) % 4) == 0) {
             out[j++] = (accum >> 16);
 
-            if (j < outLen) { out[j++] = (accum >> 8) & 0xff; } 
+            if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
             if (j < outLen) { out[j++] = accum & 0xff; }
 
             accum = 0;
diff --git a/media/libstagefright/http/Android.mk b/media/libstagefright/http/Android.mk
new file mode 100644
index 0000000..7f3307d
--- /dev/null
+++ b/media/libstagefright/http/Android.mk
@@ -0,0 +1,28 @@
+LOCAL_PATH:= $(call my-dir)
+
+ifneq ($(TARGET_BUILD_PDK), true)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:=       \
+        HTTPHelper.cpp          \
+
+LOCAL_C_INCLUDES:= \
+	$(TOP)/frameworks/av/media/libstagefright \
+	$(TOP)/frameworks/native/include/media/openmax \
+	$(TOP)/frameworks/base/core/jni \
+
+LOCAL_SHARED_LIBRARIES := \
+	libstagefright liblog libutils libbinder libstagefright_foundation \
+        libandroid_runtime \
+        libmedia
+
+LOCAL_MODULE:= libstagefright_http_support
+
+LOCAL_CFLAGS += -Wno-multichar
+
+LOCAL_CFLAGS += -Werror
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/media/libstagefright/http/HTTPHelper.cpp b/media/libstagefright/http/HTTPHelper.cpp
new file mode 100644
index 0000000..77845e2
--- /dev/null
+++ b/media/libstagefright/http/HTTPHelper.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "HTTPHelper"
+#include <utils/Log.h>
+
+#include "HTTPHelper.h"
+
+#include "android_runtime/AndroidRuntime.h"
+#include "android_util_Binder.h"
+#include <media/IMediaHTTPService.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include "jni.h"
+
+namespace android {
+
+sp<IMediaHTTPService> CreateHTTPServiceInCurrentJavaContext() {
+    if (AndroidRuntime::getJavaVM() == NULL) {
+        ALOGE("CreateHTTPServiceInCurrentJavaContext called outside "
+              "JAVA environment.");
+        return NULL;
+    }
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    ScopedLocalRef<jclass> clazz(
+            env, env->FindClass("android/media/MediaHTTPService"));
+    CHECK(clazz.get() != NULL);
+
+    jmethodID constructID = env->GetMethodID(clazz.get(), "<init>", "()V");
+    CHECK(constructID != NULL);
+
+    ScopedLocalRef<jobject> httpServiceObj(
+            env, env->NewObject(clazz.get(), constructID));
+
+    sp<IMediaHTTPService> httpService;
+    if (httpServiceObj.get() != NULL) {
+        jmethodID asBinderID =
+            env->GetMethodID(clazz.get(), "asBinder", "()Landroid/os/IBinder;");
+        CHECK(asBinderID != NULL);
+
+        ScopedLocalRef<jobject> httpServiceBinderObj(
+                env, env->CallObjectMethod(httpServiceObj.get(), asBinderID));
+        CHECK(httpServiceBinderObj.get() != NULL);
+
+        sp<IBinder> binder =
+            ibinderForJavaObject(env, httpServiceBinderObj.get());
+
+        httpService = interface_cast<IMediaHTTPService>(binder);
+    }
+
+    return httpService;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/http/HTTPHelper.h b/media/libstagefright/http/HTTPHelper.h
new file mode 100644
index 0000000..8aef115
--- /dev/null
+++ b/media/libstagefright/http/HTTPHelper.h
@@ -0,0 +1,31 @@
+/*
+ * 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 HTTP_HELPER_H_
+
+#define HTTP_HELPER_H_
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct IMediaHTTPService;
+
+sp<IMediaHTTPService> CreateHTTPServiceInCurrentJavaContext();
+
+}  // namespace android
+
+#endif  // HTTP_HELPER_H_
diff --git a/media/libstagefright/http/MediaHTTP.cpp b/media/libstagefright/http/MediaHTTP.cpp
new file mode 100644
index 0000000..2d29913
--- /dev/null
+++ b/media/libstagefright/http/MediaHTTP.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaHTTP"
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaHTTP.h>
+
+#include <binder/IServiceManager.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/Utils.h>
+
+#include <media/IMediaHTTPConnection.h>
+
+namespace android {
+
+MediaHTTP::MediaHTTP(const sp<IMediaHTTPConnection> &conn)
+    : mInitCheck(NO_INIT),
+      mHTTPConnection(conn),
+      mCachedSizeValid(false),
+      mCachedSize(0ll),
+      mDrmManagerClient(NULL) {
+    mInitCheck = OK;
+}
+
+MediaHTTP::~MediaHTTP() {
+    clearDRMState_l();
+}
+
+status_t MediaHTTP::connect(
+        const char *uri,
+        const KeyedVector<String8, String8> *headers,
+        off64_t /* offset */) {
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    KeyedVector<String8, String8> extHeaders;
+    if (headers != NULL) {
+        extHeaders = *headers;
+    }
+    extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str()));
+
+    bool success = mHTTPConnection->connect(uri, &extHeaders);
+
+    mLastHeaders = extHeaders;
+    mLastURI = uri;
+
+    mCachedSizeValid = false;
+
+    return success ? OK : UNKNOWN_ERROR;
+}
+
+void MediaHTTP::disconnect() {
+    if (mInitCheck != OK) {
+        return;
+    }
+
+    mHTTPConnection->disconnect();
+}
+
+status_t MediaHTTP::initCheck() const {
+    return mInitCheck;
+}
+
+ssize_t MediaHTTP::readAt(off64_t offset, void *data, size_t size) {
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    int64_t startTimeUs = ALooper::GetNowUs();
+
+    size_t numBytesRead = 0;
+    while (numBytesRead < size) {
+        size_t copy = size - numBytesRead;
+
+        if (copy > 64 * 1024) {
+            // limit the buffer sizes transferred across binder boundaries
+            // to avoid spurious transaction failures.
+            copy = 64 * 1024;
+        }
+
+        ssize_t n = mHTTPConnection->readAt(
+                offset + numBytesRead, (uint8_t *)data + numBytesRead, copy);
+
+        if (n < 0) {
+            return n;
+        } else if (n == 0) {
+            break;
+        }
+
+        numBytesRead += n;
+    }
+
+    int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
+
+    addBandwidthMeasurement(numBytesRead, delayUs);
+
+    return numBytesRead;
+}
+
+status_t MediaHTTP::getSize(off64_t *size) {
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    // Caching the returned size so that it stays valid even after a
+    // disconnect. NuCachedSource2 relies on this.
+
+    if (!mCachedSizeValid) {
+        mCachedSize = mHTTPConnection->getSize();
+        mCachedSizeValid = true;
+    }
+
+    *size = mCachedSize;
+
+    return *size < 0 ? *size : OK;
+}
+
+uint32_t MediaHTTP::flags() {
+    return kWantsPrefetching | kIsHTTPBasedSource;
+}
+
+status_t MediaHTTP::reconnectAtOffset(off64_t offset) {
+    return connect(mLastURI.c_str(), &mLastHeaders, offset);
+}
+
+// DRM...
+
+sp<DecryptHandle> MediaHTTP::DrmInitialization(const char* mime) {
+    if (mDrmManagerClient == NULL) {
+        mDrmManagerClient = new DrmManagerClient();
+    }
+
+    if (mDrmManagerClient == NULL) {
+        return NULL;
+    }
+
+    if (mDecryptHandle == NULL) {
+        mDecryptHandle = mDrmManagerClient->openDecryptSession(
+                String8(mLastURI.c_str()), mime);
+    }
+
+    if (mDecryptHandle == NULL) {
+        delete mDrmManagerClient;
+        mDrmManagerClient = NULL;
+    }
+
+    return mDecryptHandle;
+}
+
+void MediaHTTP::getDrmInfo(
+        sp<DecryptHandle> &handle, DrmManagerClient **client) {
+    handle = mDecryptHandle;
+    *client = mDrmManagerClient;
+}
+
+String8 MediaHTTP::getUri() {
+    String8 uri;
+    if (OK == mHTTPConnection->getUri(&uri)) {
+        return uri;
+    }
+    return String8(mLastURI.c_str());
+}
+
+String8 MediaHTTP::getMIMEType() const {
+    if (mInitCheck != OK) {
+        return String8("application/octet-stream");
+    }
+
+    String8 mimeType;
+    status_t err = mHTTPConnection->getMIMEType(&mimeType);
+
+    if (err != OK) {
+        return String8("application/octet-stream");
+    }
+
+    return mimeType;
+}
+
+void MediaHTTP::clearDRMState_l() {
+    if (mDecryptHandle != NULL) {
+        // To release mDecryptHandle
+        CHECK(mDrmManagerClient);
+        mDrmManagerClient->closeDecryptSession(mDecryptHandle);
+        mDecryptHandle = NULL;
+    }
+}
+
+}  // namespace android
diff --git a/media/libstagefright/httplive/Android.mk b/media/libstagefright/httplive/Android.mk
index f382e2e..9c1994a 100644
--- a/media/libstagefright/httplive/Android.mk
+++ b/media/libstagefright/httplive/Android.mk
@@ -13,6 +13,8 @@
 	$(TOP)/frameworks/native/include/media/openmax \
 	$(TOP)/external/openssl/include
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_SHARED_LIBRARIES := \
         libbinder \
         libcrypto \
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 90ee3b0..19db6eb 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -27,6 +27,8 @@
 #include "mpeg2ts/AnotherPacketSource.h"
 
 #include <cutils/properties.h>
+#include <media/IMediaHTTPConnection.h>
+#include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -34,6 +36,7 @@
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaHTTP.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
@@ -46,17 +49,13 @@
 namespace android {
 
 LiveSession::LiveSession(
-        const sp<AMessage> &notify, uint32_t flags, bool uidValid, uid_t uid)
+        const sp<AMessage> &notify, uint32_t flags,
+        const sp<IMediaHTTPService> &httpService)
     : mNotify(notify),
       mFlags(flags),
-      mUIDValid(uidValid),
-      mUID(uid),
+      mHTTPService(httpService),
       mInPreparationPhase(true),
-      mHTTPDataSource(
-              HTTPBase::Create(
-                  (mFlags & kFlagIncognito)
-                    ? HTTPBase::kFlagIncognito
-                    : 0)),
+      mHTTPDataSource(new MediaHTTP(mHTTPService->makeHTTPConnection())),
       mPrevBandwidthIndex(-1),
       mStreamMask(0),
       mNewStreamMask(0),
@@ -69,9 +68,6 @@
       mSwitchInProgress(false),
       mDisconnectReplyID(0),
       mSeekReplyID(0) {
-    if (mUIDValid) {
-        mHTTPDataSource->setUID(mUID);
-    }
 
     mStreams[kAudioIndex] = StreamItem("audio");
     mStreams[kVideoIndex] = StreamItem("video");
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index 680792d..f489ec4 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -28,6 +28,7 @@
 struct AnotherPacketSource;
 struct DataSource;
 struct HTTPBase;
+struct IMediaHTTPService;
 struct LiveDataSource;
 struct M3UParser;
 struct PlaylistFetcher;
@@ -40,7 +41,8 @@
     };
     LiveSession(
             const sp<AMessage> &notify,
-            uint32_t flags = 0, bool uidValid = false, uid_t uid = 0);
+            uint32_t flags,
+            const sp<IMediaHTTPService> &httpService);
 
     enum StreamIndex {
         kAudioIndex    = 0,
@@ -134,8 +136,7 @@
 
     sp<AMessage> mNotify;
     uint32_t mFlags;
-    bool mUIDValid;
-    uid_t mUID;
+    sp<IMediaHTTPService> mHTTPService;
 
     bool mInPreparationPhase;
 
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 7b06a2f..dacdd40 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -126,7 +126,7 @@
                 mSelectedIndex = strtoul(value, &end, 10);
                 CHECK(end > value && *end == '\0');
 
-                if (mSelectedIndex >= mMediaItems.size()) {
+                if (mSelectedIndex >= (ssize_t)mMediaItems.size()) {
                     mSelectedIndex = mMediaItems.size() - 1;
                 }
             } else {
@@ -166,14 +166,14 @@
             ALOGE("track %d does not exist", index);
             return INVALID_OPERATION;
         }
-        if (mSelectedIndex == index) {
+        if (mSelectedIndex == (ssize_t)index) {
             ALOGE("track %d already selected", index);
             return BAD_VALUE;
         }
         ALOGV("selected track %d", index);
         mSelectedIndex = index;
     } else {
-        if (mSelectedIndex != index) {
+        if (mSelectedIndex != (ssize_t)index) {
             ALOGE("track %d is not selected", index);
             return BAD_VALUE;
         }
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 012a68b..9d7cb99 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -732,7 +732,7 @@
 
         if (mPlaylist->isComplete() || mPlaylist->isEvent()) {
             mSeqNumber = getSeqNumberForTime(mStartTimeUs);
-            ALOGV("Initial sequence number for time %lld is %ld from (%ld .. %ld)",
+            ALOGV("Initial sequence number for time %lld is %d from (%d .. %d)",
                     mStartTimeUs, mSeqNumber, firstSeqNumberInPlaylist,
                     lastSeqNumberInPlaylist);
         } else {
@@ -741,7 +741,7 @@
             if (mSeqNumber < firstSeqNumberInPlaylist) {
                 mSeqNumber = firstSeqNumberInPlaylist;
             }
-            ALOGV("Initial sequence number for live event %ld from (%ld .. %ld)",
+            ALOGV("Initial sequence number for live event %d from (%d .. %d)",
                     mSeqNumber, firstSeqNumberInPlaylist,
                     lastSeqNumberInPlaylist);
         }
@@ -765,7 +765,8 @@
                 if (delayUs > kMaxMonitorDelayUs) {
                     delayUs = kMaxMonitorDelayUs;
                 }
-                ALOGV("sequence number high: %ld from (%ld .. %ld), monitor in %lld (retry=%d)",
+                ALOGV("sequence number high: %d from (%d .. %d), "
+                      "monitor in %lld (retry=%d)",
                         mSeqNumber, firstSeqNumberInPlaylist,
                         lastSeqNumberInPlaylist, delayUs, mNumRetries);
                 postMonitorQueue(delayUs);
@@ -1232,6 +1233,18 @@
             | (adtsHeader[4] << 3)
             | (adtsHeader[5] >> 5);
 
+        if (aac_frame_length == 0) {
+            const uint8_t *id3Header = adtsHeader;
+            if (!memcmp(id3Header, "ID3", 3)) {
+                ID3 id3(id3Header, buffer->size() - offset, true);
+                if (id3.isValid()) {
+                    offset += id3.rawSize();
+                    continue;
+                };
+            }
+            return ERROR_MALFORMED;
+        }
+
         CHECK_LE(offset + aac_frame_length, buffer->size());
 
         sp<ABuffer> unit = new ABuffer(aac_frame_length);
diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk
index 5a18cab..bbe807e 100644
--- a/media/libstagefright/id3/Android.mk
+++ b/media/libstagefright/id3/Android.mk
@@ -4,6 +4,8 @@
 LOCAL_SRC_FILES := \
 	ID3.cpp
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE := libstagefright_id3
 
 include $(BUILD_STATIC_LIBRARY)
@@ -15,6 +17,8 @@
 LOCAL_SRC_FILES := \
 	testid3.cpp
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright libutils liblog libbinder libstagefright_foundation
 
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 1ec4a40..f0f203c 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -468,49 +468,6 @@
     }
 }
 
-static void convertISO8859ToString8(
-        const uint8_t *data, size_t size,
-        String8 *s) {
-    size_t utf8len = 0;
-    for (size_t i = 0; i < size; ++i) {
-        if (data[i] == '\0') {
-            size = i;
-            break;
-        } else if (data[i] < 0x80) {
-            ++utf8len;
-        } else {
-            utf8len += 2;
-        }
-    }
-
-    if (utf8len == size) {
-        // Only ASCII characters present.
-
-        s->setTo((const char *)data, size);
-        return;
-    }
-
-    char *tmp = new char[utf8len];
-    char *ptr = tmp;
-    for (size_t i = 0; i < size; ++i) {
-        if (data[i] == '\0') {
-            break;
-        } else if (data[i] < 0x80) {
-            *ptr++ = data[i];
-        } else if (data[i] < 0xc0) {
-            *ptr++ = 0xc2;
-            *ptr++ = data[i];
-        } else {
-            *ptr++ = 0xc3;
-            *ptr++ = data[i] - 64;
-        }
-    }
-
-    s->setTo(tmp, utf8len);
-
-    delete[] tmp;
-    tmp = NULL;
-}
 
 // the 2nd argument is used to get the data following the \0 in a comment field
 void ID3::Iterator::getString(String8 *id, String8 *comment) const {
@@ -543,7 +500,9 @@
             return;
         }
 
-        convertISO8859ToString8(frameData, mFrameSize, id);
+        // this is supposed to be ISO-8859-1, but pass it up as-is to the caller, who will figure
+        // out the real encoding
+        id->setTo((const char*)frameData, mFrameSize);
         return;
     }
 
@@ -561,13 +520,13 @@
     }
 
     if (encoding == 0x00) {
-        // ISO 8859-1
-        convertISO8859ToString8(frameData + 1, n, id);
+        // supposedly ISO 8859-1
+        id->setTo((const char*)frameData + 1, n);
     } else if (encoding == 0x03) {
-        // UTF-8
+        // supposedly UTF-8
         id->setTo((const char *)(frameData + 1), n);
     } else if (encoding == 0x02) {
-        // UTF-16 BE, no byte order mark.
+        // supposedly UTF-16 BE, no byte order mark.
         // API wants number of characters, not number of bytes...
         int len = n / 2;
         const char16_t *framedata = (const char16_t *) (frameData + 1);
@@ -583,7 +542,7 @@
         if (framedatacopy != NULL) {
             delete[] framedatacopy;
         }
-    } else {
+    } else if (encoding == 0x01) {
         // UCS-2
         // API wants number of characters, not number of bytes...
         int len = n / 2;
@@ -602,7 +561,27 @@
             framedata++;
             len--;
         }
-        id->setTo(framedata, len);
+
+        // check if the resulting data consists entirely of 8-bit values
+        bool eightBit = true;
+        for (int i = 0; i < len; i++) {
+            if (framedata[i] > 0xff) {
+                eightBit = false;
+                break;
+            }
+        }
+        if (eightBit) {
+            // collapse to 8 bit, then let the media scanner client figure out the real encoding
+            char *frame8 = new char[len];
+            for (int i = 0; i < len; i++) {
+                frame8[i] = framedata[i];
+            }
+            id->setTo(frame8, len);
+            delete [] frame8;
+        } else {
+            id->setTo(framedata, len);
+        }
+
         if (framedatacopy != NULL) {
             delete[] framedatacopy;
         }
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 271df8e..a81bbba 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -63,6 +63,7 @@
     void setUID(uid_t uid);
 
     status_t setDataSource(
+            const sp<IMediaHTTPService> &httpService,
             const char *uri,
             const KeyedVector<String8, String8> *headers = NULL);
 
@@ -159,6 +160,7 @@
     SystemTimeSource mSystemTimeSource;
     TimeSource *mTimeSource;
 
+    sp<IMediaHTTPService> mHTTPService;
     String8 mUri;
     KeyedVector<String8, String8> mUriHeaders;
 
@@ -247,6 +249,7 @@
     sp<MediaExtractor> mExtractor;
 
     status_t setDataSource_l(
+            const sp<IMediaHTTPService> &httpService,
             const char *uri,
             const KeyedVector<String8, String8> *headers = NULL);
 
diff --git a/media/libstagefright/include/ChromiumHTTPDataSource.h b/media/libstagefright/include/ChromiumHTTPDataSource.h
deleted file mode 100644
index da188dd..0000000
--- a/media/libstagefright/include/ChromiumHTTPDataSource.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * 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 CHROME_HTTP_DATA_SOURCE_H_
-
-#define CHROME_HTTP_DATA_SOURCE_H_
-
-#include <media/stagefright/foundation/AString.h>
-#include <utils/threads.h>
-
-#include "HTTPBase.h"
-
-namespace android {
-
-struct SfDelegate;
-
-struct ChromiumHTTPDataSource : public HTTPBase {
-    ChromiumHTTPDataSource(uint32_t flags = 0);
-
-    virtual status_t connect(
-            const char *uri,
-            const KeyedVector<String8, String8> *headers = NULL,
-            off64_t offset = 0);
-
-    virtual void disconnect();
-
-    virtual status_t initCheck() const;
-
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
-    virtual status_t getSize(off64_t *size);
-    virtual uint32_t flags();
-
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime);
-
-    virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
-
-    virtual String8 getUri();
-
-    virtual String8 getMIMEType() const;
-
-    virtual status_t reconnectAtOffset(off64_t offset);
-
-    static status_t UpdateProxyConfig(
-            const char *host, int32_t port, const char *exclusionList);
-
-protected:
-    virtual ~ChromiumHTTPDataSource();
-
-private:
-    friend struct SfDelegate;
-
-    enum State {
-        DISCONNECTED,
-        CONNECTING,
-        CONNECTED,
-        READING,
-        DISCONNECTING
-    };
-
-    const uint32_t mFlags;
-
-    mutable Mutex mLock;
-    Condition mCondition;
-
-    State mState;
-
-    SfDelegate *mDelegate;
-
-    AString mURI;
-    KeyedVector<String8, String8> mHeaders;
-
-    off64_t mCurrentOffset;
-
-    // Any connection error or the result of a read operation
-    // (for the lattter this is the number of bytes read, if successful).
-    ssize_t mIOResult;
-
-    int64_t mContentSize;
-
-    String8 mContentType;
-
-    sp<DecryptHandle> mDecryptHandle;
-    DrmManagerClient *mDrmManagerClient;
-
-    void disconnect_l();
-
-    status_t connect_l(
-            const char *uri,
-            const KeyedVector<String8, String8> *headers,
-            off64_t offset);
-
-    static void InitiateRead(
-            ChromiumHTTPDataSource *me, void *data, size_t size);
-
-    void initiateRead(void *data, size_t size);
-
-    void onConnectionEstablished(
-            int64_t contentSize, const char *contentType);
-
-    void onConnectionFailed(status_t err);
-    void onReadCompleted(ssize_t size);
-    void onDisconnectComplete();
-    void onRedirect(const char *url);
-
-    void clearDRMState_l();
-
-    DISALLOW_EVIL_CONSTRUCTORS(ChromiumHTTPDataSource);
-};
-
-}  // namespace android
-
-#endif  // CHROME_HTTP_DATA_SOURCE_H_
diff --git a/media/libstagefright/include/FragmentedMP4Parser.h b/media/libstagefright/include/FragmentedMP4Parser.h
deleted file mode 100644
index dbe02b8..0000000
--- a/media/libstagefright/include/FragmentedMP4Parser.h
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef PARSER_H_
-
-#define PARSER_H_
-
-#include <media/stagefright/foundation/AHandler.h>
-#include <media/stagefright/DataSource.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-struct ABuffer;
-
-struct FragmentedMP4Parser : public AHandler {
-    struct Source : public RefBase {
-        Source() {}
-
-        virtual ssize_t readAt(off64_t offset, void *data, size_t size) = 0;
-        virtual bool isSeekable() = 0;
-
-        protected:
-        virtual ~Source() {}
-
-        private:
-        DISALLOW_EVIL_CONSTRUCTORS(Source);
-    };
-
-    FragmentedMP4Parser();
-
-    void start(const char *filename);
-    void start(const sp<Source> &source);
-    void start(sp<DataSource> &source);
-
-    sp<AMessage> getFormat(bool audio, bool synchronous = false);
-    status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit, bool synchronous = false);
-    status_t seekTo(bool audio, int64_t timeUs);
-    bool isSeekable() const;
-
-    virtual void onMessageReceived(const sp<AMessage> &msg);
-
-protected:
-    virtual ~FragmentedMP4Parser();
-
-private:
-    enum {
-        kWhatStart,
-        kWhatProceed,
-        kWhatReadMore,
-        kWhatGetFormat,
-        kWhatDequeueAccessUnit,
-        kWhatSeekTo,
-    };
-
-    struct TrackFragment;
-    struct DynamicTrackFragment;
-    struct StaticTrackFragment;
-
-    struct DispatchEntry {
-        uint32_t mType;
-        uint32_t mParentType;
-        status_t (FragmentedMP4Parser::*mHandler)(uint32_t, size_t, uint64_t);
-    };
-
-    struct Container {
-        uint64_t mOffset;
-        uint64_t mBytesRemaining;
-        uint32_t mType;
-        bool mExtendsToEOF;
-    };
-
-    struct SampleDescription {
-        uint32_t mType;
-        uint16_t mDataRefIndex;
-
-        sp<AMessage> mFormat;
-    };
-
-    struct SampleInfo {
-        off64_t mOffset;
-        size_t mSize;
-        uint32_t mPresentationTime;
-        size_t mSampleDescIndex;
-        uint32_t mFlags;
-    };
-
-    struct MediaDataInfo {
-        sp<ABuffer> mBuffer;
-        off64_t mOffset;
-    };
-
-    struct SidxEntry {
-        size_t mSize;
-        uint32_t mDurationUs;
-    };
-
-    struct TrackInfo {
-        enum Flags {
-            kTrackEnabled     = 0x01,
-            kTrackInMovie     = 0x02,
-            kTrackInPreview   = 0x04,
-        };
-
-        uint32_t mTrackID;
-        uint32_t mFlags;
-        uint32_t mDuration;  // This is the duration in terms of movie timescale!
-        uint64_t mSidxDuration; // usec, from sidx box, which can use a different timescale
-
-        uint32_t mMediaTimeScale;
-
-        uint32_t mMediaHandlerType;
-        Vector<SampleDescription> mSampleDescs;
-
-        // from track extends:
-        uint32_t mDefaultSampleDescriptionIndex;
-        uint32_t mDefaultSampleDuration;
-        uint32_t mDefaultSampleSize;
-        uint32_t mDefaultSampleFlags;
-
-        uint32_t mDecodingTime;
-
-        Vector<SidxEntry> mSidx;
-        sp<StaticTrackFragment> mStaticFragment;
-        List<sp<TrackFragment> > mFragments;
-    };
-
-    struct TrackFragmentHeaderInfo {
-        enum Flags {
-            kBaseDataOffsetPresent         = 0x01,
-            kSampleDescriptionIndexPresent = 0x02,
-            kDefaultSampleDurationPresent  = 0x08,
-            kDefaultSampleSizePresent      = 0x10,
-            kDefaultSampleFlagsPresent     = 0x20,
-            kDurationIsEmpty               = 0x10000,
-        };
-
-        uint32_t mTrackID;
-        uint32_t mFlags;
-        uint64_t mBaseDataOffset;
-        uint32_t mSampleDescriptionIndex;
-        uint32_t mDefaultSampleDuration;
-        uint32_t mDefaultSampleSize;
-        uint32_t mDefaultSampleFlags;
-
-        uint64_t mDataOffset;
-    };
-
-    static const DispatchEntry kDispatchTable[];
-
-    sp<Source> mSource;
-    off_t mBufferPos;
-    bool mSuspended;
-    bool mDoneWithMoov;
-    off_t mFirstMoofOffset; // used as the starting point for offsets calculated from the sidx box
-    sp<ABuffer> mBuffer;
-    Vector<Container> mStack;
-    KeyedVector<uint32_t, TrackInfo> mTracks;  // TrackInfo by trackID
-    Vector<MediaDataInfo> mMediaData;
-
-    uint32_t mCurrentTrackID;
-
-    status_t mFinalResult;
-
-    TrackFragmentHeaderInfo mTrackFragmentHeaderInfo;
-
-    status_t onProceed();
-    status_t onDequeueAccessUnit(size_t trackIndex, sp<ABuffer> *accessUnit);
-    status_t onSeekTo(bool wantAudio, int64_t position);
-
-    void enter(off64_t offset, uint32_t type, uint64_t size);
-
-    uint16_t readU16(size_t offset);
-    uint32_t readU32(size_t offset);
-    uint64_t readU64(size_t offset);
-    void skip(off_t distance);
-    status_t need(size_t size);
-    bool fitsContainer(uint64_t size) const;
-
-    status_t parseTrackHeader(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseMediaHeader(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseMediaHandler(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseTrackExtends(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseTrackFragmentHeader(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseTrackFragmentRun(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseVisualSampleEntry(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseAudioSampleEntry(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseSampleSizes(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseCompactSampleSizes(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseSampleToChunk(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseChunkOffsets(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseChunkOffsets64(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseAVCCodecSpecificData(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseESDSCodecSpecificData(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseMediaData(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseSegmentIndex(
-            uint32_t type, size_t offset, uint64_t size);
-
-    TrackInfo *editTrack(uint32_t trackID, bool createIfNecessary = false);
-
-    ssize_t findTrack(bool wantAudio) const;
-
-    status_t makeAccessUnit(
-            TrackInfo *info,
-            const SampleInfo &sample,
-            const MediaDataInfo &mdatInfo,
-            sp<ABuffer> *accessUnit);
-
-    status_t getSample(
-            TrackInfo *info,
-            sp<TrackFragment> *fragment,
-            SampleInfo *sampleInfo);
-
-    static int CompareSampleLocation(
-        const SampleInfo &sample, const MediaDataInfo &mdatInfo);
-
-    void resumeIfNecessary();
-
-    void copyBuffer(
-            sp<ABuffer> *dst,
-            size_t offset, uint64_t size) const;
-
-    DISALLOW_EVIL_CONSTRUCTORS(FragmentedMP4Parser);
-};
-
-}  // namespace android
-
-#endif  // PARSER_H_
-
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
index d4b7f9f..1c3cd5e 100644
--- a/media/libstagefright/include/HTTPBase.h
+++ b/media/libstagefright/include/HTTPBase.h
@@ -48,14 +48,6 @@
 
     virtual status_t setBandwidthStatCollectFreq(int32_t freqMs);
 
-    static status_t UpdateProxyConfig(
-            const char *host, int32_t port, const char *exclusionList);
-
-    void setUID(uid_t uid);
-    bool getUID(uid_t *uid) const;
-
-    static sp<HTTPBase> Create(uint32_t flags = 0);
-
     static void RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag);
     static void UnRegisterSocketUserTag(int sockfd);
 
@@ -87,9 +79,6 @@
     int32_t mPrevEstimatedBandWidthKbps;
     int32_t mBandWidthCollectFreqMs;
 
-    bool mUIDValid;
-    uid_t mUID;
-
     DISALLOW_EVIL_CONSTRUCTORS(HTTPBase);
 };
 
diff --git a/media/libstagefright/include/SDPLoader.h b/media/libstagefright/include/SDPLoader.h
index ca59dc0..2c4f543 100644
--- a/media/libstagefright/include/SDPLoader.h
+++ b/media/libstagefright/include/SDPLoader.h
@@ -25,6 +25,7 @@
 namespace android {
 
 struct HTTPBase;
+struct IMediaHTTPService;
 
 struct SDPLoader : public AHandler {
     enum Flags {
@@ -34,7 +35,10 @@
     enum {
         kWhatSDPLoaded = 'sdpl'
     };
-    SDPLoader(const sp<AMessage> &notify, uint32_t flags = 0, bool uidValid = false, uid_t uid = 0);
+    SDPLoader(
+            const sp<AMessage> &notify,
+            uint32_t flags,
+            const sp<IMediaHTTPService> &httpService);
 
     void load(const char* url, const KeyedVector<String8, String8> *headers);
 
@@ -55,8 +59,6 @@
     sp<AMessage> mNotify;
     const char* mUrl;
     uint32_t mFlags;
-    bool mUIDValid;
-    uid_t mUID;
     sp<ALooper> mNetLooper;
     bool mCancelled;
 
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index b02ed0e..6632c27 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -33,6 +33,7 @@
     virtual ~StagefrightMetadataRetriever();
 
     virtual status_t setDataSource(
+            const sp<IMediaHTTPService> &httpService,
             const char *url,
             const KeyedVector<String8, String8> *headers);
 
diff --git a/media/libstagefright/include/TimedEventQueue.h b/media/libstagefright/include/TimedEventQueue.h
index 3e84256..2963150 100644
--- a/media/libstagefright/include/TimedEventQueue.h
+++ b/media/libstagefright/include/TimedEventQueue.h
@@ -122,7 +122,7 @@
     };
 
     struct StopEvent : public TimedEventQueue::Event {
-        virtual void fire(TimedEventQueue *queue, int64_t now_us) {
+        virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
             queue->mStopped = true;
         }
     };
diff --git a/media/libstagefright/include/chromium_http_stub.h b/media/libstagefright/include/chromium_http_stub.h
deleted file mode 100644
index e0651a4..0000000
--- a/media/libstagefright/include/chromium_http_stub.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CHROMIUM_HTTP_STUB_H_
-#define CHROMIUM_HTTP_STUB_H_
-
-#include <include/HTTPBase.h>
-#include <media/stagefright/DataSource.h>
-
-namespace android {
-extern "C" {
-HTTPBase *createChromiumHTTPDataSource(uint32_t flags);
-
-status_t UpdateChromiumHTTPDataSourceProxyConfig(
-        const char *host, int32_t port, const char *exclusionList);
-
-DataSource *createDataUriSource(const char *uri);
-}
-}
-
-#endif
diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk
index 2d8c1e1..446ff8c 100644
--- a/media/libstagefright/matroska/Android.mk
+++ b/media/libstagefright/matroska/Android.mk
@@ -8,7 +8,7 @@
         $(TOP)/external/libvpx/libwebm \
         $(TOP)/frameworks/native/include/media/openmax \
 
-LOCAL_CFLAGS += -Wno-multichar
+LOCAL_CFLAGS += -Wno-multichar -Werror
 
 LOCAL_MODULE:= libstagefright_matroska
 
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index dcb1cda..6ec9263 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -193,7 +193,7 @@
     clearPendingFrames();
 }
 
-status_t MatroskaSource::start(MetaData *params) {
+status_t MatroskaSource::start(MetaData * /* params */) {
     mBlockIter.reset();
 
     return OK;
@@ -313,7 +313,7 @@
 
     *actualFrameTimeUs = -1ll;
 
-    const int64_t seekTimeNs = seekTimeUs * 1000ll;
+    const int64_t seekTimeNs = seekTimeUs * 1000ll - mExtractor->mSeekPreRollNs;
 
     mkvparser::Segment* const pSegment = mExtractor->mSegment;
 
@@ -410,7 +410,7 @@
             // Accept the first key frame
             *actualFrameTimeUs = (block()->GetTime(mCluster) + 500LL) / 1000LL;
             ALOGV("Requested seek point: %lld actual: %lld",
-                  seekTimeUs, actualFrameTimeUs);
+                  seekTimeUs, *actualFrameTimeUs);
             break;
         }
     }
@@ -628,7 +628,8 @@
       mReader(new DataSourceReader(mDataSource)),
       mSegment(NULL),
       mExtractedThumbnails(false),
-      mIsWebm(false) {
+      mIsWebm(false),
+      mSeekPreRollNs(0) {
     off64_t size;
     mIsLiveStreaming =
         (mDataSource->flags()
@@ -919,6 +920,12 @@
 
                     err = addVorbisCodecInfo(
                             meta, codecPrivate, codecPrivateSize);
+                } else if (!strcmp("A_OPUS", codecID)) {
+                    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_OPUS);
+                    meta->setData(kKeyOpusHeader, 0, codecPrivate, codecPrivateSize);
+                    meta->setInt64(kKeyOpusCodecDelay, track->GetCodecDelay());
+                    meta->setInt64(kKeyOpusSeekPreRoll, track->GetSeekPreRoll());
+                    mSeekPreRollNs = track->GetSeekPreRoll();
                 } else if (!strcmp("A_MPEG/L3", codecID)) {
                     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
                 } else {
diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h
index 1294b4f..cf200f3 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.h
+++ b/media/libstagefright/matroska/MatroskaExtractor.h
@@ -69,6 +69,7 @@
     bool mExtractedThumbnails;
     bool mIsLiveStreaming;
     bool mIsWebm;
+    int64_t mSeekPreRollNs;
 
     void addTracks();
     void findThumbnails();
diff --git a/media/libstagefright/mp4/FragmentedMP4Parser.cpp b/media/libstagefright/mp4/FragmentedMP4Parser.cpp
deleted file mode 100644
index 0102656..0000000
--- a/media/libstagefright/mp4/FragmentedMP4Parser.cpp
+++ /dev/null
@@ -1,1993 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "FragmentedMP4Parser"
-#include <utils/Log.h>
-
-#include "include/avc_utils.h"
-#include "include/ESDS.h"
-#include "include/FragmentedMP4Parser.h"
-#include "TrackFragment.h"
-
-
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/Utils.h>
-
-
-namespace android {
-
-static const char *Fourcc2String(uint32_t fourcc) {
-    static char buffer[5];
-    buffer[4] = '\0';
-    buffer[0] = fourcc >> 24;
-    buffer[1] = (fourcc >> 16) & 0xff;
-    buffer[2] = (fourcc >> 8) & 0xff;
-    buffer[3] = fourcc & 0xff;
-
-    return buffer;
-}
-
-static const char *IndentString(size_t n) {
-    static const char kSpace[] = "                              ";
-    return kSpace + sizeof(kSpace) - 2 * n - 1;
-}
-
-// static
-const FragmentedMP4Parser::DispatchEntry FragmentedMP4Parser::kDispatchTable[] = {
-    { FOURCC('m', 'o', 'o', 'v'), 0, NULL },
-    { FOURCC('t', 'r', 'a', 'k'), FOURCC('m', 'o', 'o', 'v'), NULL },
-    { FOURCC('u', 'd', 't', 'a'), FOURCC('t', 'r', 'a', 'k'), NULL },
-    { FOURCC('u', 'd', 't', 'a'), FOURCC('m', 'o', 'o', 'v'), NULL },
-    { FOURCC('m', 'e', 't', 'a'), FOURCC('u', 'd', 't', 'a'), NULL },
-    { FOURCC('i', 'l', 's', 't'), FOURCC('m', 'e', 't', 'a'), NULL },
-
-    { FOURCC('t', 'k', 'h', 'd'), FOURCC('t', 'r', 'a', 'k'),
-        &FragmentedMP4Parser::parseTrackHeader
-    },
-
-    { FOURCC('m', 'v', 'e', 'x'), FOURCC('m', 'o', 'o', 'v'), NULL },
-
-    { FOURCC('t', 'r', 'e', 'x'), FOURCC('m', 'v', 'e', 'x'),
-        &FragmentedMP4Parser::parseTrackExtends
-    },
-
-    { FOURCC('e', 'd', 't', 's'), FOURCC('t', 'r', 'a', 'k'), NULL },
-    { FOURCC('m', 'd', 'i', 'a'), FOURCC('t', 'r', 'a', 'k'), NULL },
-
-    { FOURCC('m', 'd', 'h', 'd'), FOURCC('m', 'd', 'i', 'a'),
-        &FragmentedMP4Parser::parseMediaHeader
-    },
-
-    { FOURCC('h', 'd', 'l', 'r'), FOURCC('m', 'd', 'i', 'a'),
-        &FragmentedMP4Parser::parseMediaHandler
-    },
-
-    { FOURCC('m', 'i', 'n', 'f'), FOURCC('m', 'd', 'i', 'a'), NULL },
-    { FOURCC('d', 'i', 'n', 'f'), FOURCC('m', 'i', 'n', 'f'), NULL },
-    { FOURCC('s', 't', 'b', 'l'), FOURCC('m', 'i', 'n', 'f'), NULL },
-    { FOURCC('s', 't', 's', 'd'), FOURCC('s', 't', 'b', 'l'), NULL },
-
-    { FOURCC('s', 't', 's', 'z'), FOURCC('s', 't', 'b', 'l'),
-        &FragmentedMP4Parser::parseSampleSizes },
-
-    { FOURCC('s', 't', 'z', '2'), FOURCC('s', 't', 'b', 'l'),
-        &FragmentedMP4Parser::parseCompactSampleSizes },
-
-    { FOURCC('s', 't', 's', 'c'), FOURCC('s', 't', 'b', 'l'),
-        &FragmentedMP4Parser::parseSampleToChunk },
-
-    { FOURCC('s', 't', 'c', 'o'), FOURCC('s', 't', 'b', 'l'),
-        &FragmentedMP4Parser::parseChunkOffsets },
-
-    { FOURCC('c', 'o', '6', '4'), FOURCC('s', 't', 'b', 'l'),
-        &FragmentedMP4Parser::parseChunkOffsets64 },
-
-    { FOURCC('a', 'v', 'c', 'C'), FOURCC('a', 'v', 'c', '1'),
-        &FragmentedMP4Parser::parseAVCCodecSpecificData },
-
-    { FOURCC('e', 's', 'd', 's'), FOURCC('m', 'p', '4', 'a'),
-        &FragmentedMP4Parser::parseESDSCodecSpecificData },
-
-    { FOURCC('e', 's', 'd', 's'), FOURCC('m', 'p', '4', 'v'),
-        &FragmentedMP4Parser::parseESDSCodecSpecificData },
-
-    { FOURCC('m', 'd', 'a', 't'), 0, &FragmentedMP4Parser::parseMediaData },
-
-    { FOURCC('m', 'o', 'o', 'f'), 0, NULL },
-    { FOURCC('t', 'r', 'a', 'f'), FOURCC('m', 'o', 'o', 'f'), NULL },
-
-    { FOURCC('t', 'f', 'h', 'd'), FOURCC('t', 'r', 'a', 'f'),
-        &FragmentedMP4Parser::parseTrackFragmentHeader
-    },
-    { FOURCC('t', 'r', 'u', 'n'), FOURCC('t', 'r', 'a', 'f'),
-        &FragmentedMP4Parser::parseTrackFragmentRun
-    },
-
-    { FOURCC('m', 'f', 'r', 'a'), 0, NULL },
-
-    { FOURCC('s', 'i', 'd', 'x'), 0, &FragmentedMP4Parser::parseSegmentIndex },
-};
-
-struct FileSource : public FragmentedMP4Parser::Source {
-    FileSource(const char *filename)
-        : mFile(fopen(filename, "rb")) {
-            CHECK(mFile != NULL);
-        }
-
-    virtual ~FileSource() {
-        fclose(mFile);
-    }
-
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
-        fseek(mFile, offset, SEEK_SET);
-        return fread(data, 1, size, mFile);
-    }
-
-    virtual bool isSeekable() {
-        return true;
-    }
-
-    private:
-    FILE *mFile;
-
-    DISALLOW_EVIL_CONSTRUCTORS(FileSource);
-};
-
-struct ReadTracker : public RefBase {
-    ReadTracker(off64_t size) {
-        allocSize = 1 + size / 8192; // 1 bit per kilobyte
-        bitmap = (char*) calloc(1, allocSize);
-    }
-    virtual ~ReadTracker() {
-        dumpToLog();
-        free(bitmap);
-    }
-    void mark(off64_t offset, size_t size) {
-        int firstbit = offset / 1024;
-        int lastbit = (offset + size - 1) / 1024;
-        for (int i = firstbit; i <= lastbit; i++) {
-            bitmap[i/8] |= (0x80 >> (i & 7));
-        }
-    }
-
- private:
-    void dumpToLog() {
-        // 96 chars per line, each char represents one kilobyte, 1 kb per bit
-        int numlines = allocSize / 12;
-        char buf[97];
-        char *cur = bitmap;
-        for (int i = 0; i < numlines; i++ && cur) {
-            for (int j = 0; j < 12; j++) {
-                for (int k = 0; k < 8; k++) {
-                    buf[(j * 8) + k] = (*cur & (0x80 >> k)) ? 'X' : '.';
-                }
-                cur++;
-            }
-            buf[96] = '\0';
-            ALOGI("%5dk: %s", i * 96, buf);
-        }
-    }
-
-    size_t allocSize;
-    char *bitmap;
-};
-
-struct DataSourceSource : public FragmentedMP4Parser::Source {
-    DataSourceSource(sp<DataSource> &source)
-        : mDataSource(source) {
-            CHECK(mDataSource != NULL);
-#if 0
-            off64_t size;
-            if (source->getSize(&size) == OK) {
-                mReadTracker = new ReadTracker(size);
-            } else {
-                ALOGE("couldn't get data source size");
-            }
-#endif
-        }
-
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
-        if (mReadTracker != NULL) {
-            mReadTracker->mark(offset, size);
-        }
-        return mDataSource->readAt(offset, data, size);
-    }
-
-    virtual bool isSeekable() {
-        return true;
-    }
-
-    private:
-    sp<DataSource> mDataSource;
-    sp<ReadTracker> mReadTracker;
-
-    DISALLOW_EVIL_CONSTRUCTORS(DataSourceSource);
-};
-
-FragmentedMP4Parser::FragmentedMP4Parser()
-    : mBufferPos(0),
-      mSuspended(false),
-      mDoneWithMoov(false),
-      mFirstMoofOffset(0),
-      mFinalResult(OK) {
-}
-
-FragmentedMP4Parser::~FragmentedMP4Parser() {
-}
-
-void FragmentedMP4Parser::start(const char *filename) {
-    sp<AMessage> msg = new AMessage(kWhatStart, id());
-    msg->setObject("source", new FileSource(filename));
-    msg->post();
-    ALOGV("Parser::start(%s)", filename);
-}
-
-void FragmentedMP4Parser::start(const sp<Source> &source) {
-    sp<AMessage> msg = new AMessage(kWhatStart, id());
-    msg->setObject("source", source);
-    msg->post();
-    ALOGV("Parser::start(Source)");
-}
-
-void FragmentedMP4Parser::start(sp<DataSource> &source) {
-    sp<AMessage> msg = new AMessage(kWhatStart, id());
-    msg->setObject("source", new DataSourceSource(source));
-    msg->post();
-    ALOGV("Parser::start(DataSource)");
-}
-
-sp<AMessage> FragmentedMP4Parser::getFormat(bool audio, bool synchronous) {
-
-    while (true) {
-        bool moovDone = mDoneWithMoov;
-        sp<AMessage> msg = new AMessage(kWhatGetFormat, id());
-        msg->setInt32("audio", audio);
-
-        sp<AMessage> response;
-        status_t err = msg->postAndAwaitResponse(&response);
-
-        if (err != OK) {
-            ALOGV("getFormat post failed: %d", err);
-            return NULL;
-        }
-
-        if (response->findInt32("err", &err) && err != OK) {
-            if (synchronous && err == -EWOULDBLOCK && !moovDone) {
-                resumeIfNecessary();
-                ALOGV("@getFormat parser not ready yet, retrying");
-                usleep(10000);
-                continue;
-            }
-            ALOGV("getFormat failed: %d", err);
-            return NULL;
-        }
-
-        sp<AMessage> format;
-        CHECK(response->findMessage("format", &format));
-
-        ALOGV("returning format %s", format->debugString().c_str());
-        return format;
-    }
-}
-
-status_t FragmentedMP4Parser::seekTo(bool wantAudio, int64_t timeUs) {
-    sp<AMessage> msg = new AMessage(kWhatSeekTo, id());
-    msg->setInt32("audio", wantAudio);
-    msg->setInt64("position", timeUs);
-
-    sp<AMessage> response;
-    status_t err = msg->postAndAwaitResponse(&response);
-    return err;
-}
-
-bool FragmentedMP4Parser::isSeekable() const {
-    while (mFirstMoofOffset == 0 && mFinalResult == OK) {
-        usleep(10000);
-    }
-    bool seekable = mSource->isSeekable();
-    for (size_t i = 0; seekable && i < mTracks.size(); i++) {
-        const TrackInfo *info = &mTracks.valueAt(i);
-        seekable &= !info->mSidx.empty();
-    }
-    return seekable;
-}
-
-status_t FragmentedMP4Parser::onSeekTo(bool wantAudio, int64_t position) {
-    status_t err = -EINVAL;
-    ssize_t trackIndex = findTrack(wantAudio);
-    if (trackIndex < 0) {
-        err = trackIndex;
-    } else {
-        TrackInfo *info = &mTracks.editValueAt(trackIndex);
-
-        int numSidxEntries = info->mSidx.size();
-        int64_t totalTime = 0;
-        off_t totalOffset = mFirstMoofOffset;
-        for (int i = 0; i < numSidxEntries; i++) {
-            const SidxEntry *se = &info->mSidx[i];
-            if (totalTime + se->mDurationUs > position) {
-                mBuffer->setRange(0,0);
-                mBufferPos = totalOffset;
-                if (mFinalResult == ERROR_END_OF_STREAM) {
-                    mFinalResult = OK;
-                    mSuspended = true; // force resume
-                    resumeIfNecessary();
-                }
-                info->mFragments.clear();
-                info->mDecodingTime = totalTime * info->mMediaTimeScale / 1000000ll;
-                return OK;
-            }
-            totalTime += se->mDurationUs;
-            totalOffset += se->mSize;
-        }
-    }
-    ALOGV("seekTo out of range");
-    return err;
-}
-
-status_t FragmentedMP4Parser::dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit,
-                                                bool synchronous) {
-
-    while (true) {
-        sp<AMessage> msg = new AMessage(kWhatDequeueAccessUnit, id());
-        msg->setInt32("audio", audio);
-
-        sp<AMessage> response;
-        status_t err = msg->postAndAwaitResponse(&response);
-
-        if (err != OK) {
-            ALOGV("dequeue fail 1: %d", err);
-            return err;
-        }
-
-        if (response->findInt32("err", &err) && err != OK) {
-            if (synchronous && err == -EWOULDBLOCK) {
-                resumeIfNecessary();
-                ALOGV("Parser not ready yet, retrying");
-                usleep(10000);
-                continue;
-            }
-            ALOGV("dequeue fail 2: %d, %d", err, synchronous);
-            return err;
-        }
-
-        CHECK(response->findBuffer("accessUnit", accessUnit));
-
-        return OK;
-    }
-}
-
-ssize_t FragmentedMP4Parser::findTrack(bool wantAudio) const {
-    for (size_t i = 0; i < mTracks.size(); ++i) {
-        const TrackInfo *info = &mTracks.valueAt(i);
-
-        bool isAudio =
-            info->mMediaHandlerType == FOURCC('s', 'o', 'u', 'n');
-
-        bool isVideo =
-            info->mMediaHandlerType == FOURCC('v', 'i', 'd', 'e');
-
-        if ((wantAudio && isAudio) || (!wantAudio && !isAudio)) {
-            if (info->mSampleDescs.empty()) {
-                break;
-            }
-
-            return i;
-        }
-    }
-
-    return -EWOULDBLOCK;
-}
-
-void FragmentedMP4Parser::onMessageReceived(const sp<AMessage> &msg) {
-    switch (msg->what()) {
-        case kWhatStart:
-        {
-            sp<RefBase> obj;
-            CHECK(msg->findObject("source", &obj));
-
-            mSource = static_cast<Source *>(obj.get());
-
-            mBuffer = new ABuffer(512 * 1024);
-            mBuffer->setRange(0, 0);
-
-            enter(0ll, 0, 0);
-
-            (new AMessage(kWhatProceed, id()))->post();
-            break;
-        }
-
-        case kWhatProceed:
-        {
-            CHECK(!mSuspended);
-
-            status_t err = onProceed();
-
-            if (err == OK) {
-                if (!mSuspended) {
-                    msg->post();
-                }
-            } else if (err != -EAGAIN) {
-                ALOGE("onProceed returned error %d", err);
-            }
-
-            break;
-        }
-
-        case kWhatReadMore:
-        {
-            size_t needed;
-            CHECK(msg->findSize("needed", &needed));
-
-            memmove(mBuffer->base(), mBuffer->data(), mBuffer->size());
-            mBufferPos += mBuffer->offset();
-            mBuffer->setRange(0, mBuffer->size());
-
-            size_t maxBytesToRead = mBuffer->capacity() - mBuffer->size();
-
-            if (maxBytesToRead < needed) {
-                ALOGV("resizing buffer.");
-
-                sp<ABuffer> newBuffer =
-                    new ABuffer((mBuffer->size() + needed + 1023) & ~1023);
-                memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size());
-                newBuffer->setRange(0, mBuffer->size());
-
-                mBuffer = newBuffer;
-                maxBytesToRead = mBuffer->capacity() - mBuffer->size();
-            }
-
-            CHECK_GE(maxBytesToRead, needed);
-
-            ssize_t n = mSource->readAt(
-                    mBufferPos + mBuffer->size(),
-                    mBuffer->data() + mBuffer->size(), needed);
-
-            if (n < (ssize_t)needed) {
-                ALOGV("Reached EOF when reading %d @ %d + %d", needed, mBufferPos, mBuffer->size());
-                if (n < 0) {
-                    mFinalResult = n;
-                } else if (n == 0) {
-                    mFinalResult = ERROR_END_OF_STREAM;
-                } else {
-                    mFinalResult = ERROR_IO;
-                }
-            } else {
-                mBuffer->setRange(0, mBuffer->size() + n);
-                (new AMessage(kWhatProceed, id()))->post();
-            }
-
-            break;
-        }
-
-        case kWhatGetFormat:
-        {
-            int32_t wantAudio;
-            CHECK(msg->findInt32("audio", &wantAudio));
-
-            status_t err = -EWOULDBLOCK;
-            sp<AMessage> response = new AMessage;
-
-            ssize_t trackIndex = findTrack(wantAudio);
-
-            if (trackIndex < 0) {
-                err = trackIndex;
-            } else {
-                TrackInfo *info = &mTracks.editValueAt(trackIndex);
-
-                sp<AMessage> format = info->mSampleDescs.itemAt(0).mFormat;
-                if (info->mSidxDuration) {
-                    format->setInt64("durationUs", info->mSidxDuration);
-                } else {
-                    // this is probably going to be zero. Oh well...
-                    format->setInt64("durationUs",
-                                     1000000ll * info->mDuration / info->mMediaTimeScale);
-                }
-                response->setMessage(
-                        "format", format);
-
-                err = OK;
-            }
-
-            response->setInt32("err", err);
-
-            uint32_t replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
-            response->postReply(replyID);
-            break;
-        }
-
-        case kWhatDequeueAccessUnit:
-        {
-            int32_t wantAudio;
-            CHECK(msg->findInt32("audio", &wantAudio));
-
-            status_t err = -EWOULDBLOCK;
-            sp<AMessage> response = new AMessage;
-
-            ssize_t trackIndex = findTrack(wantAudio);
-
-            if (trackIndex < 0) {
-                err = trackIndex;
-            } else {
-                sp<ABuffer> accessUnit;
-                err = onDequeueAccessUnit(trackIndex, &accessUnit);
-
-                if (err == OK) {
-                    response->setBuffer("accessUnit", accessUnit);
-                }
-            }
-
-            response->setInt32("err", err);
-
-            uint32_t replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
-            response->postReply(replyID);
-            break;
-        }
-
-        case kWhatSeekTo:
-        {
-            ALOGV("kWhatSeekTo");
-            int32_t wantAudio;
-            CHECK(msg->findInt32("audio", &wantAudio));
-            int64_t position;
-            CHECK(msg->findInt64("position", &position));
-
-            status_t err = -EWOULDBLOCK;
-            sp<AMessage> response = new AMessage;
-
-            ssize_t trackIndex = findTrack(wantAudio);
-
-            if (trackIndex < 0) {
-                err = trackIndex;
-            } else {
-                err = onSeekTo(wantAudio, position);
-            }
-            response->setInt32("err", err);
-            uint32_t replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-            response->postReply(replyID);
-            break;
-        }
-        default:
-            TRESPASS();
-    }
-}
-
-status_t FragmentedMP4Parser::onProceed() {
-    status_t err;
-
-    if ((err = need(8)) != OK) {
-        return err;
-    }
-
-    uint64_t size = readU32(0);
-    uint32_t type = readU32(4);
-
-    size_t offset = 8;
-
-    if (size == 1) {
-        if ((err = need(16)) != OK) {
-            return err;
-        }
-
-        size = readU64(offset);
-        offset += 8;
-    }
-
-    uint8_t userType[16];
-
-    if (type == FOURCC('u', 'u', 'i', 'd')) {
-        if ((err = need(offset + 16)) != OK) {
-            return err;
-        }
-
-        memcpy(userType, mBuffer->data() + offset, 16);
-        offset += 16;
-    }
-
-    CHECK(!mStack.isEmpty());
-    uint32_t ptype = mStack.itemAt(mStack.size() - 1).mType;
-
-    static const size_t kNumDispatchers =
-        sizeof(kDispatchTable) / sizeof(kDispatchTable[0]);
-
-    size_t i;
-    for (i = 0; i < kNumDispatchers; ++i) {
-        if (kDispatchTable[i].mType == type
-                && kDispatchTable[i].mParentType == ptype) {
-            break;
-        }
-    }
-
-    // SampleEntry boxes are container boxes that start with a variable
-    // amount of data depending on the media handler type.
-    // We don't look inside 'hint' type SampleEntry boxes.
-
-    bool isSampleEntryBox =
-        (ptype == FOURCC('s', 't', 's', 'd'))
-        && editTrack(mCurrentTrackID)->mMediaHandlerType
-        != FOURCC('h', 'i', 'n', 't');
-
-    if ((i < kNumDispatchers && kDispatchTable[i].mHandler == 0)
-            || isSampleEntryBox || ptype == FOURCC('i', 'l', 's', 't')) {
-        // This is a container box.
-        if (type == FOURCC('m', 'o', 'o', 'f')) {
-            if (mFirstMoofOffset == 0) {
-                ALOGV("first moof @ %08x", mBufferPos + offset);
-                mFirstMoofOffset = mBufferPos + offset - 8; // point at the size
-            }
-        }
-        if (type == FOURCC('m', 'e', 't', 'a')) {
-            if ((err = need(offset + 4)) < OK) {
-                return err;
-            }
-
-            if (readU32(offset) != 0) {
-                return -EINVAL;
-            }
-
-            offset += 4;
-        } else if (type == FOURCC('s', 't', 's', 'd')) {
-            if ((err = need(offset + 8)) < OK) {
-                return err;
-            }
-
-            if (readU32(offset) != 0) {
-                return -EINVAL;
-            }
-
-            if (readU32(offset + 4) == 0) {
-                // We need at least some entries.
-                return -EINVAL;
-            }
-
-            offset += 8;
-        } else if (isSampleEntryBox) {
-            size_t headerSize;
-
-            switch (editTrack(mCurrentTrackID)->mMediaHandlerType) {
-                case FOURCC('v', 'i', 'd', 'e'):
-                {
-                    // 8 bytes SampleEntry + 70 bytes VisualSampleEntry
-                    headerSize = 78;
-                    break;
-                }
-
-                case FOURCC('s', 'o', 'u', 'n'):
-                {
-                    // 8 bytes SampleEntry + 20 bytes AudioSampleEntry
-                    headerSize = 28;
-                    break;
-                }
-
-                case FOURCC('m', 'e', 't', 'a'):
-                {
-                    headerSize = 8;  // 8 bytes SampleEntry
-                    break;
-                }
-
-                default:
-                    TRESPASS();
-            }
-
-            if (offset + headerSize > size) {
-                return -EINVAL;
-            }
-
-            if ((err = need(offset + headerSize)) != OK) {
-                return err;
-            }
-
-            switch (editTrack(mCurrentTrackID)->mMediaHandlerType) {
-                case FOURCC('v', 'i', 'd', 'e'):
-                {
-                    err = parseVisualSampleEntry(
-                            type, offset, offset + headerSize);
-                    break;
-                }
-
-                case FOURCC('s', 'o', 'u', 'n'):
-                {
-                    err = parseAudioSampleEntry(
-                            type, offset, offset + headerSize);
-                    break;
-                }
-
-                case FOURCC('m', 'e', 't', 'a'):
-                {
-                    err = OK;
-                    break;
-                }
-
-                default:
-                    TRESPASS();
-            }
-
-            if (err != OK) {
-                return err;
-            }
-
-            offset += headerSize;
-        }
-
-        skip(offset);
-
-        ALOGV("%sentering box of type '%s'",
-                IndentString(mStack.size()), Fourcc2String(type));
-
-        enter(mBufferPos - offset, type, size - offset);
-    } else {
-        if (!fitsContainer(size)) {
-            return -EINVAL;
-        }
-
-        if (i < kNumDispatchers && kDispatchTable[i].mHandler != 0) {
-            // We have a handler for this box type.
-
-            if ((err = need(size)) != OK) {
-                return err;
-            }
-
-            ALOGV("%sparsing box of type '%s'",
-                    IndentString(mStack.size()), Fourcc2String(type));
-
-            if ((err = (this->*kDispatchTable[i].mHandler)(
-                            type, offset, size)) != OK) {
-                return err;
-            }
-        } else {
-            // Unknown box type
-
-            ALOGV("%sskipping box of type '%s', size %llu",
-                    IndentString(mStack.size()),
-                    Fourcc2String(type), size);
-
-        }
-
-        skip(size);
-    }
-
-    return OK;
-}
-
-// static
-int FragmentedMP4Parser::CompareSampleLocation(
-        const SampleInfo &sample, const MediaDataInfo &mdatInfo) {
-    if (sample.mOffset + sample.mSize < mdatInfo.mOffset) {
-        return -1;
-    }
-
-    if (sample.mOffset >= mdatInfo.mOffset + mdatInfo.mBuffer->size()) {
-        return 1;
-    }
-
-    // Otherwise make sure the sample is completely contained within this
-    // media data block.
-
-    CHECK_GE(sample.mOffset, mdatInfo.mOffset);
-
-    CHECK_LE(sample.mOffset + sample.mSize,
-             mdatInfo.mOffset + mdatInfo.mBuffer->size());
-
-    return 0;
-}
-
-void FragmentedMP4Parser::resumeIfNecessary() {
-    if (!mSuspended) {
-        return;
-    }
-
-    ALOGV("resuming.");
-
-    mSuspended = false;
-    (new AMessage(kWhatProceed, id()))->post();
-}
-
-status_t FragmentedMP4Parser::getSample(
-        TrackInfo *info, sp<TrackFragment> *fragment, SampleInfo *sampleInfo) {
-    for (;;) {
-        if (info->mFragments.empty()) {
-            if (mFinalResult != OK) {
-                return mFinalResult;
-            }
-
-            resumeIfNecessary();
-            return -EWOULDBLOCK;
-        }
-
-        *fragment = *info->mFragments.begin();
-
-        status_t err = (*fragment)->getSample(sampleInfo);
-
-        if (err == OK) {
-            return OK;
-        } else if (err != ERROR_END_OF_STREAM) {
-            return err;
-        }
-
-        // Really, end of this fragment...
-
-        info->mFragments.erase(info->mFragments.begin());
-    }
-}
-
-status_t FragmentedMP4Parser::onDequeueAccessUnit(
-        size_t trackIndex, sp<ABuffer> *accessUnit) {
-    TrackInfo *info = &mTracks.editValueAt(trackIndex);
-
-    sp<TrackFragment> fragment;
-    SampleInfo sampleInfo;
-    status_t err = getSample(info, &fragment, &sampleInfo);
-
-    if (err == -EWOULDBLOCK) {
-        resumeIfNecessary();
-        return err;
-    } else if (err != OK) {
-        return err;
-    }
-
-    err = -EWOULDBLOCK;
-
-    bool checkDroppable = false;
-
-    for (size_t i = 0; i < mMediaData.size(); ++i) {
-        const MediaDataInfo &mdatInfo = mMediaData.itemAt(i);
-
-        int cmp = CompareSampleLocation(sampleInfo, mdatInfo);
-
-        if (cmp < 0 && !mSource->isSeekable()) {
-            return -EPIPE;
-        } else if (cmp == 0) {
-            if (i > 0) {
-                checkDroppable = true;
-            }
-
-            err = makeAccessUnit(info, sampleInfo, mdatInfo, accessUnit);
-            break;
-        }
-    }
-
-    if (err != OK) {
-        return err;
-    }
-
-    fragment->advance();
-
-    if (!mMediaData.empty() && checkDroppable) {
-        size_t numDroppable = 0;
-        bool done = false;
-
-        // XXX FIXME: if one of the tracks is not advanced (e.g. if you play an audio+video
-        // file with sf2), then mMediaData will not be pruned and keeps growing
-        for (size_t i = 0; !done && i < mMediaData.size(); ++i) {
-            const MediaDataInfo &mdatInfo = mMediaData.itemAt(i);
-
-            for (size_t j = 0; j < mTracks.size(); ++j) {
-                TrackInfo *info = &mTracks.editValueAt(j);
-
-                sp<TrackFragment> fragment;
-                SampleInfo sampleInfo;
-                err = getSample(info, &fragment, &sampleInfo);
-
-                if (err != OK) {
-                    done = true;
-                    break;
-                }
-
-                int cmp = CompareSampleLocation(sampleInfo, mdatInfo);
-
-                if (cmp <= 0) {
-                    done = true;
-                    break;
-                }
-            }
-
-            if (!done) {
-                ++numDroppable;
-            }
-        }
-
-        if (numDroppable > 0) {
-            mMediaData.removeItemsAt(0, numDroppable);
-
-            if (mMediaData.size() < 5) {
-                resumeIfNecessary();
-            }
-        }
-    }
-
-    return err;
-}
-
-static size_t parseNALSize(size_t nalLengthSize, const uint8_t *data) {
-    switch (nalLengthSize) {
-        case 1:
-            return *data;
-        case 2:
-            return U16_AT(data);
-        case 3:
-            return ((size_t)data[0] << 16) | U16_AT(&data[1]);
-        case 4:
-            return U32_AT(data);
-    }
-
-    // This cannot happen, mNALLengthSize springs to life by adding 1 to
-    // a 2-bit integer.
-    TRESPASS();
-
-    return 0;
-}
-
-status_t FragmentedMP4Parser::makeAccessUnit(
-        TrackInfo *info,
-        const SampleInfo &sample,
-        const MediaDataInfo &mdatInfo,
-        sp<ABuffer> *accessUnit) {
-    if (sample.mSampleDescIndex < 1
-            || sample.mSampleDescIndex > info->mSampleDescs.size()) {
-        return ERROR_MALFORMED;
-    }
-
-    int64_t presentationTimeUs =
-        1000000ll * sample.mPresentationTime / info->mMediaTimeScale;
-
-    const SampleDescription &sampleDesc =
-        info->mSampleDescs.itemAt(sample.mSampleDescIndex - 1);
-
-    size_t nalLengthSize;
-    if (!sampleDesc.mFormat->findSize("nal-length-size", &nalLengthSize)) {
-        *accessUnit = new ABuffer(sample.mSize);
-
-        memcpy((*accessUnit)->data(),
-               mdatInfo.mBuffer->data() + (sample.mOffset - mdatInfo.mOffset),
-               sample.mSize);
-
-        (*accessUnit)->meta()->setInt64("timeUs", presentationTimeUs);
-        if (IsIDR(*accessUnit)) {
-            (*accessUnit)->meta()->setInt32("is-sync-frame", 1);
-        }
-
-        return OK;
-    }
-
-    const uint8_t *srcPtr =
-        mdatInfo.mBuffer->data() + (sample.mOffset - mdatInfo.mOffset);
-
-    for (int i = 0; i < 2 ; ++i) {
-        size_t srcOffset = 0;
-        size_t dstOffset = 0;
-
-        while (srcOffset < sample.mSize) {
-            if (srcOffset + nalLengthSize > sample.mSize) {
-                return ERROR_MALFORMED;
-            }
-
-            size_t nalSize = parseNALSize(nalLengthSize, &srcPtr[srcOffset]);
-            srcOffset += nalLengthSize;
-
-            if (srcOffset + nalSize > sample.mSize) {
-                return ERROR_MALFORMED;
-            }
-
-            if (i == 1) {
-                memcpy((*accessUnit)->data() + dstOffset,
-                       "\x00\x00\x00\x01",
-                       4);
-
-                memcpy((*accessUnit)->data() + dstOffset + 4,
-                       srcPtr + srcOffset,
-                       nalSize);
-            }
-
-            srcOffset += nalSize;
-            dstOffset += nalSize + 4;
-        }
-
-        if (i == 0) {
-            (*accessUnit) = new ABuffer(dstOffset);
-            (*accessUnit)->meta()->setInt64(
-                    "timeUs", presentationTimeUs);
-        }
-    }
-    if (IsIDR(*accessUnit)) {
-        (*accessUnit)->meta()->setInt32("is-sync-frame", 1);
-    }
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::need(size_t size) {
-    if (!fitsContainer(size)) {
-        return -EINVAL;
-    }
-
-    if (size <= mBuffer->size()) {
-        return OK;
-    }
-
-    sp<AMessage> msg = new AMessage(kWhatReadMore, id());
-    msg->setSize("needed", size - mBuffer->size());
-    msg->post();
-
-    // ALOGV("need(%d) returning -EAGAIN, only have %d", size, mBuffer->size());
-
-    return -EAGAIN;
-}
-
-void FragmentedMP4Parser::enter(off64_t offset, uint32_t type, uint64_t size) {
-    Container container;
-    container.mOffset = offset;
-    container.mType = type;
-    container.mExtendsToEOF = (size == 0);
-    container.mBytesRemaining = size;
-
-    mStack.push(container);
-}
-
-bool FragmentedMP4Parser::fitsContainer(uint64_t size) const {
-    CHECK(!mStack.isEmpty());
-    const Container &container = mStack.itemAt(mStack.size() - 1);
-
-    return container.mExtendsToEOF || size <= container.mBytesRemaining;
-}
-
-uint16_t FragmentedMP4Parser::readU16(size_t offset) {
-    CHECK_LE(offset + 2, mBuffer->size());
-
-    const uint8_t *ptr = mBuffer->data() + offset;
-    return (ptr[0] << 8) | ptr[1];
-}
-
-uint32_t FragmentedMP4Parser::readU32(size_t offset) {
-    CHECK_LE(offset + 4, mBuffer->size());
-
-    const uint8_t *ptr = mBuffer->data() + offset;
-    return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
-}
-
-uint64_t FragmentedMP4Parser::readU64(size_t offset) {
-    return (((uint64_t)readU32(offset)) << 32) | readU32(offset + 4);
-}
-
-void FragmentedMP4Parser::skip(off_t distance) {
-    CHECK(!mStack.isEmpty());
-    for (size_t i = mStack.size(); i-- > 0;) {
-        Container *container = &mStack.editItemAt(i);
-        if (!container->mExtendsToEOF) {
-            CHECK_LE(distance, (off_t)container->mBytesRemaining);
-
-            container->mBytesRemaining -= distance;
-
-            if (container->mBytesRemaining == 0) {
-                ALOGV("%sleaving box of type '%s'",
-                        IndentString(mStack.size() - 1),
-                        Fourcc2String(container->mType));
-
-#if 0
-                if (container->mType == FOURCC('s', 't', 's', 'd')) {
-                    TrackInfo *trackInfo = editTrack(mCurrentTrackID);
-                    for (size_t i = 0;
-                            i < trackInfo->mSampleDescs.size(); ++i) {
-                        ALOGI("format #%d: %s",
-                              i,
-                              trackInfo->mSampleDescs.itemAt(i)
-                                .mFormat->debugString().c_str());
-                    }
-                }
-#endif
-
-                if (container->mType == FOURCC('s', 't', 'b', 'l')) {
-                    TrackInfo *trackInfo = editTrack(mCurrentTrackID);
-
-                    trackInfo->mStaticFragment->signalCompletion();
-
-                    CHECK(trackInfo->mFragments.empty());
-                    trackInfo->mFragments.push_back(trackInfo->mStaticFragment);
-                    trackInfo->mStaticFragment.clear();
-                } else if (container->mType == FOURCC('t', 'r', 'a', 'f')) {
-                    TrackInfo *trackInfo =
-                        editTrack(mTrackFragmentHeaderInfo.mTrackID);
-
-                    const sp<TrackFragment> &fragment =
-                        *--trackInfo->mFragments.end();
-
-                    static_cast<DynamicTrackFragment *>(
-                            fragment.get())->signalCompletion();
-                } else if (container->mType == FOURCC('m', 'o', 'o', 'v')) {
-                    mDoneWithMoov = true;
-                }
-
-                container = NULL;
-                mStack.removeItemsAt(i);
-            }
-        }
-    }
-
-    if (distance < (off_t)mBuffer->size()) {
-        mBuffer->setRange(mBuffer->offset() + distance, mBuffer->size() - distance);
-        mBufferPos += distance;
-        return;
-    }
-
-    mBuffer->setRange(0, 0);
-    mBufferPos += distance;
-}
-
-status_t FragmentedMP4Parser::parseTrackHeader(
-        uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 4 > size) {
-        return -EINVAL;
-    }
-
-    uint32_t flags = readU32(offset);
-
-    uint32_t version = flags >> 24;
-    flags &= 0xffffff;
-
-    uint32_t trackID;
-    uint64_t duration;
-
-    if (version == 1) {
-        if (offset + 36 > size) {
-            return -EINVAL;
-        }
-
-        trackID = readU32(offset + 20);
-        duration = readU64(offset + 28);
-
-        offset += 36;
-    } else if (version == 0) {
-        if (offset + 24 > size) {
-            return -EINVAL;
-        }
-
-        trackID = readU32(offset + 12);
-        duration = readU32(offset + 20);
-
-        offset += 24;
-    } else {
-        return -EINVAL;
-    }
-
-    TrackInfo *info = editTrack(trackID, true /* createIfNecessary */);
-    info->mFlags = flags;
-    info->mDuration = duration;
-    if (info->mDuration == 0xffffffff) {
-        // ffmpeg sets this to -1, which is incorrect.
-        info->mDuration = 0;
-    }
-
-    info->mStaticFragment = new StaticTrackFragment;
-
-    mCurrentTrackID = trackID;
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseMediaHeader(
-        uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 4 > size) {
-        return -EINVAL;
-    }
-
-    uint32_t versionAndFlags = readU32(offset);
-
-    if (versionAndFlags & 0xffffff) {
-        return ERROR_MALFORMED;
-    }
-
-    uint32_t version = versionAndFlags >> 24;
-
-    TrackInfo *info = editTrack(mCurrentTrackID);
-
-    if (version == 1) {
-        if (offset + 4 + 32 > size) {
-            return -EINVAL;
-        }
-        info->mMediaTimeScale = U32_AT(mBuffer->data() + offset + 20);
-    } else if (version == 0) {
-        if (offset + 4 + 20 > size) {
-            return -EINVAL;
-        }
-        info->mMediaTimeScale = U32_AT(mBuffer->data() + offset + 12);
-    } else {
-        return ERROR_MALFORMED;
-    }
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseMediaHandler(
-        uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 12 > size) {
-        return -EINVAL;
-    }
-
-    if (readU32(offset) != 0) {
-        return -EINVAL;
-    }
-
-    uint32_t handlerType = readU32(offset + 8);
-
-    switch (handlerType) {
-        case FOURCC('v', 'i', 'd', 'e'):
-        case FOURCC('s', 'o', 'u', 'n'):
-        case FOURCC('h', 'i', 'n', 't'):
-        case FOURCC('m', 'e', 't', 'a'):
-            break;
-
-        default:
-            return -EINVAL;
-    }
-
-    editTrack(mCurrentTrackID)->mMediaHandlerType = handlerType;
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseVisualSampleEntry(
-        uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 78 > size) {
-        return -EINVAL;
-    }
-
-    TrackInfo *trackInfo = editTrack(mCurrentTrackID);
-
-    trackInfo->mSampleDescs.push();
-    SampleDescription *sampleDesc =
-        &trackInfo->mSampleDescs.editItemAt(
-                trackInfo->mSampleDescs.size() - 1);
-
-    sampleDesc->mType = type;
-    sampleDesc->mDataRefIndex = readU16(offset + 6);
-
-    sp<AMessage> format = new AMessage;
-
-    switch (type) {
-        case FOURCC('a', 'v', 'c', '1'):
-            format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
-            break;
-        case FOURCC('m', 'p', '4', 'v'):
-            format->setString("mime", MEDIA_MIMETYPE_VIDEO_MPEG4);
-            break;
-        case FOURCC('s', '2', '6', '3'):
-        case FOURCC('h', '2', '6', '3'):
-        case FOURCC('H', '2', '6', '3'):
-            format->setString("mime", MEDIA_MIMETYPE_VIDEO_H263);
-            break;
-        default:
-            format->setString("mime", "application/octet-stream");
-            break;
-    }
-
-    format->setInt32("width", readU16(offset + 8 + 16));
-    format->setInt32("height", readU16(offset + 8 + 18));
-
-    sampleDesc->mFormat = format;
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseAudioSampleEntry(
-        uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 28 > size) {
-        return -EINVAL;
-    }
-
-    TrackInfo *trackInfo = editTrack(mCurrentTrackID);
-
-    trackInfo->mSampleDescs.push();
-    SampleDescription *sampleDesc =
-        &trackInfo->mSampleDescs.editItemAt(
-                trackInfo->mSampleDescs.size() - 1);
-
-    sampleDesc->mType = type;
-    sampleDesc->mDataRefIndex = readU16(offset + 6);
-
-    sp<AMessage> format = new AMessage;
-
-    format->setInt32("channel-count", readU16(offset + 8 + 8));
-    format->setInt32("sample-size", readU16(offset + 8 + 10));
-    format->setInt32("sample-rate", readU32(offset + 8 + 16) / 65536.0f);
-
-    switch (type) {
-        case FOURCC('m', 'p', '4', 'a'):
-            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
-            break;
-
-        case FOURCC('s', 'a', 'm', 'r'):
-            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_NB);
-            format->setInt32("channel-count", 1);
-            format->setInt32("sample-rate", 8000);
-            break;
-
-        case FOURCC('s', 'a', 'w', 'b'):
-            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_WB);
-            format->setInt32("channel-count", 1);
-            format->setInt32("sample-rate", 16000);
-            break;
-        default:
-            format->setString("mime", "application/octet-stream");
-            break;
-    }
-
-    sampleDesc->mFormat = format;
-
-    return OK;
-}
-
-static void addCodecSpecificData(
-        const sp<AMessage> &format, int32_t index,
-        const void *data, size_t size,
-        bool insertStartCode = false) {
-    sp<ABuffer> csd = new ABuffer(insertStartCode ? size + 4 : size);
-
-    memcpy(csd->data() + (insertStartCode ? 4 : 0), data, size);
-
-    if (insertStartCode) {
-        memcpy(csd->data(), "\x00\x00\x00\x01", 4);
-    }
-
-    csd->meta()->setInt32("csd", true);
-    csd->meta()->setInt64("timeUs", 0ll);
-
-    format->setBuffer(StringPrintf("csd-%d", index).c_str(), csd);
-}
-
-status_t FragmentedMP4Parser::parseSampleSizes(
-        uint32_t type, size_t offset, uint64_t size) {
-    return editTrack(mCurrentTrackID)->mStaticFragment->parseSampleSizes(
-            this, type, offset, size);
-}
-
-status_t FragmentedMP4Parser::parseCompactSampleSizes(
-        uint32_t type, size_t offset, uint64_t size) {
-    return editTrack(mCurrentTrackID)->mStaticFragment->parseCompactSampleSizes(
-            this, type, offset, size);
-}
-
-status_t FragmentedMP4Parser::parseSampleToChunk(
-        uint32_t type, size_t offset, uint64_t size) {
-    return editTrack(mCurrentTrackID)->mStaticFragment->parseSampleToChunk(
-            this, type, offset, size);
-}
-
-status_t FragmentedMP4Parser::parseChunkOffsets(
-        uint32_t type, size_t offset, uint64_t size) {
-    return editTrack(mCurrentTrackID)->mStaticFragment->parseChunkOffsets(
-            this, type, offset, size);
-}
-
-status_t FragmentedMP4Parser::parseChunkOffsets64(
-        uint32_t type, size_t offset, uint64_t size) {
-    return editTrack(mCurrentTrackID)->mStaticFragment->parseChunkOffsets64(
-            this, type, offset, size);
-}
-
-status_t FragmentedMP4Parser::parseAVCCodecSpecificData(
-        uint32_t type, size_t offset, uint64_t size) {
-    TrackInfo *trackInfo = editTrack(mCurrentTrackID);
-
-    SampleDescription *sampleDesc =
-        &trackInfo->mSampleDescs.editItemAt(
-                trackInfo->mSampleDescs.size() - 1);
-
-    if (sampleDesc->mType != FOURCC('a', 'v', 'c', '1')) {
-        return -EINVAL;
-    }
-
-    const uint8_t *ptr = mBuffer->data() + offset;
-
-    size -= offset;
-    offset = 0;
-
-    if (size < 7 || ptr[0] != 0x01) {
-        return ERROR_MALFORMED;
-    }
-
-    sampleDesc->mFormat->setSize("nal-length-size", 1 + (ptr[4] & 3));
-
-    size_t numSPS = ptr[5] & 31;
-
-    ptr += 6;
-    size -= 6;
-
-    for (size_t i = 0; i < numSPS; ++i) {
-        if (size < 2) {
-            return ERROR_MALFORMED;
-        }
-
-        size_t length = U16_AT(ptr);
-
-        ptr += 2;
-        size -= 2;
-
-        if (size < length) {
-            return ERROR_MALFORMED;
-        }
-
-        addCodecSpecificData(
-                sampleDesc->mFormat, i, ptr, length,
-                true /* insertStartCode */);
-
-        ptr += length;
-        size -= length;
-    }
-
-    if (size < 1) {
-        return ERROR_MALFORMED;
-    }
-
-    size_t numPPS = *ptr;
-    ++ptr;
-    --size;
-
-    for (size_t i = 0; i < numPPS; ++i) {
-        if (size < 2) {
-            return ERROR_MALFORMED;
-        }
-
-        size_t length = U16_AT(ptr);
-
-        ptr += 2;
-        size -= 2;
-
-        if (size < length) {
-            return ERROR_MALFORMED;
-        }
-
-        addCodecSpecificData(
-                sampleDesc->mFormat, numSPS + i, ptr, length,
-                true /* insertStartCode */);
-
-        ptr += length;
-        size -= length;
-    }
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseESDSCodecSpecificData(
-        uint32_t type, size_t offset, uint64_t size) {
-    TrackInfo *trackInfo = editTrack(mCurrentTrackID);
-
-    SampleDescription *sampleDesc =
-        &trackInfo->mSampleDescs.editItemAt(
-                trackInfo->mSampleDescs.size() - 1);
-
-    if (sampleDesc->mType != FOURCC('m', 'p', '4', 'a')
-            && sampleDesc->mType != FOURCC('m', 'p', '4', 'v')) {
-        return -EINVAL;
-    }
-
-    const uint8_t *ptr = mBuffer->data() + offset;
-
-    size -= offset;
-    offset = 0;
-
-    if (size < 4) {
-        return -EINVAL;
-    }
-
-    if (U32_AT(ptr) != 0) {
-        return -EINVAL;
-    }
-
-    ptr += 4;
-    size -=4;
-
-    ESDS esds(ptr, size);
-
-    uint8_t objectTypeIndication;
-    if (esds.getObjectTypeIndication(&objectTypeIndication) != OK) {
-        return ERROR_MALFORMED;
-    }
-
-    const uint8_t *csd;
-    size_t csd_size;
-    if (esds.getCodecSpecificInfo(
-                (const void **)&csd, &csd_size) != OK) {
-        return ERROR_MALFORMED;
-    }
-
-    addCodecSpecificData(sampleDesc->mFormat, 0, csd, csd_size);
-
-    if (sampleDesc->mType != FOURCC('m', 'p', '4', 'a')) {
-        return OK;
-    }
-
-    if (csd_size == 0) {
-        // There's no further information, i.e. no codec specific data
-        // Let's assume that the information provided in the mpeg4 headers
-        // is accurate and hope for the best.
-
-        return OK;
-    }
-
-    if (csd_size < 2) {
-        return ERROR_MALFORMED;
-    }
-
-    uint32_t objectType = csd[0] >> 3;
-
-    if (objectType == 31) {
-        return ERROR_UNSUPPORTED;
-    }
-
-    uint32_t freqIndex = (csd[0] & 7) << 1 | (csd[1] >> 7);
-    int32_t sampleRate = 0;
-    int32_t numChannels = 0;
-    if (freqIndex == 15) {
-        if (csd_size < 5) {
-            return ERROR_MALFORMED;
-        }
-
-        sampleRate = (csd[1] & 0x7f) << 17
-                        | csd[2] << 9
-                        | csd[3] << 1
-                        | (csd[4] >> 7);
-
-        numChannels = (csd[4] >> 3) & 15;
-    } else {
-        static uint32_t kSamplingRate[] = {
-            96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
-            16000, 12000, 11025, 8000, 7350
-        };
-
-        if (freqIndex == 13 || freqIndex == 14) {
-            return ERROR_MALFORMED;
-        }
-
-        sampleRate = kSamplingRate[freqIndex];
-        numChannels = (csd[1] >> 3) & 15;
-    }
-
-    if (numChannels == 0) {
-        return ERROR_UNSUPPORTED;
-    }
-
-    sampleDesc->mFormat->setInt32("sample-rate", sampleRate);
-    sampleDesc->mFormat->setInt32("channel-count", numChannels);
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseMediaData(
-        uint32_t type, size_t offset, uint64_t size) {
-    ALOGV("skipping 'mdat' chunk at offsets 0x%08lx-0x%08llx.",
-          mBufferPos + offset, mBufferPos + size);
-
-    sp<ABuffer> buffer = new ABuffer(size - offset);
-    memcpy(buffer->data(), mBuffer->data() + offset, size - offset);
-
-    mMediaData.push();
-    MediaDataInfo *info = &mMediaData.editItemAt(mMediaData.size() - 1);
-    info->mBuffer = buffer;
-    info->mOffset = mBufferPos + offset;
-
-    if (mMediaData.size() > 10) {
-        ALOGV("suspending for now.");
-        mSuspended = true;
-    }
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseSegmentIndex(
-        uint32_t type, size_t offset, uint64_t size) {
-    ALOGV("sidx box type %d, offset %d, size %d", type, int(offset), int(size));
-//    AString sidxstr;
-//    hexdump(mBuffer->data() + offset, size, 0 /* indent */, &sidxstr);
-//    ALOGV("raw sidx:");
-//    ALOGV("%s", sidxstr.c_str());
-    if (offset + 12 > size) {
-        return -EINVAL;
-    }
-
-    uint32_t flags = readU32(offset);
-
-    uint32_t version = flags >> 24;
-    flags &= 0xffffff;
-
-    ALOGV("sidx version %d", version);
-
-    uint32_t referenceId = readU32(offset + 4);
-    uint32_t timeScale = readU32(offset + 8);
-    ALOGV("sidx refid/timescale: %d/%d", referenceId, timeScale);
-
-    uint64_t earliestPresentationTime;
-    uint64_t firstOffset;
-
-    offset += 12;
-
-    if (version == 0) {
-        if (offset + 8 > size) {
-            return -EINVAL;
-        }
-        earliestPresentationTime = readU32(offset);
-        firstOffset = readU32(offset + 4);
-        offset += 8;
-    } else {
-        if (offset + 16 > size) {
-            return -EINVAL;
-        }
-        earliestPresentationTime = readU64(offset);
-        firstOffset = readU64(offset + 8);
-        offset += 16;
-    }
-    ALOGV("sidx pres/off: %Ld/%Ld", earliestPresentationTime, firstOffset);
-
-    if (offset + 4 > size) {
-        return -EINVAL;
-    }
-    if (readU16(offset) != 0) { // reserved
-        return -EINVAL;
-    }
-    int32_t referenceCount = readU16(offset + 2);
-    offset += 4;
-    ALOGV("refcount: %d", referenceCount);
-
-    if (offset + referenceCount * 12 > size) {
-        return -EINVAL;
-    }
-
-    TrackInfo *info = editTrack(mCurrentTrackID);
-    uint64_t total_duration = 0;
-    for (int i = 0; i < referenceCount; i++) {
-        uint32_t d1 = readU32(offset);
-        uint32_t d2 = readU32(offset + 4);
-        uint32_t d3 = readU32(offset + 8);
-
-        if (d1 & 0x80000000) {
-            ALOGW("sub-sidx boxes not supported yet");
-        }
-        bool sap = d3 & 0x80000000;
-        bool saptype = d3 >> 28;
-        if (!sap || saptype > 2) {
-            ALOGW("not a stream access point, or unsupported type");
-        }
-        total_duration += d2;
-        offset += 12;
-        ALOGV(" item %d, %08x %08x %08x", i, d1, d2, d3);
-        SidxEntry se;
-        se.mSize = d1 & 0x7fffffff;
-        se.mDurationUs = 1000000LL * d2 / timeScale;
-        info->mSidx.add(se);
-    }
-
-    info->mSidxDuration = total_duration * 1000000 / timeScale;
-    ALOGV("duration: %lld", info->mSidxDuration);
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseTrackExtends(
-        uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 24 > size) {
-        return -EINVAL;
-    }
-
-    if (readU32(offset) != 0) {
-        return -EINVAL;
-    }
-
-    uint32_t trackID = readU32(offset + 4);
-
-    TrackInfo *info = editTrack(trackID, true /* createIfNecessary */);
-    info->mDefaultSampleDescriptionIndex = readU32(offset + 8);
-    info->mDefaultSampleDuration = readU32(offset + 12);
-    info->mDefaultSampleSize = readU32(offset + 16);
-    info->mDefaultSampleFlags = readU32(offset + 20);
-
-    return OK;
-}
-
-FragmentedMP4Parser::TrackInfo *FragmentedMP4Parser::editTrack(
-        uint32_t trackID, bool createIfNecessary) {
-    ssize_t i = mTracks.indexOfKey(trackID);
-
-    if (i >= 0) {
-        return &mTracks.editValueAt(i);
-    }
-
-    if (!createIfNecessary) {
-        return NULL;
-    }
-
-    TrackInfo info;
-    info.mTrackID = trackID;
-    info.mFlags = 0;
-    info.mDuration = 0xffffffff;
-    info.mSidxDuration = 0;
-    info.mMediaTimeScale = 0;
-    info.mMediaHandlerType = 0;
-    info.mDefaultSampleDescriptionIndex = 0;
-    info.mDefaultSampleDuration = 0;
-    info.mDefaultSampleSize = 0;
-    info.mDefaultSampleFlags = 0;
-
-    info.mDecodingTime = 0;
-
-    mTracks.add(trackID, info);
-    return &mTracks.editValueAt(mTracks.indexOfKey(trackID));
-}
-
-status_t FragmentedMP4Parser::parseTrackFragmentHeader(
-        uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 8 > size) {
-        return -EINVAL;
-    }
-
-    uint32_t flags = readU32(offset);
-
-    if (flags & 0xff000000) {
-        return -EINVAL;
-    }
-
-    mTrackFragmentHeaderInfo.mFlags = flags;
-
-    mTrackFragmentHeaderInfo.mTrackID = readU32(offset + 4);
-    offset += 8;
-
-    if (flags & TrackFragmentHeaderInfo::kBaseDataOffsetPresent) {
-        if (offset + 8 > size) {
-            return -EINVAL;
-        }
-
-        mTrackFragmentHeaderInfo.mBaseDataOffset = readU64(offset);
-        offset += 8;
-    }
-
-    if (flags & TrackFragmentHeaderInfo::kSampleDescriptionIndexPresent) {
-        if (offset + 4 > size) {
-            return -EINVAL;
-        }
-
-        mTrackFragmentHeaderInfo.mSampleDescriptionIndex = readU32(offset);
-        offset += 4;
-    }
-
-    if (flags & TrackFragmentHeaderInfo::kDefaultSampleDurationPresent) {
-        if (offset + 4 > size) {
-            return -EINVAL;
-        }
-
-        mTrackFragmentHeaderInfo.mDefaultSampleDuration = readU32(offset);
-        offset += 4;
-    }
-
-    if (flags & TrackFragmentHeaderInfo::kDefaultSampleSizePresent) {
-        if (offset + 4 > size) {
-            return -EINVAL;
-        }
-
-        mTrackFragmentHeaderInfo.mDefaultSampleSize = readU32(offset);
-        offset += 4;
-    }
-
-    if (flags & TrackFragmentHeaderInfo::kDefaultSampleFlagsPresent) {
-        if (offset + 4 > size) {
-            return -EINVAL;
-        }
-
-        mTrackFragmentHeaderInfo.mDefaultSampleFlags = readU32(offset);
-        offset += 4;
-    }
-
-    if (!(flags & TrackFragmentHeaderInfo::kBaseDataOffsetPresent)) {
-        // This should point to the position of the first byte of the
-        // enclosing 'moof' container for the first track and
-        // the end of the data of the preceding fragment for subsequent
-        // tracks.
-
-        CHECK_GE(mStack.size(), 2u);
-
-        mTrackFragmentHeaderInfo.mBaseDataOffset =
-            mStack.itemAt(mStack.size() - 2).mOffset;
-
-        // XXX TODO: This does not do the right thing for the 2nd and
-        // subsequent tracks yet.
-    }
-
-    mTrackFragmentHeaderInfo.mDataOffset =
-        mTrackFragmentHeaderInfo.mBaseDataOffset;
-
-    TrackInfo *trackInfo = editTrack(mTrackFragmentHeaderInfo.mTrackID);
-
-    if (trackInfo->mFragments.empty()
-            || (*trackInfo->mFragments.begin())->complete()) {
-        trackInfo->mFragments.push_back(new DynamicTrackFragment);
-    }
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseTrackFragmentRun(
-        uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 8 > size) {
-        return -EINVAL;
-    }
-
-    enum {
-        kDataOffsetPresent                  = 0x01,
-        kFirstSampleFlagsPresent            = 0x04,
-        kSampleDurationPresent              = 0x100,
-        kSampleSizePresent                  = 0x200,
-        kSampleFlagsPresent                 = 0x400,
-        kSampleCompositionTimeOffsetPresent = 0x800,
-    };
-
-    uint32_t flags = readU32(offset);
-
-    if (flags & 0xff000000) {
-        return -EINVAL;
-    }
-
-    if ((flags & kFirstSampleFlagsPresent) && (flags & kSampleFlagsPresent)) {
-        // These two shall not be used together.
-        return -EINVAL;
-    }
-
-    uint32_t sampleCount = readU32(offset + 4);
-    offset += 8;
-
-    uint64_t dataOffset = mTrackFragmentHeaderInfo.mDataOffset;
-
-    uint32_t firstSampleFlags = 0;
-
-    if (flags & kDataOffsetPresent) {
-        if (offset + 4 > size) {
-            return -EINVAL;
-        }
-
-        int32_t dataOffsetDelta = (int32_t)readU32(offset);
-
-        dataOffset = mTrackFragmentHeaderInfo.mBaseDataOffset + dataOffsetDelta;
-
-        offset += 4;
-    }
-
-    if (flags & kFirstSampleFlagsPresent) {
-        if (offset + 4 > size) {
-            return -EINVAL;
-        }
-
-        firstSampleFlags = readU32(offset);
-        offset += 4;
-    }
-
-    TrackInfo *info = editTrack(mTrackFragmentHeaderInfo.mTrackID);
-
-    if (info == NULL) {
-        return -EINVAL;
-    }
-
-    uint32_t sampleDuration = 0, sampleSize = 0, sampleFlags = 0,
-             sampleCtsOffset = 0;
-
-    size_t bytesPerSample = 0;
-    if (flags & kSampleDurationPresent) {
-        bytesPerSample += 4;
-    } else if (mTrackFragmentHeaderInfo.mFlags
-            & TrackFragmentHeaderInfo::kDefaultSampleDurationPresent) {
-        sampleDuration = mTrackFragmentHeaderInfo.mDefaultSampleDuration;
-    } else {
-        sampleDuration = info->mDefaultSampleDuration;
-    }
-
-    if (flags & kSampleSizePresent) {
-        bytesPerSample += 4;
-    } else if (mTrackFragmentHeaderInfo.mFlags
-            & TrackFragmentHeaderInfo::kDefaultSampleSizePresent) {
-        sampleSize = mTrackFragmentHeaderInfo.mDefaultSampleSize;
-    } else {
-        sampleSize = info->mDefaultSampleSize;
-    }
-
-    if (flags & kSampleFlagsPresent) {
-        bytesPerSample += 4;
-    } else if (mTrackFragmentHeaderInfo.mFlags
-            & TrackFragmentHeaderInfo::kDefaultSampleFlagsPresent) {
-        sampleFlags = mTrackFragmentHeaderInfo.mDefaultSampleFlags;
-    } else {
-        sampleFlags = info->mDefaultSampleFlags;
-    }
-
-    if (flags & kSampleCompositionTimeOffsetPresent) {
-        bytesPerSample += 4;
-    } else {
-        sampleCtsOffset = 0;
-    }
-
-    if (offset + sampleCount * bytesPerSample > size) {
-        return -EINVAL;
-    }
-
-    uint32_t sampleDescIndex =
-        (mTrackFragmentHeaderInfo.mFlags
-            & TrackFragmentHeaderInfo::kSampleDescriptionIndexPresent)
-            ? mTrackFragmentHeaderInfo.mSampleDescriptionIndex
-            : info->mDefaultSampleDescriptionIndex;
-
-    for (uint32_t i = 0; i < sampleCount; ++i) {
-        if (flags & kSampleDurationPresent) {
-            sampleDuration = readU32(offset);
-            offset += 4;
-        }
-
-        if (flags & kSampleSizePresent) {
-            sampleSize = readU32(offset);
-            offset += 4;
-        }
-
-        if (flags & kSampleFlagsPresent) {
-            sampleFlags = readU32(offset);
-            offset += 4;
-        }
-
-        if (flags & kSampleCompositionTimeOffsetPresent) {
-            sampleCtsOffset = readU32(offset);
-            offset += 4;
-        }
-
-        ALOGV("adding sample at offset 0x%08llx, size %u, duration %u, "
-              "sampleDescIndex=%u, flags 0x%08x",
-                dataOffset, sampleSize, sampleDuration,
-                sampleDescIndex,
-                (flags & kFirstSampleFlagsPresent) && i == 0
-                    ? firstSampleFlags : sampleFlags);
-
-        const sp<TrackFragment> &fragment = *--info->mFragments.end();
-
-        uint32_t decodingTime = info->mDecodingTime;
-        info->mDecodingTime += sampleDuration;
-        uint32_t presentationTime = decodingTime + sampleCtsOffset;
-
-        static_cast<DynamicTrackFragment *>(
-                fragment.get())->addSample(
-                    dataOffset,
-                    sampleSize,
-                    presentationTime,
-                    sampleDescIndex,
-                    ((flags & kFirstSampleFlagsPresent) && i == 0)
-                        ? firstSampleFlags : sampleFlags);
-
-        dataOffset += sampleSize;
-    }
-
-    mTrackFragmentHeaderInfo.mDataOffset = dataOffset;
-
-    return OK;
-}
-
-void FragmentedMP4Parser::copyBuffer(
-        sp<ABuffer> *dst, size_t offset, uint64_t size) const {
-    sp<ABuffer> buf = new ABuffer(size);
-    memcpy(buf->data(), mBuffer->data() + offset, size);
-
-    *dst = buf;
-}
-
-}  // namespace android
diff --git a/media/libstagefright/mp4/TrackFragment.cpp b/media/libstagefright/mp4/TrackFragment.cpp
deleted file mode 100644
index 3699038..0000000
--- a/media/libstagefright/mp4/TrackFragment.cpp
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "TrackFragment"
-#include <utils/Log.h>
-
-#include "TrackFragment.h"
-
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/hexdump.h>
-
-namespace android {
-
-FragmentedMP4Parser::DynamicTrackFragment::DynamicTrackFragment()
-    : mComplete(false),
-      mSampleIndex(0) {
-}
-
-FragmentedMP4Parser::DynamicTrackFragment::~DynamicTrackFragment() {
-}
-
-status_t FragmentedMP4Parser::DynamicTrackFragment::getSample(SampleInfo *info) {
-    if (mSampleIndex >= mSamples.size()) {
-        return mComplete ? ERROR_END_OF_STREAM : -EWOULDBLOCK;
-    }
-
-    *info = mSamples.itemAt(mSampleIndex);
-
-    return OK;
-}
-
-void FragmentedMP4Parser::DynamicTrackFragment::advance() {
-    ++mSampleIndex;
-}
-
-void FragmentedMP4Parser::DynamicTrackFragment::addSample(
-        off64_t dataOffset, size_t sampleSize,
-        uint32_t presentationTime,
-        size_t sampleDescIndex,
-        uint32_t flags) {
-    mSamples.push();
-    SampleInfo *sampleInfo = &mSamples.editItemAt(mSamples.size() - 1);
-
-    sampleInfo->mOffset = dataOffset;
-    sampleInfo->mSize = sampleSize;
-    sampleInfo->mPresentationTime = presentationTime;
-    sampleInfo->mSampleDescIndex = sampleDescIndex;
-    sampleInfo->mFlags = flags;
-}
-
-status_t FragmentedMP4Parser::DynamicTrackFragment::signalCompletion() {
-    mComplete = true;
-
-    return OK;
-}
-
-bool FragmentedMP4Parser::DynamicTrackFragment::complete() const {
-    return mComplete;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-FragmentedMP4Parser::StaticTrackFragment::StaticTrackFragment()
-    : mSampleIndex(0),
-      mSampleCount(0),
-      mChunkIndex(0),
-      mSampleToChunkIndex(-1),
-      mSampleToChunkRemaining(0),
-      mPrevChunkIndex(0xffffffff),
-      mNextSampleOffset(0) {
-}
-
-FragmentedMP4Parser::StaticTrackFragment::~StaticTrackFragment() {
-}
-
-status_t FragmentedMP4Parser::StaticTrackFragment::getSample(SampleInfo *info) {
-    if (mSampleIndex >= mSampleCount) {
-        return ERROR_END_OF_STREAM;
-    }
-
-    *info = mSampleInfo;
-
-    ALOGV("returning sample %d at [0x%08llx, 0x%08llx)",
-          mSampleIndex,
-          info->mOffset, info->mOffset + info->mSize);
-
-    return OK;
-}
-
-void FragmentedMP4Parser::StaticTrackFragment::updateSampleInfo() {
-    if (mSampleIndex >= mSampleCount) {
-        return;
-    }
-
-    if (mSampleSizes != NULL) {
-        uint32_t defaultSampleSize = U32_AT(mSampleSizes->data() + 4);
-        if (defaultSampleSize > 0) {
-            mSampleInfo.mSize = defaultSampleSize;
-        } else {
-            mSampleInfo.mSize= U32_AT(mSampleSizes->data() + 12 + 4 * mSampleIndex);
-        }
-    } else {
-        CHECK(mCompactSampleSizes != NULL);
-
-        uint32_t fieldSize = U32_AT(mCompactSampleSizes->data() + 4);
-
-        switch (fieldSize) {
-            case 4:
-            {
-                unsigned byte = mCompactSampleSizes->data()[12 + mSampleIndex / 2];
-                mSampleInfo.mSize = (mSampleIndex & 1) ? byte & 0x0f : byte >> 4;
-                break;
-            }
-
-            case 8:
-            {
-                mSampleInfo.mSize = mCompactSampleSizes->data()[12 + mSampleIndex];
-                break;
-            }
-
-            default:
-            {
-                CHECK_EQ(fieldSize, 16);
-                mSampleInfo.mSize =
-                    U16_AT(mCompactSampleSizes->data() + 12 + mSampleIndex * 2);
-                break;
-            }
-        }
-    }
-
-    CHECK_GT(mSampleToChunkRemaining, 0);
-
-    // The sample desc index is 1-based... XXX
-    mSampleInfo.mSampleDescIndex =
-        U32_AT(mSampleToChunk->data() + 8 + 12 * mSampleToChunkIndex + 8);
-
-    if (mChunkIndex != mPrevChunkIndex) {
-        mPrevChunkIndex = mChunkIndex;
-
-        if (mChunkOffsets != NULL) {
-            uint32_t entryCount = U32_AT(mChunkOffsets->data() + 4);
-
-            if (mChunkIndex >= entryCount) {
-                mSampleIndex = mSampleCount;
-                return;
-            }
-
-            mNextSampleOffset =
-                U32_AT(mChunkOffsets->data() + 8 + 4 * mChunkIndex);
-        } else {
-            CHECK(mChunkOffsets64 != NULL);
-
-            uint32_t entryCount = U32_AT(mChunkOffsets64->data() + 4);
-
-            if (mChunkIndex >= entryCount) {
-                mSampleIndex = mSampleCount;
-                return;
-            }
-
-            mNextSampleOffset =
-                U64_AT(mChunkOffsets64->data() + 8 + 8 * mChunkIndex);
-        }
-    }
-
-    mSampleInfo.mOffset = mNextSampleOffset;
-
-    mSampleInfo.mPresentationTime = 0;
-    mSampleInfo.mFlags = 0;
-}
-
-void FragmentedMP4Parser::StaticTrackFragment::advance() {
-    mNextSampleOffset += mSampleInfo.mSize;
-
-    ++mSampleIndex;
-    if (--mSampleToChunkRemaining == 0) {
-        ++mChunkIndex;
-
-        uint32_t entryCount = U32_AT(mSampleToChunk->data() + 4);
-
-        // If this is the last entry in the sample to chunk table, we will
-        // stay on this entry.
-        if ((uint32_t)(mSampleToChunkIndex + 1) < entryCount) {
-            uint32_t nextChunkIndex =
-                U32_AT(mSampleToChunk->data() + 8 + 12 * (mSampleToChunkIndex + 1));
-
-            CHECK_GE(nextChunkIndex, 1u);
-            --nextChunkIndex;
-
-            if (mChunkIndex >= nextChunkIndex) {
-                CHECK_EQ(mChunkIndex, nextChunkIndex);
-                ++mSampleToChunkIndex;
-            }
-        }
-
-        mSampleToChunkRemaining =
-            U32_AT(mSampleToChunk->data() + 8 + 12 * mSampleToChunkIndex + 4);
-    }
-
-    updateSampleInfo();
-}
-
-static void setU32At(uint8_t *ptr, uint32_t x) {
-    ptr[0] = x >> 24;
-    ptr[1] = (x >> 16) & 0xff;
-    ptr[2] = (x >> 8) & 0xff;
-    ptr[3] = x & 0xff;
-}
-
-status_t FragmentedMP4Parser::StaticTrackFragment::signalCompletion() {
-    mSampleToChunkIndex = 0;
-
-    mSampleToChunkRemaining =
-        (mSampleToChunk == NULL)
-            ? 0
-            : U32_AT(mSampleToChunk->data() + 8 + 12 * mSampleToChunkIndex + 4);
-
-    updateSampleInfo();
-
-    return OK;
-}
-
-bool FragmentedMP4Parser::StaticTrackFragment::complete() const {
-    return true;
-}
-
-status_t FragmentedMP4Parser::StaticTrackFragment::parseSampleSizes(
-        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 12 > size) {
-        return ERROR_MALFORMED;
-    }
-
-    if (parser->readU32(offset) != 0) {
-        return ERROR_MALFORMED;
-    }
-
-    uint32_t sampleSize = parser->readU32(offset + 4);
-    uint32_t sampleCount = parser->readU32(offset + 8);
-
-    if (sampleSize == 0 && offset + 12 + sampleCount * 4 != size) {
-        return ERROR_MALFORMED;
-    }
-
-    parser->copyBuffer(&mSampleSizes, offset, size);
-
-    mSampleCount = sampleCount;
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::StaticTrackFragment::parseCompactSampleSizes(
-        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 12 > size) {
-        return ERROR_MALFORMED;
-    }
-
-    if (parser->readU32(offset) != 0) {
-        return ERROR_MALFORMED;
-    }
-
-    uint32_t fieldSize = parser->readU32(offset + 4);
-
-    if (fieldSize != 4 && fieldSize != 8 && fieldSize != 16) {
-        return ERROR_MALFORMED;
-    }
-
-    uint32_t sampleCount = parser->readU32(offset + 8);
-
-    if (offset + 12 + (sampleCount * fieldSize + 4) / 8 != size) {
-        return ERROR_MALFORMED;
-    }
-
-    parser->copyBuffer(&mCompactSampleSizes, offset, size);
-
-    mSampleCount = sampleCount;
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::StaticTrackFragment::parseSampleToChunk(
-        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 8 > size) {
-        return ERROR_MALFORMED;
-    }
-
-    if (parser->readU32(offset) != 0) {
-        return ERROR_MALFORMED;
-    }
-
-    uint32_t entryCount = parser->readU32(offset + 4);
-
-    if (entryCount == 0) {
-        return OK;
-    }
-
-    if (offset + 8 + entryCount * 12 != size) {
-        return ERROR_MALFORMED;
-    }
-
-    parser->copyBuffer(&mSampleToChunk, offset, size);
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::StaticTrackFragment::parseChunkOffsets(
-        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 8 > size) {
-        return ERROR_MALFORMED;
-    }
-
-    if (parser->readU32(offset) != 0) {
-        return ERROR_MALFORMED;
-    }
-
-    uint32_t entryCount = parser->readU32(offset + 4);
-
-    if (offset + 8 + entryCount * 4 != size) {
-        return ERROR_MALFORMED;
-    }
-
-    parser->copyBuffer(&mChunkOffsets, offset, size);
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::StaticTrackFragment::parseChunkOffsets64(
-        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 8 > size) {
-        return ERROR_MALFORMED;
-    }
-
-    if (parser->readU32(offset) != 0) {
-        return ERROR_MALFORMED;
-    }
-
-    uint32_t entryCount = parser->readU32(offset + 4);
-
-    if (offset + 8 + entryCount * 8 != size) {
-        return ERROR_MALFORMED;
-    }
-
-    parser->copyBuffer(&mChunkOffsets64, offset, size);
-
-    return OK;
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/mp4/TrackFragment.h b/media/libstagefright/mp4/TrackFragment.h
deleted file mode 100644
index e1ad46e..0000000
--- a/media/libstagefright/mp4/TrackFragment.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TRACK_FRAGMENT_H_
-
-#define TRACK_FRAGMENT_H_
-
-#include "include/FragmentedMP4Parser.h"
-
-namespace android {
-
-struct FragmentedMP4Parser::TrackFragment : public RefBase {
-    TrackFragment() {}
-
-    virtual status_t getSample(SampleInfo *info) = 0;
-    virtual void advance() = 0;
-
-    virtual status_t signalCompletion() = 0;
-    virtual bool complete() const = 0;
-
-protected:
-    virtual ~TrackFragment() {}
-
-private:
-    DISALLOW_EVIL_CONSTRUCTORS(TrackFragment);
-};
-
-struct FragmentedMP4Parser::DynamicTrackFragment : public FragmentedMP4Parser::TrackFragment {
-    DynamicTrackFragment();
-
-    virtual status_t getSample(SampleInfo *info);
-    virtual void advance();
-
-    void addSample(
-            off64_t dataOffset, size_t sampleSize,
-            uint32_t presentationTime,
-            size_t sampleDescIndex,
-            uint32_t flags);
-
-    // No more samples will be added to this fragment.
-    virtual status_t signalCompletion();
-
-    virtual bool complete() const;
-
-protected:
-    virtual ~DynamicTrackFragment();
-
-private:
-    bool mComplete;
-    size_t mSampleIndex;
-    Vector<SampleInfo> mSamples;
-
-    DISALLOW_EVIL_CONSTRUCTORS(DynamicTrackFragment);
-};
-
-struct FragmentedMP4Parser::StaticTrackFragment : public FragmentedMP4Parser::TrackFragment {
-    StaticTrackFragment();
-
-    virtual status_t getSample(SampleInfo *info);
-    virtual void advance();
-
-    virtual status_t signalCompletion();
-    virtual bool complete() const;
-
-    status_t parseSampleSizes(
-            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseCompactSampleSizes(
-            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseSampleToChunk(
-            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseChunkOffsets(
-            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseChunkOffsets64(
-            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
-
-protected:
-    virtual ~StaticTrackFragment();
-
-private:
-    size_t mSampleIndex;
-    size_t mSampleCount;
-    uint32_t mChunkIndex;
-
-    SampleInfo mSampleInfo;
-
-    sp<ABuffer> mSampleSizes;
-    sp<ABuffer> mCompactSampleSizes;
-
-    sp<ABuffer> mSampleToChunk;
-    ssize_t mSampleToChunkIndex;
-    size_t mSampleToChunkRemaining;
-
-    sp<ABuffer> mChunkOffsets;
-    sp<ABuffer> mChunkOffsets64;
-    uint32_t mPrevChunkIndex;
-    uint64_t mNextSampleOffset;
-
-    void updateSampleInfo();
-
-    DISALLOW_EVIL_CONSTRUCTORS(StaticTrackFragment);
-};
-
-}  // namespace android
-
-#endif  // TRACK_FRAGMENT_H_
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index cb57a2f..d039f7d 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -862,7 +862,7 @@
 }
 
 void ATSParser::Stream::onPayloadData(
-        unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS,
+        unsigned PTS_DTS_flags, uint64_t PTS, uint64_t /* DTS */,
         const uint8_t *data, size_t size) {
 #if 0
     ALOGI("payload streamType 0x%02x, PTS = 0x%016llx, dPTS = %lld",
@@ -1267,7 +1267,7 @@
 }
 
 void ATSParser::updatePCR(
-        unsigned PID, uint64_t PCR, size_t byteOffsetFromStart) {
+        unsigned /* PID */, uint64_t PCR, size_t byteOffsetFromStart) {
     ALOGV("PCR 0x%016llx @ %d", PCR, byteOffsetFromStart);
 
     if (mNumPCRs == 2) {
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
index c1a7a9d..c17a0b7 100644
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -13,6 +13,8 @@
 	$(TOP)/frameworks/av/media/libstagefright \
 	$(TOP)/frameworks/native/include/media/openmax
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE:= libstagefright_mpeg2ts
 
 ifeq ($(TARGET_ARCH),arm)
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 2b0bf30..6dfaa94 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -62,7 +62,7 @@
 AnotherPacketSource::~AnotherPacketSource() {
 }
 
-status_t AnotherPacketSource::start(MetaData *params) {
+status_t AnotherPacketSource::start(MetaData * /* params */) {
     return OK;
 }
 
diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
index dd714c9..bc2a16d 100644
--- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
@@ -130,7 +130,8 @@
     return new WrappedTrack(this, mTracks.valueAt(index));
 }
 
-sp<MetaData> MPEG2PSExtractor::getTrackMetaData(size_t index, uint32_t flags) {
+sp<MetaData> MPEG2PSExtractor::getTrackMetaData(
+        size_t index, uint32_t /* flags */) {
     if (index >= mTracks.size()) {
         return NULL;
     }
@@ -625,7 +626,7 @@
 
 status_t MPEG2PSExtractor::Track::appendPESData(
         unsigned PTS_DTS_flags,
-        uint64_t PTS, uint64_t DTS,
+        uint64_t PTS, uint64_t /* DTS */,
         const uint8_t *data, size_t size) {
     if (mQueue == NULL) {
         return OK;
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index d449c34..35ca118 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -141,7 +141,7 @@
 }
 
 sp<MetaData> MPEG2TSExtractor::getTrackMetaData(
-        size_t index, uint32_t flags) {
+        size_t index, uint32_t /* flags */) {
     return index < mSourceImpls.size()
         ? mSourceImpls.editItemAt(index)->getFormat() : NULL;
 }
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 44f0be7..5bea7a6 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -41,16 +41,21 @@
     mNumFramesAvailable(0),
     mEndOfStream(false),
     mEndOfStreamSent(false),
-    mRepeatAfterUs(-1ll),
     mMaxTimestampGapUs(-1ll),
     mPrevOriginalTimeUs(-1ll),
     mPrevModifiedTimeUs(-1ll),
+    mSkipFramesBeforeNs(-1ll),
+    mRepeatAfterUs(-1ll),
     mRepeatLastFrameGeneration(0),
     mRepeatLastFrameTimestamp(-1ll),
     mLatestSubmittedBufferId(-1),
     mLatestSubmittedBufferFrameNum(0),
     mLatestSubmittedBufferUseCount(0),
-    mRepeatBufferDeferred(false) {
+    mRepeatBufferDeferred(false),
+    mTimePerCaptureUs(-1ll),
+    mTimePerFrameUs(-1ll),
+    mPrevCaptureUs(-1ll),
+    mPrevFrameUs(-1ll) {
 
     ALOGV("GraphicBufferSource w=%u h=%u c=%u",
             bufferWidth, bufferHeight, bufferCount);
@@ -414,7 +419,18 @@
         mBufferSlot[item.mBuf] = item.mGraphicBuffer;
     }
 
-    err = submitBuffer_l(item, cbi);
+    err = UNKNOWN_ERROR;
+
+    // only submit sample if start time is unspecified, or sample
+    // is queued after the specified start time
+    if (mSkipFramesBeforeNs < 0ll || item.mTimestamp >= mSkipFramesBeforeNs) {
+        // if start time is set, offset time stamp by start time
+        if (mSkipFramesBeforeNs > 0) {
+            item.mTimestamp -= mSkipFramesBeforeNs;
+        }
+        err = submitBuffer_l(item, cbi);
+    }
+
     if (err != OK) {
         ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf);
         mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber,
@@ -548,7 +564,30 @@
 int64_t GraphicBufferSource::getTimestamp(const BufferQueue::BufferItem &item) {
     int64_t timeUs = item.mTimestamp / 1000;
 
-    if (mMaxTimestampGapUs > 0ll) {
+    if (mTimePerCaptureUs > 0ll) {
+        // Time lapse or slow motion mode
+        if (mPrevCaptureUs < 0ll) {
+            // first capture
+            mPrevCaptureUs = timeUs;
+            mPrevFrameUs = timeUs;
+        } else {
+            // snap to nearest capture point
+            int64_t nFrames = (timeUs + mTimePerCaptureUs / 2 - mPrevCaptureUs)
+                    / mTimePerCaptureUs;
+            if (nFrames <= 0) {
+                // skip this frame as it's too close to previous capture
+                ALOGV("skipping frame, timeUs %lld", timeUs);
+                return -1;
+            }
+            mPrevCaptureUs = mPrevCaptureUs + nFrames * mTimePerCaptureUs;
+            mPrevFrameUs += mTimePerFrameUs * nFrames;
+        }
+
+        ALOGV("timeUs %lld, captureUs %lld, frameUs %lld",
+                timeUs, mPrevCaptureUs, mPrevFrameUs);
+
+        return mPrevFrameUs;
+    } else if (mMaxTimestampGapUs > 0ll) {
         /* Cap timestamp gap between adjacent frames to specified max
          *
          * In the scenario of cast mirroring, encoding could be suspended for
@@ -699,7 +738,7 @@
             // If this is the first time we're seeing this buffer, add it to our
             // slot table.
             if (item.mGraphicBuffer != NULL) {
-                ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mBuf);
+                ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mBuf);
                 mBufferSlot[item.mBuf] = item.mGraphicBuffer;
             }
             mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber,
@@ -738,6 +777,11 @@
     }
 }
 
+// BufferQueue::ConsumerListener callback
+void GraphicBufferSource::onSidebandStreamChanged() {
+    ALOG_ASSERT(false, "GraphicBufferSource can't consume sideband streams");
+}
+
 status_t GraphicBufferSource::setRepeatPreviousFrameDelayUs(
         int64_t repeatAfterUs) {
     Mutex::Autolock autoLock(mMutex);
@@ -762,6 +806,27 @@
 
     return OK;
 }
+
+void GraphicBufferSource::setSkipFramesBeforeUs(int64_t skipFramesBeforeUs) {
+    Mutex::Autolock autoLock(mMutex);
+
+    mSkipFramesBeforeNs =
+            (skipFramesBeforeUs > 0) ? (skipFramesBeforeUs * 1000) : -1ll;
+}
+
+status_t GraphicBufferSource::setTimeLapseUs(int64_t* data) {
+    Mutex::Autolock autoLock(mMutex);
+
+    if (mExecuting || data[0] <= 0ll || data[1] <= 0ll) {
+        return INVALID_OPERATION;
+    }
+
+    mTimePerFrameUs = data[0];
+    mTimePerCaptureUs = data[1];
+
+    return OK;
+}
+
 void GraphicBufferSource::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatRepeatLastFrame:
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 3b0e454..757edc8 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -118,6 +118,17 @@
     // of suspension on input.
     status_t setMaxTimestampGapUs(int64_t maxGapUs);
 
+    // Sets the time lapse (or slow motion) parameters.
+    // data[0] is the time (us) between two frames for playback
+    // data[1] is the time (us) between two frames for capture
+    // When set, the sample's timestamp will be modified to playback framerate,
+    // and capture timestamp will be modified to capture rate.
+    status_t setTimeLapseUs(int64_t* data);
+
+    // Sets the start time us (in system time), samples before which should
+    // be dropped and not submitted to encoder
+    void setSkipFramesBeforeUs(int64_t startTimeUs);
+
 protected:
     // BufferQueue::ConsumerListener interface, called when a new frame of
     // data is available.  If we're executing and a codec buffer is
@@ -132,6 +143,11 @@
     // set of mBufferSlot entries.
     virtual void onBuffersReleased();
 
+    // BufferQueue::ConsumerListener interface, called when the client has
+    // changed the sideband stream. GraphicBufferSource doesn't handle sideband
+    // streams so this is a no-op (and should never be called).
+    virtual void onSidebandStreamChanged();
+
 private:
     // Keep track of codec input buffers.  They may either be available
     // (mGraphicBuffer == NULL) or in use by the codec.
@@ -223,16 +239,17 @@
     enum {
         kRepeatLastFrameCount = 10,
     };
-    int64_t mRepeatAfterUs;
-    int64_t mMaxTimestampGapUs;
 
     KeyedVector<int64_t, int64_t> mOriginalTimeUs;
+    int64_t mMaxTimestampGapUs;
     int64_t mPrevOriginalTimeUs;
     int64_t mPrevModifiedTimeUs;
+    int64_t mSkipFramesBeforeNs;
 
     sp<ALooper> mLooper;
     sp<AHandlerReflector<GraphicBufferSource> > mReflector;
 
+    int64_t mRepeatAfterUs;
     int32_t mRepeatLastFrameGeneration;
     int64_t mRepeatLastFrameTimestamp;
     int32_t mRepeatLastFrameCount;
@@ -245,6 +262,12 @@
     // no codec buffer was available at the time.
     bool mRepeatBufferDeferred;
 
+    // Time lapse / slow motion configuration
+    int64_t mTimePerCaptureUs;
+    int64_t mTimePerFrameUs;
+    int64_t mPrevCaptureUs;
+    int64_t mPrevFrameUs;
+
     void onMessageReceived(const sp<AMessage> &msg);
 
     DISALLOW_EVIL_CONSTRUCTORS(GraphicBufferSource);
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 274f2eb..a608479 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -185,7 +185,7 @@
     instance->onObserverDied(mMaster);
 }
 
-bool OMX::livesLocally(node_id node, pid_t pid) {
+bool OMX::livesLocally(node_id /* node */, pid_t pid) {
     return pid == getpid();
 }
 
@@ -424,7 +424,7 @@
         OMX_IN OMX_EVENTTYPE eEvent,
         OMX_IN OMX_U32 nData1,
         OMX_IN OMX_U32 nData2,
-        OMX_IN OMX_PTR pEventData) {
+        OMX_IN OMX_PTR /* pEventData */) {
     ALOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
 
     // Forward to OMXNodeInstance.
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 6c5c857..0fb38fa 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -266,7 +266,7 @@
 }
 
 status_t OMXNodeInstance::getParameter(
-        OMX_INDEXTYPE index, void *params, size_t size) {
+        OMX_INDEXTYPE index, void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
 
     OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
@@ -275,7 +275,7 @@
 }
 
 status_t OMXNodeInstance::setParameter(
-        OMX_INDEXTYPE index, const void *params, size_t size) {
+        OMX_INDEXTYPE index, const void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
 
     OMX_ERRORTYPE err = OMX_SetParameter(
@@ -285,7 +285,7 @@
 }
 
 status_t OMXNodeInstance::getConfig(
-        OMX_INDEXTYPE index, void *params, size_t size) {
+        OMX_INDEXTYPE index, void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
 
     OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
@@ -293,7 +293,7 @@
 }
 
 status_t OMXNodeInstance::setConfig(
-        OMX_INDEXTYPE index, const void *params, size_t size) {
+        OMX_INDEXTYPE index, const void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
 
     OMX_ERRORTYPE err = OMX_SetConfig(
@@ -610,7 +610,7 @@
 }
 
 status_t OMXNodeInstance::updateGraphicBufferInMeta(
-        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
+        OMX_U32 /* portIndex */, const sp<GraphicBuffer>& graphicBuffer,
         OMX::buffer_id buffer) {
     Mutex::Autolock autoLock(mLock);
 
@@ -850,6 +850,8 @@
         case IOMX::INTERNAL_OPTION_SUSPEND:
         case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY:
         case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP:
+        case IOMX::INTERNAL_OPTION_START_TIME:
+        case IOMX::INTERNAL_OPTION_TIME_LAPSE:
         {
             const sp<GraphicBufferSource> &bufferSource =
                 getGraphicBufferSource();
@@ -874,7 +876,8 @@
                 int64_t delayUs = *(int64_t *)data;
 
                 return bufferSource->setRepeatPreviousFrameDelayUs(delayUs);
-            } else {
+            } else if (type ==
+                    IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP){
                 if (size != sizeof(int64_t)) {
                     return INVALID_OPERATION;
                 }
@@ -882,6 +885,20 @@
                 int64_t maxGapUs = *(int64_t *)data;
 
                 return bufferSource->setMaxTimestampGapUs(maxGapUs);
+            } else if (type == IOMX::INTERNAL_OPTION_START_TIME) {
+                if (size != sizeof(int64_t)) {
+                    return INVALID_OPERATION;
+                }
+
+                int64_t skipFramesBeforeUs = *(int64_t *)data;
+
+                bufferSource->setSkipFramesBeforeUs(skipFramesBeforeUs);
+            } else { // IOMX::INTERNAL_OPTION_TIME_LAPSE
+                if (size != sizeof(int64_t) * 2) {
+                    return INVALID_OPERATION;
+                }
+
+                bufferSource->setTimeLapseUs((int64_t *)data);
             }
 
             return OK;
@@ -961,7 +978,7 @@
 
 // static
 OMX_ERRORTYPE OMXNodeInstance::OnEvent(
-        OMX_IN OMX_HANDLETYPE hComponent,
+        OMX_IN OMX_HANDLETYPE /* hComponent */,
         OMX_IN OMX_PTR pAppData,
         OMX_IN OMX_EVENTTYPE eEvent,
         OMX_IN OMX_U32 nData1,
@@ -977,7 +994,7 @@
 
 // static
 OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
-        OMX_IN OMX_HANDLETYPE hComponent,
+        OMX_IN OMX_HANDLETYPE /* hComponent */,
         OMX_IN OMX_PTR pAppData,
         OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
     OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
@@ -989,7 +1006,7 @@
 
 // static
 OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
-        OMX_IN OMX_HANDLETYPE hComponent,
+        OMX_IN OMX_HANDLETYPE /* hComponent */,
         OMX_IN OMX_PTR pAppData,
         OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
     OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
diff --git a/media/libstagefright/omx/SoftOMXComponent.cpp b/media/libstagefright/omx/SoftOMXComponent.cpp
index b1c34dc..646cd32 100644
--- a/media/libstagefright/omx/SoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftOMXComponent.cpp
@@ -257,69 +257,69 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 OMX_ERRORTYPE SoftOMXComponent::sendCommand(
-        OMX_COMMANDTYPE cmd, OMX_U32 param, OMX_PTR data) {
+        OMX_COMMANDTYPE /* cmd */, OMX_U32 /* param */, OMX_PTR /* data */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::getParameter(
-        OMX_INDEXTYPE index, OMX_PTR params) {
+        OMX_INDEXTYPE /* index */, OMX_PTR /* params */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::setParameter(
-        OMX_INDEXTYPE index, const OMX_PTR params) {
+        OMX_INDEXTYPE /* index */, const OMX_PTR /* params */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::getConfig(
-        OMX_INDEXTYPE index, OMX_PTR params) {
+        OMX_INDEXTYPE /* index */, OMX_PTR /* params */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::setConfig(
-        OMX_INDEXTYPE index, const OMX_PTR params) {
+        OMX_INDEXTYPE /* index */, const OMX_PTR /* params */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::getExtensionIndex(
-        const char *name, OMX_INDEXTYPE *index) {
+        const char * /* name */, OMX_INDEXTYPE * /* index */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::useBuffer(
-        OMX_BUFFERHEADERTYPE **buffer,
-        OMX_U32 portIndex,
-        OMX_PTR appPrivate,
-        OMX_U32 size,
-        OMX_U8 *ptr) {
+        OMX_BUFFERHEADERTYPE ** /* buffer */,
+        OMX_U32 /* portIndex */,
+        OMX_PTR /* appPrivate */,
+        OMX_U32 /* size */,
+        OMX_U8 * /* ptr */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::allocateBuffer(
-        OMX_BUFFERHEADERTYPE **buffer,
-        OMX_U32 portIndex,
-        OMX_PTR appPrivate,
-        OMX_U32 size) {
+        OMX_BUFFERHEADERTYPE ** /* buffer */,
+        OMX_U32 /* portIndex */,
+        OMX_PTR /* appPrivate */,
+        OMX_U32 /* size */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::freeBuffer(
-        OMX_U32 portIndex,
-        OMX_BUFFERHEADERTYPE *buffer) {
+        OMX_U32 /* portIndex */,
+        OMX_BUFFERHEADERTYPE * /* buffer */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::emptyThisBuffer(
-        OMX_BUFFERHEADERTYPE *buffer) {
+        OMX_BUFFERHEADERTYPE * /* buffer */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::fillThisBuffer(
-        OMX_BUFFERHEADERTYPE *buffer) {
+        OMX_BUFFERHEADERTYPE * /* buffer */) {
     return OMX_ErrorUndefined;
 }
 
-OMX_ERRORTYPE SoftOMXComponent::getState(OMX_STATETYPE *state) {
+OMX_ERRORTYPE SoftOMXComponent::getState(OMX_STATETYPE * /* state */) {
     return OMX_ErrorUndefined;
 }
 
diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp
index d6cde73..65f5404 100644
--- a/media/libstagefright/omx/SoftOMXPlugin.cpp
+++ b/media/libstagefright/omx/SoftOMXPlugin.cpp
@@ -50,6 +50,7 @@
     { "OMX.google.mpeg4.encoder", "mpeg4enc", "video_encoder.mpeg4" },
     { "OMX.google.mp3.decoder", "mp3dec", "audio_decoder.mp3" },
     { "OMX.google.vorbis.decoder", "vorbisdec", "audio_decoder.vorbis" },
+    { "OMX.google.opus.decoder", "opusdec", "audio_decoder.opus" },
     { "OMX.google.vp8.decoder", "vpxdec", "video_decoder.vp8" },
     { "OMX.google.vp9.decoder", "vpxdec", "video_decoder.vp9" },
     { "OMX.google.vp8.encoder", "vpxenc", "video_encoder.vp8" },
@@ -154,7 +155,7 @@
 
 OMX_ERRORTYPE SoftOMXPlugin::enumerateComponents(
         OMX_STRING name,
-        size_t size,
+        size_t /* size */,
         OMX_U32 index) {
     if (index >= kNumComponents) {
         return OMX_ErrorNoMore;
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index e368134..447b29e 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -11,6 +11,8 @@
 	$(TOP)/frameworks/av/media/libstagefright \
 	$(TOP)/frameworks/native/include/media/openmax
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE := omx_tests
 
 LOCAL_MODULE_TAGS := tests
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 44e4f9d..f4dfd6b 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -26,6 +26,7 @@
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
 #include <binder/MemoryDealer.h>
+#include <media/IMediaHTTPService.h>
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
@@ -242,7 +243,8 @@
 };
 
 static sp<MediaExtractor> CreateExtractorFromURI(const char *uri) {
-    sp<DataSource> source = DataSource::CreateFromURI(uri);
+    sp<DataSource> source =
+        DataSource::CreateFromURI(NULL /* httpService */, uri);
 
     if (source == NULL) {
         return NULL;
@@ -461,6 +463,7 @@
         { "audio_decoder.aac", "audio/mp4a-latm" },
         { "audio_decoder.mp3", "audio/mpeg" },
         { "audio_decoder.vorbis", "audio/vorbis" },
+        { "audio_decoder.opus", "audio/opus" },
         { "audio_decoder.g711alaw", MEDIA_MIMETYPE_AUDIO_G711_ALAW },
         { "audio_decoder.g711mlaw", MEDIA_MIMETYPE_AUDIO_G711_MLAW },
     };
@@ -493,6 +496,7 @@
         { "audio/mpeg",
           "file:///sdcard/media_api/music/MP3_48KHz_128kbps_s_1_17_CBR.mp3" },
         { "audio/vorbis", NULL },
+        { "audio/opus", NULL },
         { "video/x-vnd.on2.vp8",
           "file:///sdcard/media_api/video/big-buck-bunny_trailer.webm" },
         { MEDIA_MIMETYPE_AUDIO_G711_ALAW, "file:///sdcard/M1F1-Alaw-AFsp.wav" },
diff --git a/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp b/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp
index 4c9bf5b..dca5c89 100644
--- a/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp
@@ -34,7 +34,9 @@
 namespace android {
 
 AMPEG2TSAssembler::AMPEG2TSAssembler(
-        const sp<AMessage> &notify, const char *desc, const AString &params)
+        const sp<AMessage> &notify,
+        const char * /* desc */,
+        const AString & /* params */)
     : mNotifyMsg(notify),
       mNextExpectedSeqNoValid(false),
       mNextExpectedSeqNo(0) {
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 462c384..09f52bc 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -23,7 +23,7 @@
 #include "ARawAudioAssembler.h"
 #include "ASessionDescription.h"
 
-#include "avc_utils.h"
+#include "include/avc_utils.h"
 
 #include <ctype.h>
 
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 0d07043..c46d16f 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -114,7 +114,7 @@
     return (mFlags & kFlagEOS) != 0;
 }
 
-status_t ARTPWriter::start(MetaData *params) {
+status_t ARTPWriter::start(MetaData * /* params */) {
     Mutex::Autolock autoLock(mLock);
     if (mFlags & kFlagStarted) {
         return INVALID_OPERATION;
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 492bd4a..cc3b63c 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -33,7 +33,7 @@
 #include <openssl/md5.h>
 #include <sys/socket.h>
 
-#include "HTTPBase.h"
+#include "include/HTTPBase.h"
 
 namespace android {
 
diff --git a/media/libstagefright/rtsp/ARawAudioAssembler.cpp b/media/libstagefright/rtsp/ARawAudioAssembler.cpp
index 0da5dd2..167f7a4 100644
--- a/media/libstagefright/rtsp/ARawAudioAssembler.cpp
+++ b/media/libstagefright/rtsp/ARawAudioAssembler.cpp
@@ -34,7 +34,9 @@
 namespace android {
 
 ARawAudioAssembler::ARawAudioAssembler(
-        const sp<AMessage> &notify, const char *desc, const AString &params)
+        const sp<AMessage> &notify,
+        const char * /* desc */,
+        const AString & /* params */)
     : mNotifyMsg(notify),
       mNextExpectedSeqNoValid(false),
       mNextExpectedSeqNo(0) {
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index e77c69c..39eedc0 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -20,7 +20,7 @@
         SDPLoader.cpp               \
 
 LOCAL_C_INCLUDES:= \
-	$(TOP)/frameworks/av/media/libstagefright/include \
+	$(TOP)/frameworks/av/media/libstagefright \
 	$(TOP)/frameworks/native/include/media/openmax \
 	$(TOP)/external/openssl/include
 
@@ -30,6 +30,8 @@
     LOCAL_CFLAGS += -Wno-psabi
 endif
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_STATIC_LIBRARY)
 
 ################################################################################
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index e7580c2..f3dfc59 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -19,7 +19,11 @@
 #define MY_HANDLER_H_
 
 //#define LOG_NDEBUG 0
+
+#ifndef LOG_TAG
 #define LOG_TAG "MyHandler"
+#endif
+
 #include <utils/Log.h>
 
 #include "APacketSource.h"
@@ -42,6 +46,12 @@
 
 #include "HTTPBase.h"
 
+#if LOG_NDEBUG
+#define UNUSED_UNLESS_VERBOSE(x) (void)(x)
+#else
+#define UNUSED_UNLESS_VERBOSE(x)
+#endif
+
 // If no access units are received within 5 secs, assume that the rtp
 // stream has ended and signal end of stream.
 static int64_t kAccessUnitTimeoutUs = 10000000ll;
@@ -178,7 +188,7 @@
         mConn->connect(mOriginalSessionURL.c_str(), reply);
     }
 
-    AString getControlURL(sp<ASessionDescription> desc) {
+    AString getControlURL() {
         AString sessionLevelControlURL;
         if (mSessionDesc->findAttribute(
                 0,
@@ -556,7 +566,7 @@
                                 mBaseURL = tmp;
                             }
 
-                            mControlURL = getControlURL(mSessionDesc);
+                            mControlURL = getControlURL();
 
                             if (mSessionDesc->countTracks() < 2) {
                                 // There's no actual tracks in this session.
@@ -602,7 +612,7 @@
 
                         mSeekable = !isLiveStream(mSessionDesc);
 
-                        mControlURL = getControlURL(mSessionDesc);
+                        mControlURL = getControlURL();
 
                         if (mSessionDesc->countTracks() < 2) {
                             // There's no actual tracks in this session.
@@ -1816,6 +1826,8 @@
     bool addMediaTimestamp(
             int32_t trackIndex, const TrackInfo *track,
             const sp<ABuffer> &accessUnit) {
+        UNUSED_UNLESS_VERBOSE(trackIndex);
+
         uint32_t rtpTime;
         CHECK(accessUnit->meta()->findInt32(
                     "rtp-time", (int32_t *)&rtpTime));
diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp
index 3c7d82a..13e8da3 100644
--- a/media/libstagefright/rtsp/SDPLoader.cpp
+++ b/media/libstagefright/rtsp/SDPLoader.cpp
@@ -18,11 +18,13 @@
 #define LOG_TAG "SDPLoader"
 #include <utils/Log.h>
 
-#include "SDPLoader.h"
+#include "include/SDPLoader.h"
 
 #include "ASessionDescription.h"
-#include "HTTPBase.h"
 
+#include <media/IMediaHTTPConnection.h>
+#include <media/IMediaHTTPService.h>
+#include <media/stagefright/MediaHTTP.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 
@@ -30,22 +32,15 @@
 
 namespace android {
 
-SDPLoader::SDPLoader(const sp<AMessage> &notify, uint32_t flags, bool uidValid, uid_t uid)
+SDPLoader::SDPLoader(
+        const sp<AMessage> &notify,
+        uint32_t flags,
+        const sp<IMediaHTTPService> &httpService)
     : mNotify(notify),
       mFlags(flags),
-      mUIDValid(uidValid),
-      mUID(uid),
       mNetLooper(new ALooper),
       mCancelled(false),
-      mHTTPDataSource(
-              HTTPBase::Create(
-                  (mFlags & kFlagIncognito)
-                    ? HTTPBase::kFlagIncognito
-                    : 0)) {
-    if (mUIDValid) {
-        mHTTPDataSource->setUID(mUID);
-    }
-
+      mHTTPDataSource(new MediaHTTP(httpService->makeHTTPConnection())) {
     mNetLooper->setName("sdp net");
     mNetLooper->start(false /* runOnCallingThread */,
                       false /* canCallJava */,
@@ -130,7 +125,7 @@
         ssize_t readSize = mHTTPDataSource->readAt(0, buffer->data(), sdpSize);
 
         if (readSize < 0) {
-            ALOGE("Failed to read SDP, error code = %ld", readSize);
+            ALOGE("Failed to read SDP, error code = %d", readSize);
             err = UNKNOWN_ERROR;
         } else {
             desc = new ASessionDescription;
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
index 49ffcd6..a3093d0 100644
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -35,7 +35,6 @@
 #include <gui/SurfaceComposerClient.h>
 
 #include <binder/ProcessState.h>
-#include <ui/FramebufferNativeWindow.h>
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBufferGroup.h>
@@ -527,7 +526,8 @@
 }
 
 // Dequeuing and queuing the buffer without really filling it in.
-void SurfaceMediaSourceTest::oneBufferPassNoFill(int width, int height ) {
+void SurfaceMediaSourceTest::oneBufferPassNoFill(
+        int /* width */, int /* height  */) {
     ANativeWindowBuffer* anb;
     ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
     ASSERT_TRUE(anb != NULL);
@@ -746,9 +746,8 @@
     CHECK(fd >= 0);
 
     sp<MediaRecorder> mr = SurfaceMediaSourceGLTest::setUpMediaRecorder(fd,
-            VIDEO_SOURCE_GRALLOC_BUFFER,
-            OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth,
-            mYuvTexHeight, 30);
+            VIDEO_SOURCE_SURFACE, OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264,
+            mYuvTexWidth, mYuvTexHeight, 30);
     // get the reference to the surfacemediasource living in
     // mediaserver that is created by stagefrightrecorder
     sp<IGraphicBufferProducer> iST = mr->querySurfaceMediaSourceFromMediaServer();
@@ -880,7 +879,7 @@
     }
     CHECK(fd >= 0);
 
-    sp<MediaRecorder> mr = setUpMediaRecorder(fd, VIDEO_SOURCE_GRALLOC_BUFFER,
+    sp<MediaRecorder> mr = setUpMediaRecorder(fd, VIDEO_SOURCE_SURFACE,
             OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth, mYuvTexHeight, 30);
 
     // get the reference to the surfacemediasource living in
@@ -923,7 +922,7 @@
     }
     CHECK(fd >= 0);
 
-    sp<MediaRecorder> mr = setUpMediaRecorder(fd, VIDEO_SOURCE_GRALLOC_BUFFER,
+    sp<MediaRecorder> mr = setUpMediaRecorder(fd, VIDEO_SOURCE_SURFACE,
             OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth, mYuvTexHeight, 30);
 
     // get the reference to the surfacemediasource living in
diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk
index f099bbd..6a8b9fc 100644
--- a/media/libstagefright/timedtext/Android.mk
+++ b/media/libstagefright/timedtext/Android.mk
@@ -9,7 +9,8 @@
         TimedTextSRTSource.cpp    \
         TimedTextPlayer.cpp
 
-LOCAL_CFLAGS += -Wno-multichar
+LOCAL_CFLAGS += -Wno-multichar -Werror
+
 LOCAL_C_INCLUDES:= \
         $(TOP)/frameworks/av/include/media/stagefright/timedtext \
         $(TOP)/frameworks/av/media/libstagefright
diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp
index 12fd7f4..71aa21e 100644
--- a/media/libstagefright/timedtext/TimedTextDriver.cpp
+++ b/media/libstagefright/timedtext/TimedTextDriver.cpp
@@ -20,6 +20,7 @@
 
 #include <binder/IPCThreadState.h>
 
+#include <media/IMediaHTTPService.h>
 #include <media/mediaplayer.h>
 #include <media/MediaPlayerInterface.h>
 #include <media/stagefright/DataSource.h>
@@ -40,9 +41,11 @@
 namespace android {
 
 TimedTextDriver::TimedTextDriver(
-        const wp<MediaPlayerBase> &listener)
+        const wp<MediaPlayerBase> &listener,
+        const sp<IMediaHTTPService> &httpService)
     : mLooper(new ALooper),
       mListener(listener),
+      mHTTPService(httpService),
       mState(UNINITIALIZED),
       mCurrentTrackIndex(UINT_MAX) {
     mLooper->setName("TimedTextDriver");
@@ -207,7 +210,7 @@
     }
 
     sp<DataSource> dataSource =
-            DataSource::CreateFromURI(uri);
+            DataSource::CreateFromURI(mHTTPService, uri);
     return createOutOfBandTextSource(trackIndex, mimeType, dataSource);
 }
 
diff --git a/media/libstagefright/timedtext/TimedTextSource.h b/media/libstagefright/timedtext/TimedTextSource.h
index 756cc31..8c1c1cd 100644
--- a/media/libstagefright/timedtext/TimedTextSource.h
+++ b/media/libstagefright/timedtext/TimedTextSource.h
@@ -47,7 +47,7 @@
           int64_t *endTimeUs,
           Parcel *parcel,
           const MediaSource::ReadOptions *options = NULL) = 0;
-  virtual status_t extractGlobalDescriptions(Parcel *parcel) {
+  virtual status_t extractGlobalDescriptions(Parcel * /* parcel */) {
       return INVALID_OPERATION;
   }
   virtual sp<MetaData> getFormat();
diff --git a/media/libstagefright/timedtext/test/Android.mk b/media/libstagefright/timedtext/test/Android.mk
index a5e7ba2..9a9fde2 100644
--- a/media/libstagefright/timedtext/test/Android.mk
+++ b/media/libstagefright/timedtext/test/Android.mk
@@ -2,7 +2,6 @@
 
 # ================================================================
 # Unit tests for libstagefright_timedtext
-# See also /development/testrunner/test_defs.xml
 # ================================================================
 
 # ================================================================
@@ -18,10 +17,13 @@
 
 LOCAL_C_INCLUDES := \
     $(TOP)/external/expat/lib \
-    $(TOP)/frameworks/base/media/libstagefright/timedtext
+    $(TOP)/frameworks/av/media/libstagefright/timedtext
 
 LOCAL_SHARED_LIBRARIES := \
+    libbinder \
     libexpat \
-    libstagefright
+    libstagefright \
+    libstagefright_foundation \
+    libutils
 
 include $(BUILD_NATIVE_TEST)
diff --git a/media/libstagefright/webm/Android.mk b/media/libstagefright/webm/Android.mk
new file mode 100644
index 0000000..7081463
--- /dev/null
+++ b/media/libstagefright/webm/Android.mk
@@ -0,0 +1,23 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_CPPFLAGS += -D__STDINT_LIMITS \
+                  -Werror
+
+LOCAL_SRC_FILES:= EbmlUtil.cpp        \
+                  WebmElement.cpp     \
+                  WebmFrame.cpp       \
+                  WebmFrameThread.cpp \
+                  WebmWriter.cpp
+
+
+LOCAL_C_INCLUDES += $(TOP)/frameworks/av/include
+
+LOCAL_SHARED_LIBRARIES += libstagefright_foundation \
+                          libstagefright \
+                          libutils \
+                          liblog
+
+LOCAL_MODULE:= libstagefright_webm
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/webm/EbmlUtil.cpp b/media/libstagefright/webm/EbmlUtil.cpp
new file mode 100644
index 0000000..449fec6
--- /dev/null
+++ b/media/libstagefright/webm/EbmlUtil.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+namespace {
+
+// Table for Seal's algorithm for Number of Trailing Zeros. Hacker's Delight
+// online, Figure 5-18 (http://www.hackersdelight.org/revisions.pdf)
+// The entries whose value is -1 are never referenced.
+int NTZ_TABLE[] = {
+    32,  0,  1, 12,  2,  6, -1, 13,   3, -1,  7, -1, -1, -1, -1, 14,
+    10,  4, -1, -1,  8, -1, -1, 25,  -1, -1, -1, -1, -1, 21, 27, 15,
+    31, 11,  5, -1, -1, -1, -1, -1,   9, -1, -1, 24, -1, -1, 20, 26,
+    30, -1, -1, -1, -1, 23, -1, 19,  29, -1, 22, 18, 28, 17, 16, -1
+};
+
+int numberOfTrailingZeros32(int32_t i) {
+    uint32_t u = (i & -i) * 0x0450FBAF;
+    return NTZ_TABLE[(u) >> 26];
+}
+
+uint64_t highestOneBit(uint64_t n) {
+    n |= (n >> 1);
+    n |= (n >> 2);
+    n |= (n >> 4);
+    n |= (n >> 8);
+    n |= (n >> 16);
+    n |= (n >> 32);
+    return n - (n >> 1);
+}
+
+uint64_t _powerOf2(uint64_t u) {
+    uint64_t powerOf2 = highestOneBit(u);
+    return powerOf2 ? powerOf2 : 1;
+}
+
+// Based on Long.numberOfTrailingZeros in Long.java
+int numberOfTrailingZeros(uint64_t u) {
+    int32_t low = u;
+    return low !=0 ? numberOfTrailingZeros32(low)
+                   : 32 + numberOfTrailingZeros32((int32_t) (u >> 32));
+}
+}
+
+namespace webm {
+
+// Encode the id and/or size of an EBML element bytes by setting a leading length descriptor bit:
+//
+//   1xxxxxxx                                                                - 1-byte values
+//   01xxxxxx xxxxxxxx                                                       -
+//   001xxxxx xxxxxxxx xxxxxxxx                                              -
+//   0001xxxx xxxxxxxx xxxxxxxx xxxxxxxx                                     - ...
+//   00001xxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx                            -
+//   000001xx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx                   -
+//   0000001x xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx          -
+//   00000001 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx - 8-byte values
+//
+// This function uses the least the number of bytes possible.
+uint64_t encodeUnsigned(uint64_t u) {
+    uint64_t powerOf2 = _powerOf2(u);
+    if (u + 1 == powerOf2 << 1)
+        powerOf2 <<= 1;
+    int shiftWidth = (7 + numberOfTrailingZeros(powerOf2)) / 7 * 7;
+    long lengthDescriptor = 1 << shiftWidth;
+    return lengthDescriptor | u;
+}
+
+// Like above but pads the input value with leading zeros up to the specified width. The length
+// descriptor is calculated based on width.
+uint64_t encodeUnsigned(uint64_t u, int width) {
+    int shiftWidth = 7 * width;
+    uint64_t lengthDescriptor = 1;
+    lengthDescriptor <<= shiftWidth;
+    return lengthDescriptor | u;
+}
+
+// Calculate the length of an EBML coded id or size from its length descriptor.
+int sizeOf(uint64_t u) {
+    uint64_t powerOf2 = _powerOf2(u);
+    int unsignedLength = numberOfTrailingZeros(powerOf2) / 8 + 1;
+    return unsignedLength;
+}
+
+// Serialize an EBML coded id or size in big-endian order.
+int serializeCodedUnsigned(uint64_t u, uint8_t* bary) {
+    int unsignedLength = sizeOf(u);
+    for (int i = unsignedLength - 1; i >= 0; i--) {
+        bary[i] = u & 0xff;
+        u >>= 8;
+    }
+    return unsignedLength;
+}
+
+}
diff --git a/media/libstagefright/webm/EbmlUtil.h b/media/libstagefright/webm/EbmlUtil.h
new file mode 100644
index 0000000..eb9c37c
--- /dev/null
+++ b/media/libstagefright/webm/EbmlUtil.h
@@ -0,0 +1,50 @@
+/*
+ * 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 EBMLUTIL_H_
+#define EBMLUTIL_H_
+
+#include <stdint.h>
+
+namespace webm {
+
+// Encode the id and/or size of an EBML element bytes by setting a leading length descriptor bit:
+//
+//   1xxxxxxx                                                                - 1-byte values
+//   01xxxxxx xxxxxxxx                                                       -
+//   001xxxxx xxxxxxxx xxxxxxxx                                              -
+//   0001xxxx xxxxxxxx xxxxxxxx xxxxxxxx                                     - ...
+//   00001xxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx                            -
+//   000001xx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx                   -
+//   0000001x xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx          -
+//   00000001 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx - 8-byte values
+//
+// This function uses the least the number of bytes possible.
+uint64_t encodeUnsigned(uint64_t u);
+
+// Like above but pads the input value with leading zeros up to the specified width. The length
+// descriptor is calculated based on width.
+uint64_t encodeUnsigned(uint64_t u, int width);
+
+// Serialize an EBML coded id or size in big-endian order.
+int serializeCodedUnsigned(uint64_t u, uint8_t* bary);
+
+// Calculate the length of an EBML coded id or size from its length descriptor.
+int sizeOf(uint64_t u);
+
+}
+
+#endif /* EBMLUTIL_H_ */
diff --git a/media/libstagefright/webm/LinkedBlockingQueue.h b/media/libstagefright/webm/LinkedBlockingQueue.h
new file mode 100644
index 0000000..0b6a9a1
--- /dev/null
+++ b/media/libstagefright/webm/LinkedBlockingQueue.h
@@ -0,0 +1,79 @@
+/*
+ * 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 LINKEDBLOCKINGQUEUE_H_
+#define LINKEDBLOCKINGQUEUE_H_
+
+#include <utils/List.h>
+#include <utils/Mutex.h>
+#include <utils/Condition.h>
+
+namespace android {
+
+template<typename T>
+class LinkedBlockingQueue {
+    List<T> mList;
+    Mutex mLock;
+    Condition mContentAvailableCondition;
+
+    T front(bool remove) {
+        Mutex::Autolock autolock(mLock);
+        while (mList.empty()) {
+            mContentAvailableCondition.wait(mLock);
+        }
+        T e = *(mList.begin());
+        if (remove) {
+            mList.erase(mList.begin());
+        }
+        return e;
+    }
+
+    DISALLOW_EVIL_CONSTRUCTORS(LinkedBlockingQueue);
+
+public:
+    LinkedBlockingQueue() {
+    }
+
+    ~LinkedBlockingQueue() {
+    }
+
+    bool empty() {
+        Mutex::Autolock autolock(mLock);
+        return mList.empty();
+    }
+
+    void clear() {
+        Mutex::Autolock autolock(mLock);
+        mList.clear();
+    }
+
+    T peek() {
+        return front(false);
+    }
+
+    T take() {
+        return front(true);
+    }
+
+    void push(T e) {
+        Mutex::Autolock autolock(mLock);
+        mList.push_back(e);
+        mContentAvailableCondition.signal();
+    }
+};
+
+} /* namespace android */
+#endif /* LINKEDBLOCKINGQUEUE_H_ */
diff --git a/media/libstagefright/webm/WebmConstants.h b/media/libstagefright/webm/WebmConstants.h
new file mode 100644
index 0000000..c53f458
--- /dev/null
+++ b/media/libstagefright/webm/WebmConstants.h
@@ -0,0 +1,133 @@
+/*
+ * 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 WEBMCONSTANTS_H_
+#define WEBMCONSTANTS_H_
+
+#include <stdint.h>
+
+namespace webm {
+
+const int kMinEbmlVoidSize = 2;
+const int64_t kMaxMetaSeekSize = 64;
+const int64_t kMkvUnknownLength = 0x01ffffffffffffffl;
+
+// EBML element id's from http://matroska.org/technical/specs/index.html
+enum Mkv {
+    kMkvEbml = 0x1A45DFA3,
+    kMkvEbmlVersion = 0x4286,
+    kMkvEbmlReadVersion = 0x42F7,
+    kMkvEbmlMaxIdlength = 0x42F2,
+    kMkvEbmlMaxSizeLength = 0x42F3,
+    kMkvDocType = 0x4282,
+    kMkvDocTypeVersion = 0x4287,
+    kMkvDocTypeReadVersion = 0x4285,
+    kMkvVoid = 0xEC,
+    kMkvSignatureSlot = 0x1B538667,
+    kMkvSignatureAlgo = 0x7E8A,
+    kMkvSignatureHash = 0x7E9A,
+    kMkvSignaturePublicKey = 0x7EA5,
+    kMkvSignature = 0x7EB5,
+    kMkvSignatureElements = 0x7E5B,
+    kMkvSignatureElementList = 0x7E7B,
+    kMkvSignedElement = 0x6532,
+    kMkvSegment = 0x18538067,
+    kMkvSeekHead = 0x114D9B74,
+    kMkvSeek = 0x4DBB,
+    kMkvSeekId = 0x53AB,
+    kMkvSeekPosition = 0x53AC,
+    kMkvInfo = 0x1549A966,
+    kMkvTimecodeScale = 0x2AD7B1,
+    kMkvSegmentDuration = 0x4489,
+    kMkvDateUtc = 0x4461,
+    kMkvMuxingApp = 0x4D80,
+    kMkvWritingApp = 0x5741,
+    kMkvCluster = 0x1F43B675,
+    kMkvTimecode = 0xE7,
+    kMkvPrevSize = 0xAB,
+    kMkvBlockGroup = 0xA0,
+    kMkvBlock = 0xA1,
+    kMkvBlockAdditions = 0x75A1,
+    kMkvBlockMore = 0xA6,
+    kMkvBlockAddId = 0xEE,
+    kMkvBlockAdditional = 0xA5,
+    kMkvBlockDuration = 0x9B,
+    kMkvReferenceBlock = 0xFB,
+    kMkvLaceNumber = 0xCC,
+    kMkvSimpleBlock = 0xA3,
+    kMkvTracks = 0x1654AE6B,
+    kMkvTrackEntry = 0xAE,
+    kMkvTrackNumber = 0xD7,
+    kMkvTrackUid = 0x73C5,
+    kMkvTrackType = 0x83,
+    kMkvFlagEnabled = 0xB9,
+    kMkvFlagDefault = 0x88,
+    kMkvFlagForced = 0x55AA,
+    kMkvFlagLacing = 0x9C,
+    kMkvDefaultDuration = 0x23E383,
+    kMkvMaxBlockAdditionId = 0x55EE,
+    kMkvName = 0x536E,
+    kMkvLanguage = 0x22B59C,
+    kMkvCodecId = 0x86,
+    kMkvCodecPrivate = 0x63A2,
+    kMkvCodecName = 0x258688,
+    kMkvVideo = 0xE0,
+    kMkvFlagInterlaced = 0x9A,
+    kMkvStereoMode = 0x53B8,
+    kMkvAlphaMode = 0x53C0,
+    kMkvPixelWidth = 0xB0,
+    kMkvPixelHeight = 0xBA,
+    kMkvPixelCropBottom = 0x54AA,
+    kMkvPixelCropTop = 0x54BB,
+    kMkvPixelCropLeft = 0x54CC,
+    kMkvPixelCropRight = 0x54DD,
+    kMkvDisplayWidth = 0x54B0,
+    kMkvDisplayHeight = 0x54BA,
+    kMkvDisplayUnit = 0x54B2,
+    kMkvAspectRatioType = 0x54B3,
+    kMkvFrameRate = 0x2383E3,
+    kMkvAudio = 0xE1,
+    kMkvSamplingFrequency = 0xB5,
+    kMkvOutputSamplingFrequency = 0x78B5,
+    kMkvChannels = 0x9F,
+    kMkvBitDepth = 0x6264,
+    kMkvCues = 0x1C53BB6B,
+    kMkvCuePoint = 0xBB,
+    kMkvCueTime = 0xB3,
+    kMkvCueTrackPositions = 0xB7,
+    kMkvCueTrack = 0xF7,
+    kMkvCueClusterPosition = 0xF1,
+    kMkvCueBlockNumber = 0x5378
+};
+
+enum TrackTypes {
+    kInvalidType = -1,
+    kVideoType = 0x1,
+    kAudioType = 0x2,
+    kComplexType = 0x3,
+    kLogoType = 0x10,
+    kSubtitleType = 0x11,
+    kButtonsType = 0x12,
+    kControlType = 0x20
+};
+
+enum TrackNum {
+    kVideoTrackNum = 0x1,
+    kAudioTrackNum = 0x2
+};
+}
+
+#endif /* WEBMCONSTANTS_H_ */
diff --git a/media/libstagefright/webm/WebmElement.cpp b/media/libstagefright/webm/WebmElement.cpp
new file mode 100644
index 0000000..c978966
--- /dev/null
+++ b/media/libstagefright/webm/WebmElement.cpp
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "WebmElement"
+
+#include "EbmlUtil.h"
+#include "WebmElement.h"
+#include "WebmConstants.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <utils/Log.h>
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+using namespace android;
+using namespace webm;
+
+namespace {
+
+int64_t voidSize(int64_t totalSize) {
+    if (totalSize < 2) {
+        return -1;
+    }
+    if (totalSize < 9) {
+        return totalSize - 2;
+    }
+    return totalSize - 9;
+}
+
+uint64_t childrenSum(const List<sp<WebmElement> >& children) {
+    uint64_t total = 0;
+    for (List<sp<WebmElement> >::const_iterator it = children.begin();
+            it != children.end(); ++it) {
+        total += (*it)->totalSize();
+    }
+    return total;
+}
+
+void populateCommonTrackEntries(
+        int num,
+        uint64_t uid,
+        bool lacing,
+        const char *lang,
+        const char *codec,
+        TrackTypes type,
+        List<sp<WebmElement> > &ls) {
+    ls.push_back(new WebmUnsigned(kMkvTrackNumber, num));
+    ls.push_back(new WebmUnsigned(kMkvTrackUid, uid));
+    ls.push_back(new WebmUnsigned(kMkvFlagLacing, lacing));
+    ls.push_back(new WebmString(kMkvLanguage, lang));
+    ls.push_back(new WebmString(kMkvCodecId, codec));
+    ls.push_back(new WebmUnsigned(kMkvTrackType, type));
+}
+}
+
+namespace android {
+
+WebmElement::WebmElement(uint64_t id, uint64_t size)
+    : mId(id), mSize(size) {
+}
+
+WebmElement::~WebmElement() {
+}
+
+int WebmElement::serializePayloadSize(uint8_t *buf) {
+    return serializeCodedUnsigned(encodeUnsigned(mSize), buf);
+}
+
+uint64_t WebmElement::serializeInto(uint8_t *buf) {
+    uint8_t *cur = buf;
+    int head = serializeCodedUnsigned(mId, cur);
+    cur += head;
+    int neck = serializePayloadSize(cur);
+    cur += neck;
+    serializePayload(cur);
+    cur += mSize;
+    return cur - buf;
+}
+
+uint64_t WebmElement::totalSize() {
+    uint8_t buf[8];
+    //............... + sizeOf(encodeUnsigned(size))
+    return sizeOf(mId) + serializePayloadSize(buf) + mSize;
+}
+
+uint8_t *WebmElement::serialize(uint64_t& size) {
+    size = totalSize();
+    uint8_t *buf = new uint8_t[size];
+    serializeInto(buf);
+    return buf;
+}
+
+int WebmElement::write(int fd, uint64_t& size) {
+    uint8_t buf[8];
+    size = totalSize();
+    off64_t off = ::lseek64(fd, (size - 1), SEEK_CUR) - (size - 1);
+    ::write(fd, buf, 1); // extend file
+
+    off64_t curOff = off + size;
+    off64_t alignedOff = off & ~(::sysconf(_SC_PAGE_SIZE) - 1);
+    off64_t mapSize = curOff - alignedOff;
+    off64_t pageOff = off - alignedOff;
+    void *dst = ::mmap64(NULL, mapSize, PROT_WRITE, MAP_SHARED, fd, alignedOff);
+    if ((int) dst == -1) {
+        ALOGE("mmap64 failed; errno = %d", errno);
+        ALOGE("fd %d; flags: %o", fd, ::fcntl(fd, F_GETFL, 0));
+        return errno;
+    } else {
+        serializeInto((uint8_t*) dst + pageOff);
+        ::msync(dst, mapSize, MS_SYNC);
+        return ::munmap(dst, mapSize);
+    }
+}
+
+//=================================================================================================
+
+WebmUnsigned::WebmUnsigned(uint64_t id, uint64_t value)
+    : WebmElement(id, sizeOf(value)), mValue(value) {
+}
+
+void WebmUnsigned::serializePayload(uint8_t *buf) {
+    serializeCodedUnsigned(mValue, buf);
+}
+
+//=================================================================================================
+
+WebmFloat::WebmFloat(uint64_t id, double value)
+    : WebmElement(id, sizeof(double)), mValue(value) {
+}
+
+WebmFloat::WebmFloat(uint64_t id, float value)
+    : WebmElement(id, sizeof(float)), mValue(value) {
+}
+
+void WebmFloat::serializePayload(uint8_t *buf) {
+    uint64_t data;
+    if (mSize == sizeof(float)) {
+        float f = mValue;
+        data = *reinterpret_cast<const uint32_t*>(&f);
+    } else {
+        data = *reinterpret_cast<const uint64_t*>(&mValue);
+    }
+    for (int i = mSize - 1; i >= 0; --i) {
+        buf[i] = data & 0xff;
+        data >>= 8;
+    }
+}
+
+//=================================================================================================
+
+WebmBinary::WebmBinary(uint64_t id, const sp<ABuffer> &ref)
+    : WebmElement(id, ref->size()), mRef(ref) {
+}
+
+void WebmBinary::serializePayload(uint8_t *buf) {
+    memcpy(buf, mRef->data(), mRef->size());
+}
+
+//=================================================================================================
+
+WebmString::WebmString(uint64_t id, const char *str)
+    : WebmElement(id, strlen(str)), mStr(str) {
+}
+
+void WebmString::serializePayload(uint8_t *buf) {
+    memcpy(buf, mStr, strlen(mStr));
+}
+
+//=================================================================================================
+
+WebmSimpleBlock::WebmSimpleBlock(
+        int trackNum,
+        int16_t relTimecode,
+        bool key,
+        const sp<ABuffer>& orig)
+    // ............................ trackNum*1 + timecode*2 + flags*1
+    //                                ^^^
+    // Only the least significant byte of trackNum is encoded
+    : WebmElement(kMkvSimpleBlock, orig->size() + 4),
+      mTrackNum(trackNum),
+      mRelTimecode(relTimecode),
+      mKey(key),
+      mRef(orig) {
+}
+
+void WebmSimpleBlock::serializePayload(uint8_t *buf) {
+    serializeCodedUnsigned(encodeUnsigned(mTrackNum), buf);
+    buf[1] = (mRelTimecode & 0xff00) >> 8;
+    buf[2] = mRelTimecode & 0xff;
+    buf[3] = mKey ? 0x80 : 0;
+    memcpy(buf + 4, mRef->data(), mSize - 4);
+}
+
+//=================================================================================================
+
+EbmlVoid::EbmlVoid(uint64_t totalSize)
+    : WebmElement(kMkvVoid, voidSize(totalSize)),
+      mSizeWidth(totalSize - sizeOf(kMkvVoid) - voidSize(totalSize)) {
+    CHECK_GE(voidSize(totalSize), 0);
+}
+
+int EbmlVoid::serializePayloadSize(uint8_t *buf) {
+    return serializeCodedUnsigned(encodeUnsigned(mSize, mSizeWidth), buf);
+}
+
+void EbmlVoid::serializePayload(uint8_t *buf) {
+    ::memset(buf, 0, mSize);
+    return;
+}
+
+//=================================================================================================
+
+WebmMaster::WebmMaster(uint64_t id, const List<sp<WebmElement> >& children)
+    : WebmElement(id, childrenSum(children)), mChildren(children) {
+}
+
+WebmMaster::WebmMaster(uint64_t id)
+    : WebmElement(id, 0) {
+}
+
+int WebmMaster::serializePayloadSize(uint8_t *buf) {
+    if (mSize == 0){
+        return serializeCodedUnsigned(kMkvUnknownLength, buf);
+    }
+    return WebmElement::serializePayloadSize(buf);
+}
+
+void WebmMaster::serializePayload(uint8_t *buf) {
+    uint64_t off = 0;
+    for (List<sp<WebmElement> >::const_iterator it = mChildren.begin(); it != mChildren.end();
+            ++it) {
+        sp<WebmElement> child = (*it);
+        child->serializeInto(buf + off);
+        off += child->totalSize();
+    }
+}
+
+//=================================================================================================
+
+sp<WebmElement> WebmElement::CuePointEntry(uint64_t time, int track, uint64_t off) {
+    List<sp<WebmElement> > cuePointEntryFields;
+    cuePointEntryFields.push_back(new WebmUnsigned(kMkvCueTrack, track));
+    cuePointEntryFields.push_back(new WebmUnsigned(kMkvCueClusterPosition, off));
+    WebmElement *cueTrackPositions = new WebmMaster(kMkvCueTrackPositions, cuePointEntryFields);
+
+    cuePointEntryFields.clear();
+    cuePointEntryFields.push_back(new WebmUnsigned(kMkvCueTime, time));
+    cuePointEntryFields.push_back(cueTrackPositions);
+    return new WebmMaster(kMkvCuePoint, cuePointEntryFields);
+}
+
+sp<WebmElement> WebmElement::SeekEntry(uint64_t id, uint64_t off) {
+    List<sp<WebmElement> > seekEntryFields;
+    seekEntryFields.push_back(new WebmUnsigned(kMkvSeekId, id));
+    seekEntryFields.push_back(new WebmUnsigned(kMkvSeekPosition, off));
+    return new WebmMaster(kMkvSeek, seekEntryFields);
+}
+
+sp<WebmElement> WebmElement::EbmlHeader(
+        int ver,
+        int readVer,
+        int maxIdLen,
+        int maxSizeLen,
+        int docVer,
+        int docReadVer) {
+    List<sp<WebmElement> > headerFields;
+    headerFields.push_back(new WebmUnsigned(kMkvEbmlVersion, ver));
+    headerFields.push_back(new WebmUnsigned(kMkvEbmlReadVersion, readVer));
+    headerFields.push_back(new WebmUnsigned(kMkvEbmlMaxIdlength, maxIdLen));
+    headerFields.push_back(new WebmUnsigned(kMkvEbmlMaxSizeLength, maxSizeLen));
+    headerFields.push_back(new WebmString(kMkvDocType, "webm"));
+    headerFields.push_back(new WebmUnsigned(kMkvDocTypeVersion, docVer));
+    headerFields.push_back(new WebmUnsigned(kMkvDocTypeReadVersion, docReadVer));
+    return new WebmMaster(kMkvEbml, headerFields);
+}
+
+sp<WebmElement> WebmElement::SegmentInfo(uint64_t scale, double dur) {
+    List<sp<WebmElement> > segmentInfo;
+    // place duration first; easier to patch
+    segmentInfo.push_back(new WebmFloat(kMkvSegmentDuration, dur));
+    segmentInfo.push_back(new WebmUnsigned(kMkvTimecodeScale, scale));
+    segmentInfo.push_back(new WebmString(kMkvMuxingApp, "android"));
+    segmentInfo.push_back(new WebmString(kMkvWritingApp, "android"));
+    return new WebmMaster(kMkvInfo, segmentInfo);
+}
+
+sp<WebmElement> WebmElement::AudioTrackEntry(
+        int chans,
+        double rate,
+        const sp<ABuffer> &buf,
+        int bps,
+        uint64_t uid,
+        bool lacing,
+        const char *lang) {
+    if (uid == 0) {
+        uid = kAudioTrackNum;
+    }
+
+    List<sp<WebmElement> > trackEntryFields;
+    populateCommonTrackEntries(
+            kAudioTrackNum,
+            uid,
+            lacing,
+            lang,
+            "A_VORBIS",
+            kAudioType,
+            trackEntryFields);
+
+    List<sp<WebmElement> > audioInfo;
+    audioInfo.push_back(new WebmUnsigned(kMkvChannels, chans));
+    audioInfo.push_back(new WebmFloat(kMkvSamplingFrequency, rate));
+    if (bps) {
+        WebmElement *bitDepth = new WebmUnsigned(kMkvBitDepth, bps);
+        audioInfo.push_back(bitDepth);
+    }
+
+    trackEntryFields.push_back(new WebmMaster(kMkvAudio, audioInfo));
+    trackEntryFields.push_back(new WebmBinary(kMkvCodecPrivate, buf));
+    return new WebmMaster(kMkvTrackEntry, trackEntryFields);
+}
+
+sp<WebmElement> WebmElement::VideoTrackEntry(
+        uint64_t width,
+        uint64_t height,
+        uint64_t uid,
+        bool lacing,
+        const char *lang) {
+    if (uid == 0) {
+        uid = kVideoTrackNum;
+    }
+
+    List<sp<WebmElement> > trackEntryFields;
+    populateCommonTrackEntries(
+            kVideoTrackNum,
+            uid,
+            lacing,
+            lang,
+            "V_VP8",
+            kVideoType,
+            trackEntryFields);
+
+    List<sp<WebmElement> > videoInfo;
+    videoInfo.push_back(new WebmUnsigned(kMkvPixelWidth, width));
+    videoInfo.push_back(new WebmUnsigned(kMkvPixelHeight, height));
+
+    trackEntryFields.push_back(new WebmMaster(kMkvVideo, videoInfo));
+    return new WebmMaster(kMkvTrackEntry, trackEntryFields);
+}
+} /* namespace android */
diff --git a/media/libstagefright/webm/WebmElement.h b/media/libstagefright/webm/WebmElement.h
new file mode 100644
index 0000000..f19933e
--- /dev/null
+++ b/media/libstagefright/webm/WebmElement.h
@@ -0,0 +1,127 @@
+/*
+ * 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 WEBMELEMENT_H_
+#define WEBMELEMENT_H_
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <utils/List.h>
+
+namespace android {
+
+struct WebmElement : public LightRefBase<WebmElement> {
+    const uint64_t mId, mSize;
+
+    WebmElement(uint64_t id, uint64_t size);
+    virtual ~WebmElement();
+
+    virtual int serializePayloadSize(uint8_t *buf);
+    virtual void serializePayload(uint8_t *buf)=0;
+    uint64_t totalSize();
+    uint64_t serializeInto(uint8_t *buf);
+    uint8_t *serialize(uint64_t& size);
+    int write(int fd, uint64_t& size);
+
+    static sp<WebmElement> EbmlHeader(
+            int ver = 1,
+            int readVer = 1,
+            int maxIdLen = 4,
+            int maxSizeLen = 8,
+            int docVer = 2,
+            int docReadVer = 2);
+
+    static sp<WebmElement> SegmentInfo(uint64_t scale = 1000000, double dur = 0);
+
+    static sp<WebmElement> AudioTrackEntry(
+            int chans,
+            double rate,
+            const sp<ABuffer> &buf,
+            int bps = 0,
+            uint64_t uid = 0,
+            bool lacing = false,
+            const char *lang = "und");
+
+    static sp<WebmElement> VideoTrackEntry(
+            uint64_t width,
+            uint64_t height,
+            uint64_t uid = 0,
+            bool lacing = false,
+            const char *lang = "und");
+
+    static sp<WebmElement> SeekEntry(uint64_t id, uint64_t off);
+    static sp<WebmElement> CuePointEntry(uint64_t time, int track, uint64_t off);
+    static sp<WebmElement> SimpleBlock(
+            int trackNum,
+            int16_t timecode,
+            bool key,
+            const uint8_t *data,
+            uint64_t dataSize);
+};
+
+struct WebmUnsigned : public WebmElement {
+    WebmUnsigned(uint64_t id, uint64_t value);
+    const uint64_t mValue;
+    void serializePayload(uint8_t *buf);
+};
+
+struct WebmFloat : public WebmElement {
+    const double mValue;
+    WebmFloat(uint64_t id, float value);
+    WebmFloat(uint64_t id, double value);
+    void serializePayload(uint8_t *buf);
+};
+
+struct WebmBinary : public WebmElement {
+    const sp<ABuffer> mRef;
+    WebmBinary(uint64_t id, const sp<ABuffer> &ref);
+    void serializePayload(uint8_t *buf);
+};
+
+struct WebmString : public WebmElement {
+    const char *const mStr;
+    WebmString(uint64_t id, const char *str);
+    void serializePayload(uint8_t *buf);
+};
+
+struct WebmSimpleBlock : public WebmElement {
+    const int mTrackNum;
+    const int16_t mRelTimecode;
+    const bool mKey;
+    const sp<ABuffer> mRef;
+
+    WebmSimpleBlock(int trackNum, int16_t timecode, bool key, const sp<ABuffer>& orig);
+    void serializePayload(uint8_t *buf);
+};
+
+struct EbmlVoid : public WebmElement {
+    const uint64_t mSizeWidth;
+    EbmlVoid(uint64_t totalSize);
+    int serializePayloadSize(uint8_t *buf);
+    void serializePayload(uint8_t *buf);
+};
+
+struct WebmMaster : public WebmElement {
+    const List<sp<WebmElement> > mChildren;
+    WebmMaster(uint64_t id);
+    WebmMaster(uint64_t id, const List<sp<WebmElement> > &children);
+    int serializePayloadSize(uint8_t *buf);
+    void serializePayload(uint8_t *buf);
+};
+
+} /* namespace android */
+#endif /* WEBMELEMENT_H_ */
diff --git a/media/libstagefright/webm/WebmFrame.cpp b/media/libstagefright/webm/WebmFrame.cpp
new file mode 100644
index 0000000..e5134ed
--- /dev/null
+++ b/media/libstagefright/webm/WebmFrame.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "WebmFrame"
+
+#include "WebmFrame.h"
+#include "WebmConstants.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <unistd.h>
+
+using namespace android;
+using namespace webm;
+
+namespace {
+sp<ABuffer> toABuffer(MediaBuffer *mbuf) {
+    sp<ABuffer> abuf = new ABuffer(mbuf->range_length());
+    memcpy(abuf->data(), (uint8_t*) mbuf->data() + mbuf->range_offset(), mbuf->range_length());
+    return abuf;
+}
+}
+
+namespace android {
+
+const sp<WebmFrame> WebmFrame::EOS = new WebmFrame();
+
+WebmFrame::WebmFrame()
+    : mType(kInvalidType),
+      mKey(false),
+      mAbsTimecode(UINT64_MAX),
+      mData(new ABuffer(0)),
+      mEos(true) {
+}
+
+WebmFrame::WebmFrame(int type, bool key, uint64_t absTimecode, MediaBuffer *mbuf)
+    : mType(type),
+      mKey(key),
+      mAbsTimecode(absTimecode),
+      mData(toABuffer(mbuf)),
+      mEos(false) {
+}
+
+sp<WebmElement> WebmFrame::SimpleBlock(uint64_t baseTimecode) const {
+    return new WebmSimpleBlock(
+            mType == kVideoType ? kVideoTrackNum : kAudioTrackNum,
+            mAbsTimecode - baseTimecode,
+            mKey,
+            mData);
+}
+
+bool WebmFrame::operator<(const WebmFrame &other) const {
+    if (this->mEos) {
+        return false;
+    }
+    if (other.mEos) {
+        return true;
+    }
+    if (this->mAbsTimecode == other.mAbsTimecode) {
+        if (this->mType == kAudioType && other.mType == kVideoType) {
+            return true;
+        }
+        if (this->mType == kVideoType && other.mType == kAudioType) {
+            return false;
+        }
+        return false;
+    }
+    return this->mAbsTimecode < other.mAbsTimecode;
+}
+} /* namespace android */
diff --git a/media/libstagefright/webm/WebmFrame.h b/media/libstagefright/webm/WebmFrame.h
new file mode 100644
index 0000000..4f0b055
--- /dev/null
+++ b/media/libstagefright/webm/WebmFrame.h
@@ -0,0 +1,46 @@
+/*
+ * 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 WEBMFRAME_H_
+#define WEBMFRAME_H_
+
+#include "WebmElement.h"
+
+namespace android {
+
+struct WebmFrame : LightRefBase<WebmFrame> {
+public:
+    const int mType;
+    const bool mKey;
+    const uint64_t mAbsTimecode;
+    const sp<ABuffer> mData;
+    const bool mEos;
+
+    WebmFrame();
+    WebmFrame(int type, bool key, uint64_t absTimecode, MediaBuffer *buf);
+    ~WebmFrame() {}
+
+    sp<WebmElement> SimpleBlock(uint64_t baseTimecode) const;
+
+    bool operator<(const WebmFrame &other) const;
+
+    static const sp<WebmFrame> EOS;
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(WebmFrame);
+};
+
+} /* namespace android */
+#endif /* WEBMFRAME_H_ */
diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp
new file mode 100644
index 0000000..5addd3c
--- /dev/null
+++ b/media/libstagefright/webm/WebmFrameThread.cpp
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "WebmFrameThread"
+
+#include "WebmConstants.h"
+#include "WebmFrameThread.h"
+
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <utils/Log.h>
+#include <inttypes.h>
+
+using namespace webm;
+
+namespace android {
+
+void *WebmFrameThread::wrap(void *arg) {
+    WebmFrameThread *worker = reinterpret_cast<WebmFrameThread*>(arg);
+    worker->run();
+    return NULL;
+}
+
+status_t WebmFrameThread::start() {
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+    pthread_create(&mThread, &attr, WebmFrameThread::wrap, this);
+    pthread_attr_destroy(&attr);
+    return OK;
+}
+
+status_t WebmFrameThread::stop() {
+    void *status;
+    pthread_join(mThread, &status);
+    return (status_t) status;
+}
+
+//=================================================================================================
+
+WebmFrameSourceThread::WebmFrameSourceThread(
+    int type,
+    LinkedBlockingQueue<const sp<WebmFrame> >& sink)
+    : mType(type), mSink(sink) {
+}
+
+//=================================================================================================
+
+WebmFrameSinkThread::WebmFrameSinkThread(
+        const int& fd,
+        const uint64_t& off,
+        sp<WebmFrameSourceThread> videoThread,
+        sp<WebmFrameSourceThread> audioThread,
+        List<sp<WebmElement> >& cues)
+    : mFd(fd),
+      mSegmentDataStart(off),
+      mVideoFrames(videoThread->mSink),
+      mAudioFrames(audioThread->mSink),
+      mCues(cues),
+      mDone(true) {
+}
+
+WebmFrameSinkThread::WebmFrameSinkThread(
+        const int& fd,
+        const uint64_t& off,
+        LinkedBlockingQueue<const sp<WebmFrame> >& videoSource,
+        LinkedBlockingQueue<const sp<WebmFrame> >& audioSource,
+        List<sp<WebmElement> >& cues)
+    : mFd(fd),
+      mSegmentDataStart(off),
+      mVideoFrames(videoSource),
+      mAudioFrames(audioSource),
+      mCues(cues),
+      mDone(true) {
+}
+
+// Initializes a webm cluster with its starting timecode.
+//
+// frames:
+//   sequence of input audio/video frames received from the source.
+//
+// clusterTimecodeL:
+//   the starting timecode of the cluster; this is the timecode of the first
+//   frame since frames are ordered by timestamp.
+//
+// children:
+//   list to hold child elements in a webm cluster (start timecode and
+//   simple blocks).
+//
+// static
+void WebmFrameSinkThread::initCluster(
+    List<const sp<WebmFrame> >& frames,
+    uint64_t& clusterTimecodeL,
+    List<sp<WebmElement> >& children) {
+    CHECK(!frames.empty() && children.empty());
+
+    const sp<WebmFrame> f = *(frames.begin());
+    clusterTimecodeL = f->mAbsTimecode;
+    WebmUnsigned *clusterTimecode = new WebmUnsigned(kMkvTimecode, clusterTimecodeL);
+    children.clear();
+    children.push_back(clusterTimecode);
+}
+
+void WebmFrameSinkThread::writeCluster(List<sp<WebmElement> >& children) {
+    // children must contain at least one simpleblock and its timecode
+    CHECK_GE(children.size(), 2);
+
+    uint64_t size;
+    sp<WebmElement> cluster = new WebmMaster(kMkvCluster, children);
+    cluster->write(mFd, size);
+    children.clear();
+}
+
+// Write out (possibly multiple) webm cluster(s) from frames split on video key frames.
+//
+// last:
+//   current flush is triggered by EOS instead of a second outstanding video key frame.
+void WebmFrameSinkThread::flushFrames(List<const sp<WebmFrame> >& frames, bool last) {
+    if (frames.empty()) {
+        return;
+    }
+
+    uint64_t clusterTimecodeL;
+    List<sp<WebmElement> > children;
+    initCluster(frames, clusterTimecodeL, children);
+
+    uint64_t cueTime = clusterTimecodeL;
+    off_t fpos = ::lseek(mFd, 0, SEEK_CUR);
+    size_t n = frames.size();
+    if (!last) {
+        // If we are not flushing the last sequence of outstanding frames, flushFrames
+        // must have been called right after we have pushed a second outstanding video key
+        // frame (the last frame), which belongs to the next cluster; also hold back on
+        // flushing the second to last frame before we check its type. A audio frame
+        // should precede the aforementioned video key frame in the next sequence, a video
+        // frame should be the last frame in the current (to-be-flushed) sequence.
+        CHECK_GE(n, 2);
+        n -= 2;
+    }
+
+    for (size_t i = 0; i < n; i++) {
+        const sp<WebmFrame> f = *(frames.begin());
+        if (f->mType == kVideoType && f->mKey) {
+            cueTime = f->mAbsTimecode;
+        }
+
+        if (f->mAbsTimecode - clusterTimecodeL > INT16_MAX) {
+            writeCluster(children);
+            initCluster(frames, clusterTimecodeL, children);
+        }
+
+        frames.erase(frames.begin());
+        children.push_back(f->SimpleBlock(clusterTimecodeL));
+    }
+
+    // equivalent to last==false
+    if (!frames.empty()) {
+        // decide whether to write out the second to last frame.
+        const sp<WebmFrame> secondLastFrame = *(frames.begin());
+        if (secondLastFrame->mType == kVideoType) {
+            frames.erase(frames.begin());
+            children.push_back(secondLastFrame->SimpleBlock(clusterTimecodeL));
+        }
+    }
+
+    writeCluster(children);
+    sp<WebmElement> cuePoint = WebmElement::CuePointEntry(cueTime, 1, fpos - mSegmentDataStart);
+    mCues.push_back(cuePoint);
+}
+
+status_t WebmFrameSinkThread::start() {
+    mDone = false;
+    return WebmFrameThread::start();
+}
+
+status_t WebmFrameSinkThread::stop() {
+    mDone = true;
+    mVideoFrames.push(WebmFrame::EOS);
+    mAudioFrames.push(WebmFrame::EOS);
+    return WebmFrameThread::stop();
+}
+
+void WebmFrameSinkThread::run() {
+    int numVideoKeyFrames = 0;
+    List<const sp<WebmFrame> > outstandingFrames;
+    while (!mDone) {
+        ALOGV("wait v frame");
+        const sp<WebmFrame> videoFrame = mVideoFrames.peek();
+        ALOGV("v frame: %p", videoFrame.get());
+
+        ALOGV("wait a frame");
+        const sp<WebmFrame> audioFrame = mAudioFrames.peek();
+        ALOGV("a frame: %p", audioFrame.get());
+
+        if (videoFrame->mEos && audioFrame->mEos) {
+            break;
+        }
+
+        if (*audioFrame < *videoFrame) {
+            ALOGV("take a frame");
+            mAudioFrames.take();
+            outstandingFrames.push_back(audioFrame);
+        } else {
+            ALOGV("take v frame");
+            mVideoFrames.take();
+            outstandingFrames.push_back(videoFrame);
+            if (videoFrame->mKey)
+                numVideoKeyFrames++;
+        }
+
+        if (numVideoKeyFrames == 2) {
+            flushFrames(outstandingFrames, /* last = */ false);
+            numVideoKeyFrames--;
+        }
+    }
+    ALOGV("flushing last cluster (size %zu)", outstandingFrames.size());
+    flushFrames(outstandingFrames, /* last = */ true);
+    mDone = true;
+}
+
+//=================================================================================================
+
+static const int64_t kInitialDelayTimeUs = 700000LL;
+
+void WebmFrameMediaSourceThread::clearFlags() {
+    mDone = false;
+    mPaused = false;
+    mResumed = false;
+    mStarted = false;
+    mReachedEOS = false;
+}
+
+WebmFrameMediaSourceThread::WebmFrameMediaSourceThread(
+        const sp<MediaSource>& source,
+        int type,
+        LinkedBlockingQueue<const sp<WebmFrame> >& sink,
+        uint64_t timeCodeScale,
+        int64_t startTimeRealUs,
+        int32_t startTimeOffsetMs,
+        int numTracks,
+        bool realTimeRecording)
+    : WebmFrameSourceThread(type, sink),
+      mSource(source),
+      mTimeCodeScale(timeCodeScale),
+      mTrackDurationUs(0) {
+    clearFlags();
+    mStartTimeUs = startTimeRealUs;
+    if (realTimeRecording && numTracks > 1) {
+        /*
+         * Copied from MPEG4Writer
+         *
+         * This extra delay of accepting incoming audio/video signals
+         * helps to align a/v start time at the beginning of a recording
+         * session, and it also helps eliminate the "recording" sound for
+         * camcorder applications.
+         *
+         * If client does not set the start time offset, we fall back to
+         * use the default initial delay value.
+         */
+        int64_t startTimeOffsetUs = startTimeOffsetMs * 1000LL;
+        if (startTimeOffsetUs < 0) {  // Start time offset was not set
+            startTimeOffsetUs = kInitialDelayTimeUs;
+        }
+        mStartTimeUs += startTimeOffsetUs;
+        ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs);
+    }
+}
+
+status_t WebmFrameMediaSourceThread::start() {
+    sp<MetaData> meta = new MetaData;
+    meta->setInt64(kKeyTime, mStartTimeUs);
+    status_t err = mSource->start(meta.get());
+    if (err != OK) {
+        mDone = true;
+        mReachedEOS = true;
+        return err;
+    } else {
+        mStarted = true;
+        return WebmFrameThread::start();
+    }
+}
+
+status_t WebmFrameMediaSourceThread::resume() {
+    if (!mDone && mPaused) {
+        mPaused = false;
+        mResumed = true;
+    }
+    return OK;
+}
+
+status_t WebmFrameMediaSourceThread::pause() {
+    if (mStarted) {
+        mPaused = true;
+    }
+    return OK;
+}
+
+status_t WebmFrameMediaSourceThread::stop() {
+    if (mStarted) {
+        mStarted = false;
+        mDone = true;
+        mSource->stop();
+        return WebmFrameThread::stop();
+    }
+    return OK;
+}
+
+void WebmFrameMediaSourceThread::run() {
+    int32_t count = 0;
+    int64_t timestampUs = 0xdeadbeef;
+    int64_t lastTimestampUs = 0; // Previous sample time stamp
+    int64_t lastDurationUs = 0; // Previous sample duration
+    int64_t previousPausedDurationUs = 0;
+
+    const uint64_t kUninitialized = 0xffffffffffffffffL;
+    mStartTimeUs = kUninitialized;
+
+    status_t err = OK;
+    MediaBuffer *buffer;
+    while (!mDone && (err = mSource->read(&buffer, NULL)) == OK) {
+        if (buffer->range_length() == 0) {
+            buffer->release();
+            buffer = NULL;
+            continue;
+        }
+
+        sp<MetaData> md = buffer->meta_data();
+        CHECK(md->findInt64(kKeyTime, &timestampUs));
+        if (mStartTimeUs == kUninitialized) {
+            mStartTimeUs = timestampUs;
+        }
+        timestampUs -= mStartTimeUs;
+
+        if (mPaused && !mResumed) {
+            lastDurationUs = timestampUs - lastTimestampUs;
+            lastTimestampUs = timestampUs;
+            buffer->release();
+            buffer = NULL;
+            continue;
+        }
+        ++count;
+
+        // adjust time-stamps after pause/resume
+        if (mResumed) {
+            int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
+            CHECK_GE(durExcludingEarlierPausesUs, 0ll);
+            int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
+            CHECK_GE(pausedDurationUs, lastDurationUs);
+            previousPausedDurationUs += pausedDurationUs - lastDurationUs;
+            mResumed = false;
+        }
+        timestampUs -= previousPausedDurationUs;
+        CHECK_GE(timestampUs, 0ll);
+
+        int32_t isSync = false;
+        md->findInt32(kKeyIsSyncFrame, &isSync);
+        const sp<WebmFrame> f = new WebmFrame(
+            mType,
+            isSync,
+            timestampUs * 1000 / mTimeCodeScale,
+            buffer);
+        mSink.push(f);
+
+        ALOGV(
+            "%s %s frame at %" PRId64 " size %zu\n",
+            mType == kVideoType ? "video" : "audio",
+            isSync ? "I" : "P",
+            timestampUs * 1000 / mTimeCodeScale,
+            buffer->range_length());
+
+        buffer->release();
+        buffer = NULL;
+
+        if (timestampUs > mTrackDurationUs) {
+            mTrackDurationUs = timestampUs;
+        }
+        lastDurationUs = timestampUs - lastTimestampUs;
+        lastTimestampUs = timestampUs;
+    }
+
+    mTrackDurationUs += lastDurationUs;
+    mSink.push(WebmFrame::EOS);
+}
+}
diff --git a/media/libstagefright/webm/WebmFrameThread.h b/media/libstagefright/webm/WebmFrameThread.h
new file mode 100644
index 0000000..d65d9b7
--- /dev/null
+++ b/media/libstagefright/webm/WebmFrameThread.h
@@ -0,0 +1,160 @@
+/*
+ * 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 WEBMFRAMETHREAD_H_
+#define WEBMFRAMETHREAD_H_
+
+#include "WebmFrame.h"
+#include "LinkedBlockingQueue.h"
+
+#include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaSource.h>
+
+#include <utils/List.h>
+#include <utils/Errors.h>
+
+#include <pthread.h>
+
+namespace android {
+
+class WebmFrameThread : public LightRefBase<WebmFrameThread> {
+public:
+    virtual void run() = 0;
+    virtual bool running() { return false; }
+    virtual status_t start();
+    virtual status_t pause() { return OK; }
+    virtual status_t resume() { return OK; }
+    virtual status_t stop();
+    virtual ~WebmFrameThread() { stop(); }
+    static void *wrap(void *arg);
+
+protected:
+    WebmFrameThread()
+        : mThread(0) {
+    }
+
+private:
+    pthread_t mThread;
+    DISALLOW_EVIL_CONSTRUCTORS(WebmFrameThread);
+};
+
+//=================================================================================================
+
+class WebmFrameSourceThread;
+class WebmFrameSinkThread : public WebmFrameThread {
+public:
+    WebmFrameSinkThread(
+            const int& fd,
+            const uint64_t& off,
+            sp<WebmFrameSourceThread> videoThread,
+            sp<WebmFrameSourceThread> audioThread,
+            List<sp<WebmElement> >& cues);
+
+    WebmFrameSinkThread(
+            const int& fd,
+            const uint64_t& off,
+            LinkedBlockingQueue<const sp<WebmFrame> >& videoSource,
+            LinkedBlockingQueue<const sp<WebmFrame> >& audioSource,
+            List<sp<WebmElement> >& cues);
+
+    void run();
+    bool running() {
+        return !mDone;
+    }
+    status_t start();
+    status_t stop();
+
+private:
+    const int& mFd;
+    const uint64_t& mSegmentDataStart;
+    LinkedBlockingQueue<const sp<WebmFrame> >& mVideoFrames;
+    LinkedBlockingQueue<const sp<WebmFrame> >& mAudioFrames;
+    List<sp<WebmElement> >& mCues;
+
+    volatile bool mDone;
+
+    static void initCluster(
+            List<const sp<WebmFrame> >& frames,
+            uint64_t& clusterTimecodeL,
+            List<sp<WebmElement> >& children);
+    void writeCluster(List<sp<WebmElement> >& children);
+    void flushFrames(List<const sp<WebmFrame> >& frames, bool last);
+};
+
+//=================================================================================================
+
+class WebmFrameSourceThread : public WebmFrameThread {
+public:
+    WebmFrameSourceThread(int type, LinkedBlockingQueue<const sp<WebmFrame> >& sink);
+    virtual int64_t getDurationUs() = 0;
+protected:
+    const int mType;
+    LinkedBlockingQueue<const sp<WebmFrame> >& mSink;
+
+    friend class WebmFrameSinkThread;
+};
+
+//=================================================================================================
+
+class WebmFrameEmptySourceThread : public WebmFrameSourceThread {
+public:
+    WebmFrameEmptySourceThread(int type, LinkedBlockingQueue<const sp<WebmFrame> >& sink)
+        : WebmFrameSourceThread(type, sink) {
+    }
+    void run() { mSink.push(WebmFrame::EOS); }
+    int64_t getDurationUs() { return 0; }
+};
+
+//=================================================================================================
+
+class WebmFrameMediaSourceThread: public WebmFrameSourceThread {
+public:
+    WebmFrameMediaSourceThread(
+            const sp<MediaSource>& source,
+            int type,
+            LinkedBlockingQueue<const sp<WebmFrame> >& sink,
+            uint64_t timeCodeScale,
+            int64_t startTimeRealUs,
+            int32_t startTimeOffsetMs,
+            int numPeers,
+            bool realTimeRecording);
+
+    void run();
+    status_t start();
+    status_t resume();
+    status_t pause();
+    status_t stop();
+    int64_t getDurationUs() {
+        return mTrackDurationUs;
+    }
+
+private:
+    const sp<MediaSource> mSource;
+    const uint64_t mTimeCodeScale;
+    uint64_t mStartTimeUs;
+
+    volatile bool mDone;
+    volatile bool mPaused;
+    volatile bool mResumed;
+    volatile bool mStarted;
+    volatile bool mReachedEOS;
+    int64_t mTrackDurationUs;
+
+    void clearFlags();
+};
+} /* namespace android */
+
+#endif /* WEBMFRAMETHREAD_H_ */
diff --git a/media/libstagefright/webm/WebmWriter.cpp b/media/libstagefright/webm/WebmWriter.cpp
new file mode 100644
index 0000000..03cf92a
--- /dev/null
+++ b/media/libstagefright/webm/WebmWriter.cpp
@@ -0,0 +1,551 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "WebmWriter"
+
+#include "EbmlUtil.h"
+#include "WebmWriter.h"
+
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <utils/Errors.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+
+using namespace webm;
+
+namespace {
+size_t XiphLaceCodeLen(size_t size) {
+    return size / 0xff + 1;
+}
+
+size_t XiphLaceEnc(uint8_t *buf, size_t size) {
+    size_t i;
+    for (i = 0; size >= 0xff; ++i, size -= 0xff) {
+        buf[i] = 0xff;
+    }
+    buf[i++] = size;
+    return i;
+}
+}
+
+namespace android {
+
+static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024;
+
+WebmWriter::WebmWriter(int fd)
+    : mFd(dup(fd)),
+      mInitCheck(mFd < 0 ? NO_INIT : OK),
+      mTimeCodeScale(1000000),
+      mStartTimestampUs(0),
+      mStartTimeOffsetMs(0),
+      mSegmentOffset(0),
+      mSegmentDataStart(0),
+      mInfoOffset(0),
+      mInfoSize(0),
+      mTracksOffset(0),
+      mCuesOffset(0),
+      mPaused(false),
+      mStarted(false),
+      mIsFileSizeLimitExplicitlyRequested(false),
+      mIsRealTimeRecording(false),
+      mStreamableFile(true),
+      mEstimatedCuesSize(0) {
+    mStreams[kAudioIndex] = WebmStream(kAudioType, "Audio", &WebmWriter::audioTrack);
+    mStreams[kVideoIndex] = WebmStream(kVideoType, "Video", &WebmWriter::videoTrack);
+    mSinkThread = new WebmFrameSinkThread(
+            mFd,
+            mSegmentDataStart,
+            mStreams[kVideoIndex].mSink,
+            mStreams[kAudioIndex].mSink,
+            mCuePoints);
+}
+
+WebmWriter::WebmWriter(const char *filename)
+    : mInitCheck(NO_INIT),
+      mTimeCodeScale(1000000),
+      mStartTimestampUs(0),
+      mStartTimeOffsetMs(0),
+      mSegmentOffset(0),
+      mSegmentDataStart(0),
+      mInfoOffset(0),
+      mInfoSize(0),
+      mTracksOffset(0),
+      mCuesOffset(0),
+      mPaused(false),
+      mStarted(false),
+      mIsFileSizeLimitExplicitlyRequested(false),
+      mIsRealTimeRecording(false),
+      mStreamableFile(true),
+      mEstimatedCuesSize(0) {
+    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+    if (mFd >= 0) {
+        ALOGV("fd %d; flags: %o", mFd, fcntl(mFd, F_GETFL, 0));
+        mInitCheck = OK;
+    }
+    mStreams[kAudioIndex] = WebmStream(kAudioType, "Audio", &WebmWriter::audioTrack);
+    mStreams[kVideoIndex] = WebmStream(kVideoType, "Video", &WebmWriter::videoTrack);
+    mSinkThread = new WebmFrameSinkThread(
+            mFd,
+            mSegmentDataStart,
+            mStreams[kVideoIndex].mSink,
+            mStreams[kAudioIndex].mSink,
+            mCuePoints);
+}
+
+// static
+sp<WebmElement> WebmWriter::videoTrack(const sp<MetaData>& md) {
+    int32_t width, height;
+    CHECK(md->findInt32(kKeyWidth, &width));
+    CHECK(md->findInt32(kKeyHeight, &height));
+    return WebmElement::VideoTrackEntry(width, height);
+}
+
+// static
+sp<WebmElement> WebmWriter::audioTrack(const sp<MetaData>& md) {
+    int32_t nChannels, samplerate;
+    uint32_t type;
+    const void *headerData1;
+    const char headerData2[] = { 3, 'v', 'o', 'r', 'b', 'i', 's', 7, 0, 0, 0,
+            'a', 'n', 'd', 'r', 'o', 'i', 'd', 0, 0, 0, 0, 1 };
+    const void *headerData3;
+    size_t headerSize1, headerSize2 = sizeof(headerData2), headerSize3;
+
+    CHECK(md->findInt32(kKeyChannelCount, &nChannels));
+    CHECK(md->findInt32(kKeySampleRate, &samplerate));
+    CHECK(md->findData(kKeyVorbisInfo, &type, &headerData1, &headerSize1));
+    CHECK(md->findData(kKeyVorbisBooks, &type, &headerData3, &headerSize3));
+
+    size_t codecPrivateSize = 1;
+    codecPrivateSize += XiphLaceCodeLen(headerSize1);
+    codecPrivateSize += XiphLaceCodeLen(headerSize2);
+    codecPrivateSize += headerSize1 + headerSize2 + headerSize3;
+
+    off_t off = 0;
+    sp<ABuffer> codecPrivateBuf = new ABuffer(codecPrivateSize);
+    uint8_t *codecPrivateData = codecPrivateBuf->data();
+    codecPrivateData[off++] = 2;
+
+    off += XiphLaceEnc(codecPrivateData + off, headerSize1);
+    off += XiphLaceEnc(codecPrivateData + off, headerSize2);
+
+    memcpy(codecPrivateData + off, headerData1, headerSize1);
+    off += headerSize1;
+    memcpy(codecPrivateData + off, headerData2, headerSize2);
+    off += headerSize2;
+    memcpy(codecPrivateData + off, headerData3, headerSize3);
+
+    sp<WebmElement> entry = WebmElement::AudioTrackEntry(
+            nChannels,
+            samplerate,
+            codecPrivateBuf);
+    return entry;
+}
+
+size_t WebmWriter::numTracks() {
+    Mutex::Autolock autolock(mLock);
+
+    size_t numTracks = 0;
+    for (size_t i = 0; i < kMaxStreams; ++i) {
+        if (mStreams[i].mTrackEntry != NULL) {
+            numTracks++;
+        }
+    }
+
+    return numTracks;
+}
+
+uint64_t WebmWriter::estimateCuesSize(int32_t bitRate) {
+    // This implementation is based on estimateMoovBoxSize in MPEG4Writer.
+    //
+    // Statistical analysis shows that metadata usually accounts
+    // for a small portion of the total file size, usually < 0.6%.
+
+    // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2,
+    // where 1MB is the common file size limit for MMS application.
+    // The default MAX _MOOV_BOX_SIZE value is based on about 3
+    // minute video recording with a bit rate about 3 Mbps, because
+    // statistics also show that most of the video captured are going
+    // to be less than 3 minutes.
+
+    // If the estimation is wrong, we will pay the price of wasting
+    // some reserved space. This should not happen so often statistically.
+    static const int32_t factor = 2;
+    static const int64_t MIN_CUES_SIZE = 3 * 1024;  // 3 KB
+    static const int64_t MAX_CUES_SIZE = (180 * 3000000 * 6LL / 8000);
+    int64_t size = MIN_CUES_SIZE;
+
+    // Max file size limit is set
+    if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
+        size = mMaxFileSizeLimitBytes * 6 / 1000;
+    }
+
+    // Max file duration limit is set
+    if (mMaxFileDurationLimitUs != 0) {
+        if (bitRate > 0) {
+            int64_t size2 = ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000);
+            if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
+                // When both file size and duration limits are set,
+                // we use the smaller limit of the two.
+                if (size > size2) {
+                    size = size2;
+                }
+            } else {
+                // Only max file duration limit is set
+                size = size2;
+            }
+        }
+    }
+
+    if (size < MIN_CUES_SIZE) {
+        size = MIN_CUES_SIZE;
+    }
+
+    // Any long duration recording will be probably end up with
+    // non-streamable webm file.
+    if (size > MAX_CUES_SIZE) {
+        size = MAX_CUES_SIZE;
+    }
+
+    ALOGV("limits: %" PRId64 "/%" PRId64 " bytes/us,"
+            " bit rate: %d bps and the estimated cues size %" PRId64 " bytes",
+            mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
+    return factor * size;
+}
+
+void WebmWriter::initStream(size_t idx) {
+    if (mStreams[idx].mThread != NULL) {
+        return;
+    }
+    if (mStreams[idx].mSource == NULL) {
+        ALOGV("adding dummy source ... ");
+        mStreams[idx].mThread = new WebmFrameEmptySourceThread(
+                mStreams[idx].mType, mStreams[idx].mSink);
+    } else {
+        ALOGV("adding source %p", mStreams[idx].mSource.get());
+        mStreams[idx].mThread = new WebmFrameMediaSourceThread(
+                mStreams[idx].mSource,
+                mStreams[idx].mType,
+                mStreams[idx].mSink,
+                mTimeCodeScale,
+                mStartTimestampUs,
+                mStartTimeOffsetMs,
+                numTracks(),
+                mIsRealTimeRecording);
+    }
+}
+
+void WebmWriter::release() {
+    close(mFd);
+    mFd = -1;
+    mInitCheck = NO_INIT;
+    mStarted = false;
+}
+
+status_t WebmWriter::reset() {
+    if (mInitCheck != OK) {
+        return OK;
+    } else {
+        if (!mStarted) {
+            release();
+            return OK;
+        }
+    }
+
+    status_t err = OK;
+    int64_t maxDurationUs = 0;
+    int64_t minDurationUs = 0x7fffffffffffffffLL;
+    for (int i = 0; i < kMaxStreams; ++i) {
+        if (mStreams[i].mThread == NULL) {
+            continue;
+        }
+
+        status_t status = mStreams[i].mThread->stop();
+        if (err == OK && status != OK) {
+            err = status;
+        }
+
+        int64_t durationUs = mStreams[i].mThread->getDurationUs();
+        if (durationUs > maxDurationUs) {
+            maxDurationUs = durationUs;
+        }
+        if (durationUs < minDurationUs) {
+            minDurationUs = durationUs;
+        }
+    }
+
+    if (numTracks() > 1) {
+        ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us", minDurationUs, maxDurationUs);
+    }
+
+    mSinkThread->stop();
+
+    // Do not write out movie header on error.
+    if (err != OK) {
+        release();
+        return err;
+    }
+
+    sp<WebmElement> cues = new WebmMaster(kMkvCues, mCuePoints);
+    uint64_t cuesSize = cues->totalSize();
+    // TRICKY Even when the cues do fit in the space we reserved, if they do not fit
+    // perfectly, we still need to check if there is enough "extra space" to write an
+    // EBML void element.
+    if (cuesSize != mEstimatedCuesSize && cuesSize > mEstimatedCuesSize - kMinEbmlVoidSize) {
+        mCuesOffset = ::lseek(mFd, 0, SEEK_CUR);
+        cues->write(mFd, cuesSize);
+    } else {
+        uint64_t spaceSize;
+        ::lseek(mFd, mCuesOffset, SEEK_SET);
+        cues->write(mFd, cuesSize);
+        sp<WebmElement> space = new EbmlVoid(mEstimatedCuesSize - cuesSize);
+        space->write(mFd, spaceSize);
+    }
+
+    mCuePoints.clear();
+    mStreams[kVideoIndex].mSink.clear();
+    mStreams[kAudioIndex].mSink.clear();
+
+    uint8_t bary[sizeof(uint64_t)];
+    uint64_t totalSize = ::lseek(mFd, 0, SEEK_END);
+    uint64_t segmentSize = totalSize - mSegmentDataStart;
+    ::lseek(mFd, mSegmentOffset + sizeOf(kMkvSegment), SEEK_SET);
+    uint64_t segmentSizeCoded = encodeUnsigned(segmentSize, sizeOf(kMkvUnknownLength));
+    serializeCodedUnsigned(segmentSizeCoded, bary);
+    ::write(mFd, bary, sizeOf(kMkvUnknownLength));
+
+    uint64_t size;
+    uint64_t durationOffset = mInfoOffset + sizeOf(kMkvInfo) + sizeOf(mInfoSize)
+        + sizeOf(kMkvSegmentDuration) + sizeOf(sizeof(double));
+    sp<WebmElement> duration = new WebmFloat(
+            kMkvSegmentDuration,
+            (double) (maxDurationUs * 1000 / mTimeCodeScale));
+    duration->serializePayload(bary);
+    ::lseek(mFd, durationOffset, SEEK_SET);
+    ::write(mFd, bary, sizeof(double));
+
+    List<sp<WebmElement> > seekEntries;
+    seekEntries.push_back(WebmElement::SeekEntry(kMkvInfo, mInfoOffset - mSegmentDataStart));
+    seekEntries.push_back(WebmElement::SeekEntry(kMkvTracks, mTracksOffset - mSegmentDataStart));
+    seekEntries.push_back(WebmElement::SeekEntry(kMkvCues, mCuesOffset - mSegmentDataStart));
+    sp<WebmElement> seekHead = new WebmMaster(kMkvSeekHead, seekEntries);
+
+    uint64_t metaSeekSize;
+    ::lseek(mFd, mSegmentDataStart, SEEK_SET);
+    seekHead->write(mFd, metaSeekSize);
+
+    uint64_t spaceSize;
+    sp<WebmElement> space = new EbmlVoid(kMaxMetaSeekSize - metaSeekSize);
+    space->write(mFd, spaceSize);
+
+    release();
+    return err;
+}
+
+status_t WebmWriter::addSource(const sp<MediaSource> &source) {
+    Mutex::Autolock l(mLock);
+    if (mStarted) {
+        ALOGE("Attempt to add source AFTER recording is started");
+        return UNKNOWN_ERROR;
+    }
+
+    // At most 2 tracks can be supported.
+    if (mStreams[kVideoIndex].mTrackEntry != NULL
+            && mStreams[kAudioIndex].mTrackEntry != NULL) {
+        ALOGE("Too many tracks (2) to add");
+        return ERROR_UNSUPPORTED;
+    }
+
+    CHECK(source != NULL);
+
+    // A track of type other than video or audio is not supported.
+    const char *mime;
+    source->getFormat()->findCString(kKeyMIMEType, &mime);
+    const char *vp8 = MEDIA_MIMETYPE_VIDEO_VP8;
+    const char *vorbis = MEDIA_MIMETYPE_AUDIO_VORBIS;
+
+    size_t streamIndex;
+    if (!strncasecmp(mime, vp8, strlen(vp8))) {
+        streamIndex = kVideoIndex;
+    } else if (!strncasecmp(mime, vorbis, strlen(vorbis))) {
+        streamIndex = kAudioIndex;
+    } else {
+        ALOGE("Track (%s) other than %s or %s is not supported", mime, vp8, vorbis);
+        return ERROR_UNSUPPORTED;
+    }
+
+    // No more than one video or one audio track is supported.
+    if (mStreams[streamIndex].mTrackEntry != NULL) {
+        ALOGE("%s track already exists", mStreams[streamIndex].mName);
+        return ERROR_UNSUPPORTED;
+    }
+
+    // This is the first track of either audio or video.
+    // Go ahead to add the track.
+    mStreams[streamIndex].mSource = source;
+    mStreams[streamIndex].mTrackEntry = mStreams[streamIndex].mMakeTrack(source->getFormat());
+
+    return OK;
+}
+
+status_t WebmWriter::start(MetaData *params) {
+    if (mInitCheck != OK) {
+        return UNKNOWN_ERROR;
+    }
+
+    if (mStreams[kVideoIndex].mTrackEntry == NULL
+            && mStreams[kAudioIndex].mTrackEntry == NULL) {
+        ALOGE("No source added");
+        return INVALID_OPERATION;
+    }
+
+    if (mMaxFileSizeLimitBytes != 0) {
+        mIsFileSizeLimitExplicitlyRequested = true;
+    }
+
+    if (params) {
+        int32_t isRealTimeRecording;
+        params->findInt32(kKeyRealTimeRecording, &isRealTimeRecording);
+        mIsRealTimeRecording = isRealTimeRecording;
+    }
+
+    if (mStarted) {
+        if (mPaused) {
+            mPaused = false;
+            mStreams[kAudioIndex].mThread->resume();
+            mStreams[kVideoIndex].mThread->resume();
+        }
+        return OK;
+    }
+
+    if (params) {
+        int32_t tcsl;
+        if (params->findInt32(kKeyTimeScale, &tcsl)) {
+            mTimeCodeScale = tcsl;
+        }
+    }
+    CHECK_GT(mTimeCodeScale, 0);
+    ALOGV("movie time scale: %" PRIu64, mTimeCodeScale);
+
+    /*
+     * When the requested file size limit is small, the priority
+     * is to meet the file size limit requirement, rather than
+     * to make the file streamable. mStreamableFile does not tell
+     * whether the actual recorded file is streamable or not.
+     */
+    mStreamableFile = (!mMaxFileSizeLimitBytes)
+        || (mMaxFileSizeLimitBytes >= kMinStreamableFileSizeInBytes);
+
+    /*
+     * Write various metadata.
+     */
+    sp<WebmElement> ebml, segment, info, seekHead, tracks, cues;
+    ebml = WebmElement::EbmlHeader();
+    segment = new WebmMaster(kMkvSegment);
+    seekHead = new EbmlVoid(kMaxMetaSeekSize);
+    info = WebmElement::SegmentInfo(mTimeCodeScale, 0);
+
+    List<sp<WebmElement> > children;
+    for (size_t i = 0; i < kMaxStreams; ++i) {
+        if (mStreams[i].mTrackEntry != NULL) {
+            children.push_back(mStreams[i].mTrackEntry);
+        }
+    }
+    tracks = new WebmMaster(kMkvTracks, children);
+
+    if (!mStreamableFile) {
+        cues = NULL;
+    } else {
+        int32_t bitRate = -1;
+        if (params) {
+            params->findInt32(kKeyBitRate, &bitRate);
+        }
+        mEstimatedCuesSize = estimateCuesSize(bitRate);
+        CHECK_GE(mEstimatedCuesSize, 8);
+        cues = new EbmlVoid(mEstimatedCuesSize);
+    }
+
+    sp<WebmElement> elems[] = { ebml, segment, seekHead, info, tracks, cues };
+    size_t nElems = sizeof(elems) / sizeof(elems[0]);
+    uint64_t offsets[nElems];
+    uint64_t sizes[nElems];
+    for (uint32_t i = 0; i < nElems; i++) {
+        WebmElement *e = elems[i].get();
+        if (!e) {
+            continue;
+        }
+
+        uint64_t size;
+        offsets[i] = ::lseek(mFd, 0, SEEK_CUR);
+        sizes[i] = e->mSize;
+        e->write(mFd, size);
+    }
+
+    mSegmentOffset = offsets[1];
+    mSegmentDataStart = offsets[2];
+    mInfoOffset = offsets[3];
+    mInfoSize = sizes[3];
+    mTracksOffset = offsets[4];
+    mCuesOffset = offsets[5];
+
+    // start threads
+    if (params) {
+        params->findInt64(kKeyTime, &mStartTimestampUs);
+    }
+
+    initStream(kAudioIndex);
+    initStream(kVideoIndex);
+
+    mStreams[kAudioIndex].mThread->start();
+    mStreams[kVideoIndex].mThread->start();
+    mSinkThread->start();
+
+    mStarted = true;
+    return OK;
+}
+
+status_t WebmWriter::pause() {
+    if (mInitCheck != OK) {
+        return OK;
+    }
+    mPaused = true;
+    status_t err = OK;
+    for (int i = 0; i < kMaxStreams; ++i) {
+        if (mStreams[i].mThread == NULL) {
+            continue;
+        }
+        status_t status = mStreams[i].mThread->pause();
+        if (status != OK) {
+            err = status;
+        }
+    }
+    return err;
+}
+
+status_t WebmWriter::stop() {
+    return reset();
+}
+
+bool WebmWriter::reachedEOS() {
+    return !mSinkThread->running();
+}
+} /* namespace android */
diff --git a/media/libstagefright/webm/WebmWriter.h b/media/libstagefright/webm/WebmWriter.h
new file mode 100644
index 0000000..529dec8
--- /dev/null
+++ b/media/libstagefright/webm/WebmWriter.h
@@ -0,0 +1,130 @@
+/*
+ * 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 WEBMWRITER_H_
+#define WEBMWRITER_H_
+
+#include "WebmConstants.h"
+#include "WebmFrameThread.h"
+#include "LinkedBlockingQueue.h"
+
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MediaWriter.h>
+
+#include <utils/Errors.h>
+#include <utils/Mutex.h>
+#include <utils/StrongPointer.h>
+
+#include <stdint.h>
+
+using namespace webm;
+
+namespace android {
+
+class WebmWriter : public MediaWriter {
+public:
+    WebmWriter(int fd);
+    WebmWriter(const char *filename);
+    ~WebmWriter() { reset(); }
+
+
+    status_t addSource(const sp<MediaSource> &source);
+    status_t start(MetaData *param = NULL);
+    status_t stop();
+    status_t pause();
+    bool reachedEOS();
+
+    void setStartTimeOffsetMs(int ms) { mStartTimeOffsetMs = ms; }
+    int32_t getStartTimeOffsetMs() const { return mStartTimeOffsetMs; }
+
+private:
+    int mFd;
+    status_t mInitCheck;
+
+    uint64_t mTimeCodeScale;
+    int64_t mStartTimestampUs;
+    int32_t mStartTimeOffsetMs;
+
+    uint64_t mSegmentOffset;
+    uint64_t mSegmentDataStart;
+    uint64_t mInfoOffset;
+    uint64_t mInfoSize;
+    uint64_t mTracksOffset;
+    uint64_t mCuesOffset;
+
+    bool mPaused;
+    bool mStarted;
+    bool mIsFileSizeLimitExplicitlyRequested;
+    bool mIsRealTimeRecording;
+    bool mStreamableFile;
+    uint64_t mEstimatedCuesSize;
+
+    Mutex mLock;
+    List<sp<WebmElement> > mCuePoints;
+
+    enum {
+        kAudioIndex     =  0,
+        kVideoIndex     =  1,
+        kMaxStreams     =  2,
+    };
+
+    struct WebmStream {
+        int mType;
+        const char *mName;
+        sp<WebmElement> (*mMakeTrack)(const sp<MetaData>&);
+
+        sp<MediaSource> mSource;
+        sp<WebmElement> mTrackEntry;
+        sp<WebmFrameSourceThread> mThread;
+        LinkedBlockingQueue<const sp<WebmFrame> > mSink;
+
+        WebmStream()
+            : mType(kInvalidType),
+              mName("Invalid"),
+              mMakeTrack(NULL) {
+        }
+
+        WebmStream(int type, const char *name, sp<WebmElement> (*makeTrack)(const sp<MetaData>&))
+            : mType(type),
+              mName(name),
+              mMakeTrack(makeTrack) {
+        }
+
+        WebmStream &operator=(const WebmStream &other) {
+            mType = other.mType;
+            mName = other.mName;
+            mMakeTrack = other.mMakeTrack;
+            return *this;
+        }
+    };
+    WebmStream mStreams[kMaxStreams];
+
+    sp<WebmFrameSinkThread> mSinkThread;
+
+    size_t numTracks();
+    uint64_t estimateCuesSize(int32_t bitRate);
+    void initStream(size_t idx);
+    void release();
+    status_t reset();
+
+    static sp<WebmElement> videoTrack(const sp<MetaData>& md);
+    static sp<WebmElement> audioTrack(const sp<MetaData>& md);
+
+    DISALLOW_EVIL_CONSTRUCTORS(WebmWriter);
+};
+
+} /* namespace android */
+#endif /* WEBMWRITER_H_ */
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.cpp b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
index 1887b8b..e88a3bd 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.cpp
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
@@ -685,9 +685,8 @@
     return OK;
 }
 
-status_t RTPSender::parseReceiverReport(const uint8_t *data, size_t size) {
-    // hexdump(data, size);
-
+status_t RTPSender::parseReceiverReport(
+        const uint8_t *data, size_t /* size */) {
     float fractionLost = data[12] / 256.0f;
 
     ALOGI("lost %.2f %% of packets during report interval.",
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index 286ea13..1a5acba 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -29,6 +29,7 @@
 #include <binder/IServiceManager.h>
 #include <cutils/properties.h>
 #include <media/IHDCP.h>
+#include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -749,7 +750,8 @@
 
     mExtractor = new NuMediaExtractor;
 
-    status_t err = mExtractor->setDataSource(mMediaPath.c_str());
+    status_t err = mExtractor->setDataSource(
+            NULL /* httpService */, mMediaPath.c_str());
 
     if (err != OK) {
         return err;
diff --git a/media/libstagefright/wifi-display/source/RepeaterSource.cpp b/media/libstagefright/wifi-display/source/RepeaterSource.cpp
index cc8dee3..59d7e6e 100644
--- a/media/libstagefright/wifi-display/source/RepeaterSource.cpp
+++ b/media/libstagefright/wifi-display/source/RepeaterSource.cpp
@@ -79,6 +79,8 @@
 
     ALOGV("stopping");
 
+    status_t err = mSource->stop();
+
     if (mLooper != NULL) {
         mLooper->stop();
         mLooper.clear();
@@ -92,7 +94,6 @@
         mBuffer = NULL;
     }
 
-    status_t err = mSource->stop();
 
     ALOGV("stopped");
 
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index 05e4018..da405e2 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -746,7 +746,7 @@
 }
 
 status_t WifiDisplaySource::onReceiveM1Response(
-        int32_t sessionID, const sp<ParsedMessage> &msg) {
+        int32_t /* sessionID */, const sp<ParsedMessage> &msg) {
     int32_t statusCode;
     if (!msg->getStatusCode(&statusCode)) {
         return ERROR_MALFORMED;
@@ -991,7 +991,7 @@
 }
 
 status_t WifiDisplaySource::onReceiveM5Response(
-        int32_t sessionID, const sp<ParsedMessage> &msg) {
+        int32_t /* sessionID */, const sp<ParsedMessage> &msg) {
     int32_t statusCode;
     if (!msg->getStatusCode(&statusCode)) {
         return ERROR_MALFORMED;
@@ -1005,7 +1005,7 @@
 }
 
 status_t WifiDisplaySource::onReceiveM16Response(
-        int32_t sessionID, const sp<ParsedMessage> &msg) {
+        int32_t sessionID, const sp<ParsedMessage> & /* msg */) {
     // If only the response was required to include a "Session:" header...
 
     CHECK_EQ(sessionID, mClientSessionID);
@@ -1680,7 +1680,7 @@
 }
 
 void WifiDisplaySource::HDCPObserver::notify(
-        int msg, int ext1, int ext2, const Parcel *obj) {
+        int msg, int ext1, int ext2, const Parcel * /* obj */) {
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("msg", msg);
     notify->setInt32("ext1", ext1);
diff --git a/media/libstagefright/yuv/Android.mk b/media/libstagefright/yuv/Android.mk
index b3f7b1b..bb86dfc 100644
--- a/media/libstagefright/yuv/Android.mk
+++ b/media/libstagefright/yuv/Android.mk
@@ -12,5 +12,7 @@
 LOCAL_MODULE:= libstagefright_yuv
 
 
+LOCAL_CFLAGS += -Werror
+
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/yuv/YUVImage.cpp b/media/libstagefright/yuv/YUVImage.cpp
index 7b9000b..bb3e2fd 100644
--- a/media/libstagefright/yuv/YUVImage.cpp
+++ b/media/libstagefright/yuv/YUVImage.cpp
@@ -226,8 +226,8 @@
             &ySrcOffsetIncrement, &uSrcOffsetIncrement, &vSrcOffsetIncrement);
 
     int32_t yDestOffsetIncrement;
-    int32_t uDestOffsetIncrement;
-    int32_t vDestOffsetIncrement;
+    int32_t uDestOffsetIncrement = 0;
+    int32_t vDestOffsetIncrement = 0;
     destImage.getOffsetIncrementsPerDataRow(
             &yDestOffsetIncrement, &uDestOffsetIncrement, &vDestOffsetIncrement);
 
@@ -309,7 +309,7 @@
 
     int32_t yDestOffsetIncrement;
     int32_t uDestOffsetIncrement;
-    int32_t vDestOffsetIncrement;
+    int32_t vDestOffsetIncrement = 0;
     destImage.getOffsetIncrementsPerDataRow(
             &yDestOffsetIncrement, &uDestOffsetIncrement, &vDestOffsetIncrement);
 
@@ -393,9 +393,9 @@
     fprintf(fp, "255\n");
     for (int32_t y = 0; y < mHeight; ++y) {
         for (int32_t x = 0; x < mWidth; ++x) {
-            uint8_t yValue;
-            uint8_t uValue;
-            uint8_t vValue;
+            uint8_t yValue = 0u;
+            uint8_t uValue = 0u;
+            uint8_t vValue = 0u;
             getPixelValue(x, y, &yValue, &uValue, & vValue);
 
             uint8_t rValue;
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index d07bc99..d3e546a 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -15,6 +15,8 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	libaudioflinger \
+	libaudiopolicy \
+	libcamera_metadata\
 	libcameraservice \
 	libmedialogservice \
 	libcutils \
@@ -32,6 +34,7 @@
     frameworks/av/media/libmediaplayerservice \
     frameworks/av/services/medialog \
     frameworks/av/services/audioflinger \
+    frameworks/av/services/audiopolicy \
     frameworks/av/services/camera/libcameraservice
 
 LOCAL_MODULE:= mediaserver
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index d5207d5..a347951 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -37,7 +37,7 @@
 
 using namespace android;
 
-int main(int argc, char** argv)
+int main(int argc __unused, char** argv)
 {
     signal(SIGPIPE, SIG_IGN);
     char value[PROPERTY_VALUE_MAX];
diff --git a/media/mtp/MtpProperty.cpp b/media/mtp/MtpProperty.cpp
index 375ed9a..3838ce8 100644
--- a/media/mtp/MtpProperty.cpp
+++ b/media/mtp/MtpProperty.cpp
@@ -190,9 +190,9 @@
             if (deviceProp)
                 writeValue(packet, mCurrentValue);
     }
-    packet.putUInt32(mGroupCode);
     if (!deviceProp)
-        packet.putUInt8(mFormFlag);
+        packet.putUInt32(mGroupCode);
+    packet.putUInt8(mFormFlag);
     if (mFormFlag == kFormRange) {
             writeValue(packet, mMinimumValue);
             writeValue(packet, mMaximumValue);
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index df87db4..dadfb54 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -93,6 +93,7 @@
     MTP_EVENT_OBJECT_REMOVED,
     MTP_EVENT_STORE_ADDED,
     MTP_EVENT_STORE_REMOVED,
+    MTP_EVENT_DEVICE_PROP_CHANGED,
 };
 
 MtpServer::MtpServer(int fd, MtpDatabase* database, bool ptp,
@@ -261,6 +262,11 @@
     sendEvent(MTP_EVENT_STORE_REMOVED, id);
 }
 
+void MtpServer::sendDevicePropertyChanged(MtpDeviceProperty property) {
+    ALOGV("sendDevicePropertyChanged %d\n", property);
+    sendEvent(MTP_EVENT_DEVICE_PROP_CHANGED, property);
+}
+
 void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
     if (mSessionOpen) {
         mEvent.setEventCode(code);
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index dfa8258..b3a11e0 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -104,6 +104,7 @@
 
     void                sendObjectAdded(MtpObjectHandle handle);
     void                sendObjectRemoved(MtpObjectHandle handle);
+    void                sendDevicePropertyChanged(MtpDeviceProperty property);
 
 private:
     void                sendStoreAdded(MtpStorageID id);
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 5fcc9ba..de7e3c3 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -13,6 +13,16 @@
 
 include $(CLEAR_VARS)
 
+LOCAL_SRC_FILES := \
+    ServiceUtilities.cpp
+
+# FIXME Move this library to frameworks/native
+LOCAL_MODULE := libserviceutility
+
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
 LOCAL_SRC_FILES:=               \
     AudioFlinger.cpp            \
     Threads.cpp                 \
@@ -20,14 +30,14 @@
     Effects.cpp                 \
     AudioMixer.cpp.arm          \
     AudioResampler.cpp.arm      \
-    AudioPolicyService.cpp      \
-    ServiceUtilities.cpp        \
     AudioResamplerCubic.cpp.arm \
-    AudioResamplerSinc.cpp.arm
+    AudioResamplerSinc.cpp.arm  \
+    AudioResamplerDyn.cpp.arm
 
 LOCAL_SRC_FILES += StateQueue.cpp
 
 LOCAL_C_INCLUDES := \
+    $(TOPDIR)frameworks/av/services/audiopolicy \
     $(call include-path-for, audio-effects) \
     $(call include-path-for, audio-utils)
 
@@ -49,7 +59,8 @@
 LOCAL_STATIC_LIBRARIES := \
     libscheduling_policy \
     libcpustats \
-    libmedia_helper
+    libmedia_helper \
+    libserviceutility
 
 LOCAL_MODULE:= libaudioflinger
 LOCAL_32_BIT_ONLY := true
@@ -75,12 +86,20 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=               \
-	test-resample.cpp 			\
+    test-resample.cpp           \
     AudioResampler.cpp.arm      \
-	AudioResamplerCubic.cpp.arm \
-    AudioResamplerSinc.cpp.arm
+    AudioResamplerCubic.cpp.arm \
+    AudioResamplerSinc.cpp.arm  \
+    AudioResamplerDyn.cpp.arm
+
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, audio-utils)
+
+LOCAL_STATIC_LIBRARIES := \
+    libsndfile
 
 LOCAL_SHARED_LIBRARIES := \
+    libaudioutils \
     libdl \
     libcutils \
     libutils \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 26dac95..50179c5 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -104,6 +104,27 @@
 
 // ----------------------------------------------------------------------------
 
+const char *formatToString(audio_format_t format) {
+    switch(format) {
+    case AUDIO_FORMAT_PCM_SUB_8_BIT: return "pcm8";
+    case AUDIO_FORMAT_PCM_SUB_16_BIT: return "pcm16";
+    case AUDIO_FORMAT_PCM_SUB_32_BIT: return "pcm32";
+    case AUDIO_FORMAT_PCM_SUB_8_24_BIT: return "pcm8.24";
+    case AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED: return "pcm24";
+    case AUDIO_FORMAT_PCM_SUB_FLOAT: return "pcmfloat";
+    case AUDIO_FORMAT_MP3: return "mp3";
+    case AUDIO_FORMAT_AMR_NB: return "amr-nb";
+    case AUDIO_FORMAT_AMR_WB: return "amr-wb";
+    case AUDIO_FORMAT_AAC: return "aac";
+    case AUDIO_FORMAT_HE_AAC_V1: return "he-aac-v1";
+    case AUDIO_FORMAT_HE_AAC_V2: return "he-aac-v2";
+    case AUDIO_FORMAT_VORBIS: return "vorbis";
+    default:
+        break;
+    }
+    return "unknown";
+}
+
 static int load_audio_interface(const char *if_name, audio_hw_device_t **dev)
 {
     const hw_module_t *mod;
@@ -162,12 +183,16 @@
         (void) property_get("af.tee", value, "0");
         teeEnabled = atoi(value);
     }
-    if (teeEnabled & 1)
+    // FIXME symbolic constants here
+    if (teeEnabled & 1) {
         mTeeSinkInputEnabled = true;
-    if (teeEnabled & 2)
+    }
+    if (teeEnabled & 2) {
         mTeeSinkOutputEnabled = true;
-    if (teeEnabled & 4)
+    }
+    if (teeEnabled & 4) {
         mTeeSinkTrackEnabled = true;
+    }
 #endif
 }
 
@@ -210,6 +235,18 @@
         audio_hw_device_close(mAudioHwDevs.valueAt(i)->hwDevice());
         delete mAudioHwDevs.valueAt(i);
     }
+
+    // Tell media.log service about any old writers that still need to be unregistered
+    sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
+    if (binder != 0) {
+        sp<IMediaLogService> mediaLogService(interface_cast<IMediaLogService>(binder));
+        for (size_t count = mUnregisteredWriters.size(); count > 0; count--) {
+            sp<IMemory> iMemory(mUnregisteredWriters.top()->getIMemory());
+            mUnregisteredWriters.pop();
+            mediaLogService->unregisterWriter(iMemory);
+        }
+    }
+
 }
 
 static const char * const audio_interfaces[] = {
@@ -249,7 +286,7 @@
     return NULL;
 }
 
-void AudioFlinger::dumpClients(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpClients(int fd, const Vector<String16>& args __unused)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -271,17 +308,17 @@
     }
 
     result.append("Global session refs:\n");
-    result.append(" session pid count\n");
+    result.append("  session   pid count\n");
     for (size_t i = 0; i < mAudioSessionRefs.size(); i++) {
         AudioSessionRef *r = mAudioSessionRefs[i];
-        snprintf(buffer, SIZE, " %7d %3d %3d\n", r->mSessionid, r->mPid, r->mCnt);
+        snprintf(buffer, SIZE, "  %7d %5d %5d\n", r->mSessionid, r->mPid, r->mCnt);
         result.append(buffer);
     }
     write(fd, result.string(), result.size());
 }
 
 
-void AudioFlinger::dumpInternals(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpInternals(int fd, const Vector<String16>& args __unused)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -296,7 +333,7 @@
     write(fd, result.string(), result.size());
 }
 
-void AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args __unused)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -403,16 +440,44 @@
 
 sp<NBLog::Writer> AudioFlinger::newWriter_l(size_t size, const char *name)
 {
+    // If there is no memory allocated for logs, return a dummy writer that does nothing
     if (mLogMemoryDealer == 0) {
         return new NBLog::Writer();
     }
-    sp<IMemory> shared = mLogMemoryDealer->allocate(NBLog::Timeline::sharedSize(size));
-    sp<NBLog::Writer> writer = new NBLog::Writer(size, shared);
     sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
-    if (binder != 0) {
-        interface_cast<IMediaLogService>(binder)->registerWriter(shared, size, name);
+    // Similarly if we can't contact the media.log service, also return a dummy writer
+    if (binder == 0) {
+        return new NBLog::Writer();
     }
-    return writer;
+    sp<IMediaLogService> mediaLogService(interface_cast<IMediaLogService>(binder));
+    sp<IMemory> shared = mLogMemoryDealer->allocate(NBLog::Timeline::sharedSize(size));
+    // If allocation fails, consult the vector of previously unregistered writers
+    // and garbage-collect one or more them until an allocation succeeds
+    if (shared == 0) {
+        Mutex::Autolock _l(mUnregisteredWritersLock);
+        for (size_t count = mUnregisteredWriters.size(); count > 0; count--) {
+            {
+                // Pick the oldest stale writer to garbage-collect
+                sp<IMemory> iMemory(mUnregisteredWriters[0]->getIMemory());
+                mUnregisteredWriters.removeAt(0);
+                mediaLogService->unregisterWriter(iMemory);
+                // Now the media.log remote reference to IMemory is gone.  When our last local
+                // reference to IMemory also drops to zero at end of this block,
+                // the IMemory destructor will deallocate the region from mLogMemoryDealer.
+            }
+            // Re-attempt the allocation
+            shared = mLogMemoryDealer->allocate(NBLog::Timeline::sharedSize(size));
+            if (shared != 0) {
+                goto success;
+            }
+        }
+        // Even after garbage-collecting all old writers, there is still not enough memory,
+        // so return a dummy writer
+        return new NBLog::Writer();
+    }
+success:
+    mediaLogService->registerWriter(shared, size, name);
+    return new NBLog::Writer(size, shared);
 }
 
 void AudioFlinger::unregisterWriter(const sp<NBLog::Writer>& writer)
@@ -424,13 +489,10 @@
     if (iMemory == 0) {
         return;
     }
-    sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
-    if (binder != 0) {
-        interface_cast<IMediaLogService>(binder)->unregisterWriter(iMemory);
-        // Now the media.log remote reference to IMemory is gone.
-        // When our last local reference to IMemory also drops to zero,
-        // the IMemory destructor will deallocate the region from mMemoryDealer.
-    }
+    // Rather than removing the writer immediately, append it to a queue of old writers to
+    // be garbage-collected later.  This allows us to continue to view old logs for a while.
+    Mutex::Autolock _l(mUnregisteredWritersLock);
+    mUnregisteredWriters.push(writer);
 }
 
 // IAudioFlinger interface
@@ -441,13 +503,12 @@
         uint32_t sampleRate,
         audio_format_t format,
         audio_channel_mask_t channelMask,
-        size_t frameCount,
+        size_t *frameCount,
         IAudioFlinger::track_flags_t *flags,
         const sp<IMemory>& sharedBuffer,
         audio_io_handle_t output,
         pid_t tid,
         int *sessionId,
-        String8& name,
         int clientUid,
         status_t *status)
 {
@@ -465,10 +526,31 @@
         goto Exit;
     }
 
+    // further sample rate checks are performed by createTrack_l() depending on the thread type
+    if (sampleRate == 0) {
+        ALOGE("createTrack() invalid sample rate %u", sampleRate);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    // further channel mask checks are performed by createTrack_l() depending on the thread type
+    if (!audio_is_output_channel(channelMask)) {
+        ALOGE("createTrack() invalid channel mask %#x", channelMask);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
     // client is responsible for conversion of 8-bit PCM to 16-bit PCM,
     // and we don't yet support 8.24 or 32-bit PCM
-    if (audio_is_linear_pcm(format) && format != AUDIO_FORMAT_PCM_16_BIT) {
-        ALOGE("createTrack() invalid format %d", format);
+    if (!audio_is_valid_format(format) ||
+            (audio_is_linear_pcm(format) && format != AUDIO_FORMAT_PCM_16_BIT)) {
+        ALOGE("createTrack() invalid format %#x", format);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    if (sharedBuffer != 0 && sharedBuffer->pointer() == NULL) {
+        ALOGE("createTrack() sharedBuffer is non-0 but has NULL pointer()");
         lStatus = BAD_VALUE;
         goto Exit;
     }
@@ -476,7 +558,6 @@
     {
         Mutex::Autolock _l(mLock);
         PlaybackThread *thread = checkPlaybackThread_l(output);
-        PlaybackThread *effectThread = NULL;
         if (thread == NULL) {
             ALOGE("no playback thread found for output handle %d", output);
             lStatus = BAD_VALUE;
@@ -484,24 +565,23 @@
         }
 
         pid_t pid = IPCThreadState::self()->getCallingPid();
-
         client = registerPid_l(pid);
 
-        ALOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId);
-        if (sessionId != NULL && *sessionId != AUDIO_SESSION_OUTPUT_MIX) {
+        PlaybackThread *effectThread = NULL;
+        if (sessionId != NULL && *sessionId != AUDIO_SESSION_ALLOCATE) {
+            lSessionId = *sessionId;
             // check if an effect chain with the same session ID is present on another
             // output thread and move it here.
             for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
                 sp<PlaybackThread> t = mPlaybackThreads.valueAt(i);
                 if (mPlaybackThreads.keyAt(i) != output) {
-                    uint32_t sessions = t->hasAudioSession(*sessionId);
+                    uint32_t sessions = t->hasAudioSession(lSessionId);
                     if (sessions & PlaybackThread::EFFECT_SESSION) {
                         effectThread = t.get();
                         break;
                     }
                 }
             }
-            lSessionId = *sessionId;
         } else {
             // if no audio session id is provided, create one here
             lSessionId = nextUniqueId();
@@ -519,6 +599,7 @@
         // move effect chain to this output thread if an effect on same session was waiting
         // for a track to be created
         if (lStatus == NO_ERROR && effectThread != NULL) {
+            // no risk of deadlock because AudioFlinger::mLock is held
             Mutex::Autolock _dl(thread->mLock);
             Mutex::Autolock _sl(effectThread->mLock);
             moveEffectChain_l(lSessionId, effectThread, thread, true);
@@ -538,23 +619,22 @@
                 }
             }
         }
-    }
-    if (lStatus == NO_ERROR) {
-        // s for server's pid, n for normal mixer name, f for fast index
-        name = String8::format("s:%d;n:%d;f:%d", getpid_cached, track->name() - AudioMixer::TRACK0,
-                track->fastIndex());
-        trackHandle = new TrackHandle(track);
-    } else {
-        // remove local strong reference to Client before deleting the Track so that the Client
-        // destructor is called by the TrackBase destructor with mLock held
-        client.clear();
-        track.clear();
+
     }
 
-Exit:
-    if (status != NULL) {
-        *status = lStatus;
+    if (lStatus != NO_ERROR) {
+        // remove local strong reference to Client before deleting the Track so that the
+        // Client destructor is called by the TrackBase destructor with mLock held
+        client.clear();
+        track.clear();
+        goto Exit;
     }
+
+    // return handle to client
+    trackHandle = new TrackHandle(track);
+
+Exit:
+    *status = lStatus;
     return trackHandle;
 }
 
@@ -1212,7 +1292,7 @@
 {
 }
 
-void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who)
+void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who __unused)
 {
     sp<NotificationClient> keep(this);
     mAudioFlinger->removeNotificationClient(mPid);
@@ -1230,7 +1310,7 @@
         uint32_t sampleRate,
         audio_format_t format,
         audio_channel_mask_t channelMask,
-        size_t frameCount,
+        size_t *frameCount,
         IAudioFlinger::track_flags_t *flags,
         pid_t tid,
         int *sessionId,
@@ -1240,8 +1320,6 @@
     sp<RecordHandle> recordHandle;
     sp<Client> client;
     status_t lStatus;
-    RecordThread *thread;
-    size_t inFrameCount;
     int lSessionId;
 
     // check calling permissions
@@ -1251,16 +1329,31 @@
         goto Exit;
     }
 
-    if (format != AUDIO_FORMAT_PCM_16_BIT) {
-        ALOGE("openRecord() invalid format %d", format);
+    // further sample rate checks are performed by createRecordTrack_l()
+    if (sampleRate == 0) {
+        ALOGE("openRecord() invalid sample rate %u", sampleRate);
         lStatus = BAD_VALUE;
         goto Exit;
     }
 
-    // add client to list
-    { // scope for mLock
+    // we don't yet support anything other than 16-bit PCM
+    if (!(audio_is_valid_format(format) &&
+            audio_is_linear_pcm(format) && format == AUDIO_FORMAT_PCM_16_BIT)) {
+        ALOGE("openRecord() invalid format %#x", format);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    // further channel mask checks are performed by createRecordTrack_l()
+    if (!audio_is_input_channel(channelMask)) {
+        ALOGE("openRecord() invalid channel mask %#x", channelMask);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
+    {
         Mutex::Autolock _l(mLock);
-        thread = checkRecordThread_l(input);
+        RecordThread *thread = checkRecordThread_l(input);
         if (thread == NULL) {
             ALOGE("openRecord() checkRecordThread_l failed");
             lStatus = BAD_VALUE;
@@ -1277,17 +1370,17 @@
         pid_t pid = IPCThreadState::self()->getCallingPid();
         client = registerPid_l(pid);
 
-        // If no audio session id is provided, create one here
-        if (sessionId != NULL && *sessionId != AUDIO_SESSION_OUTPUT_MIX) {
+        if (sessionId != NULL && *sessionId != AUDIO_SESSION_ALLOCATE) {
             lSessionId = *sessionId;
         } else {
+            // if no audio session id is provided, create one here
             lSessionId = nextUniqueId();
             if (sessionId != NULL) {
                 *sessionId = lSessionId;
             }
         }
-        // create new record track.
-        // The record track uses one track in mHardwareMixerThread by convention.
+        ALOGV("openRecord() lSessionId: %d", lSessionId);
+
         // TODO: the uid should be passed in as a parameter to openRecord
         recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask,
                                                   frameCount, lSessionId,
@@ -1295,6 +1388,7 @@
                                                   flags, tid, &lStatus);
         LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));
     }
+
     if (lStatus != NO_ERROR) {
         // remove local strong reference to Client before deleting the RecordTrack so that the
         // Client destructor is called by the TrackBase destructor with mLock held
@@ -1303,14 +1397,11 @@
         goto Exit;
     }
 
-    // return to handle to client
+    // return handle to client
     recordHandle = new RecordHandle(recordTrack);
-    lStatus = NO_ERROR;
 
 Exit:
-    if (status) {
-        *status = lStatus;
-    }
+    *status = lStatus;
     return recordHandle;
 }
 
@@ -1451,18 +1542,15 @@
                                            audio_output_flags_t flags,
                                            const audio_offload_info_t *offloadInfo)
 {
-    PlaybackThread *thread = NULL;
     struct audio_config config;
+    memset(&config, 0, sizeof(config));
     config.sample_rate = (pSamplingRate != NULL) ? *pSamplingRate : 0;
     config.channel_mask = (pChannelMask != NULL) ? *pChannelMask : 0;
     config.format = (pFormat != NULL) ? *pFormat : AUDIO_FORMAT_DEFAULT;
-    if (offloadInfo) {
+    if (offloadInfo != NULL) {
         config.offload_info = *offloadInfo;
     }
 
-    audio_stream_out_t *outStream = NULL;
-    AudioHwDevice *outHwDev;
-
     ALOGV("openOutput(), module %d Device %x, SamplingRate %d, Format %#08x, Channels %x, flags %x",
               module,
               (pDevices != NULL) ? *pDevices : 0,
@@ -1471,7 +1559,7 @@
               config.channel_mask,
               flags);
     ALOGV("openOutput(), offloadInfo %p version 0x%04x",
-          offloadInfo, offloadInfo == NULL ? -1 : offloadInfo->version );
+          offloadInfo, offloadInfo == NULL ? -1 : offloadInfo->version);
 
     if (pDevices == NULL || *pDevices == 0) {
         return 0;
@@ -1479,15 +1567,17 @@
 
     Mutex::Autolock _l(mLock);
 
-    outHwDev = findSuitableHwDev_l(module, *pDevices);
-    if (outHwDev == NULL)
+    AudioHwDevice *outHwDev = findSuitableHwDev_l(module, *pDevices);
+    if (outHwDev == NULL) {
         return 0;
+    }
 
     audio_hw_device_t *hwDevHal = outHwDev->hwDevice();
     audio_io_handle_t id = nextUniqueId();
 
     mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
 
+    audio_stream_out_t *outStream = NULL;
     status_t status = hwDevHal->open_output_stream(hwDevHal,
                                           id,
                                           *pDevices,
@@ -1507,6 +1597,7 @@
     if (status == NO_ERROR && outStream != NULL) {
         AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream, flags);
 
+        PlaybackThread *thread;
         if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
             thread = new OffloadThread(this, output, id, *pDevices);
             ALOGV("openOutput() created offload output: ID %d thread %p", id, thread);
@@ -1674,18 +1765,15 @@
                                           audio_format_t *pFormat,
                                           audio_channel_mask_t *pChannelMask)
 {
-    status_t status;
-    RecordThread *thread = NULL;
     struct audio_config config;
+    memset(&config, 0, sizeof(config));
     config.sample_rate = (pSamplingRate != NULL) ? *pSamplingRate : 0;
     config.channel_mask = (pChannelMask != NULL) ? *pChannelMask : 0;
     config.format = (pFormat != NULL) ? *pFormat : AUDIO_FORMAT_DEFAULT;
 
     uint32_t reqSamplingRate = config.sample_rate;
     audio_format_t reqFormat = config.format;
-    audio_channel_mask_t reqChannels = config.channel_mask;
-    audio_stream_in_t *inStream = NULL;
-    AudioHwDevice *inHwDev;
+    audio_channel_mask_t reqChannelMask = config.channel_mask;
 
     if (pDevices == NULL || *pDevices == 0) {
         return 0;
@@ -1693,16 +1781,18 @@
 
     Mutex::Autolock _l(mLock);
 
-    inHwDev = findSuitableHwDev_l(module, *pDevices);
-    if (inHwDev == NULL)
+    AudioHwDevice *inHwDev = findSuitableHwDev_l(module, *pDevices);
+    if (inHwDev == NULL) {
         return 0;
+    }
 
     audio_hw_device_t *inHwHal = inHwDev->hwDevice();
     audio_io_handle_t id = nextUniqueId();
 
-    status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config,
+    audio_stream_in_t *inStream = NULL;
+    status_t status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config,
                                         &inStream);
-    ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, "
+    ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %#x, Channels %x, "
             "status %d",
             inStream,
             config.sample_rate,
@@ -1716,10 +1806,12 @@
     if (status == BAD_VALUE &&
         reqFormat == config.format && config.format == AUDIO_FORMAT_PCM_16_BIT &&
         (config.sample_rate <= 2 * reqSamplingRate) &&
-        (popcount(config.channel_mask) <= FCC_2) && (popcount(reqChannels) <= FCC_2)) {
+        (popcount(config.channel_mask) <= FCC_2) && (popcount(reqChannelMask) <= FCC_2)) {
+        // FIXME describe the change proposed by HAL (save old values so we can log them here)
         ALOGV("openInput() reopening with proposed sampling rate and channel mask");
         inStream = NULL;
         status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config, &inStream);
+        // FIXME log this new status; HAL should not propose any further changes
     }
 
     if (status == NO_ERROR && inStream != NULL) {
@@ -1737,13 +1829,13 @@
                                         popcount(inStream->common.get_channels(&inStream->common)));
         if (!mTeeSinkInputEnabled) {
             kind = TEE_SINK_NO;
-        } else if (format == Format_Invalid) {
+        } else if (!Format_isValid(format)) {
             kind = TEE_SINK_NO;
         } else if (mRecordTeeSink == 0) {
             kind = TEE_SINK_NEW;
         } else if (mRecordTeeSink->getStrongCount() != 1) {
             kind = TEE_SINK_NO;
-        } else if (format == mRecordTeeSink->format()) {
+        } else if (Format_isEqual(format, mRecordTeeSink->format())) {
             kind = TEE_SINK_OLD;
         } else {
             kind = TEE_SINK_NEW;
@@ -1778,10 +1870,8 @@
         // Start record thread
         // RecordThread requires both input and output device indication to forward to audio
         // pre processing modules
-        thread = new RecordThread(this,
+        RecordThread *thread = new RecordThread(this,
                                   input,
-                                  reqSamplingRate,
-                                  reqChannels,
                                   id,
                                   primaryOutputDevice_l(),
                                   *pDevices
@@ -1798,7 +1888,7 @@
             *pFormat = config.format;
         }
         if (pChannelMask != NULL) {
-            *pChannelMask = reqChannels;
+            *pChannelMask = reqChannelMask;
         }
 
         // notify client processes of the new input creation
@@ -1843,10 +1933,10 @@
     return NO_ERROR;
 }
 
-status_t AudioFlinger::setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output)
+status_t AudioFlinger::invalidateStream(audio_stream_type_t stream)
 {
     Mutex::Autolock _l(mLock);
-    ALOGV("setStreamOutput() stream %d to output %d", stream, output);
+    ALOGV("invalidateStream() stream %d", stream);
 
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
         PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
@@ -1862,18 +1952,21 @@
     return nextUniqueId();
 }
 
-void AudioFlinger::acquireAudioSessionId(int audioSession)
+void AudioFlinger::acquireAudioSessionId(int audioSession, pid_t pid)
 {
     Mutex::Autolock _l(mLock);
     pid_t caller = IPCThreadState::self()->getCallingPid();
-    ALOGV("acquiring %d from %d", audioSession, caller);
+    ALOGV("acquiring %d from %d, for %d", audioSession, caller, pid);
+    if (pid != -1 && (caller == getpid_cached)) {
+        caller = pid;
+    }
 
     // Ignore requests received from processes not known as notification client. The request
     // is likely proxied by mediaserver (e.g CameraService) and releaseAudioSessionId() can be
     // called from a different pid leaving a stale session reference.  Also we don't know how
     // to clear this reference if the client process dies.
     if (mNotificationClients.indexOfKey(caller) < 0) {
-        ALOGV("acquireAudioSessionId() unknown client %d for session %d", caller, audioSession);
+        ALOGW("acquireAudioSessionId() unknown client %d for session %d", caller, audioSession);
         return;
     }
 
@@ -1890,11 +1983,14 @@
     ALOGV(" added new entry for %d", audioSession);
 }
 
-void AudioFlinger::releaseAudioSessionId(int audioSession)
+void AudioFlinger::releaseAudioSessionId(int audioSession, pid_t pid)
 {
     Mutex::Autolock _l(mLock);
     pid_t caller = IPCThreadState::self()->getCallingPid();
-    ALOGV("releasing %d from %d", audioSession, caller);
+    ALOGV("releasing %d from %d for %d", audioSession, caller, pid);
+    if (pid != -1 && (caller == getpid_cached)) {
+        caller = pid;
+    }
     size_t num = mAudioSessionRefs.size();
     for (size_t i = 0; i< num; i++) {
         AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
@@ -1956,7 +2052,7 @@
             }
         }
         if (!found) {
-            Mutex::Autolock _l (t->mLock);
+            Mutex::Autolock _l(t->mLock);
             // remove all effects from the chain
             while (ec->mEffects.size()) {
                 sp<EffectModule> effect = ec->mEffects[0];
@@ -2023,7 +2119,7 @@
                                     int triggerSession,
                                     int listenerSession,
                                     sync_event_callback_t callBack,
-                                    void *cookie)
+                                    wp<RefBase> cookie)
 {
     Mutex::Autolock _l(mLock);
 
@@ -2251,9 +2347,7 @@
     }
 
 Exit:
-    if (status != NULL) {
-        *status = lStatus;
-    }
+    *status = lStatus;
     return handle;
 }
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 7320144..2367d7d 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -60,8 +60,8 @@
 
 namespace android {
 
-class audio_track_cblk_t;
-class effect_param_cblk_t;
+struct audio_track_cblk_t;
+struct effect_param_cblk_t;
 class AudioMixer;
 class AudioBuffer;
 class AudioResampler;
@@ -102,26 +102,25 @@
                                 uint32_t sampleRate,
                                 audio_format_t format,
                                 audio_channel_mask_t channelMask,
-                                size_t frameCount,
+                                size_t *pFrameCount,
                                 IAudioFlinger::track_flags_t *flags,
                                 const sp<IMemory>& sharedBuffer,
                                 audio_io_handle_t output,
                                 pid_t tid,
                                 int *sessionId,
-                                String8& name,
                                 int clientUid,
-                                status_t *status);
+                                status_t *status /*non-NULL*/);
 
     virtual sp<IAudioRecord> openRecord(
                                 audio_io_handle_t input,
                                 uint32_t sampleRate,
                                 audio_format_t format,
                                 audio_channel_mask_t channelMask,
-                                size_t frameCount,
+                                size_t *pFrameCount,
                                 IAudioFlinger::track_flags_t *flags,
                                 pid_t tid,
                                 int *sessionId,
-                                status_t *status);
+                                status_t *status /*non-NULL*/);
 
     virtual     uint32_t    sampleRate(audio_io_handle_t output) const;
     virtual     int         channelCount(audio_io_handle_t output) const;
@@ -182,7 +181,7 @@
 
     virtual status_t closeInput(audio_io_handle_t input);
 
-    virtual status_t setStreamOutput(audio_stream_type_t stream, audio_io_handle_t output);
+    virtual status_t invalidateStream(audio_stream_type_t stream);
 
     virtual status_t setVoiceVolume(float volume);
 
@@ -193,9 +192,9 @@
 
     virtual int newAudioSessionId();
 
-    virtual void acquireAudioSessionId(int audioSession);
+    virtual void acquireAudioSessionId(int audioSession, pid_t pid);
 
-    virtual void releaseAudioSessionId(int audioSession);
+    virtual void releaseAudioSessionId(int audioSession, pid_t pid);
 
     virtual status_t queryNumberEffects(uint32_t *numEffects) const;
 
@@ -210,7 +209,7 @@
                         int32_t priority,
                         audio_io_handle_t io,
                         int sessionId,
-                        status_t *status,
+                        status_t *status /*non-NULL*/,
                         int *id,
                         int *enabled);
 
@@ -235,8 +234,12 @@
     sp<NBLog::Writer>   newWriter_l(size_t size, const char *name);
     void                unregisterWriter(const sp<NBLog::Writer>& writer);
 private:
-    static const size_t kLogMemorySize = 10 * 1024;
+    static const size_t kLogMemorySize = 40 * 1024;
     sp<MemoryDealer>    mLogMemoryDealer;   // == 0 when NBLog is disabled
+    // When a log writer is unregistered, it is done lazily so that media.log can continue to see it
+    // for as long as possible.  The memory is only freed when it is needed for another log writer.
+    Vector< sp<NBLog::Writer> > mUnregisteredWriters;
+    Mutex               mUnregisteredWritersLock;
 public:
 
     class SyncEvent;
@@ -249,7 +252,7 @@
                   int triggerSession,
                   int listenerSession,
                   sync_event_callback_t callBack,
-                  void *cookie)
+                  wp<RefBase> cookie)
         : mType(type), mTriggerSession(triggerSession), mListenerSession(listenerSession),
           mCallback(callBack), mCookie(cookie)
         {}
@@ -262,14 +265,14 @@
         AudioSystem::sync_event_t type() const { return mType; }
         int triggerSession() const { return mTriggerSession; }
         int listenerSession() const { return mListenerSession; }
-        void *cookie() const { return mCookie; }
+        wp<RefBase> cookie() const { return mCookie; }
 
     private:
           const AudioSystem::sync_event_t mType;
           const int mTriggerSession;
           const int mListenerSession;
           sync_event_callback_t mCallback;
-          void * const mCookie;
+          const wp<RefBase> mCookie;
           mutable Mutex mLock;
     };
 
@@ -277,7 +280,7 @@
                                         int triggerSession,
                                         int listenerSession,
                                         sync_event_callback_t callBack,
-                                        void *cookie);
+                                        wp<RefBase> cookie);
 
 private:
     class AudioHwDevice;    // fwd declaration for findSuitableHwDev_l
@@ -499,7 +502,7 @@
     private:
         const char * const mModuleName;
         audio_hw_device_t * const mHwDevice;
-        Flags mFlags;
+        const Flags mFlags;
     };
 
     // AudioStreamOut and AudioStreamIn are immutable, so their fields are const.
@@ -509,7 +512,7 @@
     struct AudioStreamOut {
         AudioHwDevice* const audioHwDev;
         audio_stream_out_t* const stream;
-        audio_output_flags_t flags;
+        const audio_output_flags_t flags;
 
         audio_hw_device_t* hwDev() const { return audioHwDev->hwDevice(); }
 
@@ -634,7 +637,7 @@
     // 0x200000 stereo 16-bit PCM frames = 47.5 seconds at 44.1 kHz, 8 megabytes
     static const size_t kTeeSinkInputFramesDefault = 0x200000;
     static const size_t kTeeSinkOutputFramesDefault = 0x200000;
-    static const size_t kTeeSinkTrackFramesDefault = 0x1000;
+    static const size_t kTeeSinkTrackFramesDefault = 0x200000;
 #endif
 
     // This method reads from a variable without mLock, but the variable is updated under mLock.  So
@@ -651,6 +654,8 @@
 
 #undef INCLUDING_FROM_AUDIOFLINGER_H
 
+const char *formatToString(audio_format_t format);
+
 // ----------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index f92421e..3ac5da9 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -58,7 +58,7 @@
 status_t AudioMixer::DownmixerBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer,
         int64_t pts) {
     //ALOGV("DownmixerBufferProvider::getNextBuffer()");
-    if (this->mTrackBufferProvider != NULL) {
+    if (mTrackBufferProvider != NULL) {
         status_t res = mTrackBufferProvider->getNextBuffer(pBuffer, pts);
         if (res == OK) {
             mDownmixConfig.inputCfg.buffer.frameCount = pBuffer->frameCount;
@@ -81,7 +81,7 @@
 
 void AudioMixer::DownmixerBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) {
     //ALOGV("DownmixerBufferProvider::releaseBuffer()");
-    if (this->mTrackBufferProvider != NULL) {
+    if (mTrackBufferProvider != NULL) {
         mTrackBufferProvider->releaseBuffer(pBuffer);
     } else {
         ALOGE("DownmixerBufferProvider::releaseBuffer() error: NULL track buffer provider");
@@ -90,9 +90,9 @@
 
 
 // ----------------------------------------------------------------------------
-bool AudioMixer::isMultichannelCapable = false;
+bool AudioMixer::sIsMultichannelCapable = false;
 
-effect_descriptor_t AudioMixer::dwnmFxDesc;
+effect_descriptor_t AudioMixer::sDwnmFxDesc;
 
 // Ensure mConfiguredNames bitmask is initialized properly on all architectures.
 // The value of 1 << x is undefined in C when x >= 32.
@@ -113,8 +113,6 @@
     // AudioMixer is not yet capable of multi-channel output beyond stereo
     ALOG_ASSERT(2 == MAX_NUM_CHANNELS, "bad MAX_NUM_CHANNELS %d", MAX_NUM_CHANNELS);
 
-    LocalClock lc;
-
     pthread_once(&sOnceControl, &sInitRoutine);
 
     mState.enabledTracks= 0;
@@ -136,27 +134,6 @@
         t++;
     }
 
-    // find multichannel downmix effect if we have to play multichannel content
-    uint32_t numEffects = 0;
-    int ret = EffectQueryNumberEffects(&numEffects);
-    if (ret != 0) {
-        ALOGE("AudioMixer() error %d querying number of effects", ret);
-        return;
-    }
-    ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
-
-    for (uint32_t i = 0 ; i < numEffects ; i++) {
-        if (EffectQueryEffect(i, &dwnmFxDesc) == 0) {
-            ALOGV("effect %d is called %s", i, dwnmFxDesc.name);
-            if (memcmp(&dwnmFxDesc.type, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0) {
-                ALOGI("found effect \"%s\" from %s",
-                        dwnmFxDesc.name, dwnmFxDesc.implementor);
-                isMultichannelCapable = true;
-                break;
-            }
-        }
-    }
-    ALOGE_IF(!isMultichannelCapable, "unable to find downmix effect");
 }
 
 AudioMixer::~AudioMixer()
@@ -216,6 +193,7 @@
         t->mainBuffer = NULL;
         t->auxBuffer = NULL;
         t->downmixerBufferProvider = NULL;
+        t->mMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
 
         status_t status = initTrackDownmix(&mState.tracks[n], n, channelMask);
         if (status == OK) {
@@ -229,7 +207,7 @@
 
 void AudioMixer::invalidateState(uint32_t mask)
 {
-    if (mask) {
+    if (mask != 0) {
         mState.needsChanged |= mask;
         mState.hook = process__validate;
     }
@@ -252,7 +230,7 @@
     return status;
 }
 
-void AudioMixer::unprepareTrackForDownmix(track_t* pTrack, int trackName) {
+void AudioMixer::unprepareTrackForDownmix(track_t* pTrack, int trackName __unused) {
     ALOGV("AudioMixer::unprepareTrackForDownmix(%d)", trackName);
 
     if (pTrack->downmixerBufferProvider != NULL) {
@@ -276,13 +254,13 @@
     DownmixerBufferProvider* pDbp = new DownmixerBufferProvider();
     int32_t status;
 
-    if (!isMultichannelCapable) {
+    if (!sIsMultichannelCapable) {
         ALOGE("prepareTrackForDownmix(%d) fails: mixer doesn't support multichannel content",
                 trackName);
         goto noDownmixForActiveTrack;
     }
 
-    if (EffectCreate(&dwnmFxDesc.uuid,
+    if (EffectCreate(&sDwnmFxDesc.uuid,
             pTrack->sessionId /*sessionId*/, -2 /*ioId not relevant here, using random value*/,
             &pDbp->mDownmixHandle/*pHandle*/) != 0) {
         ALOGE("prepareTrackForDownmix(%d) fails: error creating downmixer effect", trackName);
@@ -463,6 +441,13 @@
         //         for a specific track? or per mixer?
         /* case DOWNMIX_TYPE:
             break          */
+        case MIXER_FORMAT: {
+            audio_format_t format = static_cast<audio_format_t>(valueInt);
+            if (track.mMixerFormat != format) {
+                track.mMixerFormat = format;
+                ALOGV("setParameter(TRACK, MIXER_FORMAT, %#x)", format);
+            }
+            } break;
         default:
             LOG_FATAL("bad param");
         }
@@ -560,14 +545,14 @@
                 // Should have a way to distinguish tracks with static ratios vs. dynamic ratios.
                 if (!((value == 44100 && devSampleRate == 48000) ||
                       (value == 48000 && devSampleRate == 44100))) {
-                    quality = AudioResampler::LOW_QUALITY;
+                    quality = AudioResampler::DYN_LOW_QUALITY;
                 } else {
                     quality = AudioResampler::DEFAULT_QUALITY;
                 }
                 resampler = AudioResampler::create(
                         format,
                         // the resampler sees the number of channels after the downmixer, if any
-                        downmixerBufferProvider != NULL ? MAX_NUM_CHANNELS : channelCount,
+                        (int) (downmixerBufferProvider != NULL ? MAX_NUM_CHANNELS : channelCount),
                         devSampleRate, quality);
                 resampler->setLocalTimeFreq(sLocalTimeFreq);
             }
@@ -668,27 +653,29 @@
         countActiveTracks++;
         track_t& t = state->tracks[i];
         uint32_t n = 0;
+        // FIXME can overflow (mask is only 3 bits)
         n |= NEEDS_CHANNEL_1 + t.channelCount - 1;
-        n |= NEEDS_FORMAT_16;
-        n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED;
+        if (t.doesResample()) {
+            n |= NEEDS_RESAMPLE;
+        }
         if (t.auxLevel != 0 && t.auxBuffer != NULL) {
-            n |= NEEDS_AUX_ENABLED;
+            n |= NEEDS_AUX;
         }
 
         if (t.volumeInc[0]|t.volumeInc[1]) {
             volumeRamp = true;
         } else if (!t.doesResample() && t.volumeRL == 0) {
-            n |= NEEDS_MUTE_ENABLED;
+            n |= NEEDS_MUTE;
         }
         t.needs = n;
 
-        if ((n & NEEDS_MUTE__MASK) == NEEDS_MUTE_ENABLED) {
+        if (n & NEEDS_MUTE) {
             t.hook = track__nop;
         } else {
-            if ((n & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
+            if (n & NEEDS_AUX) {
                 all16BitsStereoNoResample = false;
             }
-            if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
+            if (n & NEEDS_RESAMPLE) {
                 all16BitsStereoNoResample = false;
                 resampling = true;
                 t.hook = track__genericResample;
@@ -710,7 +697,7 @@
 
     // select the processing hooks
     state->hook = process__nop;
-    if (countActiveTracks) {
+    if (countActiveTracks > 0) {
         if (resampling) {
             if (!state->outputTemp) {
                 state->outputTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount];
@@ -746,16 +733,15 @@
 
     // Now that the volume ramp has been done, set optimal state and
     // track hooks for subsequent mixer process
-    if (countActiveTracks) {
+    if (countActiveTracks > 0) {
         bool allMuted = true;
         uint32_t en = state->enabledTracks;
         while (en) {
             const int i = 31 - __builtin_clz(en);
             en &= ~(1<<i);
             track_t& t = state->tracks[i];
-            if (!t.doesResample() && t.volumeRL == 0)
-            {
-                t.needs |= NEEDS_MUTE_ENABLED;
+            if (!t.doesResample() && t.volumeRL == 0) {
+                t.needs |= NEEDS_MUTE;
                 t.hook = track__nop;
             } else {
                 allMuted = false;
@@ -806,8 +792,8 @@
     }
 }
 
-void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp,
-        int32_t* aux)
+void AudioMixer::track__nop(track_t* t __unused, int32_t* out __unused,
+        size_t outFrameCount __unused, int32_t* temp __unused, int32_t* aux __unused)
 {
 }
 
@@ -883,8 +869,8 @@
     }
 }
 
-void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp,
-        int32_t* aux)
+void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount,
+        int32_t* temp __unused, int32_t* aux)
 {
     const int16_t *in = static_cast<const int16_t *>(t->in);
 
@@ -974,8 +960,8 @@
     t->in = in;
 }
 
-void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp,
-        int32_t* aux)
+void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount,
+        int32_t* temp __unused, int32_t* aux)
 {
     const int16_t *in = static_cast<int16_t const *>(t->in);
 
@@ -1065,7 +1051,7 @@
 void AudioMixer::process__nop(state_t* state, int64_t pts)
 {
     uint32_t e0 = state->enabledTracks;
-    size_t bufSize = state->frameCount * sizeof(int16_t) * MAX_NUM_CHANNELS;
+    size_t sampleCount = state->frameCount * MAX_NUM_CHANNELS;
     while (e0) {
         // process by group of tracks with same output buffer to
         // avoid multiple memset() on same buffer
@@ -1084,7 +1070,8 @@
             }
             e0 &= ~(e1);
 
-            memset(t1.mainBuffer, 0, bufSize);
+            memset(t1.mainBuffer, 0, sampleCount
+                    * audio_bytes_per_sample(t1.mMixerFormat));
         }
 
         while (e1) {
@@ -1154,7 +1141,7 @@
                 track_t& t = state->tracks[i];
                 size_t outFrames = BLOCKSIZE;
                 int32_t *aux = NULL;
-                if (CC_UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED)) {
+                if (CC_UNLIKELY(t.needs & NEEDS_AUX)) {
                     aux = t.auxBuffer + numFrames;
                 }
                 while (outFrames) {
@@ -1166,7 +1153,7 @@
                         break;
                     }
                     size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
-                    if (inFrames) {
+                    if (inFrames > 0) {
                         t.hook(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames,
                                 state->resampleTemp, aux);
                         t.frameCount -= inFrames;
@@ -1192,8 +1179,18 @@
                     }
                 }
             }
-            ditherAndClamp(out, outTemp, BLOCKSIZE);
-            out += BLOCKSIZE;
+            switch (t1.mMixerFormat) {
+            case AUDIO_FORMAT_PCM_FLOAT:
+                memcpy_to_float_from_q19_12(reinterpret_cast<float *>(out), outTemp, BLOCKSIZE * 2);
+                out += BLOCKSIZE * 2; // output is 2 floats/frame.
+                break;
+            case AUDIO_FORMAT_PCM_16_BIT:
+                ditherAndClamp(out, outTemp, BLOCKSIZE);
+                out += BLOCKSIZE; // output is 1 int32_t (2 int16_t samples)/frame
+                break;
+            default:
+                LOG_ALWAYS_FATAL("bad mixer format: %d", t1.mMixerFormat);
+            }
             numFrames += BLOCKSIZE;
         } while (numFrames < state->frameCount);
     }
@@ -1242,14 +1239,14 @@
             e1 &= ~(1<<i);
             track_t& t = state->tracks[i];
             int32_t *aux = NULL;
-            if (CC_UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED)) {
+            if (CC_UNLIKELY(t.needs & NEEDS_AUX)) {
                 aux = t.auxBuffer;
             }
 
             // this is a little goofy, on the resampling case we don't
             // acquire/release the buffers because it's done by
             // the resampler.
-            if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
+            if (t.needs & NEEDS_RESAMPLE) {
                 t.resampler->setPTS(pts);
                 t.hook(&t, outTemp, numFrames, state->resampleTemp, aux);
             } else {
@@ -1275,7 +1272,16 @@
                 }
             }
         }
-        ditherAndClamp(out, outTemp, numFrames);
+        switch (t1.mMixerFormat) {
+        case AUDIO_FORMAT_PCM_FLOAT:
+            memcpy_to_float_from_q19_12(reinterpret_cast<float*>(out), outTemp, numFrames*2);
+            break;
+        case AUDIO_FORMAT_PCM_16_BIT:
+            ditherAndClamp(out, outTemp, numFrames);
+            break;
+        default:
+            LOG_ALWAYS_FATAL("bad mixer format: %d", t1.mMixerFormat);
+        }
     }
 }
 
@@ -1316,27 +1322,46 @@
         }
         size_t outFrames = b.frameCount;
 
-        if (CC_UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
-            // volume is boosted, so we might need to clamp even though
-            // we process only one track.
+        switch (t.mMixerFormat) {
+        case AUDIO_FORMAT_PCM_FLOAT: {
+            float *fout = reinterpret_cast<float*>(out);
             do {
                 uint32_t rl = *reinterpret_cast<const uint32_t *>(in);
                 in += 2;
-                int32_t l = mulRL(1, rl, vrl) >> 12;
-                int32_t r = mulRL(0, rl, vrl) >> 12;
-                // clamping...
-                l = clamp16(l);
-                r = clamp16(r);
-                *out++ = (r<<16) | (l & 0xFFFF);
+                int32_t l = mulRL(1, rl, vrl);
+                int32_t r = mulRL(0, rl, vrl);
+                *fout++ = float_from_q19_12(l);
+                *fout++ = float_from_q19_12(r);
+                // Note: In case of later int16_t sink output,
+                // conversion and clamping is done by memcpy_to_i16_from_float().
             } while (--outFrames);
-        } else {
-            do {
-                uint32_t rl = *reinterpret_cast<const uint32_t *>(in);
-                in += 2;
-                int32_t l = mulRL(1, rl, vrl) >> 12;
-                int32_t r = mulRL(0, rl, vrl) >> 12;
-                *out++ = (r<<16) | (l & 0xFFFF);
-            } while (--outFrames);
+            } break;
+        case AUDIO_FORMAT_PCM_16_BIT:
+            if (CC_UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
+                // volume is boosted, so we might need to clamp even though
+                // we process only one track.
+                do {
+                    uint32_t rl = *reinterpret_cast<const uint32_t *>(in);
+                    in += 2;
+                    int32_t l = mulRL(1, rl, vrl) >> 12;
+                    int32_t r = mulRL(0, rl, vrl) >> 12;
+                    // clamping...
+                    l = clamp16(l);
+                    r = clamp16(r);
+                    *out++ = (r<<16) | (l & 0xFFFF);
+                } while (--outFrames);
+            } else {
+                do {
+                    uint32_t rl = *reinterpret_cast<const uint32_t *>(in);
+                    in += 2;
+                    int32_t l = mulRL(1, rl, vrl) >> 12;
+                    int32_t r = mulRL(0, rl, vrl) >> 12;
+                    *out++ = (r<<16) | (l & 0xFFFF);
+                } while (--outFrames);
+            }
+            break;
+        default:
+            LOG_ALWAYS_FATAL("bad mixer format: %d", t.mMixerFormat);
         }
         numFrames -= b.frameCount;
         t.bufferProvider->releaseBuffer(&b);
@@ -1449,8 +1474,9 @@
 int64_t AudioMixer::calculateOutputPTS(const track_t& t, int64_t basePTS,
                                        int outputFrameIndex)
 {
-    if (AudioBufferProvider::kInvalidPTS == basePTS)
+    if (AudioBufferProvider::kInvalidPTS == basePTS) {
         return AudioBufferProvider::kInvalidPTS;
+    }
 
     return basePTS + ((outputFrameIndex * sLocalTimeFreq) / t.sampleRate);
 }
@@ -1462,6 +1488,28 @@
 {
     LocalClock lc;
     sLocalTimeFreq = lc.getLocalFreq();
+
+    // find multichannel downmix effect if we have to play multichannel content
+    uint32_t numEffects = 0;
+    int ret = EffectQueryNumberEffects(&numEffects);
+    if (ret != 0) {
+        ALOGE("AudioMixer() error %d querying number of effects", ret);
+        return;
+    }
+    ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects);
+
+    for (uint32_t i = 0 ; i < numEffects ; i++) {
+        if (EffectQueryEffect(i, &sDwnmFxDesc) == 0) {
+            ALOGV("effect %d is called %s", i, sDwnmFxDesc.name);
+            if (memcmp(&sDwnmFxDesc.type, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0) {
+                ALOGI("found effect \"%s\" from %s",
+                        sDwnmFxDesc.name, sDwnmFxDesc.implementor);
+                sIsMultichannelCapable = true;
+                break;
+            }
+        }
+    }
+    ALOGW_IF(!sIsMultichannelCapable, "unable to find downmix effect");
 }
 
 // ----------------------------------------------------------------------------
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 43aeb86..e5e120c 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -77,6 +77,7 @@
         MAIN_BUFFER     = 0x4002,
         AUX_BUFFER      = 0x4003,
         DOWNMIX_TYPE    = 0X4004,
+        MIXER_FORMAT    = 0x4005, // AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
         // for target RESAMPLE
         SAMPLE_RATE     = 0x4100, // Configure sample rate conversion on this track name;
                                   // parameter 'value' is the new sample rate in Hz.
@@ -120,27 +121,19 @@
 private:
 
     enum {
+        // FIXME this representation permits up to 8 channels
         NEEDS_CHANNEL_COUNT__MASK   = 0x00000007,
-        NEEDS_FORMAT__MASK          = 0x000000F0,
-        NEEDS_MUTE__MASK            = 0x00000100,
-        NEEDS_RESAMPLE__MASK        = 0x00001000,
-        NEEDS_AUX__MASK             = 0x00010000,
     };
 
     enum {
-        NEEDS_CHANNEL_1             = 0x00000000,
-        NEEDS_CHANNEL_2             = 0x00000001,
+        NEEDS_CHANNEL_1             = 0x00000000,   // mono
+        NEEDS_CHANNEL_2             = 0x00000001,   // stereo
 
-        NEEDS_FORMAT_16             = 0x00000010,
+        // sample format is not explicitly specified, and is assumed to be AUDIO_FORMAT_PCM_16_BIT
 
-        NEEDS_MUTE_DISABLED         = 0x00000000,
-        NEEDS_MUTE_ENABLED          = 0x00000100,
-
-        NEEDS_RESAMPLE_DISABLED     = 0x00000000,
-        NEEDS_RESAMPLE_ENABLED      = 0x00001000,
-
-        NEEDS_AUX_DISABLED     = 0x00000000,
-        NEEDS_AUX_ENABLED      = 0x00010000,
+        NEEDS_MUTE                  = 0x00000100,
+        NEEDS_RESAMPLE              = 0x00001000,
+        NEEDS_AUX                   = 0x00010000,
     };
 
     struct state_t;
@@ -201,7 +194,9 @@
 
         int32_t     sessionId;
 
-        int32_t     padding[2];
+        audio_format_t mMixerFormat; // at this time: AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
+
+        int32_t     padding[1];
 
         // 16-byte boundary
 
@@ -224,7 +219,7 @@
         NBLog::Writer*  mLog;
         int32_t         reserved[1];
         // FIXME allocate dynamically to save some memory when maxNumTracks < MAX_NUM_TRACKS
-        track_t         tracks[MAX_NUM_TRACKS]; __attribute__((aligned(32)));
+        track_t         tracks[MAX_NUM_TRACKS] __attribute__((aligned(32)));
     };
 
     // AudioBufferProvider that wraps a track AudioBufferProvider by a call to a downmix effect
@@ -256,9 +251,9 @@
     state_t         mState __attribute__((aligned(32)));
 
     // effect descriptor for the downmixer used by the mixer
-    static effect_descriptor_t dwnmFxDesc;
+    static effect_descriptor_t sDwnmFxDesc;
     // indicates whether a downmix effect has been found and is usable by this mixer
-    static bool                isMultichannelCapable;
+    static bool                sIsMultichannelCapable;
 
     // Call after changing either the enabled status of a track, or parameters of an enabled track.
     // OK to call more often than that, but unnecessary.
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index e5cceb1..ca98f16 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -25,6 +25,7 @@
 #include "AudioResampler.h"
 #include "AudioResamplerSinc.h"
 #include "AudioResamplerCubic.h"
+#include "AudioResamplerDyn.h"
 
 #ifdef __arm__
 #include <machine/cpu-features.h>
@@ -77,6 +78,9 @@
     int mX0R;
 };
 
+/*static*/
+const double AudioResampler::kPhaseMultiplier = 1L << AudioResampler::kNumPhaseBits;
+
 bool AudioResampler::qualityIsSupported(src_quality quality)
 {
     switch (quality) {
@@ -85,6 +89,9 @@
     case MED_QUALITY:
     case HIGH_QUALITY:
     case VERY_HIGH_QUALITY:
+    case DYN_LOW_QUALITY:
+    case DYN_MED_QUALITY:
+    case DYN_HIGH_QUALITY:
         return true;
     default:
         return false;
@@ -105,7 +112,7 @@
         if (*endptr == '\0') {
             defaultQuality = (src_quality) l;
             ALOGD("forcing AudioResampler quality to %d", defaultQuality);
-            if (defaultQuality < DEFAULT_QUALITY || defaultQuality > VERY_HIGH_QUALITY) {
+            if (defaultQuality < DEFAULT_QUALITY || defaultQuality > DYN_HIGH_QUALITY) {
                 defaultQuality = DEFAULT_QUALITY;
             }
         }
@@ -125,6 +132,12 @@
         return 20;
     case VERY_HIGH_QUALITY:
         return 34;
+    case DYN_LOW_QUALITY:
+        return 4;
+    case DYN_MED_QUALITY:
+        return 6;
+    case DYN_HIGH_QUALITY:
+        return 12;
     }
 }
 
@@ -148,6 +161,16 @@
         atFinalQuality = true;
     }
 
+    /* if the caller requests DEFAULT_QUALITY and af.resampler.property
+     * has not been set, the target resampler quality is set to DYN_MED_QUALITY,
+     * and allowed to "throttle" down to DYN_LOW_QUALITY if necessary
+     * due to estimated CPU load of having too many active resamplers
+     * (the code below the if).
+     */
+    if (quality == DEFAULT_QUALITY) {
+        quality = DYN_MED_QUALITY;
+    }
+
     // naive implementation of CPU load throttling doesn't account for whether resampler is active
     pthread_mutex_lock(&mutex);
     for (;;) {
@@ -162,7 +185,6 @@
         // not enough CPU available for proposed quality level, so try next lowest level
         switch (quality) {
         default:
-        case DEFAULT_QUALITY:
         case LOW_QUALITY:
             atFinalQuality = true;
             break;
@@ -175,6 +197,15 @@
         case VERY_HIGH_QUALITY:
             quality = HIGH_QUALITY;
             break;
+        case DYN_LOW_QUALITY:
+            atFinalQuality = true;
+            break;
+        case DYN_MED_QUALITY:
+            quality = DYN_LOW_QUALITY;
+            break;
+        case DYN_HIGH_QUALITY:
+            quality = DYN_MED_QUALITY;
+            break;
         }
     }
     pthread_mutex_unlock(&mutex);
@@ -183,7 +214,6 @@
 
     switch (quality) {
     default:
-    case DEFAULT_QUALITY:
     case LOW_QUALITY:
         ALOGV("Create linear Resampler");
         resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
@@ -200,6 +230,12 @@
         ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d", quality);
         resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate, quality);
         break;
+    case DYN_LOW_QUALITY:
+    case DYN_MED_QUALITY:
+    case DYN_HIGH_QUALITY:
+        ALOGV("Create dynamic Resampler = %d", quality);
+        resampler = new AudioResamplerDyn(bitDepth, inChannelCount, sampleRate, quality);
+        break;
     }
 
     // initialize resampler
@@ -305,7 +341,7 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
-    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+    size_t inFrameCount = getInFrameCountRequired(outFrameCount);
 
     // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
     //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
@@ -339,8 +375,9 @@
             out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction);
             out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction);
             Advance(&inputIndex, &phaseFraction, phaseIncrement);
-            if (outputIndex == outputSampleCount)
+            if (outputIndex == outputSampleCount) {
                 break;
+            }
         }
 
         // process input samples
@@ -402,7 +439,7 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
-    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+    size_t inFrameCount = getInFrameCountRequired(outFrameCount);
 
     // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
     //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
@@ -434,8 +471,9 @@
             out[outputIndex++] += vl * sample;
             out[outputIndex++] += vr * sample;
             Advance(&inputIndex, &phaseFraction, phaseIncrement);
-            if (outputIndex == outputSampleCount)
+            if (outputIndex == outputSampleCount) {
                 break;
+            }
         }
 
         // process input samples
@@ -514,6 +552,16 @@
             size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
             uint32_t &phaseFraction, uint32_t phaseIncrement)
 {
+    (void)maxOutPt; // remove unused parameter warnings
+    (void)maxInIdx;
+    (void)outputIndex;
+    (void)out;
+    (void)inputIndex;
+    (void)vl;
+    (void)vr;
+    (void)phaseFraction;
+    (void)phaseIncrement;
+    (void)in;
 #define MO_PARAM5   "36"        // offset of parameter 5 (outputIndex)
 
     asm(
@@ -625,6 +673,16 @@
             size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
             uint32_t &phaseFraction, uint32_t phaseIncrement)
 {
+    (void)maxOutPt; // remove unused parameter warnings
+    (void)maxInIdx;
+    (void)outputIndex;
+    (void)out;
+    (void)inputIndex;
+    (void)vl;
+    (void)vr;
+    (void)phaseFraction;
+    (void)phaseIncrement;
+    (void)in;
 #define ST_PARAM5    "40"     // offset of parameter 5 (outputIndex)
     asm(
         "stmfd  sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n"
diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h
index 33e64ce..0592855 100644
--- a/services/audioflinger/AudioResampler.h
+++ b/services/audioflinger/AudioResampler.h
@@ -41,6 +41,9 @@
         MED_QUALITY=2,
         HIGH_QUALITY=3,
         VERY_HIGH_QUALITY=4,
+        DYN_LOW_QUALITY=5,
+        DYN_MED_QUALITY=6,
+        DYN_HIGH_QUALITY=7,
     };
 
     static AudioResampler* create(int bitDepth, int inChannelCount,
@@ -81,7 +84,7 @@
     static const uint32_t kPhaseMask = (1LU<<kNumPhaseBits)-1;
 
     // multiplier to calculate fixed point phase increment
-    static const double kPhaseMultiplier = 1L << kNumPhaseBits;
+    static const double kPhaseMultiplier;
 
     AudioResampler(int bitDepth, int inChannelCount, int32_t sampleRate, src_quality quality);
 
@@ -107,6 +110,38 @@
     uint64_t mLocalTimeFreq;
     int64_t mPTS;
 
+    // returns the inFrameCount required to generate outFrameCount frames.
+    //
+    // Placed here to be a consistent for all resamplers.
+    //
+    // Right now, we use the upper bound without regards to the current state of the
+    // input buffer using integer arithmetic, as follows:
+    //
+    // (static_cast<uint64_t>(outFrameCount)*mInSampleRate + (mSampleRate - 1))/mSampleRate;
+    //
+    // The double precision equivalent (float may not be precise enough):
+    // ceil(static_cast<double>(outFrameCount) * mInSampleRate / mSampleRate);
+    //
+    // this relies on the fact that the mPhaseIncrement is rounded down from
+    // #phases * mInSampleRate/mSampleRate and the fact that Sum(Floor(x)) <= Floor(Sum(x)).
+    // http://www.proofwiki.org/wiki/Sum_of_Floors_Not_Greater_Than_Floor_of_Sums
+    //
+    // (so long as double precision is computed accurately enough to be considered
+    // greater than or equal to the Floor(x) value in int32_t arithmetic; thus this
+    // will not necessarily hold for floats).
+    //
+    // TODO:
+    // Greater accuracy and a tight bound is obtained by:
+    // 1) subtract and adjust for the current state of the AudioBufferProvider buffer.
+    // 2) using the exact integer formula where (ignoring 64b casting)
+    //  inFrameCount = (mPhaseIncrement * (outFrameCount - 1) + mPhaseFraction) / phaseWrapLimit;
+    //  phaseWrapLimit is the wraparound (1 << kNumPhaseBits), if not specified explicitly.
+    //
+    inline size_t getInFrameCountRequired(size_t outFrameCount) {
+        return (static_cast<uint64_t>(outFrameCount)*mInSampleRate
+                + (mSampleRate - 1))/mSampleRate;
+    }
+
 private:
     const src_quality mQuality;
 
diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp
index 18e59e9..8f14ff9 100644
--- a/services/audioflinger/AudioResamplerCubic.cpp
+++ b/services/audioflinger/AudioResamplerCubic.cpp
@@ -60,14 +60,15 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
-    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+    size_t inFrameCount = getInFrameCountRequired(outFrameCount);
 
     // fetch first buffer
     if (mBuffer.frameCount == 0) {
         mBuffer.frameCount = inFrameCount;
         provider->getNextBuffer(&mBuffer, mPTS);
-        if (mBuffer.raw == NULL)
+        if (mBuffer.raw == NULL) {
             return;
+        }
         // ALOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount);
     }
     int16_t *in = mBuffer.i16;
@@ -97,8 +98,9 @@
                 mBuffer.frameCount = inFrameCount;
                 provider->getNextBuffer(&mBuffer,
                                         calculateOutputPTS(outputIndex / 2));
-                if (mBuffer.raw == NULL)
+                if (mBuffer.raw == NULL) {
                     goto save_state;  // ugly, but efficient
+                }
                 in = mBuffer.i16;
                 // ALOGW("New buffer: offset=%p, frames=%d", mBuffer.raw, mBuffer.frameCount);
             }
@@ -126,14 +128,15 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
-    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+    size_t inFrameCount = getInFrameCountRequired(outFrameCount);
 
     // fetch first buffer
     if (mBuffer.frameCount == 0) {
         mBuffer.frameCount = inFrameCount;
         provider->getNextBuffer(&mBuffer, mPTS);
-        if (mBuffer.raw == NULL)
+        if (mBuffer.raw == NULL) {
             return;
+        }
         // ALOGW("New buffer: offset=%p, frames=%d", mBuffer.raw, mBuffer.frameCount);
     }
     int16_t *in = mBuffer.i16;
@@ -163,8 +166,9 @@
                 mBuffer.frameCount = inFrameCount;
                 provider->getNextBuffer(&mBuffer,
                                         calculateOutputPTS(outputIndex / 2));
-                if (mBuffer.raw == NULL)
+                if (mBuffer.raw == NULL) {
                     goto save_state;  // ugly, but efficient
+                }
                 // ALOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount);
                 in = mBuffer.i16;
             }
diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/services/audioflinger/AudioResamplerDyn.cpp
new file mode 100644
index 0000000..7e4ca0c
--- /dev/null
+++ b/services/audioflinger/AudioResamplerDyn.cpp
@@ -0,0 +1,559 @@
+/*
+ * 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 "AudioResamplerDyn"
+//#define LOG_NDEBUG 0
+
+#include <malloc.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <math.h>
+
+#include <cutils/compiler.h>
+#include <cutils/properties.h>
+#include <utils/Log.h>
+
+#include "AudioResamplerFirOps.h" // USE_NEON and USE_INLINE_ASSEMBLY defined here
+#include "AudioResamplerFirProcess.h"
+#include "AudioResamplerFirProcessNeon.h"
+#include "AudioResamplerFirGen.h" // requires math.h
+#include "AudioResamplerDyn.h"
+
+//#define DEBUG_RESAMPLER
+
+namespace android {
+
+// generate a unique resample type compile-time constant (constexpr)
+#define RESAMPLETYPE(CHANNELS, LOCKED, STRIDE, COEFTYPE) \
+    ((((CHANNELS)-1)&1) | !!(LOCKED)<<1 | (COEFTYPE)<<2 \
+    | ((STRIDE)==8 ? 1 : (STRIDE)==16 ? 2 : 0)<<3)
+
+/*
+ * InBuffer is a type agnostic input buffer.
+ *
+ * Layout of the state buffer for halfNumCoefs=8.
+ *
+ * [rrrrrrppppppppnnnnnnnnrrrrrrrrrrrrrrrrrrr.... rrrrrrr]
+ *  S            I                                R
+ *
+ * S = mState
+ * I = mImpulse
+ * R = mRingFull
+ * p = past samples, convoluted with the (p)ositive side of sinc()
+ * n = future samples, convoluted with the (n)egative side of sinc()
+ * r = extra space for implementing the ring buffer
+ */
+
+template<typename TI>
+AudioResamplerDyn::InBuffer<TI>::InBuffer()
+    : mState(NULL), mImpulse(NULL), mRingFull(NULL), mStateSize(0) {
+}
+
+template<typename TI>
+AudioResamplerDyn::InBuffer<TI>::~InBuffer() {
+    init();
+}
+
+template<typename TI>
+void AudioResamplerDyn::InBuffer<TI>::init() {
+    free(mState);
+    mState = NULL;
+    mImpulse = NULL;
+    mRingFull = NULL;
+    mStateSize = 0;
+}
+
+// resizes the state buffer to accommodate the appropriate filter length
+template<typename TI>
+void AudioResamplerDyn::InBuffer<TI>::resize(int CHANNELS, int halfNumCoefs) {
+    // calculate desired state size
+    int stateSize = halfNumCoefs * CHANNELS * 2
+            * kStateSizeMultipleOfFilterLength;
+
+    // check if buffer needs resizing
+    if (mState
+            && stateSize == mStateSize
+            && mRingFull-mState == mStateSize-halfNumCoefs*CHANNELS) {
+        return;
+    }
+
+    // create new buffer
+    TI* state = (int16_t*)memalign(32, stateSize*sizeof(*state));
+    memset(state, 0, stateSize*sizeof(*state));
+
+    // attempt to preserve state
+    if (mState) {
+        TI* srcLo = mImpulse - halfNumCoefs*CHANNELS;
+        TI* srcHi = mImpulse + halfNumCoefs*CHANNELS;
+        TI* dst = state;
+
+        if (srcLo < mState) {
+            dst += mState-srcLo;
+            srcLo = mState;
+        }
+        if (srcHi > mState + mStateSize) {
+            srcHi = mState + mStateSize;
+        }
+        memcpy(dst, srcLo, (srcHi - srcLo) * sizeof(*srcLo));
+        free(mState);
+    }
+
+    // set class member vars
+    mState = state;
+    mStateSize = stateSize;
+    mImpulse = mState + halfNumCoefs*CHANNELS; // actually one sample greater than needed
+    mRingFull = mState + mStateSize - halfNumCoefs*CHANNELS;
+}
+
+// copy in the input data into the head (impulse+halfNumCoefs) of the buffer.
+template<typename TI>
+template<int CHANNELS>
+void AudioResamplerDyn::InBuffer<TI>::readAgain(TI*& impulse, const int halfNumCoefs,
+        const TI* const in, const size_t inputIndex) {
+    int16_t* head = impulse + halfNumCoefs*CHANNELS;
+    for (size_t i=0 ; i<CHANNELS ; i++) {
+        head[i] = in[inputIndex*CHANNELS + i];
+    }
+}
+
+// advance the impulse pointer, and load in data into the head (impulse+halfNumCoefs)
+template<typename TI>
+template<int CHANNELS>
+void AudioResamplerDyn::InBuffer<TI>::readAdvance(TI*& impulse, const int halfNumCoefs,
+        const TI* const in, const size_t inputIndex) {
+    impulse += CHANNELS;
+
+    if (CC_UNLIKELY(impulse >= mRingFull)) {
+        const size_t shiftDown = mRingFull - mState - halfNumCoefs*CHANNELS;
+        memcpy(mState, mState+shiftDown, halfNumCoefs*CHANNELS*2*sizeof(TI));
+        impulse -= shiftDown;
+    }
+    readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
+}
+
+void AudioResamplerDyn::Constants::set(
+        int L, int halfNumCoefs, int inSampleRate, int outSampleRate)
+{
+    int bits = 0;
+    int lscale = inSampleRate/outSampleRate < 2 ? L - 1 :
+            static_cast<int>(static_cast<uint64_t>(L)*inSampleRate/outSampleRate);
+    for (int i=lscale; i; ++bits, i>>=1)
+        ;
+    mL = L;
+    mShift = kNumPhaseBits - bits;
+    mHalfNumCoefs = halfNumCoefs;
+}
+
+AudioResamplerDyn::AudioResamplerDyn(int bitDepth,
+        int inChannelCount, int32_t sampleRate, src_quality quality)
+    : AudioResampler(bitDepth, inChannelCount, sampleRate, quality),
+    mResampleType(0), mFilterSampleRate(0), mFilterQuality(DEFAULT_QUALITY),
+    mCoefBuffer(NULL)
+{
+    mVolumeSimd[0] = mVolumeSimd[1] = 0;
+    // The AudioResampler base class assumes we are always ready for 1:1 resampling.
+    // We reset mInSampleRate to 0, so setSampleRate() will calculate filters for
+    // setSampleRate() for 1:1. (May be removed if precalculated filters are used.)
+    mInSampleRate = 0;
+    mConstants.set(128, 8, mSampleRate, mSampleRate); // TODO: set better
+}
+
+AudioResamplerDyn::~AudioResamplerDyn() {
+    free(mCoefBuffer);
+}
+
+void AudioResamplerDyn::init() {
+    mFilterSampleRate = 0; // always trigger new filter generation
+    mInBuffer.init();
+}
+
+void AudioResamplerDyn::setVolume(int16_t left, int16_t right) {
+    AudioResampler::setVolume(left, right);
+    mVolumeSimd[0] = static_cast<int32_t>(left)<<16;
+    mVolumeSimd[1] = static_cast<int32_t>(right)<<16;
+}
+
+template <typename T> T max(T a, T b) {return a > b ? a : b;}
+
+template <typename T> T absdiff(T a, T b) {return a > b ? a - b : b - a;}
+
+template<typename T>
+void AudioResamplerDyn::createKaiserFir(Constants &c, double stopBandAtten,
+        int inSampleRate, int outSampleRate, double tbwCheat) {
+    T* buf = reinterpret_cast<T*>(memalign(32, (c.mL+1)*c.mHalfNumCoefs*sizeof(T)));
+    static const double atten = 0.9998;   // to avoid ripple overflow
+    double fcr;
+    double tbw = firKaiserTbw(c.mHalfNumCoefs, stopBandAtten);
+
+    if (inSampleRate < outSampleRate) { // upsample
+        fcr = max(0.5*tbwCheat - tbw/2, tbw/2);
+    } else { // downsample
+        fcr = max(0.5*tbwCheat*outSampleRate/inSampleRate - tbw/2, tbw/2);
+    }
+    // create and set filter
+    firKaiserGen(buf, c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, atten);
+    c.setBuf(buf);
+    if (mCoefBuffer) {
+        free(mCoefBuffer);
+    }
+    mCoefBuffer = buf;
+#ifdef DEBUG_RESAMPLER
+    // print basic filter stats
+    printf("L:%d  hnc:%d  stopBandAtten:%lf  fcr:%lf  atten:%lf  tbw:%lf\n",
+            c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, atten, tbw);
+    // test the filter and report results
+    double fp = (fcr - tbw/2)/c.mL;
+    double fs = (fcr + tbw/2)/c.mL;
+    double passMin, passMax, passRipple;
+    double stopMax, stopRipple;
+    testFir(buf, c.mL, c.mHalfNumCoefs, fp, fs, /*passSteps*/ 1000, /*stopSteps*/ 100000,
+            passMin, passMax, passRipple, stopMax, stopRipple);
+    printf("passband(%lf, %lf): %.8lf %.8lf %.8lf\n", 0., fp, passMin, passMax, passRipple);
+    printf("stopband(%lf, %lf): %.8lf %.3lf\n", fs, 0.5, stopMax, stopRipple);
+#endif
+}
+
+// recursive gcd. Using objdump, it appears the tail recursion is converted to a while loop.
+static int gcd(int n, int m) {
+    if (m == 0) {
+        return n;
+    }
+    return gcd(m, n % m);
+}
+
+static bool isClose(int32_t newSampleRate, int32_t prevSampleRate,
+        int32_t filterSampleRate, int32_t outSampleRate) {
+
+    // different upsampling ratios do not need a filter change.
+    if (filterSampleRate != 0
+            && filterSampleRate < outSampleRate
+            && newSampleRate < outSampleRate)
+        return true;
+
+    // check design criteria again if downsampling is detected.
+    int pdiff = absdiff(newSampleRate, prevSampleRate);
+    int adiff = absdiff(newSampleRate, filterSampleRate);
+
+    // allow up to 6% relative change increments.
+    // allow up to 12% absolute change increments (from filter design)
+    return pdiff < prevSampleRate>>4 && adiff < filterSampleRate>>3;
+}
+
+void AudioResamplerDyn::setSampleRate(int32_t inSampleRate) {
+    if (mInSampleRate == inSampleRate) {
+        return;
+    }
+    int32_t oldSampleRate = mInSampleRate;
+    int32_t oldHalfNumCoefs = mConstants.mHalfNumCoefs;
+    uint32_t oldPhaseWrapLimit = mConstants.mL << mConstants.mShift;
+    bool useS32 = false;
+
+    mInSampleRate = inSampleRate;
+
+    // TODO: Add precalculated Equiripple filters
+
+    if (mFilterQuality != getQuality() ||
+            !isClose(inSampleRate, oldSampleRate, mFilterSampleRate, mSampleRate)) {
+        mFilterSampleRate = inSampleRate;
+        mFilterQuality = getQuality();
+
+        // Begin Kaiser Filter computation
+        //
+        // The quantization floor for S16 is about 96db - 10*log_10(#length) + 3dB.
+        // Keep the stop band attenuation no greater than 84-85dB for 32 length S16 filters
+        //
+        // For s32 we keep the stop band attenuation at the same as 16b resolution, about
+        // 96-98dB
+        //
+
+        double stopBandAtten;
+        double tbwCheat = 1.; // how much we "cheat" into aliasing
+        int halfLength;
+        if (mFilterQuality == DYN_HIGH_QUALITY) {
+            // 32b coefficients, 64 length
+            useS32 = true;
+            stopBandAtten = 98.;
+            if (inSampleRate >= mSampleRate * 4) {
+                halfLength = 48;
+            } else if (inSampleRate >= mSampleRate * 2) {
+                halfLength = 40;
+            } else {
+                halfLength = 32;
+            }
+        } else if (mFilterQuality == DYN_LOW_QUALITY) {
+            // 16b coefficients, 16-32 length
+            useS32 = false;
+            stopBandAtten = 80.;
+            if (inSampleRate >= mSampleRate * 4) {
+                halfLength = 24;
+            } else if (inSampleRate >= mSampleRate * 2) {
+                halfLength = 16;
+            } else {
+                halfLength = 8;
+            }
+            if (inSampleRate <= mSampleRate) {
+                tbwCheat = 1.05;
+            } else {
+                tbwCheat = 1.03;
+            }
+        } else { // DYN_MED_QUALITY
+            // 16b coefficients, 32-64 length
+            // note: > 64 length filters with 16b coefs can have quantization noise problems
+            useS32 = false;
+            stopBandAtten = 84.;
+            if (inSampleRate >= mSampleRate * 4) {
+                halfLength = 32;
+            } else if (inSampleRate >= mSampleRate * 2) {
+                halfLength = 24;
+            } else {
+                halfLength = 16;
+            }
+            if (inSampleRate <= mSampleRate) {
+                tbwCheat = 1.03;
+            } else {
+                tbwCheat = 1.01;
+            }
+        }
+
+        // determine the number of polyphases in the filterbank.
+        // for 16b, it is desirable to have 2^(16/2) = 256 phases.
+        // https://ccrma.stanford.edu/~jos/resample/Relation_Interpolation_Error_Quantization.html
+        //
+        // We are a bit more lax on this.
+
+        int phases = mSampleRate / gcd(mSampleRate, inSampleRate);
+
+        // TODO: Once dynamic sample rate change is an option, the code below
+        // should be modified to execute only when dynamic sample rate change is enabled.
+        //
+        // as above, #phases less than 63 is too few phases for accurate linear interpolation.
+        // we increase the phases to compensate, but more phases means more memory per
+        // filter and more time to compute the filter.
+        //
+        // if we know that the filter will be used for dynamic sample rate changes,
+        // that would allow us skip this part for fixed sample rate resamplers.
+        //
+        while (phases<63) {
+            phases *= 2; // this code only needed to support dynamic rate changes
+        }
+
+        if (phases>=256) {  // too many phases, always interpolate
+            phases = 127;
+        }
+
+        // create the filter
+        mConstants.set(phases, halfLength, inSampleRate, mSampleRate);
+        if (useS32) {
+            createKaiserFir<int32_t>(mConstants, stopBandAtten,
+                    inSampleRate, mSampleRate, tbwCheat);
+        } else {
+            createKaiserFir<int16_t>(mConstants, stopBandAtten,
+                    inSampleRate, mSampleRate, tbwCheat);
+        }
+    } // End Kaiser filter
+
+    // update phase and state based on the new filter.
+    const Constants& c(mConstants);
+    mInBuffer.resize(mChannelCount, c.mHalfNumCoefs);
+    const uint32_t phaseWrapLimit = c.mL << c.mShift;
+    // try to preserve as much of the phase fraction as possible for on-the-fly changes
+    mPhaseFraction = static_cast<unsigned long long>(mPhaseFraction)
+            * phaseWrapLimit / oldPhaseWrapLimit;
+    mPhaseFraction %= phaseWrapLimit; // should not do anything, but just in case.
+    mPhaseIncrement = static_cast<uint32_t>(static_cast<double>(phaseWrapLimit)
+            * inSampleRate / mSampleRate);
+
+    // determine which resampler to use
+    // check if locked phase (works only if mPhaseIncrement has no "fractional phase bits")
+    int locked = (mPhaseIncrement << (sizeof(mPhaseIncrement)*8 - c.mShift)) == 0;
+    int stride = (c.mHalfNumCoefs&7)==0 ? 16 : (c.mHalfNumCoefs&3)==0 ? 8 : 2;
+    if (locked) {
+        mPhaseFraction = mPhaseFraction >> c.mShift << c.mShift; // remove fractional phase
+    }
+
+    mResampleType = RESAMPLETYPE(mChannelCount, locked, stride, !!useS32);
+#ifdef DEBUG_RESAMPLER
+    printf("channels:%d  %s  stride:%d  %s  coef:%d  shift:%d\n",
+            mChannelCount, locked ? "locked" : "interpolated",
+            stride, useS32 ? "S32" : "S16", 2*c.mHalfNumCoefs, c.mShift);
+#endif
+}
+
+void AudioResamplerDyn::resample(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider)
+{
+    // TODO:
+    // 24 cases - this perhaps can be reduced later, as testing might take too long
+    switch (mResampleType) {
+
+    // stride 16 (falls back to stride 2 for machines that do not support NEON)
+    case RESAMPLETYPE(1, true, 16, 0):
+        return resample<1, true, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
+    case RESAMPLETYPE(2, true, 16, 0):
+        return resample<2, true, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
+    case RESAMPLETYPE(1, false, 16, 0):
+        return resample<1, false, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
+    case RESAMPLETYPE(2, false, 16, 0):
+        return resample<2, false, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
+    case RESAMPLETYPE(1, true, 16, 1):
+        return resample<1, true, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
+    case RESAMPLETYPE(2, true, 16, 1):
+        return resample<2, true, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
+    case RESAMPLETYPE(1, false, 16, 1):
+        return resample<1, false, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
+    case RESAMPLETYPE(2, false, 16, 1):
+        return resample<2, false, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
+#if 0
+    // TODO: Remove these?
+    // stride 8
+    case RESAMPLETYPE(1, true, 8, 0):
+        return resample<1, true, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
+    case RESAMPLETYPE(2, true, 8, 0):
+        return resample<2, true, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
+    case RESAMPLETYPE(1, false, 8, 0):
+        return resample<1, false, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
+    case RESAMPLETYPE(2, false, 8, 0):
+        return resample<2, false, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
+    case RESAMPLETYPE(1, true, 8, 1):
+        return resample<1, true, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
+    case RESAMPLETYPE(2, true, 8, 1):
+        return resample<2, true, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
+    case RESAMPLETYPE(1, false, 8, 1):
+        return resample<1, false, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
+    case RESAMPLETYPE(2, false, 8, 1):
+        return resample<2, false, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
+    // stride 2 (can handle any filter length)
+    case RESAMPLETYPE(1, true, 2, 0):
+        return resample<1, true, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
+    case RESAMPLETYPE(2, true, 2, 0):
+        return resample<2, true, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
+    case RESAMPLETYPE(1, false, 2, 0):
+        return resample<1, false, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
+    case RESAMPLETYPE(2, false, 2, 0):
+        return resample<2, false, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
+    case RESAMPLETYPE(1, true, 2, 1):
+        return resample<1, true, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
+    case RESAMPLETYPE(2, true, 2, 1):
+        return resample<2, true, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
+    case RESAMPLETYPE(1, false, 2, 1):
+        return resample<1, false, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
+    case RESAMPLETYPE(2, false, 2, 1):
+        return resample<2, false, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
+#endif
+    default:
+        ; // error
+    }
+}
+
+template<int CHANNELS, bool LOCKED, int STRIDE, typename TC>
+void AudioResamplerDyn::resample(int32_t* out, size_t outFrameCount,
+        const TC* const coefs,  AudioBufferProvider* provider)
+{
+    const Constants& c(mConstants);
+    int16_t* impulse = mInBuffer.getImpulse();
+    size_t inputIndex = mInputIndex;
+    uint32_t phaseFraction = mPhaseFraction;
+    const uint32_t phaseIncrement = mPhaseIncrement;
+    size_t outputIndex = 0;
+    size_t outputSampleCount = outFrameCount * 2;   // stereo output
+    size_t inFrameCount = getInFrameCountRequired(outFrameCount);
+    const uint32_t phaseWrapLimit = c.mL << c.mShift;
+
+    // NOTE: be very careful when modifying the code here. register
+    // pressure is very high and a small change might cause the compiler
+    // to generate far less efficient code.
+    // Always sanity check the result with objdump or test-resample.
+
+    // the following logic is a bit convoluted to keep the main processing loop
+    // as tight as possible with register allocation.
+    while (outputIndex < outputSampleCount) {
+        // buffer is empty, fetch a new one
+        while (mBuffer.frameCount == 0) {
+            mBuffer.frameCount = inFrameCount;
+            provider->getNextBuffer(&mBuffer,
+                    calculateOutputPTS(outputIndex / 2));
+            if (mBuffer.raw == NULL) {
+                goto resample_exit;
+            }
+            if (phaseFraction >= phaseWrapLimit) { // read in data
+                mInBuffer.readAdvance<CHANNELS>(
+                        impulse, c.mHalfNumCoefs, mBuffer.i16, inputIndex);
+                phaseFraction -= phaseWrapLimit;
+                while (phaseFraction >= phaseWrapLimit) {
+                    inputIndex++;
+                    if (inputIndex >= mBuffer.frameCount) {
+                        inputIndex -= mBuffer.frameCount;
+                        provider->releaseBuffer(&mBuffer);
+                        break;
+                    }
+                    mInBuffer.readAdvance<CHANNELS>(
+                            impulse, c.mHalfNumCoefs, mBuffer.i16, inputIndex);
+                    phaseFraction -= phaseWrapLimit;
+                }
+            }
+        }
+        const int16_t* const in = mBuffer.i16;
+        const size_t frameCount = mBuffer.frameCount;
+        const int coefShift = c.mShift;
+        const int halfNumCoefs = c.mHalfNumCoefs;
+        const int32_t* const volumeSimd = mVolumeSimd;
+
+        // reread the last input in.
+        mInBuffer.readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
+
+        // main processing loop
+        while (CC_LIKELY(outputIndex < outputSampleCount)) {
+            // caution: fir() is inlined and may be large.
+            // output will be loaded with the appropriate values
+            //
+            // from the input samples in impulse[-halfNumCoefs+1]... impulse[halfNumCoefs]
+            // from the polyphase filter of (phaseFraction / phaseWrapLimit) in coefs.
+            //
+            fir<CHANNELS, LOCKED, STRIDE>(
+                    &out[outputIndex],
+                    phaseFraction, phaseWrapLimit,
+                    coefShift, halfNumCoefs, coefs,
+                    impulse, volumeSimd);
+            outputIndex += 2;
+
+            phaseFraction += phaseIncrement;
+            while (phaseFraction >= phaseWrapLimit) {
+                inputIndex++;
+                if (inputIndex >= frameCount) {
+                    goto done;  // need a new buffer
+                }
+                mInBuffer.readAdvance<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
+                phaseFraction -= phaseWrapLimit;
+            }
+        }
+done:
+        // often arrives here when input buffer runs out
+        if (inputIndex >= frameCount) {
+            inputIndex -= frameCount;
+            provider->releaseBuffer(&mBuffer);
+            // mBuffer.frameCount MUST be zero here.
+        }
+    }
+
+resample_exit:
+    mInBuffer.setImpulse(impulse);
+    mInputIndex = inputIndex;
+    mPhaseFraction = phaseFraction;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/audioflinger/AudioResamplerDyn.h b/services/audioflinger/AudioResamplerDyn.h
new file mode 100644
index 0000000..df1fdbe
--- /dev/null
+++ b/services/audioflinger/AudioResamplerDyn.h
@@ -0,0 +1,124 @@
+/*
+ * 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_RESAMPLER_DYN_H
+#define ANDROID_AUDIO_RESAMPLER_DYN_H
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+
+#include "AudioResampler.h"
+
+namespace android {
+
+class AudioResamplerDyn: public AudioResampler {
+public:
+    AudioResamplerDyn(int bitDepth, int inChannelCount, int32_t sampleRate,
+            src_quality quality);
+
+    virtual ~AudioResamplerDyn();
+
+    virtual void init();
+
+    virtual void setSampleRate(int32_t inSampleRate);
+
+    virtual void setVolume(int16_t left, int16_t right);
+
+    virtual void resample(int32_t* out, size_t outFrameCount,
+            AudioBufferProvider* provider);
+
+private:
+
+    class Constants { // stores the filter constants.
+    public:
+        Constants() :
+            mL(0), mShift(0), mHalfNumCoefs(0), mFirCoefsS16(NULL)
+        {}
+        void set(int L, int halfNumCoefs,
+                int inSampleRate, int outSampleRate);
+        inline void setBuf(int16_t* buf) {
+            mFirCoefsS16 = buf;
+        }
+        inline void setBuf(int32_t* buf) {
+            mFirCoefsS32 = buf;
+        }
+
+        int mL;       // interpolation phases in the filter.
+        int mShift;   // right shift to get polyphase index
+        unsigned int mHalfNumCoefs; // filter half #coefs
+        union {       // polyphase filter bank
+            const int16_t* mFirCoefsS16;
+            const int32_t* mFirCoefsS32;
+        };
+    };
+
+    // Input buffer management for a given input type TI, now (int16_t)
+    // Is agnostic of the actual type, can work with int32_t and float.
+    template<typename TI>
+    class InBuffer {
+    public:
+        InBuffer();
+        ~InBuffer();
+        void init();
+        void resize(int CHANNELS, int halfNumCoefs);
+
+        // used for direct management of the mImpulse pointer
+        inline TI* getImpulse() {
+            return mImpulse;
+        }
+        inline void setImpulse(TI *impulse) {
+            mImpulse = impulse;
+        }
+        template<int CHANNELS>
+        inline void readAgain(TI*& impulse, const int halfNumCoefs,
+                const TI* const in, const size_t inputIndex);
+        template<int CHANNELS>
+        inline void readAdvance(TI*& impulse, const int halfNumCoefs,
+                const TI* const in, const size_t inputIndex);
+
+    private:
+        // tuning parameter guidelines: 2 <= multiple <= 8
+        static const int kStateSizeMultipleOfFilterLength = 4;
+
+        TI* mState;    // base pointer for the input buffer storage
+        TI* mImpulse;  // current location of the impulse response (centered)
+        TI* mRingFull; // mState <= mImpulse < mRingFull
+        // in general, mRingFull = mState + mStateSize - halfNumCoefs*CHANNELS.
+        size_t mStateSize; // in units of TI.
+    };
+
+    template<int CHANNELS, bool LOCKED, int STRIDE, typename TC>
+    void resample(int32_t* out, size_t outFrameCount,
+            const TC* const coefs, AudioBufferProvider* provider);
+
+    template<typename T>
+    void createKaiserFir(Constants &c, double stopBandAtten,
+            int inSampleRate, int outSampleRate, double tbwCheat);
+
+    InBuffer<int16_t> mInBuffer;
+    Constants mConstants;  // current set of coefficient parameters
+    int32_t __attribute__ ((aligned (8))) mVolumeSimd[2];
+    int32_t mResampleType; // contains the resample type.
+    int32_t mFilterSampleRate; // designed filter sample rate.
+    src_quality mFilterQuality; // designed filter quality.
+    void* mCoefBuffer; // if a filter is created, this is not null
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif /*ANDROID_AUDIO_RESAMPLER_DYN_H*/
diff --git a/services/audioflinger/AudioResamplerFirGen.h b/services/audioflinger/AudioResamplerFirGen.h
new file mode 100644
index 0000000..fac3001
--- /dev/null
+++ b/services/audioflinger/AudioResamplerFirGen.h
@@ -0,0 +1,684 @@
+/*
+ * 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_RESAMPLER_FIR_GEN_H
+#define ANDROID_AUDIO_RESAMPLER_FIR_GEN_H
+
+namespace android {
+
+/*
+ * generates a sine wave at equal steps.
+ *
+ * As most of our functions use sine or cosine at equal steps,
+ * it is very efficient to compute them that way (single multiply and subtract),
+ * rather than invoking the math library sin() or cos() each time.
+ *
+ * SineGen uses Goertzel's Algorithm (as a generator not a filter)
+ * to calculate sine(wstart + n * wstep) or cosine(wstart + n * wstep)
+ * by stepping through 0, 1, ... n.
+ *
+ * e^i(wstart+wstep) = 2cos(wstep) * e^i(wstart) - e^i(wstart-wstep)
+ *
+ * or looking at just the imaginary sine term, as the cosine follows identically:
+ *
+ * sin(wstart+wstep) = 2cos(wstep) * sin(wstart) - sin(wstart-wstep)
+ *
+ * Goertzel's algorithm is more efficient than the angle addition formula,
+ * e^i(wstart+wstep) = e^i(wstart) * e^i(wstep), which takes up to
+ * 4 multiplies and 2 adds (or 3* and 3+) and requires both sine and
+ * cosine generation due to the complex * complex multiply (full rotation).
+ *
+ * See: http://en.wikipedia.org/wiki/Goertzel_algorithm
+ *
+ */
+
+class SineGen {
+public:
+    SineGen(double wstart, double wstep, bool cosine = false) {
+        if (cosine) {
+            mCurrent = cos(wstart);
+            mPrevious = cos(wstart - wstep);
+        } else {
+            mCurrent = sin(wstart);
+            mPrevious = sin(wstart - wstep);
+        }
+        mTwoCos = 2.*cos(wstep);
+    }
+    SineGen(double expNow, double expPrev, double twoCosStep) {
+        mCurrent = expNow;
+        mPrevious = expPrev;
+        mTwoCos = twoCosStep;
+    }
+    inline double value() const {
+        return mCurrent;
+    }
+    inline void advance() {
+        double tmp = mCurrent;
+        mCurrent = mCurrent*mTwoCos - mPrevious;
+        mPrevious = tmp;
+    }
+    inline double valueAdvance() {
+        double tmp = mCurrent;
+        mCurrent = mCurrent*mTwoCos - mPrevious;
+        mPrevious = tmp;
+        return tmp;
+    }
+
+private:
+    double mCurrent; // current value of sine/cosine
+    double mPrevious; // previous value of sine/cosine
+    double mTwoCos; // stepping factor
+};
+
+/*
+ * generates a series of sine generators, phase offset by fixed steps.
+ *
+ * This is used to generate polyphase sine generators, one per polyphase
+ * in the filter code below.
+ *
+ * The SineGen returned by value() starts at innerStart = outerStart + n*outerStep;
+ * increments by innerStep.
+ *
+ */
+
+class SineGenGen {
+public:
+    SineGenGen(double outerStart, double outerStep, double innerStep, bool cosine = false)
+            : mSineInnerCur(outerStart, outerStep, cosine),
+              mSineInnerPrev(outerStart-innerStep, outerStep, cosine)
+    {
+        mTwoCos = 2.*cos(innerStep);
+    }
+    inline SineGen value() {
+        return SineGen(mSineInnerCur.value(), mSineInnerPrev.value(), mTwoCos);
+    }
+    inline void advance() {
+        mSineInnerCur.advance();
+        mSineInnerPrev.advance();
+    }
+    inline SineGen valueAdvance() {
+        return SineGen(mSineInnerCur.valueAdvance(), mSineInnerPrev.valueAdvance(), mTwoCos);
+    }
+
+private:
+    SineGen mSineInnerCur; // generate the inner sine values (stepped by outerStep).
+    SineGen mSineInnerPrev; // generate the inner sine previous values
+                            // (behind by innerStep, stepped by outerStep).
+    double mTwoCos; // the inner stepping factor for the returned SineGen.
+};
+
+static inline double sqr(double x) {
+    return x * x;
+}
+
+/*
+ * rounds a double to the nearest integer for FIR coefficients.
+ *
+ * One variant uses noise shaping, which must keep error history
+ * to work (the err parameter, initialized to 0).
+ * The other variant is a non-noise shaped version for
+ * S32 coefficients (noise shaping doesn't gain much).
+ *
+ * Caution: No bounds saturation is applied, but isn't needed in this case.
+ *
+ * @param x is the value to round.
+ *
+ * @param maxval is the maximum integer scale factor expressed as an int64 (for headroom).
+ * Typically this may be the maximum positive integer+1 (using the fact that double precision
+ * FIR coefficients generated here are never that close to 1.0 to pose an overflow condition).
+ *
+ * @param err is the previous error (actual - rounded) for the previous rounding op.
+ * For 16b coefficients this can improve stopband dB performance by up to 2dB.
+ *
+ * Many variants exist for the noise shaping: http://en.wikipedia.org/wiki/Noise_shaping
+ *
+ */
+
+static inline int64_t toint(double x, int64_t maxval, double& err) {
+    double val = x * maxval;
+    double ival = floor(val + 0.5 + err*0.2);
+    err = val - ival;
+    return static_cast<int64_t>(ival);
+}
+
+static inline int64_t toint(double x, int64_t maxval) {
+    return static_cast<int64_t>(floor(x * maxval + 0.5));
+}
+
+/*
+ * Modified Bessel function of the first kind
+ * http://en.wikipedia.org/wiki/Bessel_function
+ *
+ * The formulas are taken from Abramowitz and Stegun,
+ * _Handbook of Mathematical Functions_ (links below):
+ *
+ * http://people.math.sfu.ca/~cbm/aands/page_375.htm
+ * http://people.math.sfu.ca/~cbm/aands/page_378.htm
+ *
+ * http://dlmf.nist.gov/10.25
+ * http://dlmf.nist.gov/10.40
+ *
+ * Note we assume x is nonnegative (the function is symmetric,
+ * pass in the absolute value as needed).
+ *
+ * Constants are compile time derived with templates I0Term<> and
+ * I0ATerm<> to the precision of the compiler.  The series can be expanded
+ * to any precision needed, but currently set around 24b precision.
+ *
+ * We use a bit of template math here, constexpr would probably be
+ * more appropriate for a C++11 compiler.
+ *
+ * For the intermediate range 3.75 < x < 15, we use minimax polynomial fit.
+ *
+ */
+
+template <int N>
+struct I0Term {
+    static const double value = I0Term<N-1>::value / (4. * N * N);
+};
+
+template <>
+struct I0Term<0> {
+    static const double value = 1.;
+};
+
+template <int N>
+struct I0ATerm {
+    static const double value = I0ATerm<N-1>::value * (2.*N-1.) * (2.*N-1.) / (8. * N);
+};
+
+template <>
+struct I0ATerm<0> { // 1/sqrt(2*PI);
+    static const double value = 0.398942280401432677939946059934381868475858631164934657665925;
+};
+
+#if USE_HORNERS_METHOD
+/* Polynomial evaluation of A + Bx + Cx^2 + Dx^3 + ...
+ * using Horner's Method: http://en.wikipedia.org/wiki/Horner's_method
+ *
+ * This has fewer multiplications than Estrin's method below, but has back to back
+ * floating point dependencies.
+ *
+ * On ARM this appears to work slower, so USE_HORNERS_METHOD is not default enabled.
+ */
+
+inline double Poly2(double A, double B, double x) {
+    return A + x * B;
+}
+
+inline double Poly4(double A, double B, double C, double D, double x) {
+    return A + x * (B + x * (C + x * (D)));
+}
+
+inline double Poly7(double A, double B, double C, double D, double E, double F, double G,
+        double x) {
+    return A + x * (B + x * (C + x * (D + x * (E + x * (F + x * (G))))));
+}
+
+inline double Poly9(double A, double B, double C, double D, double E, double F, double G,
+        double H, double I, double x) {
+    return A + x * (B + x * (C + x * (D + x * (E + x * (F + x * (G + x * (H + x * (I))))))));
+}
+
+#else
+/* Polynomial evaluation of A + Bx + Cx^2 + Dx^3 + ...
+ * using Estrin's Method: http://en.wikipedia.org/wiki/Estrin's_scheme
+ *
+ * This is typically faster, perhaps gains about 5-10% overall on ARM processors
+ * over Horner's method above.
+ */
+
+inline double Poly2(double A, double B, double x) {
+    return A + B * x;
+}
+
+inline double Poly3(double A, double B, double C, double x, double x2) {
+    return Poly2(A, B, x) + C * x2;
+}
+
+inline double Poly3(double A, double B, double C, double x) {
+    return Poly2(A, B, x) + C * x * x;
+}
+
+inline double Poly4(double A, double B, double C, double D, double x, double x2) {
+    return Poly2(A, B, x) + Poly2(C, D, x) * x2; // same as poly2(poly2, poly2, x2);
+}
+
+inline double Poly4(double A, double B, double C, double D, double x) {
+    return Poly4(A, B, C, D, x, x * x);
+}
+
+inline double Poly7(double A, double B, double C, double D, double E, double F, double G,
+        double x) {
+    double x2 = x * x;
+    return Poly4(A, B, C, D, x, x2) + Poly3(E, F, G, x, x2) * (x2 * x2);
+}
+
+inline double Poly8(double A, double B, double C, double D, double E, double F, double G,
+        double H, double x, double x2, double x4) {
+    return Poly4(A, B, C, D, x, x2) + Poly4(E, F, G, H, x, x2) * x4;
+}
+
+inline double Poly9(double A, double B, double C, double D, double E, double F, double G,
+        double H, double I, double x) {
+    double x2 = x * x;
+#if 1
+    // It does not seem faster to explicitly decompose Poly8 into Poly4, but
+    // could depend on compiler floating point scheduling.
+    double x4 = x2 * x2;
+    return Poly8(A, B, C, D, E, F, G, H, x, x2, x4) + I * (x4 * x4);
+#else
+    double val = Poly4(A, B, C, D, x, x2);
+    double x4 = x2 * x2;
+    return val + Poly4(E, F, G, H, x, x2) * x4 + I * (x4 * x4);
+#endif
+}
+#endif
+
+static inline double I0(double x) {
+    if (x < 3.75) {
+        x *= x;
+        return Poly7(I0Term<0>::value, I0Term<1>::value,
+                I0Term<2>::value, I0Term<3>::value,
+                I0Term<4>::value, I0Term<5>::value,
+                I0Term<6>::value, x); // e < 1.6e-7
+    }
+    if (1) {
+        /*
+         * Series expansion coefs are easy to calculate, but are expanded around 0,
+         * so error is unequal over the interval 0 < x < 3.75, the error being
+         * significantly better near 0.
+         *
+         * A better solution is to use precise minimax polynomial fits.
+         *
+         * We use a slightly more complicated solution for 3.75 < x < 15, based on
+         * the tables in Blair and Edwards, "Stable Rational Minimax Approximations
+         * to the Modified Bessel Functions I0(x) and I1(x)", Chalk Hill Nuclear Laboratory,
+         * AECL-4928.
+         *
+         * http://www.iaea.org/inis/collection/NCLCollectionStore/_Public/06/178/6178667.pdf
+         *
+         * See Table 11 for 0 < x < 15; e < 10^(-7.13).
+         *
+         * Note: Beta cannot exceed 15 (hence Stopband cannot exceed 144dB = 24b).
+         *
+         * This speeds up overall computation by about 40% over using the else clause below,
+         * which requires sqrt and exp.
+         *
+         */
+
+        x *= x;
+        double num = Poly9(-0.13544938430e9, -0.33153754512e8,
+                -0.19406631946e7, -0.48058318783e5,
+                -0.63269783360e3, -0.49520779070e1,
+                -0.24970910370e-1, -0.74741159550e-4,
+                -0.18257612460e-6, x);
+        double y = x - 225.; // reflection around 15 (squared)
+        double den = Poly4(-0.34598737196e8, 0.23852643181e6,
+                -0.70699387620e3, 0.10000000000e1, y);
+        return num / den;
+
+#if IO_EXTENDED_BETA
+        /* Table 42 for x > 15; e < 10^(-8.11).
+         * This is used for Beta>15, but is disabled here as
+         * we never use Beta that high.
+         *
+         * NOTE: This should be enabled only for x > 15.
+         */
+
+        double y = 1./x;
+        double z = y - (1./15);
+        double num = Poly2(0.415079861746e1, -0.5149092496e1, z);
+        double den = Poly3(0.103150763823e2, -0.14181687413e2,
+                0.1000000000e1, z);
+        return exp(x) * sqrt(y) * num / den;
+#endif
+    } else {
+        /*
+         * NOT USED, but reference for large Beta.
+         *
+         * Abramowitz and Stegun asymptotic formula.
+         * works for x > 3.75.
+         */
+        double y = 1./x;
+        return exp(x) * sqrt(y) *
+                // note: reciprocal squareroot may be easier!
+                // http://en.wikipedia.org/wiki/Fast_inverse_square_root
+                Poly9(I0ATerm<0>::value, I0ATerm<1>::value,
+                        I0ATerm<2>::value, I0ATerm<3>::value,
+                        I0ATerm<4>::value, I0ATerm<5>::value,
+                        I0ATerm<6>::value, I0ATerm<7>::value,
+                        I0ATerm<8>::value, y); // (... e) < 1.9e-7
+    }
+}
+
+/*
+ * calculates the transition bandwidth for a Kaiser filter
+ *
+ * Formula 3.2.8, Vaidyanathan, _Multirate Systems and Filter Banks_, p. 48
+ * Formula 7.76, Oppenheim and Schafer, _Discrete-time Signal Processing, 3e_, p. 542
+ *
+ * @param halfNumCoef is half the number of coefficients per filter phase.
+ *
+ * @param stopBandAtten is the stop band attenuation desired.
+ *
+ * @return the transition bandwidth in normalized frequency (0 <= f <= 0.5)
+ */
+static inline double firKaiserTbw(int halfNumCoef, double stopBandAtten) {
+    return (stopBandAtten - 7.95)/((2.*14.36)*halfNumCoef);
+}
+
+/*
+ * calculates the fir transfer response of the overall polyphase filter at w.
+ *
+ * Calculates the DTFT transfer coefficient H(w) for 0 <= w <= PI, utilizing the
+ * fact that h[n] is symmetric (cosines only, no complex arithmetic).
+ *
+ * We use Goertzel's algorithm to accelerate the computation to essentially
+ * a single multiply and 2 adds per filter coefficient h[].
+ *
+ * Be careful be careful to consider that h[n] is the overall polyphase filter,
+ * with L phases, so rescaling H(w)/L is probably what you expect for "unity gain",
+ * as you only use one of the polyphases at a time.
+ */
+template <typename T>
+static inline double firTransfer(const T* coef, int L, int halfNumCoef, double w) {
+    double accum = static_cast<double>(coef[0])*0.5;  // "center coefficient" from first bank
+    coef += halfNumCoef;    // skip first filterbank (picked up by the last filterbank).
+#if SLOW_FIRTRANSFER
+    /* Original code for reference.  This is equivalent to the code below, but slower. */
+    for (int i=1 ; i<=L ; ++i) {
+        for (int j=0, ix=i ; j<halfNumCoef ; ++j, ix+=L) {
+            accum += cos(ix*w)*static_cast<double>(*coef++);
+        }
+    }
+#else
+    /*
+     * Our overall filter is stored striped by polyphases, not a contiguous h[n].
+     * We could fetch coefficients in a non-contiguous fashion
+     * but that will not scale to vector processing.
+     *
+     * We apply Goertzel's algorithm directly to each polyphase filter bank instead of
+     * using cosine generation/multiplication, thereby saving one multiply per inner loop.
+     *
+     * See: http://en.wikipedia.org/wiki/Goertzel_algorithm
+     * Also: Oppenheim and Schafer, _Discrete Time Signal Processing, 3e_, p. 720.
+     *
+     * We use the basic recursion to incorporate the cosine steps into real sequence x[n]:
+     * s[n] = x[n] + (2cosw)*s[n-1] + s[n-2]
+     *
+     * y[n] = s[n] - e^(iw)s[n-1]
+     *      = sum_{k=-\infty}^{n} x[k]e^(-iw(n-k))
+     *      = e^(-iwn) sum_{k=0}^{n} x[k]e^(iwk)
+     *
+     * The summation contains the frequency steps we want multiplied by the source
+     * (similar to a DTFT).
+     *
+     * Using symmetry, and just the real part (be careful, this must happen
+     * after any internal complex multiplications), the polyphase filterbank
+     * transfer function is:
+     *
+     * Hpp[n, w, w_0] = sum_{k=0}^{n} x[k] * cos(wk + w_0)
+     *                = Re{ e^(iwn + iw_0) y[n]}
+     *                = cos(wn+w_0) * s[n] - cos(w(n+1)+w_0) * s[n-1]
+     *
+     * using the fact that s[n] of real x[n] is real.
+     *
+     */
+    double dcos = 2. * cos(L*w);
+    int start = ((halfNumCoef)*L + 1);
+    SineGen cc((start - L) * w, w, true); // cosine
+    SineGen cp(start * w, w, true); // cosine
+    for (int i=1 ; i<=L ; ++i) {
+        double sc = 0;
+        double sp = 0;
+        for (int j=0 ; j<halfNumCoef ; ++j) {
+            double tmp = sc;
+            sc  = static_cast<double>(*coef++) + dcos*sc - sp;
+            sp = tmp;
+        }
+        // If we are awfully clever, we can apply Goertzel's algorithm
+        // again on the sc and sp sequences returned here.
+        accum += cc.valueAdvance() * sc - cp.valueAdvance() * sp;
+    }
+#endif
+    return accum*2.;
+}
+
+/*
+ * evaluates the minimum and maximum |H(f)| bound in a band region.
+ *
+ * This is usually done with equally spaced increments in the target band in question.
+ * The passband is often very small, and sampled that way. The stopband is often much
+ * larger.
+ *
+ * We use the fact that the overall polyphase filter has an additional bank at the end
+ * for interpolation; hence it is overspecified for the H(f) computation.  Thus the
+ * first polyphase is never actually checked, excepting its first term.
+ *
+ * In this code we use the firTransfer() evaluator above, which uses Goertzel's
+ * algorithm to calculate the transfer function at each point.
+ *
+ * TODO: An alternative with equal spacing is the FFT/DFT.  An alternative with unequal
+ * spacing is a chirp transform.
+ *
+ * @param coef is the designed polyphase filter banks
+ *
+ * @param L is the number of phases (for interpolation)
+ *
+ * @param halfNumCoef should be half the number of coefficients for a single
+ * polyphase.
+ *
+ * @param fstart is the normalized frequency start.
+ *
+ * @param fend is the normalized frequency end.
+ *
+ * @param steps is the number of steps to take (sampling) between frequency start and end
+ *
+ * @param firMin returns the minimum transfer |H(f)| found
+ *
+ * @param firMax returns the maximum transfer |H(f)| found
+ *
+ * 0 <= f <= 0.5.
+ * This is used to test passband and stopband performance.
+ */
+template <typename T>
+static void testFir(const T* coef, int L, int halfNumCoef,
+        double fstart, double fend, int steps, double &firMin, double &firMax) {
+    double wstart = fstart*(2.*M_PI);
+    double wend = fend*(2.*M_PI);
+    double wstep = (wend - wstart)/steps;
+    double fmax, fmin;
+    double trf = firTransfer(coef, L, halfNumCoef, wstart);
+    if (trf<0) {
+        trf = -trf;
+    }
+    fmin = fmax = trf;
+    wstart += wstep;
+    for (int i=1; i<steps; ++i) {
+        trf = firTransfer(coef, L, halfNumCoef, wstart);
+        if (trf<0) {
+            trf = -trf;
+        }
+        if (trf>fmax) {
+            fmax = trf;
+        }
+        else if (trf<fmin) {
+            fmin = trf;
+        }
+        wstart += wstep;
+    }
+    // renormalize - this is only needed for integer filter types
+    double norm = 1./((1ULL<<(sizeof(T)*8-1))*L);
+
+    firMin = fmin * norm;
+    firMax = fmax * norm;
+}
+
+/*
+ * evaluates the |H(f)| lowpass band characteristics.
+ *
+ * This function tests the lowpass characteristics for the overall polyphase filter,
+ * and is used to verify the design.  For this case, fp should be set to the
+ * passband normalized frequency from 0 to 0.5 for the overall filter (thus it
+ * is the designed polyphase bank value / L).  Likewise for fs.
+ *
+ * @param coef is the designed polyphase filter banks
+ *
+ * @param L is the number of phases (for interpolation)
+ *
+ * @param halfNumCoef should be half the number of coefficients for a single
+ * polyphase.
+ *
+ * @param fp is the passband normalized frequency, 0 < fp < fs < 0.5.
+ *
+ * @param fs is the stopband normalized frequency, 0 < fp < fs < 0.5.
+ *
+ * @param passSteps is the number of passband sampling steps.
+ *
+ * @param stopSteps is the number of stopband sampling steps.
+ *
+ * @param passMin is the minimum value in the passband
+ *
+ * @param passMax is the maximum value in the passband (useful for scaling).  This should
+ * be less than 1., to avoid sine wave test overflow.
+ *
+ * @param passRipple is the passband ripple.  Typically this should be less than 0.1 for
+ * an audio filter.  Generally speaker/headphone device characteristics will dominate
+ * the passband term.
+ *
+ * @param stopMax is the maximum value in the stopband.
+ *
+ * @param stopRipple is the stopband ripple, also known as stopband attenuation.
+ * Typically this should be greater than ~80dB for low quality, and greater than
+ * ~100dB for full 16b quality, otherwise aliasing may become noticeable.
+ *
+ */
+template <typename T>
+static void testFir(const T* coef, int L, int halfNumCoef,
+        double fp, double fs, int passSteps, int stopSteps,
+        double &passMin, double &passMax, double &passRipple,
+        double &stopMax, double &stopRipple) {
+    double fmin, fmax;
+    testFir(coef, L, halfNumCoef, 0., fp, passSteps, fmin, fmax);
+    double d1 = (fmax - fmin)/2.;
+    passMin = fmin;
+    passMax = fmax;
+    passRipple = -20.*log10(1. - d1); // passband ripple
+    testFir(coef, L, halfNumCoef, fs, 0.5, stopSteps, fmin, fmax);
+    // fmin is really not important for the stopband.
+    stopMax = fmax;
+    stopRipple = -20.*log10(fmax); // stopband ripple/attenuation
+}
+
+/*
+ * Calculates the overall polyphase filter based on a windowed sinc function.
+ *
+ * The windowed sinc is an odd length symmetric filter of exactly L*halfNumCoef*2+1
+ * taps for the entire kernel.  This is then decomposed into L+1 polyphase filterbanks.
+ * The last filterbank is used for interpolation purposes (and is mostly composed
+ * of the first bank shifted by one sample), and is unnecessary if one does
+ * not do interpolation.
+ *
+ * We use the last filterbank for some transfer function calculation purposes,
+ * so it needs to be generated anyways.
+ *
+ * @param coef is the caller allocated space for coefficients.  This should be
+ * exactly (L+1)*halfNumCoef in size.
+ *
+ * @param L is the number of phases (for interpolation)
+ *
+ * @param halfNumCoef should be half the number of coefficients for a single
+ * polyphase.
+ *
+ * @param stopBandAtten is the stopband value, should be >50dB.
+ *
+ * @param fcr is cutoff frequency/sampling rate (<0.5).  At this point, the energy
+ * should be 6dB less. (fcr is where the amplitude drops by half).  Use the
+ * firKaiserTbw() to calculate the transition bandwidth.  fcr is the midpoint
+ * between the stop band and the pass band (fstop+fpass)/2.
+ *
+ * @param atten is the attenuation (generally slightly less than 1).
+ */
+
+template <typename T>
+static inline void firKaiserGen(T* coef, int L, int halfNumCoef,
+        double stopBandAtten, double fcr, double atten) {
+    //
+    // Formula 3.2.5, 3.2.7, Vaidyanathan, _Multirate Systems and Filter Banks_, p. 48
+    // Formula 7.75, Oppenheim and Schafer, _Discrete-time Signal Processing, 3e_, p. 542
+    //
+    // See also: http://melodi.ee.washington.edu/courses/ee518/notes/lec17.pdf
+    //
+    // Kaiser window and beta parameter
+    //
+    //         | 0.1102*(A - 8.7)                         A > 50
+    //  beta = | 0.5842*(A - 21)^0.4 + 0.07886*(A - 21)   21 <= A <= 50
+    //         | 0.                                       A < 21
+    //
+    // with A is the desired stop-band attenuation in dBFS
+    //
+    //    30 dB    2.210
+    //    40 dB    3.384
+    //    50 dB    4.538
+    //    60 dB    5.658
+    //    70 dB    6.764
+    //    80 dB    7.865
+    //    90 dB    8.960
+    //   100 dB   10.056
+
+    const int N = L * halfNumCoef; // non-negative half
+    const double beta = 0.1102 * (stopBandAtten - 8.7); // >= 50dB always
+    const double xstep = (2. * M_PI) * fcr / L;
+    const double xfrac = 1. / N;
+    const double yscale = atten * L / (I0(beta) * M_PI);
+
+    // We use sine generators, which computes sines on regular step intervals.
+    // This speeds up overall computation about 40% from computing the sine directly.
+
+    SineGenGen sgg(0., xstep, L*xstep); // generates sine generators (one per polyphase)
+
+    for (int i=0 ; i<=L ; ++i) { // generate an extra set of coefs for interpolation
+
+        // computation for a single polyphase of the overall filter.
+        SineGen sg = sgg.valueAdvance(); // current sine generator for "j" inner loop.
+        double err = 0; // for noise shaping on int16_t coefficients (over each polyphase)
+
+        for (int j=0, ix=i ; j<halfNumCoef ; ++j, ix+=L) {
+            double y;
+            if (CC_LIKELY(ix)) {
+                double x = static_cast<double>(ix);
+
+                // sine generator: sg.valueAdvance() returns sin(ix*xstep);
+                y = I0(beta * sqrt(1.0 - sqr(x * xfrac))) * yscale * sg.valueAdvance() / x;
+            } else {
+                y = 2. * atten * fcr; // center of filter, sinc(0) = 1.
+                sg.advance();
+            }
+
+            // (caution!) float version does not need rounding
+            if (is_same<T, int16_t>::value) { // int16_t needs noise shaping
+                *coef++ = static_cast<T>(toint(y, 1ULL<<(sizeof(T)*8-1), err));
+            } else {
+                *coef++ = static_cast<T>(toint(y, 1ULL<<(sizeof(T)*8-1)));
+            }
+        }
+    }
+}
+
+}; // namespace android
+
+#endif /*ANDROID_AUDIO_RESAMPLER_FIR_GEN_H*/
diff --git a/services/audioflinger/AudioResamplerFirOps.h b/services/audioflinger/AudioResamplerFirOps.h
new file mode 100644
index 0000000..bf2163f
--- /dev/null
+++ b/services/audioflinger/AudioResamplerFirOps.h
@@ -0,0 +1,163 @@
+/*
+ * 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_RESAMPLER_FIR_OPS_H
+#define ANDROID_AUDIO_RESAMPLER_FIR_OPS_H
+
+namespace android {
+
+#if defined(__arm__) && !defined(__thumb__)
+#define USE_INLINE_ASSEMBLY (true)
+#else
+#define USE_INLINE_ASSEMBLY (false)
+#endif
+
+#if USE_INLINE_ASSEMBLY && defined(__ARM_NEON__)
+#define USE_NEON (true)
+#include <arm_neon.h>
+#else
+#define USE_NEON (false)
+#endif
+
+template<typename T, typename U>
+struct is_same
+{
+    static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T>  // partial specialization
+{
+    static const bool value = true;
+};
+
+static inline
+int32_t mulRL(int left, int32_t in, uint32_t vRL)
+{
+#if USE_INLINE_ASSEMBLY
+    int32_t out;
+    if (left) {
+        asm( "smultb %[out], %[in], %[vRL] \n"
+             : [out]"=r"(out)
+             : [in]"%r"(in), [vRL]"r"(vRL)
+             : );
+    } else {
+        asm( "smultt %[out], %[in], %[vRL] \n"
+             : [out]"=r"(out)
+             : [in]"%r"(in), [vRL]"r"(vRL)
+             : );
+    }
+    return out;
+#else
+    int16_t v = left ? static_cast<int16_t>(vRL) : static_cast<int16_t>(vRL>>16);
+    return static_cast<int32_t>((static_cast<int64_t>(in) * v) >> 16);
+#endif
+}
+
+static inline
+int32_t mulAdd(int16_t in, int16_t v, int32_t a)
+{
+#if USE_INLINE_ASSEMBLY
+    int32_t out;
+    asm( "smlabb %[out], %[v], %[in], %[a] \n"
+         : [out]"=r"(out)
+         : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
+         : );
+    return out;
+#else
+    return a + v * in;
+#endif
+}
+
+static inline
+int32_t mulAdd(int16_t in, int32_t v, int32_t a)
+{
+#if USE_INLINE_ASSEMBLY
+    int32_t out;
+    asm( "smlawb %[out], %[v], %[in], %[a] \n"
+         : [out]"=r"(out)
+         : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
+         : );
+    return out;
+#else
+    return a + static_cast<int32_t>((static_cast<int64_t>(v) * in) >> 16);
+#endif
+}
+
+static inline
+int32_t mulAdd(int32_t in, int32_t v, int32_t a)
+{
+#if USE_INLINE_ASSEMBLY
+    int32_t out;
+    asm( "smmla %[out], %[v], %[in], %[a] \n"
+         : [out]"=r"(out)
+         : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
+         : );
+    return out;
+#else
+    return a + static_cast<int32_t>((static_cast<int64_t>(v) * in) >> 32);
+#endif
+}
+
+static inline
+int32_t mulAddRL(int left, uint32_t inRL, int16_t v, int32_t a)
+{
+#if USE_INLINE_ASSEMBLY
+    int32_t out;
+    if (left) {
+        asm( "smlabb %[out], %[v], %[inRL], %[a] \n"
+             : [out]"=r"(out)
+             : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
+             : );
+    } else {
+        asm( "smlabt %[out], %[v], %[inRL], %[a] \n"
+             : [out]"=r"(out)
+             : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
+             : );
+    }
+    return out;
+#else
+    int16_t s = left ? static_cast<int16_t>(inRL) : static_cast<int16_t>(inRL>>16);
+    return a + v * s;
+#endif
+}
+
+static inline
+int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a)
+{
+#if USE_INLINE_ASSEMBLY
+    int32_t out;
+    if (left) {
+        asm( "smlawb %[out], %[v], %[inRL], %[a] \n"
+             : [out]"=r"(out)
+             : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
+             : );
+    } else {
+        asm( "smlawt %[out], %[v], %[inRL], %[a] \n"
+             : [out]"=r"(out)
+             : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
+             : );
+    }
+    return out;
+#else
+    int16_t s = left ? static_cast<int16_t>(inRL) : static_cast<int16_t>(inRL>>16);
+    return a + static_cast<int32_t>((static_cast<int64_t>(v) * s) >> 16);
+#endif
+}
+
+}; // namespace android
+
+#endif /*ANDROID_AUDIO_RESAMPLER_FIR_OPS_H*/
diff --git a/services/audioflinger/AudioResamplerFirProcess.h b/services/audioflinger/AudioResamplerFirProcess.h
new file mode 100644
index 0000000..38e387c
--- /dev/null
+++ b/services/audioflinger/AudioResamplerFirProcess.h
@@ -0,0 +1,256 @@
+/*
+ * 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_RESAMPLER_FIR_PROCESS_H
+#define ANDROID_AUDIO_RESAMPLER_FIR_PROCESS_H
+
+namespace android {
+
+// depends on AudioResamplerFirOps.h
+
+template<int CHANNELS, typename TC>
+static inline
+void mac(
+        int32_t& l, int32_t& r,
+        const TC coef,
+        const int16_t* samples)
+{
+    if (CHANNELS == 2) {
+        uint32_t rl = *reinterpret_cast<const uint32_t*>(samples);
+        l = mulAddRL(1, rl, coef, l);
+        r = mulAddRL(0, rl, coef, r);
+    } else {
+        r = l = mulAdd(samples[0], coef, l);
+    }
+}
+
+template<int CHANNELS, typename TC>
+static inline
+void interpolate(
+        int32_t& l, int32_t& r,
+        const TC coef_0, const TC coef_1,
+        const int16_t lerp, const int16_t* samples)
+{
+    TC sinc;
+
+    if (is_same<TC, int16_t>::value) {
+        sinc = (lerp * ((coef_1-coef_0)<<1)>>16) + coef_0;
+    } else {
+        sinc = mulAdd(lerp, (coef_1-coef_0)<<1, coef_0);
+    }
+    if (CHANNELS == 2) {
+        uint32_t rl = *reinterpret_cast<const uint32_t*>(samples);
+        l = mulAddRL(1, rl, sinc, l);
+        r = mulAddRL(0, rl, sinc, r);
+    } else {
+        r = l = mulAdd(samples[0], sinc, l);
+    }
+}
+
+/*
+ * Calculates a single output sample (two stereo frames).
+ *
+ * This function computes both the positive half FIR dot product and
+ * the negative half FIR dot product, accumulates, and then applies the volume.
+ *
+ * This is a locked phase filter (it does not compute the interpolation).
+ *
+ * Use fir() to compute the proper coefficient pointers for a polyphase
+ * filter bank.
+ */
+
+template <int CHANNELS, int STRIDE, typename TC>
+static inline
+void ProcessL(int32_t* const out,
+        int count,
+        const TC* coefsP,
+        const TC* coefsN,
+        const int16_t* sP,
+        const int16_t* sN,
+        const int32_t* const volumeLR)
+{
+    int32_t l = 0;
+    int32_t r = 0;
+    do {
+        mac<CHANNELS>(l, r, *coefsP++, sP);
+        sP -= CHANNELS;
+        mac<CHANNELS>(l, r, *coefsN++, sN);
+        sN += CHANNELS;
+    } while (--count > 0);
+    out[0] += 2 * mulRL(0, l, volumeLR[0]); // Note: only use top 16b
+    out[1] += 2 * mulRL(0, r, volumeLR[1]); // Note: only use top 16b
+}
+
+/*
+ * Calculates a single output sample (two stereo frames) interpolating phase.
+ *
+ * This function computes both the positive half FIR dot product and
+ * the negative half FIR dot product, accumulates, and then applies the volume.
+ *
+ * This is an interpolated phase filter.
+ *
+ * Use fir() to compute the proper coefficient pointers for a polyphase
+ * filter bank.
+ */
+
+template <int CHANNELS, int STRIDE, typename TC>
+static inline
+void Process(int32_t* const out,
+        int count,
+        const TC* coefsP,
+        const TC* coefsN,
+        const TC* coefsP1,
+        const TC* coefsN1,
+        const int16_t* sP,
+        const int16_t* sN,
+        uint32_t lerpP,
+        const int32_t* const volumeLR)
+{
+    (void) coefsP1; // suppress unused parameter warning
+    (void) coefsN1;
+    if (sizeof(*coefsP)==4) {
+        lerpP >>= 16;   // ensure lerpP is 16b
+    }
+    int32_t l = 0;
+    int32_t r = 0;
+    for (size_t i = 0; i < count; ++i) {
+        interpolate<CHANNELS>(l, r, coefsP[0], coefsP[count], lerpP, sP);
+        coefsP++;
+        sP -= CHANNELS;
+        interpolate<CHANNELS>(l, r, coefsN[count], coefsN[0], lerpP, sN);
+        coefsN++;
+        sN += CHANNELS;
+    }
+    out[0] += 2 * mulRL(0, l, volumeLR[0]); // Note: only use top 16b
+    out[1] += 2 * mulRL(0, r, volumeLR[1]); // Note: only use top 16b
+}
+
+/*
+ * Calculates a single output sample (two stereo frames) from input sample pointer.
+ *
+ * This sets up the params for the accelerated Process() and ProcessL()
+ * functions to do the appropriate dot products.
+ *
+ * @param out should point to the output buffer with at least enough space for 2 output frames.
+ *
+ * @param phase is the fractional distance between input samples for interpolation:
+ * phase >= 0  && phase < phaseWrapLimit.  It can be thought of as a rational fraction
+ * of phase/phaseWrapLimit.
+ *
+ * @param phaseWrapLimit is #polyphases<<coefShift, where #polyphases is the number of polyphases
+ * in the polyphase filter. Likewise, #polyphases can be obtained as (phaseWrapLimit>>coefShift).
+ *
+ * @param coefShift gives the bit alignment of the polyphase index in the phase parameter.
+ *
+ * @param halfNumCoefs is the half the number of coefficients per polyphase filter. Since the
+ * overall filterbank is odd-length symmetric, only halfNumCoefs need be stored.
+ *
+ * @param coefs is the polyphase filter bank, starting at from polyphase index 0, and ranging to
+ * and including the #polyphases.  Each polyphase of the filter has half-length halfNumCoefs
+ * (due to symmetry).  The total size of the filter bank in coefficients is
+ * (#polyphases+1)*halfNumCoefs.
+ *
+ * The filter bank coefs should be aligned to a minimum of 16 bytes (preferrably to cache line).
+ *
+ * The coefs should be attenuated (to compensate for passband ripple)
+ * if storing back into the native format.
+ *
+ * @param samples are unaligned input samples.  The position is in the "middle" of the
+ * sample array with respect to the FIR filter:
+ * the negative half of the filter is dot product from samples+1 to samples+halfNumCoefs;
+ * the positive half of the filter is dot product from samples to samples-halfNumCoefs+1.
+ *
+ * @param volumeLR is a pointer to an array of two 32 bit volume values, one per stereo channel,
+ * expressed as a S32 integer.  A negative value inverts the channel 180 degrees.
+ * The pointer volumeLR should be aligned to a minimum of 8 bytes.
+ * A typical value for volume is 0x1000 to align to a unity gain output of 20.12.
+ *
+ * In between calls to filterCoefficient, the phase is incremented by phaseIncrement, where
+ * phaseIncrement is calculated as inputSampling * phaseWrapLimit / outputSampling.
+ *
+ * The filter polyphase index is given by indexP = phase >> coefShift. Due to
+ * odd length symmetric filter, the polyphase index of the negative half depends on
+ * whether interpolation is used.
+ *
+ * The fractional siting between the polyphase indices is given by the bits below coefShift:
+ *
+ * lerpP = phase << 32 - coefShift >> 1;  // for 32 bit unsigned phase multiply
+ * lerpP = phase << 32 - coefShift >> 17; // for 16 bit unsigned phase multiply
+ *
+ * For integer types, this is expressed as:
+ *
+ * lerpP = phase << sizeof(phase)*8 - coefShift
+ *              >> (sizeof(phase)-sizeof(*coefs))*8 + 1;
+ *
+ */
+
+template<int CHANNELS, bool LOCKED, int STRIDE, typename TC>
+static inline
+void fir(int32_t* const out,
+        const uint32_t phase, const uint32_t phaseWrapLimit,
+        const int coefShift, const int halfNumCoefs, const TC* const coefs,
+        const int16_t* const samples, const int32_t* const volumeLR)
+{
+    // NOTE: be very careful when modifying the code here. register
+    // pressure is very high and a small change might cause the compiler
+    // to generate far less efficient code.
+    // Always sanity check the result with objdump or test-resample.
+
+    if (LOCKED) {
+        // locked polyphase (no interpolation)
+        // Compute the polyphase filter index on the positive and negative side.
+        uint32_t indexP = phase >> coefShift;
+        uint32_t indexN = (phaseWrapLimit - phase) >> coefShift;
+        const TC* coefsP = coefs + indexP*halfNumCoefs;
+        const TC* coefsN = coefs + indexN*halfNumCoefs;
+        const int16_t* sP = samples;
+        const int16_t* sN = samples + CHANNELS;
+
+        // dot product filter.
+        ProcessL<CHANNELS, STRIDE>(out,
+                halfNumCoefs, coefsP, coefsN, sP, sN, volumeLR);
+    } else {
+        // interpolated polyphase
+        // Compute the polyphase filter index on the positive and negative side.
+        uint32_t indexP = phase >> coefShift;
+        uint32_t indexN = (phaseWrapLimit - phase - 1) >> coefShift; // one's complement.
+        const TC* coefsP = coefs + indexP*halfNumCoefs;
+        const TC* coefsN = coefs + indexN*halfNumCoefs;
+        const TC* coefsP1 = coefsP + halfNumCoefs;
+        const TC* coefsN1 = coefsN + halfNumCoefs;
+        const int16_t* sP = samples;
+        const int16_t* sN = samples + CHANNELS;
+
+        // Interpolation fraction lerpP derived by shifting all the way up and down
+        // to clear the appropriate bits and align to the appropriate level
+        // for the integer multiply.  The constants should resolve in compile time.
+        //
+        // The interpolated filter coefficient is derived as follows for the pos/neg half:
+        //
+        // interpolated[P] = index[P]*lerpP + index[P+1]*(1-lerpP)
+        // interpolated[N] = index[N+1]*lerpP + index[N]*(1-lerpP)
+        uint32_t lerpP = phase << (sizeof(phase)*8 - coefShift)
+                >> ((sizeof(phase)-sizeof(*coefs))*8 + 1);
+
+        // on-the-fly interpolated dot product filter
+        Process<CHANNELS, STRIDE>(out,
+                halfNumCoefs, coefsP, coefsN, coefsP1, coefsN1, sP, sN, lerpP, volumeLR);
+    }
+}
+
+}; // namespace android
+
+#endif /*ANDROID_AUDIO_RESAMPLER_FIR_PROCESS_H*/
diff --git a/services/audioflinger/AudioResamplerFirProcessNeon.h b/services/audioflinger/AudioResamplerFirProcessNeon.h
new file mode 100644
index 0000000..f311cef
--- /dev/null
+++ b/services/audioflinger/AudioResamplerFirProcessNeon.h
@@ -0,0 +1,1149 @@
+/*
+ * 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_RESAMPLER_FIR_PROCESS_NEON_H
+#define ANDROID_AUDIO_RESAMPLER_FIR_PROCESS_NEON_H
+
+namespace android {
+
+// depends on AudioResamplerFirOps.h, AudioResamplerFirProcess.h
+
+#if USE_NEON
+//
+// NEON specializations are enabled for Process() and ProcessL()
+//
+// TODO: Stride 16 and Stride 8 can be combined with one pass stride 8 (if necessary)
+// and looping stride 16 (or vice versa). This has some polyphase coef data alignment
+// issues with S16 coefs. Consider this later.
+
+// Macros to save a mono/stereo accumulator sample in q0 (and q4) as stereo out.
+#define ASSEMBLY_ACCUMULATE_MONO \
+        "vld1.s32       {d2}, [%[vLR]:64]        \n"/* (1) load volumes */\
+        "vld1.s32       {d3}, %[out]             \n"/* (2) unaligned load the output */\
+        "vpadd.s32      d0, d0, d1               \n"/* (1) add all 4 partial sums */\
+        "vpadd.s32      d0, d0, d0               \n"/* (1+4d) and replicate L/R */\
+        "vqrdmulh.s32   d0, d0, d2               \n"/* (2+3d) apply volume */\
+        "vqadd.s32      d3, d3, d0               \n"/* (1+4d) accumulate result (saturating) */\
+        "vst1.s32       {d3}, %[out]             \n"/* (2+2d) store result */
+
+#define ASSEMBLY_ACCUMULATE_STEREO \
+        "vld1.s32       {d2}, [%[vLR]:64]        \n"/* (1) load volumes*/\
+        "vld1.s32       {d3}, %[out]             \n"/* (2) unaligned load the output*/\
+        "vpadd.s32      d0, d0, d1               \n"/* (1) add all 4 partial sums from q0*/\
+        "vpadd.s32      d8, d8, d9               \n"/* (1) add all 4 partial sums from q4*/\
+        "vpadd.s32      d0, d0, d8               \n"/* (1+4d) combine into L/R*/\
+        "vqrdmulh.s32   d0, d0, d2               \n"/* (2+3d) apply volume*/\
+        "vqadd.s32      d3, d3, d0               \n"/* (1+4d) accumulate result (saturating)*/\
+        "vst1.s32       {d3}, %[out]             \n"/* (2+2d)store result*/
+
+template <>
+inline void ProcessL<1, 16>(int32_t* const out,
+        int count,
+        const int16_t* coefsP,
+        const int16_t* coefsN,
+        const int16_t* sP,
+        const int16_t* sN,
+        const int32_t* const volumeLR)
+{
+    const int CHANNELS = 1; // template specialization does not preserve params
+    const int STRIDE = 16;
+    sP -= CHANNELS*((STRIDE>>1)-1);
+    asm (
+        "veor           q0, q0, q0               \n"// (0 - combines+) accumulator = 0
+
+        "1:                                      \n"
+
+        "vld1.16        {q2}, [%[sP]]            \n"// (2+0d) load 8 16-bits mono samples
+        "vld1.16        {q3}, [%[sN]]!           \n"// (2) load 8 16-bits mono samples
+        "vld1.16        {q8}, [%[coefsP0]:128]!  \n"// (1) load 8 16-bits coefs
+        "vld1.16        {q10}, [%[coefsN0]:128]! \n"// (1) load 8 16-bits coefs
+
+        "vrev64.16      q2, q2                   \n"// (1) reverse s3, s2, s1, s0, s7, s6, s5, s4
+
+        // reordering the vmal to do d6, d7 before d4, d5 is slower(?)
+        "vmlal.s16      q0, d4, d17              \n"// (1+0d) multiply (reversed)samples by coef
+        "vmlal.s16      q0, d5, d16              \n"// (1) multiply (reversed)samples by coef
+        "vmlal.s16      q0, d6, d20              \n"// (1) multiply neg samples
+        "vmlal.s16      q0, d7, d21              \n"// (1) multiply neg samples
+
+        // moving these ARM instructions before neon above seems to be slower
+        "subs           %[count], %[count], #8   \n"// (1) update loop counter
+        "sub            %[sP], %[sP], #16        \n"// (0) move pointer to next set of samples
+
+        // sP used after branch (warning)
+        "bne            1b                       \n"// loop
+
+         ASSEMBLY_ACCUMULATE_MONO
+
+        : [out]     "=Uv" (out[0]),
+          [count]   "+r" (count),
+          [coefsP0] "+r" (coefsP),
+          [coefsN0] "+r" (coefsN),
+          [sP]      "+r" (sP),
+          [sN]      "+r" (sN)
+        : [vLR]     "r" (volumeLR)
+        : "cc", "memory",
+          "q0", "q1", "q2", "q3",
+          "q8", "q10"
+    );
+}
+
+template <>
+inline void ProcessL<2, 16>(int32_t* const out,
+        int count,
+        const int16_t* coefsP,
+        const int16_t* coefsN,
+        const int16_t* sP,
+        const int16_t* sN,
+        const int32_t* const volumeLR)
+{
+    const int CHANNELS = 2; // template specialization does not preserve params
+    const int STRIDE = 16;
+    sP -= CHANNELS*((STRIDE>>1)-1);
+    asm (
+        "veor           q0, q0, q0               \n"// (1) acc_L = 0
+        "veor           q4, q4, q4               \n"// (0 combines+) acc_R = 0
+
+        "1:                                      \n"
+
+        "vld2.16        {q2, q3}, [%[sP]]        \n"// (3+0d) load 8 16-bits stereo samples
+        "vld2.16        {q5, q6}, [%[sN]]!       \n"// (3) load 8 16-bits stereo samples
+        "vld1.16        {q8}, [%[coefsP0]:128]!  \n"// (1) load 8 16-bits coefs
+        "vld1.16        {q10}, [%[coefsN0]:128]! \n"// (1) load 8 16-bits coefs
+
+        "vrev64.16      q2, q2                   \n"// (1) reverse 8 frames of the left positive
+        "vrev64.16      q3, q3                   \n"// (0 combines+) reverse right positive
+
+        "vmlal.s16      q0, d4, d17              \n"// (1) multiply (reversed) samples left
+        "vmlal.s16      q0, d5, d16              \n"// (1) multiply (reversed) samples left
+        "vmlal.s16      q4, d6, d17              \n"// (1) multiply (reversed) samples right
+        "vmlal.s16      q4, d7, d16              \n"// (1) multiply (reversed) samples right
+        "vmlal.s16      q0, d10, d20             \n"// (1) multiply samples left
+        "vmlal.s16      q0, d11, d21             \n"// (1) multiply samples left
+        "vmlal.s16      q4, d12, d20             \n"// (1) multiply samples right
+        "vmlal.s16      q4, d13, d21             \n"// (1) multiply samples right
+
+        // moving these ARM before neon seems to be slower
+        "subs           %[count], %[count], #8   \n"// (1) update loop counter
+        "sub            %[sP], %[sP], #32        \n"// (0) move pointer to next set of samples
+
+        // sP used after branch (warning)
+        "bne            1b                       \n"// loop
+
+        ASSEMBLY_ACCUMULATE_STEREO
+
+        : [out] "=Uv" (out[0]),
+          [count] "+r" (count),
+          [coefsP0] "+r" (coefsP),
+          [coefsN0] "+r" (coefsN),
+          [sP] "+r" (sP),
+          [sN] "+r" (sN)
+        : [vLR] "r" (volumeLR)
+        : "cc", "memory",
+          "q0", "q1", "q2", "q3",
+          "q4", "q5", "q6",
+          "q8", "q10"
+     );
+}
+
+template <>
+inline void Process<1, 16>(int32_t* const out,
+        int count,
+        const int16_t* coefsP,
+        const int16_t* coefsN,
+        const int16_t* coefsP1,
+        const int16_t* coefsN1,
+        const int16_t* sP,
+        const int16_t* sN,
+        uint32_t lerpP,
+        const int32_t* const volumeLR)
+{
+    const int CHANNELS = 1; // template specialization does not preserve params
+    const int STRIDE = 16;
+    sP -= CHANNELS*((STRIDE>>1)-1);
+    asm (
+        "vmov.32        d2[0], %[lerpP]          \n"// load the positive phase S32 Q15
+        "veor           q0, q0, q0               \n"// (0 - combines+) accumulator = 0
+
+        "1:                                      \n"
+
+        "vld1.16        {q2}, [%[sP]]            \n"// (2+0d) load 8 16-bits mono samples
+        "vld1.16        {q3}, [%[sN]]!           \n"// (2) load 8 16-bits mono samples
+        "vld1.16        {q8}, [%[coefsP0]:128]!  \n"// (1) load 8 16-bits coefs
+        "vld1.16        {q9}, [%[coefsP1]:128]!  \n"// (1) load 8 16-bits coefs for interpolation
+        "vld1.16        {q10}, [%[coefsN1]:128]! \n"// (1) load 8 16-bits coefs
+        "vld1.16        {q11}, [%[coefsN0]:128]! \n"// (1) load 8 16-bits coefs for interpolation
+
+        "vsub.s16       q9, q9, q8               \n"// (1) interpolate (step1) 1st set of coefs
+        "vsub.s16       q11, q11, q10            \n"// (1) interpolate (step1) 2nd set of coets
+
+        "vqrdmulh.s16   q9, q9, d2[0]            \n"// (2) interpolate (step2) 1st set of coefs
+        "vqrdmulh.s16   q11, q11, d2[0]          \n"// (2) interpolate (step2) 2nd set of coefs
+
+        "vrev64.16      q2, q2                   \n"// (1) reverse s3, s2, s1, s0, s7, s6, s5, s4
+
+        "vadd.s16       q8, q8, q9               \n"// (1+2d) interpolate (step3) 1st set
+        "vadd.s16       q10, q10, q11            \n"// (1+1d) interpolate (step3) 2nd set
+
+        // reordering the vmal to do d6, d7 before d4, d5 is slower(?)
+        "vmlal.s16      q0, d4, d17              \n"// (1+0d) multiply reversed samples by coef
+        "vmlal.s16      q0, d5, d16              \n"// (1) multiply reversed samples by coef
+        "vmlal.s16      q0, d6, d20              \n"// (1) multiply neg samples
+        "vmlal.s16      q0, d7, d21              \n"// (1) multiply neg samples
+
+        // moving these ARM instructions before neon above seems to be slower
+        "subs           %[count], %[count], #8   \n"// (1) update loop counter
+        "sub            %[sP], %[sP], #16        \n"// (0) move pointer to next set of samples
+
+        // sP used after branch (warning)
+        "bne            1b                       \n"// loop
+
+        ASSEMBLY_ACCUMULATE_MONO
+
+        : [out]     "=Uv" (out[0]),
+          [count]   "+r" (count),
+          [coefsP0] "+r" (coefsP),
+          [coefsN0] "+r" (coefsN),
+          [coefsP1] "+r" (coefsP1),
+          [coefsN1] "+r" (coefsN1),
+          [sP]      "+r" (sP),
+          [sN]      "+r" (sN)
+        : [lerpP]   "r" (lerpP),
+          [vLR]     "r" (volumeLR)
+        : "cc", "memory",
+          "q0", "q1", "q2", "q3",
+          "q8", "q9", "q10", "q11"
+    );
+}
+
+template <>
+inline void Process<2, 16>(int32_t* const out,
+        int count,
+        const int16_t* coefsP,
+        const int16_t* coefsN,
+        const int16_t* coefsP1,
+        const int16_t* coefsN1,
+        const int16_t* sP,
+        const int16_t* sN,
+        uint32_t lerpP,
+        const int32_t* const volumeLR)
+{
+    const int CHANNELS = 2; // template specialization does not preserve params
+    const int STRIDE = 16;
+    sP -= CHANNELS*((STRIDE>>1)-1);
+    asm (
+        "vmov.32        d2[0], %[lerpP]          \n"// load the positive phase
+        "veor           q0, q0, q0               \n"// (1) acc_L = 0
+        "veor           q4, q4, q4               \n"// (0 combines+) acc_R = 0
+
+        "1:                                      \n"
+
+        "vld2.16        {q2, q3}, [%[sP]]        \n"// (3+0d) load 8 16-bits stereo samples
+        "vld2.16        {q5, q6}, [%[sN]]!       \n"// (3) load 8 16-bits stereo samples
+        "vld1.16        {q8}, [%[coefsP0]:128]!  \n"// (1) load 8 16-bits coefs
+        "vld1.16        {q9}, [%[coefsP1]:128]!  \n"// (1) load 8 16-bits coefs for interpolation
+        "vld1.16        {q10}, [%[coefsN1]:128]! \n"// (1) load 8 16-bits coefs
+        "vld1.16        {q11}, [%[coefsN0]:128]! \n"// (1) load 8 16-bits coefs for interpolation
+
+        "vsub.s16       q9, q9, q8               \n"// (1) interpolate (step1) 1st set of coefs
+        "vsub.s16       q11, q11, q10            \n"// (1) interpolate (step1) 2nd set of coets
+
+        "vqrdmulh.s16   q9, q9, d2[0]            \n"// (2) interpolate (step2) 1st set of coefs
+        "vqrdmulh.s16   q11, q11, d2[0]          \n"// (2) interpolate (step2) 2nd set of coefs
+
+        "vrev64.16      q2, q2                   \n"// (1) reverse 8 frames of the left positive
+        "vrev64.16      q3, q3                   \n"// (1) reverse 8 frames of the right positive
+
+        "vadd.s16       q8, q8, q9               \n"// (1+1d) interpolate (step3) 1st set
+        "vadd.s16       q10, q10, q11            \n"// (1+1d) interpolate (step3) 2nd set
+
+        "vmlal.s16      q0, d4, d17              \n"// (1) multiply reversed samples left
+        "vmlal.s16      q0, d5, d16              \n"// (1) multiply reversed samples left
+        "vmlal.s16      q4, d6, d17              \n"// (1) multiply reversed samples right
+        "vmlal.s16      q4, d7, d16              \n"// (1) multiply reversed samples right
+        "vmlal.s16      q0, d10, d20             \n"// (1) multiply samples left
+        "vmlal.s16      q0, d11, d21             \n"// (1) multiply samples left
+        "vmlal.s16      q4, d12, d20             \n"// (1) multiply samples right
+        "vmlal.s16      q4, d13, d21             \n"// (1) multiply samples right
+
+        // moving these ARM before neon seems to be slower
+        "subs           %[count], %[count], #8   \n"// (1) update loop counter
+        "sub            %[sP], %[sP], #32        \n"// (0) move pointer to next set of samples
+
+        // sP used after branch (warning)
+        "bne            1b                       \n"// loop
+
+        ASSEMBLY_ACCUMULATE_STEREO
+
+        : [out] "=Uv" (out[0]),
+          [count] "+r" (count),
+          [coefsP0] "+r" (coefsP),
+          [coefsN0] "+r" (coefsN),
+          [coefsP1] "+r" (coefsP1),
+          [coefsN1] "+r" (coefsN1),
+          [sP] "+r" (sP),
+          [sN] "+r" (sN)
+        : [lerpP]   "r" (lerpP),
+          [vLR] "r" (volumeLR)
+        : "cc", "memory",
+          "q0", "q1", "q2", "q3",
+          "q4", "q5", "q6",
+          "q8", "q9", "q10", "q11"
+    );
+}
+
+template <>
+inline void ProcessL<1, 16>(int32_t* const out,
+        int count,
+        const int32_t* coefsP,
+        const int32_t* coefsN,
+        const int16_t* sP,
+        const int16_t* sN,
+        const int32_t* const volumeLR)
+{
+    const int CHANNELS = 1; // template specialization does not preserve params
+    const int STRIDE = 16;
+    sP -= CHANNELS*((STRIDE>>1)-1);
+    asm (
+        "veor           q0, q0, q0                    \n"// result, initialize to 0
+
+        "1:                                           \n"
+
+        "vld1.16        {q2}, [%[sP]]                 \n"// load 8 16-bits mono samples
+        "vld1.16        {q3}, [%[sN]]!                \n"// load 8 16-bits mono samples
+        "vld1.32        {q8, q9}, [%[coefsP0]:128]!   \n"// load 8 32-bits coefs
+        "vld1.32        {q10, q11}, [%[coefsN0]:128]! \n"// load 8 32-bits coefs
+
+        "vrev64.16      q2, q2                        \n"// reverse 8 frames of the positive side
+
+        "vshll.s16      q12, d4, #15                  \n"// extend samples to 31 bits
+        "vshll.s16      q13, d5, #15                  \n"// extend samples to 31 bits
+
+        "vshll.s16      q14, d6, #15                  \n"// extend samples to 31 bits
+        "vshll.s16      q15, d7, #15                  \n"// extend samples to 31 bits
+
+        "vqrdmulh.s32   q12, q12, q9                  \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q13, q13, q8                  \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q14, q14, q10                 \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q15, q15, q11                 \n"// multiply samples by interpolated coef
+
+        "vadd.s32       q0, q0, q12                   \n"// accumulate result
+        "vadd.s32       q13, q13, q14                 \n"// accumulate result
+        "vadd.s32       q0, q0, q15                   \n"// accumulate result
+        "vadd.s32       q0, q0, q13                   \n"// accumulate result
+
+        "sub            %[sP], %[sP], #16             \n"// move pointer to next set of samples
+        "subs           %[count], %[count], #8        \n"// update loop counter
+
+        "bne            1b                            \n"// loop
+
+        ASSEMBLY_ACCUMULATE_MONO
+
+        : [out]     "=Uv" (out[0]),
+          [count]   "+r" (count),
+          [coefsP0] "+r" (coefsP),
+          [coefsN0] "+r" (coefsN),
+          [sP]      "+r" (sP),
+          [sN]      "+r" (sN)
+        : [vLR]     "r" (volumeLR)
+        : "cc", "memory",
+          "q0", "q1", "q2", "q3",
+          "q8", "q9", "q10", "q11",
+          "q12", "q13", "q14", "q15"
+    );
+}
+
+template <>
+inline void ProcessL<2, 16>(int32_t* const out,
+        int count,
+        const int32_t* coefsP,
+        const int32_t* coefsN,
+        const int16_t* sP,
+        const int16_t* sN,
+        const int32_t* const volumeLR)
+{
+    const int CHANNELS = 2; // template specialization does not preserve params
+    const int STRIDE = 16;
+    sP -= CHANNELS*((STRIDE>>1)-1);
+    asm (
+        "veor           q0, q0, q0                    \n"// result, initialize to 0
+        "veor           q4, q4, q4                    \n"// result, initialize to 0
+
+        "1:                                           \n"
+
+        "vld2.16        {q2, q3}, [%[sP]]             \n"// load 4 16-bits stereo samples
+        "vld2.16        {q5, q6}, [%[sN]]!            \n"// load 4 16-bits stereo samples
+        "vld1.32        {q8, q9}, [%[coefsP0]:128]!   \n"// load 4 32-bits coefs
+        "vld1.32        {q10, q11}, [%[coefsN0]:128]! \n"// load 4 32-bits coefs
+
+        "vrev64.16      q2, q2                        \n"// reverse 8 frames of the positive side
+        "vrev64.16      q3, q3                        \n"// reverse 8 frames of the positive side
+
+        "vshll.s16      q12,  d4, #15                 \n"// extend samples to 31 bits
+        "vshll.s16      q13,  d5, #15                 \n"// extend samples to 31 bits
+
+        "vshll.s16      q14,  d10, #15                \n"// extend samples to 31 bits
+        "vshll.s16      q15,  d11, #15                \n"// extend samples to 31 bits
+
+        "vqrdmulh.s32   q12, q12, q9                  \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q13, q13, q8                  \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q14, q14, q10                 \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q15, q15, q11                 \n"// multiply samples by interpolated coef
+
+        "vadd.s32       q0, q0, q12                   \n"// accumulate result
+        "vadd.s32       q13, q13, q14                 \n"// accumulate result
+        "vadd.s32       q0, q0, q15                   \n"// (+1) accumulate result
+        "vadd.s32       q0, q0, q13                   \n"// (+1) accumulate result
+
+        "vshll.s16      q12,  d6, #15                 \n"// extend samples to 31 bits
+        "vshll.s16      q13,  d7, #15                 \n"// extend samples to 31 bits
+
+        "vshll.s16      q14,  d12, #15                \n"// extend samples to 31 bits
+        "vshll.s16      q15,  d13, #15                \n"// extend samples to 31 bits
+
+        "vqrdmulh.s32   q12, q12, q9                  \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q13, q13, q8                  \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q14, q14, q10                 \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q15, q15, q11                 \n"// multiply samples by interpolated coef
+
+        "vadd.s32       q4, q4, q12                   \n"// accumulate result
+        "vadd.s32       q13, q13, q14                 \n"// accumulate result
+        "vadd.s32       q4, q4, q15                   \n"// (+1) accumulate result
+        "vadd.s32       q4, q4, q13                   \n"// (+1) accumulate result
+
+        "subs           %[count], %[count], #8        \n"// update loop counter
+        "sub            %[sP], %[sP], #32             \n"// move pointer to next set of samples
+
+        "bne            1b                            \n"// loop
+
+        ASSEMBLY_ACCUMULATE_STEREO
+
+        : [out]     "=Uv" (out[0]),
+          [count]   "+r" (count),
+          [coefsP0] "+r" (coefsP),
+          [coefsN0] "+r" (coefsN),
+          [sP]      "+r" (sP),
+          [sN]      "+r" (sN)
+        : [vLR]     "r" (volumeLR)
+        : "cc", "memory",
+          "q0", "q1", "q2", "q3",
+          "q4", "q5", "q6",
+          "q8", "q9", "q10", "q11",
+          "q12", "q13", "q14", "q15"
+    );
+}
+
+template <>
+inline void Process<1, 16>(int32_t* const out,
+        int count,
+        const int32_t* coefsP,
+        const int32_t* coefsN,
+        const int32_t* coefsP1,
+        const int32_t* coefsN1,
+        const int16_t* sP,
+        const int16_t* sN,
+        uint32_t lerpP,
+        const int32_t* const volumeLR)
+{
+    const int CHANNELS = 1; // template specialization does not preserve params
+    const int STRIDE = 16;
+    sP -= CHANNELS*((STRIDE>>1)-1);
+    asm (
+        "vmov.32        d2[0], %[lerpP]               \n"// load the positive phase
+        "veor           q0, q0, q0                    \n"// result, initialize to 0
+
+        "1:                                           \n"
+
+        "vld1.16        {q2}, [%[sP]]                 \n"// load 8 16-bits mono samples
+        "vld1.16        {q3}, [%[sN]]!                \n"// load 8 16-bits mono samples
+        "vld1.32        {q8, q9}, [%[coefsP0]:128]!   \n"// load 8 32-bits coefs
+        "vld1.32        {q12, q13}, [%[coefsP1]:128]! \n"// load 8 32-bits coefs
+        "vld1.32        {q10, q11}, [%[coefsN1]:128]! \n"// load 8 32-bits coefs
+        "vld1.32        {q14, q15}, [%[coefsN0]:128]! \n"// load 8 32-bits coefs
+
+        "vsub.s32       q12, q12, q8                  \n"// interpolate (step1)
+        "vsub.s32       q13, q13, q9                  \n"// interpolate (step1)
+        "vsub.s32       q14, q14, q10                 \n"// interpolate (step1)
+        "vsub.s32       q15, q15, q11                 \n"// interpolate (step1)
+
+        "vqrdmulh.s32   q12, q12, d2[0]               \n"// interpolate (step2)
+        "vqrdmulh.s32   q13, q13, d2[0]               \n"// interpolate (step2)
+        "vqrdmulh.s32   q14, q14, d2[0]               \n"// interpolate (step2)
+        "vqrdmulh.s32   q15, q15, d2[0]               \n"// interpolate (step2)
+
+        "vadd.s32       q8, q8, q12                   \n"// interpolate (step3)
+        "vadd.s32       q9, q9, q13                   \n"// interpolate (step3)
+        "vadd.s32       q10, q10, q14                 \n"// interpolate (step3)
+        "vadd.s32       q11, q11, q15                 \n"// interpolate (step3)
+
+        "vrev64.16      q2, q2                        \n"// reverse 8 frames of the positive side
+
+        "vshll.s16      q12,  d4, #15                 \n"// extend samples to 31 bits
+        "vshll.s16      q13,  d5, #15                 \n"// extend samples to 31 bits
+
+        "vshll.s16      q14,  d6, #15                 \n"// extend samples to 31 bits
+        "vshll.s16      q15,  d7, #15                 \n"// extend samples to 31 bits
+
+        "vqrdmulh.s32   q12, q12, q9                  \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q13, q13, q8                  \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q14, q14, q10                 \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q15, q15, q11                 \n"// multiply samples by interpolated coef
+
+        "vadd.s32       q0, q0, q12                   \n"// accumulate result
+        "vadd.s32       q13, q13, q14                 \n"// accumulate result
+        "vadd.s32       q0, q0, q15                   \n"// accumulate result
+        "vadd.s32       q0, q0, q13                   \n"// accumulate result
+
+        "sub            %[sP], %[sP], #16             \n"// move pointer to next set of samples
+        "subs           %[count], %[count], #8        \n"// update loop counter
+
+        "bne            1b                            \n"// loop
+
+        ASSEMBLY_ACCUMULATE_MONO
+
+        : [out]     "=Uv" (out[0]),
+          [count]   "+r" (count),
+          [coefsP0] "+r" (coefsP),
+          [coefsN0] "+r" (coefsN),
+          [coefsP1] "+r" (coefsP1),
+          [coefsN1] "+r" (coefsN1),
+          [sP]      "+r" (sP),
+          [sN]      "+r" (sN)
+        : [lerpP]   "r" (lerpP),
+          [vLR]     "r" (volumeLR)
+        : "cc", "memory",
+          "q0", "q1", "q2", "q3",
+          "q8", "q9", "q10", "q11",
+          "q12", "q13", "q14", "q15"
+    );
+}
+
+template <>
+inline void Process<2, 16>(int32_t* const out,
+        int count,
+        const int32_t* coefsP,
+        const int32_t* coefsN,
+        const int32_t* coefsP1,
+        const int32_t* coefsN1,
+        const int16_t* sP,
+        const int16_t* sN,
+        uint32_t lerpP,
+        const int32_t* const volumeLR)
+{
+    const int CHANNELS = 2; // template specialization does not preserve params
+    const int STRIDE = 16;
+    sP -= CHANNELS*((STRIDE>>1)-1);
+    asm (
+        "vmov.32        d2[0], %[lerpP]               \n"// load the positive phase
+        "veor           q0, q0, q0                    \n"// result, initialize to 0
+        "veor           q4, q4, q4                    \n"// result, initialize to 0
+
+        "1:                                           \n"
+
+        "vld2.16        {q2, q3}, [%[sP]]             \n"// load 4 16-bits stereo samples
+        "vld2.16        {q5, q6}, [%[sN]]!            \n"// load 4 16-bits stereo samples
+        "vld1.32        {q8, q9}, [%[coefsP0]:128]!   \n"// load 8 32-bits coefs
+        "vld1.32        {q12, q13}, [%[coefsP1]:128]! \n"// load 8 32-bits coefs
+        "vld1.32        {q10, q11}, [%[coefsN1]:128]! \n"// load 8 32-bits coefs
+        "vld1.32        {q14, q15}, [%[coefsN0]:128]! \n"// load 8 32-bits coefs
+
+        "vsub.s32       q12, q12, q8                  \n"// interpolate (step1)
+        "vsub.s32       q13, q13, q9                  \n"// interpolate (step1)
+        "vsub.s32       q14, q14, q10                 \n"// interpolate (step1)
+        "vsub.s32       q15, q15, q11                 \n"// interpolate (step1)
+
+        "vqrdmulh.s32   q12, q12, d2[0]               \n"// interpolate (step2)
+        "vqrdmulh.s32   q13, q13, d2[0]               \n"// interpolate (step2)
+        "vqrdmulh.s32   q14, q14, d2[0]               \n"// interpolate (step2)
+        "vqrdmulh.s32   q15, q15, d2[0]               \n"// interpolate (step2)
+
+        "vadd.s32       q8, q8, q12                   \n"// interpolate (step3)
+        "vadd.s32       q9, q9, q13                   \n"// interpolate (step3)
+        "vadd.s32       q10, q10, q14                 \n"// interpolate (step3)
+        "vadd.s32       q11, q11, q15                 \n"// interpolate (step3)
+
+        "vrev64.16      q2, q2                        \n"// reverse 8 frames of the positive side
+        "vrev64.16      q3, q3                        \n"// reverse 8 frames of the positive side
+
+        "vshll.s16      q12,  d4, #15                 \n"// extend samples to 31 bits
+        "vshll.s16      q13,  d5, #15                 \n"// extend samples to 31 bits
+
+        "vshll.s16      q14,  d10, #15                \n"// extend samples to 31 bits
+        "vshll.s16      q15,  d11, #15                \n"// extend samples to 31 bits
+
+        "vqrdmulh.s32   q12, q12, q9                  \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q13, q13, q8                  \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q14, q14, q10                 \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q15, q15, q11                 \n"// multiply samples by interpolated coef
+
+        "vadd.s32       q0, q0, q12                   \n"// accumulate result
+        "vadd.s32       q13, q13, q14                 \n"// accumulate result
+        "vadd.s32       q0, q0, q15                   \n"// (+1) accumulate result
+        "vadd.s32       q0, q0, q13                   \n"// (+1) accumulate result
+
+        "vshll.s16      q12,  d6, #15                 \n"// extend samples to 31 bits
+        "vshll.s16      q13,  d7, #15                 \n"// extend samples to 31 bits
+
+        "vshll.s16      q14,  d12, #15                \n"// extend samples to 31 bits
+        "vshll.s16      q15,  d13, #15                \n"// extend samples to 31 bits
+
+        "vqrdmulh.s32   q12, q12, q9                  \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q13, q13, q8                  \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q14, q14, q10                 \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q15, q15, q11                 \n"// multiply samples by interpolated coef
+
+        "vadd.s32       q4, q4, q12                   \n"// accumulate result
+        "vadd.s32       q13, q13, q14                 \n"// accumulate result
+        "vadd.s32       q4, q4, q15                   \n"// (+1) accumulate result
+        "vadd.s32       q4, q4, q13                   \n"// (+1) accumulate result
+
+        "subs           %[count], %[count], #8        \n"// update loop counter
+        "sub            %[sP], %[sP], #32             \n"// move pointer to next set of samples
+
+        "bne            1b                            \n"// loop
+
+        ASSEMBLY_ACCUMULATE_STEREO
+
+        : [out]     "=Uv" (out[0]),
+          [count]   "+r" (count),
+          [coefsP0] "+r" (coefsP),
+          [coefsN0] "+r" (coefsN),
+          [coefsP1] "+r" (coefsP1),
+          [coefsN1] "+r" (coefsN1),
+          [sP]      "+r" (sP),
+          [sN]      "+r" (sN)
+        : [lerpP]   "r" (lerpP),
+          [vLR]     "r" (volumeLR)
+        : "cc", "memory",
+          "q0", "q1", "q2", "q3",
+          "q4", "q5", "q6",
+          "q8", "q9", "q10", "q11",
+          "q12", "q13", "q14", "q15"
+    );
+}
+
+template <>
+inline void ProcessL<1, 8>(int32_t* const out,
+        int count,
+        const int16_t* coefsP,
+        const int16_t* coefsN,
+        const int16_t* sP,
+        const int16_t* sN,
+        const int32_t* const volumeLR)
+{
+    const int CHANNELS = 1; // template specialization does not preserve params
+    const int STRIDE = 8;
+    sP -= CHANNELS*((STRIDE>>1)-1);
+    asm (
+        "veor           q0, q0, q0               \n"// (0 - combines+) accumulator = 0
+
+        "1:                                      \n"
+
+        "vld1.16        {d4}, [%[sP]]            \n"// (2+0d) load 4 16-bits mono samples
+        "vld1.16        {d6}, [%[sN]]!           \n"// (2) load 4 16-bits mono samples
+        "vld1.16        {d16}, [%[coefsP0]:64]!  \n"// (1) load 4 16-bits coefs
+        "vld1.16        {d20}, [%[coefsN0]:64]!  \n"// (1) load 4 16-bits coefs
+
+        "vrev64.16      d4, d4                   \n"// (1) reversed s3, s2, s1, s0, s7, s6, s5, s4
+
+        // reordering the vmal to do d6, d7 before d4, d5 is slower(?)
+        "vmlal.s16      q0, d4, d16              \n"// (1) multiply (reversed)samples by coef
+        "vmlal.s16      q0, d6, d20              \n"// (1) multiply neg samples
+
+        // moving these ARM instructions before neon above seems to be slower
+        "subs           %[count], %[count], #4   \n"// (1) update loop counter
+        "sub            %[sP], %[sP], #8         \n"// (0) move pointer to next set of samples
+
+        // sP used after branch (warning)
+        "bne            1b                       \n"// loop
+
+        ASSEMBLY_ACCUMULATE_MONO
+
+        : [out]     "=Uv" (out[0]),
+          [count]   "+r" (count),
+          [coefsP0] "+r" (coefsP),
+          [coefsN0] "+r" (coefsN),
+          [sP]      "+r" (sP),
+          [sN]      "+r" (sN)
+        : [vLR]     "r" (volumeLR)
+        : "cc", "memory",
+          "q0", "q1", "q2", "q3",
+          "q8", "q10"
+    );
+}
+
+template <>
+inline void ProcessL<2, 8>(int32_t* const out,
+        int count,
+        const int16_t* coefsP,
+        const int16_t* coefsN,
+        const int16_t* sP,
+        const int16_t* sN,
+        const int32_t* const volumeLR)
+{
+    const int CHANNELS = 2; // template specialization does not preserve params
+    const int STRIDE = 8;
+    sP -= CHANNELS*((STRIDE>>1)-1);
+    asm (
+        "veor           q0, q0, q0               \n"// (1) acc_L = 0
+        "veor           q4, q4, q4               \n"// (0 combines+) acc_R = 0
+
+        "1:                                      \n"
+
+        "vld2.16        {d4, d5}, [%[sP]]        \n"// (2+0d) load 8 16-bits stereo samples
+        "vld2.16        {d6, d7}, [%[sN]]!       \n"// (2) load 8 16-bits stereo samples
+        "vld1.16        {d16}, [%[coefsP0]:64]!  \n"// (1) load 8 16-bits coefs
+        "vld1.16        {d20}, [%[coefsN0]:64]!  \n"// (1) load 8 16-bits coefs
+
+        "vrev64.16      q2, q2                   \n"// (1) reverse 8 frames of the left positive
+
+        "vmlal.s16      q0, d4, d16              \n"// (1) multiply (reversed) samples left
+        "vmlal.s16      q4, d5, d16              \n"// (1) multiply (reversed) samples right
+        "vmlal.s16      q0, d6, d20              \n"// (1) multiply samples left
+        "vmlal.s16      q4, d7, d20              \n"// (1) multiply samples right
+
+        // moving these ARM before neon seems to be slower
+        "subs           %[count], %[count], #4   \n"// (1) update loop counter
+        "sub            %[sP], %[sP], #16        \n"// (0) move pointer to next set of samples
+
+        // sP used after branch (warning)
+        "bne            1b                       \n"// loop
+
+        ASSEMBLY_ACCUMULATE_STEREO
+
+        : [out] "=Uv" (out[0]),
+          [count] "+r" (count),
+          [coefsP0] "+r" (coefsP),
+          [coefsN0] "+r" (coefsN),
+          [sP] "+r" (sP),
+          [sN] "+r" (sN)
+        : [vLR] "r" (volumeLR)
+        : "cc", "memory",
+          "q0", "q1", "q2", "q3",
+          "q4", "q5", "q6",
+          "q8", "q10"
+     );
+}
+
+template <>
+inline void Process<1, 8>(int32_t* const out,
+        int count,
+        const int16_t* coefsP,
+        const int16_t* coefsN,
+        const int16_t* coefsP1,
+        const int16_t* coefsN1,
+        const int16_t* sP,
+        const int16_t* sN,
+        uint32_t lerpP,
+        const int32_t* const volumeLR)
+{
+    const int CHANNELS = 1; // template specialization does not preserve params
+    const int STRIDE = 8;
+    sP -= CHANNELS*((STRIDE>>1)-1);
+    asm (
+        "vmov.32        d2[0], %[lerpP]          \n"// load the positive phase S32 Q15
+        "veor           q0, q0, q0               \n"// (0 - combines+) accumulator = 0
+
+        "1:                                      \n"
+
+        "vld1.16        {d4}, [%[sP]]            \n"// (2+0d) load 4 16-bits mono samples
+        "vld1.16        {d6}, [%[sN]]!           \n"// (2) load 4 16-bits mono samples
+        "vld1.16        {d16}, [%[coefsP0]:64]!  \n"// (1) load 4 16-bits coefs
+        "vld1.16        {d17}, [%[coefsP1]:64]!  \n"// (1) load 4 16-bits coefs for interpolation
+        "vld1.16        {d20}, [%[coefsN1]:64]!  \n"// (1) load 4 16-bits coefs
+        "vld1.16        {d21}, [%[coefsN0]:64]!  \n"// (1) load 4 16-bits coefs for interpolation
+
+        "vsub.s16       d17, d17, d16            \n"// (1) interpolate (step1) 1st set of coefs
+        "vsub.s16       d21, d21, d20            \n"// (1) interpolate (step1) 2nd set of coets
+
+        "vqrdmulh.s16   d17, d17, d2[0]          \n"// (2) interpolate (step2) 1st set of coefs
+        "vqrdmulh.s16   d21, d21, d2[0]          \n"// (2) interpolate (step2) 2nd set of coefs
+
+        "vrev64.16      d4, d4                   \n"// (1) reverse s3, s2, s1, s0, s7, s6, s5, s4
+
+        "vadd.s16       d16, d16, d17            \n"// (1+2d) interpolate (step3) 1st set
+        "vadd.s16       d20, d20, d21            \n"// (1+1d) interpolate (step3) 2nd set
+
+        // reordering the vmal to do d6, d7 before d4, d5 is slower(?)
+        "vmlal.s16      q0, d4, d16              \n"// (1+0d) multiply (reversed)by coef
+        "vmlal.s16      q0, d6, d20              \n"// (1) multiply neg samples
+
+        // moving these ARM instructions before neon above seems to be slower
+        "subs           %[count], %[count], #4   \n"// (1) update loop counter
+        "sub            %[sP], %[sP], #8        \n"// move pointer to next set of samples
+
+        // sP used after branch (warning)
+        "bne            1b                       \n"// loop
+
+        ASSEMBLY_ACCUMULATE_MONO
+
+        : [out]     "=Uv" (out[0]),
+          [count]   "+r" (count),
+          [coefsP0] "+r" (coefsP),
+          [coefsN0] "+r" (coefsN),
+          [coefsP1] "+r" (coefsP1),
+          [coefsN1] "+r" (coefsN1),
+          [sP]      "+r" (sP),
+          [sN]      "+r" (sN)
+        : [lerpP]   "r" (lerpP),
+          [vLR]     "r" (volumeLR)
+        : "cc", "memory",
+          "q0", "q1", "q2", "q3",
+          "q8", "q9", "q10", "q11"
+    );
+}
+
+template <>
+inline void Process<2, 8>(int32_t* const out,
+        int count,
+        const int16_t* coefsP,
+        const int16_t* coefsN,
+        const int16_t* coefsP1,
+        const int16_t* coefsN1,
+        const int16_t* sP,
+        const int16_t* sN,
+        uint32_t lerpP,
+        const int32_t* const volumeLR)
+{
+    const int CHANNELS = 2; // template specialization does not preserve params
+    const int STRIDE = 8;
+    sP -= CHANNELS*((STRIDE>>1)-1);
+    asm (
+        "vmov.32        d2[0], %[lerpP]          \n"// load the positive phase
+        "veor           q0, q0, q0               \n"// (1) acc_L = 0
+        "veor           q4, q4, q4               \n"// (0 combines+) acc_R = 0
+
+        "1:                                      \n"
+
+        "vld2.16        {d4, d5}, [%[sP]]        \n"// (3+0d) load 8 16-bits stereo samples
+        "vld2.16        {d6, d7}, [%[sN]]!       \n"// (3) load 8 16-bits stereo samples
+        "vld1.16        {d16}, [%[coefsP0]:64]!  \n"// (1) load 8 16-bits coefs
+        "vld1.16        {d17}, [%[coefsP1]:64]!  \n"// (1) load 8 16-bits coefs for interpolation
+        "vld1.16        {d20}, [%[coefsN1]:64]!  \n"// (1) load 8 16-bits coefs
+        "vld1.16        {d21}, [%[coefsN0]:64]!  \n"// (1) load 8 16-bits coefs for interpolation
+
+        "vsub.s16       d17, d17, d16            \n"// (1) interpolate (step1) 1st set of coefs
+        "vsub.s16       d21, d21, d20            \n"// (1) interpolate (step1) 2nd set of coets
+
+        "vqrdmulh.s16   d17, d17, d2[0]          \n"// (2) interpolate (step2) 1st set of coefs
+        "vqrdmulh.s16   d21, d21, d2[0]          \n"// (2) interpolate (step2) 2nd set of coefs
+
+        "vrev64.16      q2, q2                   \n"// (1) reverse 8 frames of the left positive
+
+        "vadd.s16       d16, d16, d17            \n"// (1+1d) interpolate (step3) 1st set
+        "vadd.s16       d20, d20, d21            \n"// (1+1d) interpolate (step3) 2nd set
+
+        "vmlal.s16      q0, d4, d16              \n"// (1) multiply (reversed) samples left
+        "vmlal.s16      q4, d5, d16              \n"// (1) multiply (reversed) samples right
+        "vmlal.s16      q0, d6, d20              \n"// (1) multiply samples left
+        "vmlal.s16      q4, d7, d20              \n"// (1) multiply samples right
+
+        // moving these ARM before neon seems to be slower
+        "subs           %[count], %[count], #4   \n"// (1) update loop counter
+        "sub            %[sP], %[sP], #16        \n"// move pointer to next set of samples
+
+        // sP used after branch (warning)
+        "bne            1b                       \n"// loop
+
+        ASSEMBLY_ACCUMULATE_STEREO
+
+        : [out] "=Uv" (out[0]),
+          [count] "+r" (count),
+          [coefsP0] "+r" (coefsP),
+          [coefsN0] "+r" (coefsN),
+          [coefsP1] "+r" (coefsP1),
+          [coefsN1] "+r" (coefsN1),
+          [sP] "+r" (sP),
+          [sN] "+r" (sN)
+        : [lerpP]   "r" (lerpP),
+          [vLR] "r" (volumeLR)
+        : "cc", "memory",
+          "q0", "q1", "q2", "q3",
+          "q4", "q5", "q6",
+          "q8", "q9", "q10", "q11"
+    );
+}
+
+template <>
+inline void ProcessL<1, 8>(int32_t* const out,
+        int count,
+        const int32_t* coefsP,
+        const int32_t* coefsN,
+        const int16_t* sP,
+        const int16_t* sN,
+        const int32_t* const volumeLR)
+{
+    const int CHANNELS = 1; // template specialization does not preserve params
+    const int STRIDE = 8;
+    sP -= CHANNELS*((STRIDE>>1)-1);
+    asm (
+        "veor           q0, q0, q0               \n"// result, initialize to 0
+
+        "1:                                      \n"
+
+        "vld1.16        {d4}, [%[sP]]            \n"// load 4 16-bits mono samples
+        "vld1.16        {d6}, [%[sN]]!           \n"// load 4 16-bits mono samples
+        "vld1.32        {q8}, [%[coefsP0]:128]!  \n"// load 4 32-bits coefs
+        "vld1.32        {q10}, [%[coefsN0]:128]! \n"// load 4 32-bits coefs
+
+        "vrev64.16      d4, d4                   \n"// reverse 2 frames of the positive side
+
+        "vshll.s16      q12, d4, #15             \n"// (stall) extend samples to 31 bits
+        "vshll.s16      q14, d6, #15             \n"// extend samples to 31 bits
+
+        "vqrdmulh.s32   q12, q12, q8             \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q14, q14, q10            \n"// multiply samples by interpolated coef
+
+        "vadd.s32       q0, q0, q12              \n"// accumulate result
+        "vadd.s32       q0, q0, q14              \n"// (stall) accumulate result
+
+        "subs           %[count], %[count], #4   \n"// update loop counter
+        "sub            %[sP], %[sP], #8         \n"// move pointer to next set of samples
+
+        "bne            1b                       \n"// loop
+
+        ASSEMBLY_ACCUMULATE_MONO
+
+        : [out] "=Uv" (out[0]),
+          [count] "+r" (count),
+          [coefsP0] "+r" (coefsP),
+          [coefsN0] "+r" (coefsN),
+          [sP] "+r" (sP),
+          [sN] "+r" (sN)
+        : [vLR] "r" (volumeLR)
+        : "cc", "memory",
+          "q0", "q1", "q2", "q3",
+          "q8", "q9", "q10", "q11",
+          "q12", "q14"
+    );
+}
+
+template <>
+inline void ProcessL<2, 8>(int32_t* const out,
+        int count,
+        const int32_t* coefsP,
+        const int32_t* coefsN,
+        const int16_t* sP,
+        const int16_t* sN,
+        const int32_t* const volumeLR)
+{
+    const int CHANNELS = 2; // template specialization does not preserve params
+    const int STRIDE = 8;
+    sP -= CHANNELS*((STRIDE>>1)-1);
+    asm (
+        "veor           q0, q0, q0               \n"// result, initialize to 0
+        "veor           q4, q4, q4               \n"// result, initialize to 0
+
+        "1:                                      \n"
+
+        "vld2.16        {d4, d5}, [%[sP]]        \n"// load 4 16-bits stereo samples
+        "vld2.16        {d6, d7}, [%[sN]]!       \n"// load 4 16-bits stereo samples
+        "vld1.32        {q8}, [%[coefsP0]:128]!  \n"// load 4 32-bits coefs
+        "vld1.32        {q10}, [%[coefsN0]:128]! \n"// load 4 32-bits coefs
+
+        "vrev64.16      q2, q2                   \n"// reverse 2 frames of the positive side
+
+        "vshll.s16      q12, d4, #15             \n"// extend samples to 31 bits
+        "vshll.s16      q13, d5, #15             \n"// extend samples to 31 bits
+
+        "vshll.s16      q14, d6, #15             \n"// extend samples to 31 bits
+        "vshll.s16      q15, d7, #15             \n"// extend samples to 31 bits
+
+        "vqrdmulh.s32   q12, q12, q8             \n"// multiply samples by coef
+        "vqrdmulh.s32   q13, q13, q8             \n"// multiply samples by coef
+        "vqrdmulh.s32   q14, q14, q10            \n"// multiply samples by coef
+        "vqrdmulh.s32   q15, q15, q10            \n"// multiply samples by coef
+
+        "vadd.s32       q0, q0, q12              \n"// accumulate result
+        "vadd.s32       q4, q4, q13              \n"// accumulate result
+        "vadd.s32       q0, q0, q14              \n"// accumulate result
+        "vadd.s32       q4, q4, q15              \n"// accumulate result
+
+        "subs           %[count], %[count], #4   \n"// update loop counter
+        "sub            %[sP], %[sP], #16        \n"// move pointer to next set of samples
+
+        "bne            1b                       \n"// loop
+
+        ASSEMBLY_ACCUMULATE_STEREO
+
+        : [out]     "=Uv" (out[0]),
+          [count]   "+r" (count),
+          [coefsP0] "+r" (coefsP),
+          [coefsN0] "+r" (coefsN),
+          [sP]      "+r" (sP),
+          [sN]      "+r" (sN)
+        : [vLR]     "r" (volumeLR)
+        : "cc", "memory",
+          "q0", "q1", "q2", "q3", "q4",
+          "q8", "q9", "q10", "q11",
+          "q12", "q13", "q14", "q15"
+    );
+}
+
+template <>
+inline void Process<1, 8>(int32_t* const out,
+        int count,
+        const int32_t* coefsP,
+        const int32_t* coefsN,
+        const int32_t* coefsP1,
+        const int32_t* coefsN1,
+        const int16_t* sP,
+        const int16_t* sN,
+        uint32_t lerpP,
+        const int32_t* const volumeLR)
+{
+    const int CHANNELS = 1; // template specialization does not preserve params
+    const int STRIDE = 8;
+    sP -= CHANNELS*((STRIDE>>1)-1);
+    asm (
+        "vmov.32        d2[0], %[lerpP]          \n"// load the positive phase
+        "veor           q0, q0, q0               \n"// result, initialize to 0
+
+        "1:                                      \n"
+
+        "vld1.16        {d4}, [%[sP]]            \n"// load 4 16-bits mono samples
+        "vld1.16        {d6}, [%[sN]]!           \n"// load 4 16-bits mono samples
+        "vld1.32        {q8}, [%[coefsP0]:128]!  \n"// load 4 32-bits coefs
+        "vld1.32        {q9}, [%[coefsP1]:128]!  \n"// load 4 32-bits coefs for interpolation
+        "vld1.32        {q10}, [%[coefsN1]:128]! \n"// load 4 32-bits coefs
+        "vld1.32        {q11}, [%[coefsN0]:128]! \n"// load 4 32-bits coefs for interpolation
+
+        "vrev64.16      d4, d4                   \n"// reverse 2 frames of the positive side
+
+        "vsub.s32       q9, q9, q8               \n"// interpolate (step1) 1st set of coefs
+        "vsub.s32       q11, q11, q10            \n"// interpolate (step1) 2nd set of coets
+        "vshll.s16      q12, d4, #15             \n"// extend samples to 31 bits
+
+        "vqrdmulh.s32   q9, q9, d2[0]            \n"// interpolate (step2) 1st set of coefs
+        "vqrdmulh.s32   q11, q11, d2[0]          \n"// interpolate (step2) 2nd set of coefs
+        "vshll.s16      q14, d6, #15             \n"// extend samples to 31 bits
+
+        "vadd.s32       q8, q8, q9               \n"// interpolate (step3) 1st set
+        "vadd.s32       q10, q10, q11            \n"// interpolate (step4) 2nd set
+
+        "vqrdmulh.s32   q12, q12, q8             \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q14, q14, q10            \n"// multiply samples by interpolated coef
+
+        "vadd.s32       q0, q0, q12              \n"// accumulate result
+        "vadd.s32       q0, q0, q14              \n"// accumulate result
+
+        "subs           %[count], %[count], #4   \n"// update loop counter
+        "sub            %[sP], %[sP], #8         \n"// move pointer to next set of samples
+
+        "bne            1b                       \n"// loop
+
+        ASSEMBLY_ACCUMULATE_MONO
+
+        : [out]     "=Uv" (out[0]),
+          [count]   "+r" (count),
+          [coefsP0] "+r" (coefsP),
+          [coefsP1] "+r" (coefsP1),
+          [coefsN0] "+r" (coefsN),
+          [coefsN1] "+r" (coefsN1),
+          [sP]      "+r" (sP),
+          [sN]      "+r" (sN)
+        : [lerpP]   "r" (lerpP),
+          [vLR]     "r" (volumeLR)
+        : "cc", "memory",
+          "q0", "q1", "q2", "q3",
+          "q8", "q9", "q10", "q11",
+          "q12", "q14"
+    );
+}
+
+template <>
+inline
+void Process<2, 8>(int32_t* const out,
+        int count,
+        const int32_t* coefsP,
+        const int32_t* coefsN,
+        const int32_t* coefsP1,
+        const int32_t* coefsN1,
+        const int16_t* sP,
+        const int16_t* sN,
+        uint32_t lerpP,
+        const int32_t* const volumeLR)
+{
+    const int CHANNELS = 2; // template specialization does not preserve params
+    const int STRIDE = 8;
+    sP -= CHANNELS*((STRIDE>>1)-1);
+    asm (
+        "vmov.32        d2[0], %[lerpP]          \n"// load the positive phase
+        "veor           q0, q0, q0               \n"// result, initialize to 0
+        "veor           q4, q4, q4               \n"// result, initialize to 0
+
+        "1:                                      \n"
+        "vld2.16        {d4, d5}, [%[sP]]        \n"// load 4 16-bits stereo samples
+        "vld2.16        {d6, d7}, [%[sN]]!       \n"// load 4 16-bits stereo samples
+        "vld1.32        {q8}, [%[coefsP0]:128]!  \n"// load 4 32-bits coefs
+        "vld1.32        {q9}, [%[coefsP1]:128]!  \n"// load 4 32-bits coefs for interpolation
+        "vld1.32        {q10}, [%[coefsN1]:128]! \n"// load 4 32-bits coefs
+        "vld1.32        {q11}, [%[coefsN0]:128]! \n"// load 4 32-bits coefs for interpolation
+
+        "vrev64.16      q2, q2                   \n"// (reversed) 2 frames of the positive side
+
+        "vsub.s32       q9, q9, q8               \n"// interpolate (step1) 1st set of coefs
+        "vsub.s32       q11, q11, q10            \n"// interpolate (step1) 2nd set of coets
+        "vshll.s16      q12, d4, #15             \n"// extend samples to 31 bits
+        "vshll.s16      q13, d5, #15             \n"// extend samples to 31 bits
+
+        "vqrdmulh.s32   q9, q9, d2[0]            \n"// interpolate (step2) 1st set of coefs
+        "vqrdmulh.s32   q11, q11, d2[1]          \n"// interpolate (step3) 2nd set of coefs
+        "vshll.s16      q14, d6, #15             \n"// extend samples to 31 bits
+        "vshll.s16      q15, d7, #15             \n"// extend samples to 31 bits
+
+        "vadd.s32       q8, q8, q9               \n"// interpolate (step3) 1st set
+        "vadd.s32       q10, q10, q11            \n"// interpolate (step4) 2nd set
+
+        "vqrdmulh.s32   q12, q12, q8             \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q13, q13, q8             \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q14, q14, q10            \n"// multiply samples by interpolated coef
+        "vqrdmulh.s32   q15, q15, q10            \n"// multiply samples by interpolated coef
+
+        "vadd.s32       q0, q0, q12              \n"// accumulate result
+        "vadd.s32       q4, q4, q13              \n"// accumulate result
+        "vadd.s32       q0, q0, q14              \n"// accumulate result
+        "vadd.s32       q4, q4, q15              \n"// accumulate result
+
+        "subs           %[count], %[count], #4   \n"// update loop counter
+        "sub            %[sP], %[sP], #16        \n"// move pointer to next set of samples
+
+        "bne            1b                       \n"// loop
+
+        ASSEMBLY_ACCUMULATE_STEREO
+
+        : [out]     "=Uv" (out[0]),
+          [count]   "+r" (count),
+          [coefsP0] "+r" (coefsP),
+          [coefsP1] "+r" (coefsP1),
+          [coefsN0] "+r" (coefsN),
+          [coefsN1] "+r" (coefsN1),
+          [sP]      "+r" (sP),
+          [sN]      "+r" (sN)
+        : [lerpP]   "r" (lerpP),
+          [vLR]     "r" (volumeLR)
+        : "cc", "memory",
+          "q0", "q1", "q2", "q3", "q4",
+          "q8", "q9", "q10", "q11",
+          "q12", "q13", "q14", "q15"
+    );
+}
+
+#endif //USE_NEON
+
+}; // namespace android
+
+#endif /*ANDROID_AUDIO_RESAMPLER_FIR_PROCESS_NEON_H*/
diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp
index 207f26b..d0a7a58 100644
--- a/services/audioflinger/AudioResamplerSinc.cpp
+++ b/services/audioflinger/AudioResamplerSinc.cpp
@@ -540,7 +540,7 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
-    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+    size_t inFrameCount = getInFrameCountRequired(outFrameCount);
 
     while (outputIndex < outputSampleCount) {
         // buffer is empty, fetch a new one
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 010e233..29b56db 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -116,8 +116,9 @@
             continue;
         }
         // first non destroyed handle is considered in control
-        if (controlHandle == NULL)
+        if (controlHandle == NULL) {
             controlHandle = h;
+        }
         if (h->priority() <= priority) {
             break;
         }
@@ -804,7 +805,112 @@
     return mOffloaded;
 }
 
-void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
+String8 effectFlagsToString(uint32_t flags) {
+    String8 s;
+
+    s.append("conn. mode: ");
+    switch (flags & EFFECT_FLAG_TYPE_MASK) {
+    case EFFECT_FLAG_TYPE_INSERT: s.append("insert"); break;
+    case EFFECT_FLAG_TYPE_AUXILIARY: s.append("auxiliary"); break;
+    case EFFECT_FLAG_TYPE_REPLACE: s.append("replace"); break;
+    case EFFECT_FLAG_TYPE_PRE_PROC: s.append("preproc"); break;
+    case EFFECT_FLAG_TYPE_POST_PROC: s.append("postproc"); break;
+    default: s.append("unknown/reserved"); break;
+    }
+    s.append(", ");
+
+    s.append("insert pref: ");
+    switch (flags & EFFECT_FLAG_INSERT_MASK) {
+    case EFFECT_FLAG_INSERT_ANY: s.append("any"); break;
+    case EFFECT_FLAG_INSERT_FIRST: s.append("first"); break;
+    case EFFECT_FLAG_INSERT_LAST: s.append("last"); break;
+    case EFFECT_FLAG_INSERT_EXCLUSIVE: s.append("exclusive"); break;
+    default: s.append("unknown/reserved"); break;
+    }
+    s.append(", ");
+
+    s.append("volume mgmt: ");
+    switch (flags & EFFECT_FLAG_VOLUME_MASK) {
+    case EFFECT_FLAG_VOLUME_NONE: s.append("none"); break;
+    case EFFECT_FLAG_VOLUME_CTRL: s.append("implements control"); break;
+    case EFFECT_FLAG_VOLUME_IND: s.append("requires indication"); break;
+    default: s.append("unknown/reserved"); break;
+    }
+    s.append(", ");
+
+    uint32_t devind = flags & EFFECT_FLAG_DEVICE_MASK;
+    if (devind) {
+        s.append("device indication: ");
+        switch (devind) {
+        case EFFECT_FLAG_DEVICE_IND: s.append("requires updates"); break;
+        default: s.append("unknown/reserved"); break;
+        }
+        s.append(", ");
+    }
+
+    s.append("input mode: ");
+    switch (flags & EFFECT_FLAG_INPUT_MASK) {
+    case EFFECT_FLAG_INPUT_DIRECT: s.append("direct"); break;
+    case EFFECT_FLAG_INPUT_PROVIDER: s.append("provider"); break;
+    case EFFECT_FLAG_INPUT_BOTH: s.append("direct+provider"); break;
+    default: s.append("not set"); break;
+    }
+    s.append(", ");
+
+    s.append("output mode: ");
+    switch (flags & EFFECT_FLAG_OUTPUT_MASK) {
+    case EFFECT_FLAG_OUTPUT_DIRECT: s.append("direct"); break;
+    case EFFECT_FLAG_OUTPUT_PROVIDER: s.append("provider"); break;
+    case EFFECT_FLAG_OUTPUT_BOTH: s.append("direct+provider"); break;
+    default: s.append("not set"); break;
+    }
+    s.append(", ");
+
+    uint32_t accel = flags & EFFECT_FLAG_HW_ACC_MASK;
+    if (accel) {
+        s.append("hardware acceleration: ");
+        switch (accel) {
+        case EFFECT_FLAG_HW_ACC_SIMPLE: s.append("non-tunneled"); break;
+        case EFFECT_FLAG_HW_ACC_TUNNEL: s.append("tunneled"); break;
+        default: s.append("unknown/reserved"); break;
+        }
+        s.append(", ");
+    }
+
+    uint32_t modeind = flags & EFFECT_FLAG_AUDIO_MODE_MASK;
+    if (modeind) {
+        s.append("mode indication: ");
+        switch (modeind) {
+        case EFFECT_FLAG_AUDIO_MODE_IND: s.append("required"); break;
+        default: s.append("unknown/reserved"); break;
+        }
+        s.append(", ");
+    }
+
+    uint32_t srcind = flags & EFFECT_FLAG_AUDIO_SOURCE_MASK;
+    if (srcind) {
+        s.append("source indication: ");
+        switch (srcind) {
+        case EFFECT_FLAG_AUDIO_SOURCE_IND: s.append("required"); break;
+        default: s.append("unknown/reserved"); break;
+        }
+        s.append(", ");
+    }
+
+    if (flags & EFFECT_FLAG_OFFLOAD_MASK) {
+        s.append("offloadable, ");
+    }
+
+    int len = s.length();
+    if (s.length() > 2) {
+        char *str = s.lockBuffer(len);
+        s.unlockBuffer(len - 2);
+    }
+    return s;
+}
+
+
+void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args __unused)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -838,9 +944,10 @@
                     mDescriptor.type.node[2],
                 mDescriptor.type.node[3],mDescriptor.type.node[4],mDescriptor.type.node[5]);
     result.append(buffer);
-    snprintf(buffer, SIZE, "\t\t- apiVersion: %08X\n\t\t- flags: %08X\n",
+    snprintf(buffer, SIZE, "\t\t- apiVersion: %08X\n\t\t- flags: %08X (%s)\n",
             mDescriptor.apiVersion,
-            mDescriptor.flags);
+            mDescriptor.flags,
+            effectFlagsToString(mDescriptor.flags).string());
     result.append(buffer);
     snprintf(buffer, SIZE, "\t\t- name: %s\n",
             mDescriptor.name);
@@ -851,37 +958,37 @@
 
     result.append("\t\t- Input configuration:\n");
     result.append("\t\t\tFrames  Smp rate Channels Format Buffer\n");
-    snprintf(buffer, SIZE, "\t\t\t%05zu   %05d    %08x %6d %p\n",
+    snprintf(buffer, SIZE, "\t\t\t%05zu   %05d    %08x %6d (%s) %p\n",
             mConfig.inputCfg.buffer.frameCount,
             mConfig.inputCfg.samplingRate,
             mConfig.inputCfg.channels,
             mConfig.inputCfg.format,
+            formatToString((audio_format_t)mConfig.inputCfg.format),
             mConfig.inputCfg.buffer.raw);
     result.append(buffer);
 
     result.append("\t\t- Output configuration:\n");
     result.append("\t\t\tBuffer     Frames  Smp rate Channels Format\n");
-    snprintf(buffer, SIZE, "\t\t\t%p %05zu   %05d    %08x %d\n",
+    snprintf(buffer, SIZE, "\t\t\t%p %05zu   %05d    %08x %d (%s)\n",
             mConfig.outputCfg.buffer.raw,
             mConfig.outputCfg.buffer.frameCount,
             mConfig.outputCfg.samplingRate,
             mConfig.outputCfg.channels,
-            mConfig.outputCfg.format);
+            mConfig.outputCfg.format,
+            formatToString((audio_format_t)mConfig.outputCfg.format));
     result.append(buffer);
 
     snprintf(buffer, SIZE, "\t\t%zu Clients:\n", mHandles.size());
     result.append(buffer);
-    result.append("\t\t\tPid   Priority Ctrl Locked client server\n");
+    result.append("\t\t\t  Pid Priority Ctrl Locked client server\n");
     for (size_t i = 0; i < mHandles.size(); ++i) {
         EffectHandle *handle = mHandles[i];
         if (handle != NULL && !handle->destroyed_l()) {
-            handle->dump(buffer, SIZE);
+            handle->dumpToBuffer(buffer, SIZE);
             result.append(buffer);
         }
     }
 
-    result.append("\n");
-
     write(fd, result.string(), result.length());
 
     if (locked) {
@@ -911,18 +1018,15 @@
     }
     int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int);
     mCblkMemory = client->heap()->allocate(EFFECT_PARAM_BUFFER_SIZE + bufOffset);
-    if (mCblkMemory != 0) {
-        mCblk = static_cast<effect_param_cblk_t *>(mCblkMemory->pointer());
-
-        if (mCblk != NULL) {
-            new(mCblk) effect_param_cblk_t();
-            mBuffer = (uint8_t *)mCblk + bufOffset;
-        }
-    } else {
+    if (mCblkMemory == 0 ||
+            (mCblk = static_cast<effect_param_cblk_t *>(mCblkMemory->pointer())) == NULL) {
         ALOGE("not enough memory for Effect size=%u", EFFECT_PARAM_BUFFER_SIZE +
                 sizeof(effect_param_cblk_t));
+        mCblkMemory.clear();
         return;
     }
+    new(mCblk) effect_param_cblk_t();
+    mBuffer = (uint8_t *)mCblk + bufOffset;
 }
 
 AudioFlinger::EffectHandle::~EffectHandle()
@@ -939,6 +1043,11 @@
     disconnect(false);
 }
 
+status_t AudioFlinger::EffectHandle::initCheck()
+{
+    return mClient == 0 || mCblkMemory != 0 ? OK : NO_MEMORY;
+}
+
 status_t AudioFlinger::EffectHandle::enable()
 {
     ALOGV("enable %p", this);
@@ -1179,15 +1288,15 @@
 }
 
 
-void AudioFlinger::EffectHandle::dump(char* buffer, size_t size)
+void AudioFlinger::EffectHandle::dumpToBuffer(char* buffer, size_t size)
 {
     bool locked = mCblk != NULL && AudioFlinger::dumpTryLock(mCblk->lock);
 
-    snprintf(buffer, size, "\t\t\t%05d %05d    %01u    %01u      %05u  %05u\n",
+    snprintf(buffer, size, "\t\t\t%5d    %5d  %3s    %3s  %5u  %5u\n",
             (mClient == 0) ? getpid_cached : mClient->pid(),
             mPriority,
-            mHasControl,
-            !locked,
+            mHasControl ? "yes" : "no",
+            locked ? "yes" : "no",
             mCblk ? mCblk->clientIndex : 0,
             mCblk ? mCblk->serverIndex : 0
             );
@@ -1568,33 +1677,35 @@
     char buffer[SIZE];
     String8 result;
 
-    snprintf(buffer, SIZE, "Effects for session %d:\n", mSessionId);
+    size_t numEffects = mEffects.size();
+    snprintf(buffer, SIZE, "    %d effects for session %d\n", numEffects, mSessionId);
     result.append(buffer);
 
-    bool locked = AudioFlinger::dumpTryLock(mLock);
-    // failed to lock - AudioFlinger is probably deadlocked
-    if (!locked) {
-        result.append("\tCould not lock mutex:\n");
-    }
-
-    result.append("\tNum fx In buffer   Out buffer   Active tracks:\n");
-    snprintf(buffer, SIZE, "\t%02zu     %p  %p   %d\n",
-            mEffects.size(),
-            mInBuffer,
-            mOutBuffer,
-            mActiveTrackCnt);
-    result.append(buffer);
-    write(fd, result.string(), result.size());
-
-    for (size_t i = 0; i < mEffects.size(); ++i) {
-        sp<EffectModule> effect = mEffects[i];
-        if (effect != 0) {
-            effect->dump(fd, args);
+    if (numEffects) {
+        bool locked = AudioFlinger::dumpTryLock(mLock);
+        // failed to lock - AudioFlinger is probably deadlocked
+        if (!locked) {
+            result.append("\tCould not lock mutex:\n");
         }
-    }
 
-    if (locked) {
-        mLock.unlock();
+        result.append("\tIn buffer   Out buffer   Active tracks:\n");
+        snprintf(buffer, SIZE, "\t%p  %p   %d\n",
+                mInBuffer,
+                mOutBuffer,
+                mActiveTrackCnt);
+        result.append(buffer);
+        write(fd, result.string(), result.size());
+
+        for (size_t i = 0; i < numEffects; ++i) {
+            sp<EffectModule> effect = mEffects[i];
+            if (effect != 0) {
+                effect->dump(fd, args);
+            }
+        }
+
+        if (locked) {
+            mLock.unlock();
+        }
     }
 }
 
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index b717857..ccc4825 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -169,6 +169,7 @@
             const sp<IEffectClient>& effectClient,
             int32_t priority);
     virtual ~EffectHandle();
+    virtual status_t initCheck();
 
     // IEffect
     virtual status_t enable();
@@ -208,7 +209,7 @@
     // destroyed_l() must be called with the associated EffectModule mLock held
     bool destroyed_l() const { return mDestroyed; }
 
-    void dump(char* buffer, size_t size);
+    void dumpToBuffer(char* buffer, size_t size);
 
 protected:
     friend class AudioFlinger;          // for mEffect, mHasControl, mEnabled
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 85d637e..90122e0 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -238,7 +238,7 @@
                 }
             }
 
-            if ((format != previousFormat) || (frameCount != previous->mFrameCount)) {
+            if ((!Format_isEqual(format, previousFormat)) || (frameCount != previous->mFrameCount)) {
                 // FIXME to avoid priority inversion, don't delete here
                 delete mixer;
                 mixer = NULL;
@@ -440,8 +440,9 @@
             }
 
             int64_t pts;
-            if (outputSink == NULL || (OK != outputSink->getNextWriteTimestamp(&pts)))
+            if (outputSink == NULL || (OK != outputSink->getNextWriteTimestamp(&pts))) {
                 pts = AudioBufferProvider::kInvalidPTS;
+            }
 
             // process() is CPU-bound
             mixer->process(pts);
@@ -695,7 +696,7 @@
 void FastMixerDumpState::dump(int fd) const
 {
     if (mCommand == FastMixerState::INITIAL) {
-        fdprintf(fd, "FastMixer not initialized\n");
+        fdprintf(fd, "  FastMixer not initialized\n");
         return;
     }
 #define COMMAND_MAX 32
@@ -729,10 +730,10 @@
     double measuredWarmupMs = (mMeasuredWarmupTs.tv_sec * 1000.0) +
             (mMeasuredWarmupTs.tv_nsec / 1000000.0);
     double mixPeriodSec = (double) mFrameCount / (double) mSampleRate;
-    fdprintf(fd, "FastMixer command=%s writeSequence=%u framesWritten=%u\n"
-                 "          numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
-                 "          sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n"
-                 "          mixPeriod=%.2f ms\n",
+    fdprintf(fd, "  FastMixer command=%s writeSequence=%u framesWritten=%u\n"
+                 "            numTracks=%u writeErrors=%u underruns=%u overruns=%u\n"
+                 "            sampleRate=%u frameCount=%zu measuredWarmup=%.3g ms, warmupCycles=%u\n"
+                 "            mixPeriod=%.2f ms\n",
                  string, mWriteSequence, mFramesWritten,
                  mNumTracks, mWriteErrors, mUnderruns, mOverruns,
                  mSampleRate, mFrameCount, measuredWarmupMs, mWarmupCycles,
@@ -783,14 +784,20 @@
         previousCpukHz = sampleCpukHz;
 #endif
     }
-    fdprintf(fd, "Simple moving statistics over last %.1f seconds:\n", wall.n() * mixPeriodSec);
-    fdprintf(fd, "  wall clock time in ms per mix cycle:\n"
-                 "    mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
-                 wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6, wall.stddev()*1e-6);
-    fdprintf(fd, "  raw CPU load in us per mix cycle:\n"
-                 "    mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
-                 loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
-                 loadNs.stddev()*1e-3);
+    if (n) {
+        fdprintf(fd, "  Simple moving statistics over last %.1f seconds:\n",
+                     wall.n() * mixPeriodSec);
+        fdprintf(fd, "    wall clock time in ms per mix cycle:\n"
+                     "      mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
+                     wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6,
+                     wall.stddev()*1e-6);
+        fdprintf(fd, "    raw CPU load in us per mix cycle:\n"
+                     "      mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
+                     loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
+                     loadNs.stddev()*1e-3);
+    } else {
+        fdprintf(fd, "  No FastMixer statistics available currently\n");
+    }
 #ifdef CPU_FREQUENCY_STATISTICS
     fdprintf(fd, "  CPU clock frequency in MHz:\n"
                  "    mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
@@ -808,9 +815,9 @@
             left.sample(tail[i]);
             right.sample(tail[n - (i + 1)]);
         }
-        fdprintf(fd, "Distribution of mix cycle times in ms for the tails (> ~3 stddev outliers):\n"
-                     "  left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
-                     "  right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
+        fdprintf(fd, "  Distribution of mix cycle times in ms for the tails (> ~3 stddev outliers):\n"
+                     "    left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
+                     "    right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
                      left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6,
                      right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6,
                      right.stddev()*1e-6);
@@ -823,9 +830,9 @@
     // Instead we always display all tracks, with an indication
     // of whether we think the track is active.
     uint32_t trackMask = mTrackMask;
-    fdprintf(fd, "Fast tracks: kMaxFastTracks=%u activeMask=%#x\n",
+    fdprintf(fd, "  Fast tracks: kMaxFastTracks=%u activeMask=%#x\n",
             FastMixerState::kMaxFastTracks, trackMask);
-    fdprintf(fd, "Index Active Full Partial Empty  Recent Ready\n");
+    fdprintf(fd, "  Index Active Full Partial Empty  Recent Ready\n");
     for (uint32_t i = 0; i < FastMixerState::kMaxFastTracks; ++i, trackMask >>= 1) {
         bool isActive = trackMask & 1;
         const FastTrackDump *ftDump = &mTracks[i];
@@ -845,7 +852,7 @@
             mostRecent = "?";
             break;
         }
-        fdprintf(fd, "%5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no",
+        fdprintf(fd, "  %5u %6s %4u %7u %5u %7s %5zu\n", i, isActive ? "yes" : "no",
                 (underruns.mBitFields.mFull) & UNDERRUN_MASK,
                 (underruns.mBitFields.mPartial) & UNDERRUN_MASK,
                 (underruns.mBitFields.mEmpty) & UNDERRUN_MASK,
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 43b77f3..b5e763d 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -34,9 +34,10 @@
                                 int uid,
                                 IAudioFlinger::track_flags_t flags);
     virtual             ~Track();
+    virtual status_t    initCheck() const;
 
     static  void        appendDumpHeader(String8& result);
-            void        dump(char* buffer, size_t size);
+            void        dump(char* buffer, size_t size, bool active);
     virtual status_t    start(AudioSystem::sync_event_t event =
                                     AudioSystem::SYNC_EVENT_NONE,
                              int triggerSession = 0);
@@ -93,6 +94,8 @@
     bool isReady() const;
     void setPaused() { mState = PAUSED; }
     void reset();
+    bool isFlushPending() const { return mFlushHwPending; }
+    void flushAck();
 
     bool isOutputTrack() const {
         return (mStreamType == AUDIO_STREAM_CNT);
@@ -154,6 +157,7 @@
     bool                mIsInvalid; // non-resettable latch, set by invalidate()
     AudioTrackServerProxy*  mAudioTrackServerProxy;
     bool                mResumeToStopping; // track was paused in stopping state.
+    bool                mFlushHwPending; // track requests for thread flush
 };  // end of Track
 
 class TimedTrack : public Track {
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 57de568..3ec9889 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -45,7 +45,10 @@
                                                 return tmp; }
 
     static  void        appendDumpHeader(String8& result);
-            void        dump(char* buffer, size_t size);
+            void        dump(char* buffer, size_t size, bool active);
+
+            void        handleSyncStartEvent(const sp<SyncEvent>& event);
+            void        clearSyncStartEvent();
 
 private:
     friend class AudioFlinger;  // for mState
@@ -59,5 +62,33 @@
     // releaseBuffer() not overridden
 
     bool                mOverflow;  // overflow on most recent attempt to fill client buffer
-    AudioRecordServerProxy* mAudioRecordServerProxy;
+
+           // updated by RecordThread::readInputParameters_l()
+            AudioResampler                      *mResampler;
+
+            // interleaved stereo pairs of fixed-point signed Q19.12
+            int32_t                             *mRsmpOutBuffer;
+            // current allocated frame count for the above, which may be larger than needed
+            size_t                              mRsmpOutFrameCount;
+
+            size_t                              mRsmpInUnrel;   // unreleased frames remaining from
+                                                                // most recent getNextBuffer
+                                                                // for debug only
+
+            // rolling counter that is never cleared
+            int32_t                             mRsmpInFront;   // next available frame
+
+            AudioBufferProvider::Buffer mSink;  // references client's buffer sink in shared memory
+
+            // sync event triggering actual audio capture. Frames read before this event will
+            // be dropped and therefore not read by the application.
+            sp<SyncEvent>                       mSyncStartEvent;
+
+            // number of captured frames to drop after the start sync event has been received.
+            // when < 0, maximum frames to drop before starting capture even if sync event is
+            // not received
+            ssize_t                             mFramesToDrop;
+
+            // used by resampler to find source frames
+            ResamplerBufferProvider *mResamplerBufferProvider;
 };
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index cac785a..12d453e 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -34,6 +34,7 @@
 #include <audio_effects/effect_ns.h>
 #include <audio_effects/effect_aec.h>
 #include <audio_utils/primitives.h>
+#include <audio_utils/format.h>
 
 // NBAIO implementations
 #include <media/nbaio/AudioStreamOutSink.h>
@@ -104,10 +105,10 @@
 // maximum divider applied to the active sleep time in the mixer thread loop
 static const uint32_t kMaxThreadSleepTimeShift = 2;
 
-// minimum normal mix buffer size, expressed in milliseconds rather than frames
-static const uint32_t kMinNormalMixBufferSizeMs = 20;
-// maximum normal mix buffer size
-static const uint32_t kMaxNormalMixBufferSizeMs = 24;
+// minimum normal sink buffer size, expressed in milliseconds rather than frames
+static const uint32_t kMinNormalSinkBufferSizeMs = 20;
+// maximum normal sink buffer size
+static const uint32_t kMaxNormalSinkBufferSizeMs = 24;
 
 // Offloaded output thread standby delay: allows track transition without going to standby
 static const nsecs_t kOffloadStandbyDelayNs = seconds(1);
@@ -185,7 +186,11 @@
 {
 }
 
-void CpuStats::sample(const String8 &title) {
+void CpuStats::sample(const String8 &title
+#ifndef DEBUG_CPU_USAGE
+                __unused
+#endif
+        ) {
 #ifdef DEBUG_CPU_USAGE
     // get current thread's delta CPU time in wall clock ns
     double wcNs;
@@ -269,8 +274,9 @@
     :   Thread(false /*canCallJava*/),
         mType(type),
         mAudioFlinger(audioFlinger),
-        // mSampleRate, mFrameCount, mChannelMask, mChannelCount, mFrameSize, and mFormat are
-        // set by PlaybackThread::readOutputParameters() or RecordThread::readInputParameters()
+        // mSampleRate, mFrameCount, mChannelMask, mChannelCount, mFrameSize, mFormat, mBufferSize
+        // are set by PlaybackThread::readOutputParameters_l() or
+        // RecordThread::readInputParameters_l()
         mParamStatus(NO_ERROR),
         //FIXME: mStandby should be true here. Is this some kind of hack?
         mStandby(false), mOutDevice(outDevice), mInDevice(inDevice),
@@ -297,6 +303,17 @@
     }
 }
 
+status_t AudioFlinger::ThreadBase::readyToRun()
+{
+    status_t status = initCheck();
+    if (status == NO_ERROR) {
+        ALOGI("AudioFlinger's thread %p ready to run", this);
+    } else {
+        ALOGE("No working audio driver found.");
+    }
+    return status;
+}
+
 void AudioFlinger::ThreadBase::exit()
 {
     ALOGV("ThreadBase::exit");
@@ -369,7 +386,13 @@
 
 void AudioFlinger::ThreadBase::processConfigEvents()
 {
-    mLock.lock();
+    Mutex::Autolock _l(mLock);
+    processConfigEvents_l();
+}
+
+// post condition: mConfigEvents.isEmpty()
+void AudioFlinger::ThreadBase::processConfigEvents_l()
+{
     while (!mConfigEvents.isEmpty()) {
         ALOGV("processConfigEvents() remaining events %d", mConfigEvents.size());
         ConfigEvent *event = mConfigEvents[0];
@@ -377,35 +400,81 @@
         // release mLock before locking AudioFlinger mLock: lock order is always
         // AudioFlinger then ThreadBase to avoid cross deadlock
         mLock.unlock();
-        switch(event->type()) {
-            case CFG_EVENT_PRIO: {
-                PrioConfigEvent *prioEvent = static_cast<PrioConfigEvent *>(event);
-                // FIXME Need to understand why this has be done asynchronously
-                int err = requestPriority(prioEvent->pid(), prioEvent->tid(), prioEvent->prio(),
-                        true /*asynchronous*/);
-                if (err != 0) {
-                    ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; "
-                          "error %d",
-                          prioEvent->prio(), prioEvent->pid(), prioEvent->tid(), err);
-                }
-            } break;
-            case CFG_EVENT_IO: {
-                IoConfigEvent *ioEvent = static_cast<IoConfigEvent *>(event);
-                mAudioFlinger->mLock.lock();
+        switch (event->type()) {
+        case CFG_EVENT_PRIO: {
+            PrioConfigEvent *prioEvent = static_cast<PrioConfigEvent *>(event);
+            // FIXME Need to understand why this has be done asynchronously
+            int err = requestPriority(prioEvent->pid(), prioEvent->tid(), prioEvent->prio(),
+                    true /*asynchronous*/);
+            if (err != 0) {
+                ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
+                      prioEvent->prio(), prioEvent->pid(), prioEvent->tid(), err);
+            }
+        } break;
+        case CFG_EVENT_IO: {
+            IoConfigEvent *ioEvent = static_cast<IoConfigEvent *>(event);
+            {
+                Mutex::Autolock _l(mAudioFlinger->mLock);
                 audioConfigChanged_l(ioEvent->event(), ioEvent->param());
-                mAudioFlinger->mLock.unlock();
-            } break;
-            default:
-                ALOGE("processConfigEvents() unknown event type %d", event->type());
-                break;
+            }
+        } break;
+        default:
+            ALOGE("processConfigEvents() unknown event type %d", event->type());
+            break;
         }
         delete event;
         mLock.lock();
     }
-    mLock.unlock();
 }
 
-void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args)
+String8 channelMaskToString(audio_channel_mask_t mask, bool output) {
+    String8 s;
+    if (output) {
+        if (mask & AUDIO_CHANNEL_OUT_FRONT_LEFT) s.append("front-left, ");
+        if (mask & AUDIO_CHANNEL_OUT_FRONT_RIGHT) s.append("front-right, ");
+        if (mask & AUDIO_CHANNEL_OUT_FRONT_CENTER) s.append("front-center, ");
+        if (mask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY) s.append("low freq, ");
+        if (mask & AUDIO_CHANNEL_OUT_BACK_LEFT) s.append("back-left, ");
+        if (mask & AUDIO_CHANNEL_OUT_BACK_RIGHT) s.append("back-right, ");
+        if (mask & AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER) s.append("front-left-of-center, ");
+        if (mask & AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER) s.append("front-right-of-center, ");
+        if (mask & AUDIO_CHANNEL_OUT_BACK_CENTER) s.append("back-center, ");
+        if (mask & AUDIO_CHANNEL_OUT_SIDE_LEFT) s.append("side-left, ");
+        if (mask & AUDIO_CHANNEL_OUT_SIDE_RIGHT) s.append("side-right, ");
+        if (mask & AUDIO_CHANNEL_OUT_TOP_CENTER) s.append("top-center ,");
+        if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT) s.append("top-front-left, ");
+        if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER) s.append("top-front-center, ");
+        if (mask & AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT) s.append("top-front-right, ");
+        if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_LEFT) s.append("top-back-left, ");
+        if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_CENTER) s.append("top-back-center, " );
+        if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT) s.append("top-back-right, " );
+        if (mask & ~AUDIO_CHANNEL_OUT_ALL) s.append("unknown,  ");
+    } else {
+        if (mask & AUDIO_CHANNEL_IN_LEFT) s.append("left, ");
+        if (mask & AUDIO_CHANNEL_IN_RIGHT) s.append("right, ");
+        if (mask & AUDIO_CHANNEL_IN_FRONT) s.append("front, ");
+        if (mask & AUDIO_CHANNEL_IN_BACK) s.append("back, ");
+        if (mask & AUDIO_CHANNEL_IN_LEFT_PROCESSED) s.append("left-processed, ");
+        if (mask & AUDIO_CHANNEL_IN_RIGHT_PROCESSED) s.append("right-processed, ");
+        if (mask & AUDIO_CHANNEL_IN_FRONT_PROCESSED) s.append("front-processed, ");
+        if (mask & AUDIO_CHANNEL_IN_BACK_PROCESSED) s.append("back-processed, ");
+        if (mask & AUDIO_CHANNEL_IN_PRESSURE) s.append("pressure, ");
+        if (mask & AUDIO_CHANNEL_IN_X_AXIS) s.append("X, ");
+        if (mask & AUDIO_CHANNEL_IN_Y_AXIS) s.append("Y, ");
+        if (mask & AUDIO_CHANNEL_IN_Z_AXIS) s.append("Z, ");
+        if (mask & AUDIO_CHANNEL_IN_VOICE_UPLINK) s.append("voice-uplink, ");
+        if (mask & AUDIO_CHANNEL_IN_VOICE_DNLINK) s.append("voice-dnlink, ");
+        if (mask & ~AUDIO_CHANNEL_IN_ALL) s.append("unknown,  ");
+    }
+    int len = s.length();
+    if (s.length() > 2) {
+        char *str = s.lockBuffer(len);
+        s.unlockBuffer(len - 2);
+    }
+    return s;
+}
+
+void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args __unused)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -413,47 +482,43 @@
 
     bool locked = AudioFlinger::dumpTryLock(mLock);
     if (!locked) {
-        snprintf(buffer, SIZE, "thread %p maybe dead locked\n", this);
-        write(fd, buffer, strlen(buffer));
+        fdprintf(fd, "thread %p maybe dead locked\n", this);
     }
 
-    snprintf(buffer, SIZE, "io handle: %d\n", mId);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "TID: %d\n", getTid());
-    result.append(buffer);
-    snprintf(buffer, SIZE, "standby: %d\n", mStandby);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "Sample rate: %u\n", mSampleRate);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "HAL frame count: %zu\n", mFrameCount);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "Channel Count: %u\n", mChannelCount);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "Channel Mask: 0x%08x\n", mChannelMask);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "Format: %d\n", mFormat);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "Frame size: %zu\n", mFrameSize);
-    result.append(buffer);
-
-    snprintf(buffer, SIZE, "\nPending setParameters commands: \n");
-    result.append(buffer);
-    result.append(" Index Command");
-    for (size_t i = 0; i < mNewParameters.size(); ++i) {
-        snprintf(buffer, SIZE, "\n %02zu    ", i);
-        result.append(buffer);
-        result.append(mNewParameters[i]);
+    fdprintf(fd, "  I/O handle: %d\n", mId);
+    fdprintf(fd, "  TID: %d\n", getTid());
+    fdprintf(fd, "  Standby: %s\n", mStandby ? "yes" : "no");
+    fdprintf(fd, "  Sample rate: %u\n", mSampleRate);
+    fdprintf(fd, "  HAL frame count: %zu\n", mFrameCount);
+    fdprintf(fd, "  HAL buffer size: %u bytes\n", mBufferSize);
+    fdprintf(fd, "  Channel Count: %u\n", mChannelCount);
+    fdprintf(fd, "  Channel Mask: 0x%08x (%s)\n", mChannelMask,
+            channelMaskToString(mChannelMask, mType != RECORD).string());
+    fdprintf(fd, "  Format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
+    fdprintf(fd, "  Frame size: %zu\n", mFrameSize);
+    fdprintf(fd, "  Pending setParameters commands:");
+    size_t numParams = mNewParameters.size();
+    if (numParams) {
+        fdprintf(fd, "\n   Index Command");
+        for (size_t i = 0; i < numParams; ++i) {
+            fdprintf(fd, "\n   %02zu    ", i);
+            fdprintf(fd, mNewParameters[i]);
+        }
+        fdprintf(fd, "\n");
+    } else {
+        fdprintf(fd, " none\n");
     }
-
-    snprintf(buffer, SIZE, "\n\nPending config events: \n");
-    result.append(buffer);
-    for (size_t i = 0; i < mConfigEvents.size(); i++) {
-        mConfigEvents[i]->dump(buffer, SIZE);
-        result.append(buffer);
+    fdprintf(fd, "  Pending config events:");
+    size_t numConfig = mConfigEvents.size();
+    if (numConfig) {
+        for (size_t i = 0; i < numConfig; i++) {
+            mConfigEvents[i]->dump(buffer, SIZE);
+            fdprintf(fd, "\n    %s", buffer);
+        }
+        fdprintf(fd, "\n");
+    } else {
+        fdprintf(fd, " none\n");
     }
-    result.append("\n");
-
-    write(fd, result.string(), result.size());
 
     if (locked) {
         mLock.unlock();
@@ -466,10 +531,11 @@
     char buffer[SIZE];
     String8 result;
 
-    snprintf(buffer, SIZE, "\n- %zu Effect Chains:\n", mEffectChains.size());
+    size_t numEffectChains = mEffectChains.size();
+    snprintf(buffer, SIZE, "  %zu Effect Chains\n", numEffectChains);
     write(fd, buffer, strlen(buffer));
 
-    for (size_t i = 0; i < mEffectChains.size(); ++i) {
+    for (size_t i = 0; i < numEffectChains; ++i) {
         sp<EffectChain> chain = mEffectChains[i];
         if (chain != 0) {
             chain->dump(fd, args);
@@ -586,7 +652,7 @@
     mPowerManager.clear();
 }
 
-void AudioFlinger::ThreadBase::PMDeathRecipient::binderDied(const wp<IBinder>& who)
+void AudioFlinger::ThreadBase::PMDeathRecipient::binderDied(const wp<IBinder>& who __unused)
 {
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
@@ -739,8 +805,7 @@
         int sessionId,
         effect_descriptor_t *desc,
         int *enabled,
-        status_t *status
-        )
+        status_t *status)
 {
     sp<EffectModule> effect;
     sp<EffectHandle> handle;
@@ -756,6 +821,15 @@
         goto Exit;
     }
 
+    // Reject any effect on Direct output threads for now, since the format of
+    // mSinkBuffer is not guaranteed to be compatible with effect processing (PCM 16 stereo).
+    if (mType == DIRECT) {
+        ALOGW("createEffect_l() Cannot add effect %s on Direct output type thread %s",
+                desc->name, mName);
+        lStatus = BAD_VALUE;
+        goto Exit;
+    }
+
     // Allow global effects only on offloaded and mixer threads
     if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
         switch (mType) {
@@ -829,7 +903,10 @@
         }
         // create effect handle and connect it to effect module
         handle = new EffectHandle(effect, client, effectClient, priority);
-        lStatus = effect->addHandle(handle.get());
+        lStatus = handle->initCheck();
+        if (lStatus == OK) {
+            lStatus = effect->addHandle(handle.get());
+        }
         if (enabled != NULL) {
             *enabled = (int)effect->isEnabled();
         }
@@ -850,9 +927,7 @@
         handle.clear();
     }
 
-    if (status != NULL) {
-        *status = lStatus;
-    }
+    *status = lStatus;
     return handle;
 }
 
@@ -1001,8 +1076,18 @@
                                              audio_devices_t device,
                                              type_t type)
     :   ThreadBase(audioFlinger, id, device, AUDIO_DEVICE_NONE, type),
-        mNormalFrameCount(0), mMixBuffer(NULL),
-        mAllocMixBuffer(NULL), mSuspended(0), mBytesWritten(0),
+        mNormalFrameCount(0), mSinkBuffer(NULL),
+        mMixerBufferEnabled(false),
+        mMixerBuffer(NULL),
+        mMixerBufferSize(0),
+        mMixerBufferFormat(AUDIO_FORMAT_INVALID),
+        mMixerBufferValid(false),
+        mEffectBufferEnabled(false),
+        mEffectBuffer(NULL),
+        mEffectBufferSize(0),
+        mEffectBufferFormat(AUDIO_FORMAT_INVALID),
+        mEffectBufferValid(false),
+        mSuspended(0), mBytesWritten(0),
         mActiveTracksGeneration(0),
         // mStreamTypes[] initialized in constructor body
         mOutput(output),
@@ -1044,7 +1129,7 @@
         }
     }
 
-    readOutputParameters();
+    readOutputParameters_l();
 
     // mStreamTypes[AUDIO_STREAM_CNT] is initialized by stream_type_t default constructor
     // There is no AUDIO_STREAM_MIN, and ++ operator does not compile
@@ -1060,7 +1145,9 @@
 AudioFlinger::PlaybackThread::~PlaybackThread()
 {
     mAudioFlinger->unregisterWriter(mNBLogWriter);
-    delete [] mAllocMixBuffer;
+    free(mSinkBuffer);
+    free(mMixerBuffer);
+    free(mEffectBuffer);
 }
 
 void AudioFlinger::PlaybackThread::dump(int fd, const Vector<String16>& args)
@@ -1070,13 +1157,13 @@
     dumpEffectChains(fd, args);
 }
 
-void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args)
+void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args __unused)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
 
-    result.appendFormat("Output thread %p stream volumes in dB:\n    ", this);
+    result.appendFormat("  Stream volumes in dB: ");
     for (int i = 0; i < AUDIO_STREAM_CNT; ++i) {
         const stream_type_t *st = &mStreamTypes[i];
         if (i > 0) {
@@ -1091,75 +1178,69 @@
     write(fd, result.string(), result.length());
     result.clear();
 
-    snprintf(buffer, SIZE, "Output thread %p tracks\n", this);
-    result.append(buffer);
-    Track::appendDumpHeader(result);
-    for (size_t i = 0; i < mTracks.size(); ++i) {
-        sp<Track> track = mTracks[i];
-        if (track != 0) {
-            track->dump(buffer, SIZE);
-            result.append(buffer);
-        }
-    }
-
-    snprintf(buffer, SIZE, "Output thread %p active tracks\n", this);
-    result.append(buffer);
-    Track::appendDumpHeader(result);
-    for (size_t i = 0; i < mActiveTracks.size(); ++i) {
-        sp<Track> track = mActiveTracks[i].promote();
-        if (track != 0) {
-            track->dump(buffer, SIZE);
-            result.append(buffer);
-        }
-    }
-    write(fd, result.string(), result.size());
-
     // These values are "raw"; they will wrap around.  See prepareTracks_l() for a better way.
     FastTrackUnderruns underruns = getFastTrackUnderruns(0);
-    fdprintf(fd, "Normal mixer raw underrun counters: partial=%u empty=%u\n",
+    fdprintf(fd, "  Normal mixer raw underrun counters: partial=%u empty=%u\n",
             underruns.mBitFields.mPartial, underruns.mBitFields.mEmpty);
+
+    size_t numtracks = mTracks.size();
+    size_t numactive = mActiveTracks.size();
+    fdprintf(fd, "  %d Tracks", numtracks);
+    size_t numactiveseen = 0;
+    if (numtracks) {
+        fdprintf(fd, " of which %d are active\n", numactive);
+        Track::appendDumpHeader(result);
+        for (size_t i = 0; i < numtracks; ++i) {
+            sp<Track> track = mTracks[i];
+            if (track != 0) {
+                bool active = mActiveTracks.indexOf(track) >= 0;
+                if (active) {
+                    numactiveseen++;
+                }
+                track->dump(buffer, SIZE, active);
+                result.append(buffer);
+            }
+        }
+    } else {
+        result.append("\n");
+    }
+    if (numactiveseen != numactive) {
+        // some tracks in the active list were not in the tracks list
+        snprintf(buffer, SIZE, "  The following tracks are in the active list but"
+                " not in the track list\n");
+        result.append(buffer);
+        Track::appendDumpHeader(result);
+        for (size_t i = 0; i < numactive; ++i) {
+            sp<Track> track = mActiveTracks[i].promote();
+            if (track != 0 && mTracks.indexOf(track) < 0) {
+                track->dump(buffer, SIZE, true);
+                result.append(buffer);
+            }
+        }
+    }
+
+    write(fd, result.string(), result.size());
+
 }
 
 void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector<String16>& args)
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    snprintf(buffer, SIZE, "\nOutput thread %p internals\n", this);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "Normal frame count: %zu\n", mNormalFrameCount);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "last write occurred (msecs): %llu\n",
-            ns2ms(systemTime() - mLastWriteTime));
-    result.append(buffer);
-    snprintf(buffer, SIZE, "total writes: %d\n", mNumWrites);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "delayed writes: %d\n", mNumDelayedWrites);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "blocked in write: %d\n", mInWrite);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "suspend count: %d\n", mSuspended);
-    result.append(buffer);
-    snprintf(buffer, SIZE, "mix buffer : %p\n", mMixBuffer);
-    result.append(buffer);
-    write(fd, result.string(), result.size());
-    fdprintf(fd, "Fast track availMask=%#x\n", mFastTrackAvailMask);
+    fdprintf(fd, "\nOutput thread %p:\n", this);
+    fdprintf(fd, "  Normal frame count: %zu\n", mNormalFrameCount);
+    fdprintf(fd, "  Last write occurred (msecs): %llu\n", ns2ms(systemTime() - mLastWriteTime));
+    fdprintf(fd, "  Total writes: %d\n", mNumWrites);
+    fdprintf(fd, "  Delayed writes: %d\n", mNumDelayedWrites);
+    fdprintf(fd, "  Blocked in write: %s\n", mInWrite ? "yes" : "no");
+    fdprintf(fd, "  Suspend count: %d\n", mSuspended);
+    fdprintf(fd, "  Sink buffer : %p\n", mSinkBuffer);
+    fdprintf(fd, "  Mixer buffer: %p\n", mMixerBuffer);
+    fdprintf(fd, "  Effect buffer: %p\n", mEffectBuffer);
+    fdprintf(fd, "  Fast track availMask=%#x\n", mFastTrackAvailMask);
 
     dumpBase(fd, args);
 }
 
 // Thread virtuals
-status_t AudioFlinger::PlaybackThread::readyToRun()
-{
-    status_t status = initCheck();
-    if (status == NO_ERROR) {
-        ALOGI("AudioFlinger's thread %p ready to run", this);
-    } else {
-        ALOGE("No working audio driver found.");
-    }
-    return status;
-}
 
 void AudioFlinger::PlaybackThread::onFirstRef()
 {
@@ -1182,7 +1263,7 @@
         uint32_t sampleRate,
         audio_format_t format,
         audio_channel_mask_t channelMask,
-        size_t frameCount,
+        size_t *pFrameCount,
         const sp<IMemory>& sharedBuffer,
         int sessionId,
         IAudioFlinger::track_flags_t *flags,
@@ -1190,6 +1271,7 @@
         int uid,
         status_t *status)
 {
+    size_t frameCount = *pFrameCount;
     sp<Track> track;
     status_t lStatus;
 
@@ -1256,29 +1338,36 @@
         }
       }
     }
+    *pFrameCount = frameCount;
 
-    if (mType == DIRECT) {
+    switch (mType) {
+
+    case DIRECT:
         if ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM) {
             if (sampleRate != mSampleRate || format != mFormat || channelMask != mChannelMask) {
-                ALOGE("createTrack_l() Bad parameter: sampleRate %u format %d, channelMask 0x%08x "
-                        "for output %p with format %d",
+                ALOGE("createTrack_l() Bad parameter: sampleRate %u format %#x, channelMask 0x%08x "
+                        "for output %p with format %#x",
                         sampleRate, format, channelMask, mOutput, mFormat);
                 lStatus = BAD_VALUE;
                 goto Exit;
             }
         }
-    } else if (mType == OFFLOAD) {
+        break;
+
+    case OFFLOAD:
         if (sampleRate != mSampleRate || format != mFormat || channelMask != mChannelMask) {
-            ALOGE("createTrack_l() Bad parameter: sampleRate %d format %d, channelMask 0x%08x \""
-                    "for output %p with format %d",
+            ALOGE("createTrack_l() Bad parameter: sampleRate %d format %#x, channelMask 0x%08x \""
+                    "for output %p with format %#x",
                     sampleRate, format, channelMask, mOutput, mFormat);
             lStatus = BAD_VALUE;
             goto Exit;
         }
-    } else {
+        break;
+
+    default:
         if ((format & AUDIO_FORMAT_MAIN_MASK) != AUDIO_FORMAT_PCM) {
-                ALOGE("createTrack_l() Bad parameter: format %d \""
-                        "for output %p with format %d",
+                ALOGE("createTrack_l() Bad parameter: format %#x \""
+                        "for output %p with format %#x",
                         format, mOutput, mFormat);
                 lStatus = BAD_VALUE;
                 goto Exit;
@@ -1289,11 +1378,13 @@
             lStatus = BAD_VALUE;
             goto Exit;
         }
+        break;
+
     }
 
     lStatus = initCheck();
     if (lStatus != NO_ERROR) {
-        ALOGE("Audio driver not initialized.");
+        ALOGE("createTrack_l() audio driver not initialized");
         goto Exit;
     }
 
@@ -1325,12 +1416,14 @@
                     channelMask, frameCount, sharedBuffer, sessionId, uid);
         }
 
-        if (track == 0 || track->getCblk() == NULL || track->name() < 0) {
-            lStatus = NO_MEMORY;
+        // new Track always returns non-NULL,
+        // but TimedTrack::create() is a factory that could fail by returning NULL
+        lStatus = track != 0 ? track->initCheck() : (status_t) NO_MEMORY;
+        if (lStatus != NO_ERROR) {
+            ALOGE("createTrack_l() initCheck failed %d; no control block?", lStatus);
             // track must be cleared from the caller as the caller has the AF lock
             goto Exit;
         }
-
         mTracks.add(track);
 
         sp<EffectChain> chain = getEffectChain_l(sessionId);
@@ -1352,9 +1445,7 @@
     lStatus = NO_ERROR;
 
 Exit:
-    if (status) {
-        *status = lStatus;
-    }
+    *status = lStatus;
     return track;
 }
 
@@ -1473,9 +1564,7 @@
         status = NO_ERROR;
     }
 
-    ALOGV("signal playback thread");
-    broadcast_l();
-
+    onAddNewTrack_l();
     return status;
 }
 
@@ -1601,7 +1690,7 @@
 
 // static
 int AudioFlinger::PlaybackThread::asyncCallback(stream_callback_event_t event,
-                                                void *param,
+                                                void *param __unused,
                                                 void *cookie)
 {
     AudioFlinger::PlaybackThread *me = (AudioFlinger::PlaybackThread *)cookie;
@@ -1620,7 +1709,7 @@
     return 0;
 }
 
-void AudioFlinger::PlaybackThread::readOutputParameters()
+void AudioFlinger::PlaybackThread::readOutputParameters_l()
 {
     // unfortunately we have no way of recovering from errors here, hence the LOG_FATAL
     mSampleRate = mOutput->stream->common.get_sample_rate(&mOutput->stream->common);
@@ -1635,14 +1724,15 @@
     mChannelCount = popcount(mChannelMask);
     mFormat = mOutput->stream->common.get_format(&mOutput->stream->common);
     if (!audio_is_valid_format(mFormat)) {
-        LOG_FATAL("HAL format %d not valid for output", mFormat);
+        LOG_FATAL("HAL format %#x not valid for output", mFormat);
     }
     if ((mType == MIXER || mType == DUPLICATING) && mFormat != AUDIO_FORMAT_PCM_16_BIT) {
-        LOG_FATAL("HAL format %d not supported for mixed output; must be AUDIO_FORMAT_PCM_16_BIT",
+        LOG_FATAL("HAL format %#x not supported for mixed output; must be AUDIO_FORMAT_PCM_16_BIT",
                 mFormat);
     }
     mFrameSize = audio_stream_frame_size(&mOutput->stream->common);
-    mFrameCount = mOutput->stream->common.get_buffer_size(&mOutput->stream->common) / mFrameSize;
+    mBufferSize = mOutput->stream->common.get_buffer_size(&mOutput->stream->common);
+    mFrameCount = mBufferSize / mFrameSize;
     if (mFrameCount & 15) {
         ALOGW("HAL output buffer size is %u frames but AudioMixer requires multiples of 16 frames",
                 mFrameCount);
@@ -1657,12 +1747,12 @@
         }
     }
 
-    // Calculate size of normal mix buffer relative to the HAL output buffer size
+    // Calculate size of normal sink buffer relative to the HAL output buffer size
     double multiplier = 1.0;
     if (mType == MIXER && (kUseFastMixer == FastMixer_Static ||
             kUseFastMixer == FastMixer_Dynamic)) {
-        size_t minNormalFrameCount = (kMinNormalMixBufferSizeMs * mSampleRate) / 1000;
-        size_t maxNormalFrameCount = (kMaxNormalMixBufferSizeMs * mSampleRate) / 1000;
+        size_t minNormalFrameCount = (kMinNormalSinkBufferSizeMs * mSampleRate) / 1000;
+        size_t maxNormalFrameCount = (kMaxNormalSinkBufferSizeMs * mSampleRate) / 1000;
         // round up minimum and round down maximum to nearest 16 frames to satisfy AudioMixer
         minNormalFrameCount = (minNormalFrameCount + 15) & ~15;
         maxNormalFrameCount = maxNormalFrameCount & ~15;
@@ -1680,7 +1770,7 @@
             }
         } else {
             // prefer an even multiplier, for compatibility with doubling of fast tracks due to HAL
-            // SRC (it would be unusual for the normal mix buffer size to not be a multiple of fast
+            // SRC (it would be unusual for the normal sink buffer size to not be a multiple of fast
             // track, but we sometimes have to do this to satisfy the maximum frame count
             // constraint)
             // FIXME this rounding up should not be done if no HAL SRC
@@ -1696,18 +1786,40 @@
     mNormalFrameCount = multiplier * mFrameCount;
     // round up to nearest 16 frames to satisfy AudioMixer
     mNormalFrameCount = (mNormalFrameCount + 15) & ~15;
-    ALOGI("HAL output buffer size %u frames, normal mix buffer size %u frames", mFrameCount,
+    ALOGI("HAL output buffer size %u frames, normal sink buffer size %u frames", mFrameCount,
             mNormalFrameCount);
 
-    delete[] mAllocMixBuffer;
-    size_t align = (mFrameSize < sizeof(int16_t)) ? sizeof(int16_t) : mFrameSize;
-    mAllocMixBuffer = new int8_t[mNormalFrameCount * mFrameSize + align - 1];
-    mMixBuffer = (int16_t *) ((((size_t)mAllocMixBuffer + align - 1) / align) * align);
-    memset(mMixBuffer, 0, mNormalFrameCount * mFrameSize);
+    // mSinkBuffer is the sink buffer.  Size is always multiple-of-16 frames.
+    // Originally this was int16_t[] array, need to remove legacy implications.
+    free(mSinkBuffer);
+    mSinkBuffer = NULL;
+    // For sink buffer size, we use the frame size from the downstream sink to avoid problems
+    // with non PCM formats for compressed music, e.g. AAC, and Offload threads.
+    const size_t sinkBufferSize = mNormalFrameCount * mFrameSize;
+    (void)posix_memalign(&mSinkBuffer, 32, sinkBufferSize);
+
+    // We resize the mMixerBuffer according to the requirements of the sink buffer which
+    // drives the output.
+    free(mMixerBuffer);
+    mMixerBuffer = NULL;
+    if (mMixerBufferEnabled) {
+        mMixerBufferFormat = AUDIO_FORMAT_PCM_FLOAT; // also valid: AUDIO_FORMAT_PCM_16_BIT.
+        mMixerBufferSize = mNormalFrameCount * mChannelCount
+                * audio_bytes_per_sample(mMixerBufferFormat);
+        (void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize);
+    }
+    free(mEffectBuffer);
+    mEffectBuffer = NULL;
+    if (mEffectBufferEnabled) {
+        mEffectBufferFormat = AUDIO_FORMAT_PCM_16_BIT; // Note: Effects support 16b only
+        mEffectBufferSize = mNormalFrameCount * mChannelCount
+                * audio_bytes_per_sample(mEffectBufferFormat);
+        (void)posix_memalign(&mEffectBuffer, 32, mEffectBufferSize);
+    }
 
     // force reconfiguration of effect chains and engines to take new buffer size and audio
     // parameters into account
-    // Note that mLock is not held when readOutputParameters() is called from the constructor
+    // Note that mLock is not held when readOutputParameters_l() is called from the constructor
     // but in this case nothing is done below as no audio sessions have effect yet so it doesn't
     // matter.
     // create a copy of mEffectChains as calling moveEffectChain_l() can reorder some effect chains
@@ -1841,7 +1953,7 @@
         const Vector< sp<Track> >& tracksToRemove)
 {
     size_t count = tracksToRemove.size();
-    if (count) {
+    if (count > 0) {
         for (size_t i = 0 ; i < count ; i++) {
             const sp<Track>& track = tracksToRemove.itemAt(i);
             if (!track->isOutputTrack()) {
@@ -1882,12 +1994,12 @@
     mLastWriteTime = systemTime();
     mInWrite = true;
     ssize_t bytesWritten;
+    const size_t offset = mCurrentWriteLength - mBytesRemaining;
 
     // If an NBAIO sink is present, use it to write the normal mixer's submix
     if (mNormalSink != 0) {
-#define mBitShift 2 // FIXME
-        size_t count = mBytesRemaining >> mBitShift;
-        size_t offset = (mCurrentWriteLength - mBytesRemaining) >> 1;
+        const size_t count = mBytesRemaining / mFrameSize;
+
         ATRACE_BEGIN("write");
         // update the setpoint when AudioFlinger::mScreenState changes
         uint32_t screenState = AudioFlinger::mScreenState;
@@ -1899,10 +2011,10 @@
                         (pipe->maxFrames() * 7) / 8 : mNormalFrameCount * 2);
             }
         }
-        ssize_t framesWritten = mNormalSink->write(mMixBuffer + offset, count);
+        ssize_t framesWritten = mNormalSink->write((char *)mSinkBuffer + offset, count);
         ATRACE_END();
         if (framesWritten > 0) {
-            bytesWritten = framesWritten << mBitShift;
+            bytesWritten = framesWritten * mFrameSize;
         } else {
             bytesWritten = framesWritten;
         }
@@ -1917,7 +2029,7 @@
     // otherwise use the HAL / AudioStreamOut directly
     } else {
         // Direct output and offload threads
-        size_t offset = (mCurrentWriteLength - mBytesRemaining);
+
         if (mUseAsyncWrite) {
             ALOGW_IF(mWriteAckSequence & 1, "threadLoop_write(): out of sequence write request");
             mWriteAckSequence += 2;
@@ -1928,7 +2040,7 @@
         // FIXME We should have an implementation of timestamps for direct output threads.
         // They are used e.g for multichannel PCM playback over HDMI.
         bytesWritten = mOutput->stream->write(mOutput->stream,
-                                                   (char *)mMixBuffer + offset, mBytesRemaining);
+                                                   (char *)mSinkBuffer + offset, mBytesRemaining);
         if (mUseAsyncWrite &&
                 ((bytesWritten < 0) || (bytesWritten == (ssize_t)mBytesRemaining))) {
             // do not wait for async callback in case of error of full write
@@ -1967,7 +2079,7 @@
 
 /*
 The derived values that are cached:
- - mixBufferSize from frame count * frame size
+ - mSinkBufferSize from frame count * frame size
  - activeSleepTime from activeSleepTimeUs()
  - idleSleepTime from idleSleepTimeUs()
  - standbyDelay from mActiveSleepTimeUs (DIRECT only)
@@ -1986,7 +2098,7 @@
 
 void AudioFlinger::PlaybackThread::cacheParameters_l()
 {
-    mixBufferSize = mNormalFrameCount * mFrameSize;
+    mSinkBufferSize = mNormalFrameCount * mFrameSize;
     activeSleepTime = activeSleepTimeUs();
     idleSleepTime = idleSleepTimeUs();
 }
@@ -2009,13 +2121,14 @@
 status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& chain)
 {
     int session = chain->sessionId();
-    int16_t *buffer = mMixBuffer;
+    int16_t* buffer = reinterpret_cast<int16_t*>(mEffectBufferEnabled
+            ? mEffectBuffer : mSinkBuffer);
     bool ownsBuffer = false;
 
     ALOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
     if (session > 0) {
         // Only one effect chain can be present in direct output thread and it uses
-        // the mix buffer as input
+        // the sink buffer as input
         if (mType != DIRECT) {
             size_t numSamples = mNormalFrameCount * mChannelCount;
             buffer = new int16_t[numSamples];
@@ -2049,7 +2162,8 @@
     }
 
     chain->setInBuffer(buffer, ownsBuffer);
-    chain->setOutBuffer(mMixBuffer);
+    chain->setOutBuffer(reinterpret_cast<int16_t*>(mEffectBufferEnabled
+            ? mEffectBuffer : mSinkBuffer));
     // Effect chain for session AUDIO_SESSION_OUTPUT_STAGE is inserted at end of effect
     // chains list in order to be processed last as it contains output stage effects
     // Effect chain for session AUDIO_SESSION_OUTPUT_MIX is inserted before
@@ -2099,7 +2213,7 @@
             for (size_t i = 0; i < mTracks.size(); ++i) {
                 sp<Track> track = mTracks[i];
                 if (session == track->sessionId()) {
-                    track->setMainBuffer(mMixBuffer);
+                    track->setMainBuffer(reinterpret_cast<int16_t*>(mSinkBuffer));
                     chain->decTrackCnt();
                 }
             }
@@ -2302,14 +2416,32 @@
                 // must be written to HAL
                 threadLoop_sleepTime();
                 if (sleepTime == 0) {
-                    mCurrentWriteLength = mixBufferSize;
+                    mCurrentWriteLength = mSinkBufferSize;
                 }
             }
+            // Either threadLoop_mix() or threadLoop_sleepTime() should have set
+            // mMixerBuffer with data if mMixerBufferValid is true and sleepTime == 0.
+            // Merge mMixerBuffer data into mEffectBuffer (if any effects are valid)
+            // or mSinkBuffer (if there are no effects).
+            //
+            // This is done pre-effects computation; if effects change to
+            // support higher precision, this needs to move.
+            //
+            // mMixerBufferValid is only set true by MixerThread::prepareTracks_l().
+            // TODO use sleepTime == 0 as an additional condition.
+            if (mMixerBufferValid) {
+                void *buffer = mEffectBufferValid ? mEffectBuffer : mSinkBuffer;
+                audio_format_t format = mEffectBufferValid ? mEffectBufferFormat : mFormat;
+
+                memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat,
+                        mNormalFrameCount * mChannelCount);
+            }
+
             mBytesRemaining = mCurrentWriteLength;
             if (isSuspended()) {
                 sleepTime = suspendSleepTimeUs();
                 // simulate write to HAL when suspended
-                mBytesWritten += mixBufferSize;
+                mBytesWritten += mSinkBufferSize;
                 mBytesRemaining = 0;
             }
 
@@ -2330,6 +2462,16 @@
             }
         }
 
+        // Only if the Effects buffer is enabled and there is data in the
+        // Effects buffer (buffer valid), we need to
+        // copy into the sink buffer.
+        // TODO use sleepTime == 0 as an additional condition.
+        if (mEffectBufferValid) {
+            //ALOGV("writing effect buffer to sink buffer format %#x", mFormat);
+            memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat,
+                    mNormalFrameCount * mChannelCount);
+        }
+
         // enable changes in effect chain
         unlockEffectChains(effectChains);
 
@@ -2348,20 +2490,20 @@
                         (mMixerStatus == MIXER_DRAIN_ALL)) {
                     threadLoop_drain();
                 }
-if (mType == MIXER) {
-                // write blocked detection
-                nsecs_t now = systemTime();
-                nsecs_t delta = now - mLastWriteTime;
-                if (!mStandby && delta > maxPeriod) {
-                    mNumDelayedWrites++;
-                    if ((now - lastWarning) > kWarningThrottleNs) {
-                        ATRACE_NAME("underrun");
-                        ALOGW("write blocked for %llu msecs, %d delayed writes, thread %p",
-                                ns2ms(delta), mNumDelayedWrites, this);
-                        lastWarning = now;
+                if (mType == MIXER) {
+                    // write blocked detection
+                    nsecs_t now = systemTime();
+                    nsecs_t delta = now - mLastWriteTime;
+                    if (!mStandby && delta > maxPeriod) {
+                        mNumDelayedWrites++;
+                        if ((now - lastWarning) > kWarningThrottleNs) {
+                            ATRACE_NAME("underrun");
+                            ALOGW("write blocked for %llu msecs, %d delayed writes, thread %p",
+                                    ns2ms(delta), mNumDelayedWrites, this);
+                            lastWarning = now;
+                        }
                     }
                 }
-}
 
             } else {
                 usleep(sleepTime);
@@ -2409,7 +2551,7 @@
 void AudioFlinger::PlaybackThread::removeTracks_l(const Vector< sp<Track> >& tracksToRemove)
 {
     size_t count = tracksToRemove.size();
-    if (count) {
+    if (count > 0) {
         for (size_t i=0 ; i<count ; i++) {
             const sp<Track>& track = tracksToRemove.itemAt(i);
             mActiveTracks.remove(track);
@@ -2473,7 +2615,7 @@
     // create an NBAIO sink for the HAL output stream, and negotiate
     mOutputSink = new AudioStreamOutSink(output->stream);
     size_t numCounterOffers = 0;
-    const NBAIO_Format offers[1] = {Format_from_SR_C(mSampleRate, mChannelCount)};
+    const NBAIO_Format offers[1] = {Format_from_SR_C(mSampleRate, mChannelCount, mFormat)};
     ssize_t index = mOutputSink->negotiate(offers, 1, NULL, numCounterOffers);
     ALOG_ASSERT(index == 0);
 
@@ -2713,12 +2855,6 @@
     PlaybackThread::threadLoop_standby();
 }
 
-// Empty implementation for standard mixer
-// Overridden for offloaded playback
-void AudioFlinger::PlaybackThread::flushOutput_l()
-{
-}
-
 bool AudioFlinger::PlaybackThread::waitingAsyncCallback_l()
 {
     return false;
@@ -2750,6 +2886,12 @@
     }
 }
 
+void AudioFlinger::PlaybackThread::onAddNewTrack_l()
+{
+    ALOGV("signal playback thread");
+    broadcast_l();
+}
+
 void AudioFlinger::MixerThread::threadLoop_mix()
 {
     // obtain the presentation timestamp of the next output buffer
@@ -2768,7 +2910,7 @@
 
     // mix buffers...
     mAudioMixer->process(pts);
-    mCurrentWriteLength = mixBufferSize;
+    mCurrentWriteLength = mSinkBufferSize;
     // increase sleep time progressively when application underrun condition clears.
     // Only increase sleep time if the mixer is ready for two consecutive times to avoid
     // that a steady state of alternating ready/not ready conditions keeps the sleep time
@@ -2802,7 +2944,13 @@
             sleepTime = idleSleepTime;
         }
     } else if (mBytesWritten != 0 || (mMixerStatus == MIXER_TRACKS_ENABLED)) {
-        memset (mMixBuffer, 0, mixBufferSize);
+        // clear out mMixerBuffer or mSinkBuffer, to ensure buffers are cleared
+        // before effects processing or output.
+        if (mMixerBufferValid) {
+            memset(mMixerBuffer, 0, mMixerBufferSize);
+        } else {
+            memset(mSinkBuffer, 0, mSinkBufferSize);
+        }
         sleepTime = 0;
         ALOGV_IF(mBytesWritten == 0 && (mMixerStatus == MIXER_TRACKS_ENABLED),
                 "anticipated start");
@@ -2849,6 +2997,9 @@
         state = sq->begin();
     }
 
+    mMixerBufferValid = false;  // mMixerBuffer has no valid data until appropriate tracks found.
+    mEffectBufferValid = false; // mEffectBuffer has no valid data until tracks found.
+
     for (size_t i=0 ; i<count ; i++) {
         const sp<Track> t = mActiveTracks[i].promote();
         if (t == 0) {
@@ -3027,12 +3178,14 @@
             // +1 for rounding and +1 for additional sample needed for interpolation
             desiredFrames = (mNormalFrameCount * sr) / mSampleRate + 1 + 1;
             // add frames already consumed but not yet released by the resampler
-            // because cblk->framesReady() will include these frames
+            // because mAudioTrackServerProxy->framesReady() will include these frames
             desiredFrames += mAudioMixer->getUnreleasedFrames(track->name());
+#if 0
             // the minimum track buffer size is normally twice the number of frames necessary
             // to fill one buffer and the resampler should not leave more than one buffer worth
             // of unreleased frames after each pass, but just in case...
             ALOG_ASSERT(desiredFrames <= cblk->frameCount_);
+#endif
         }
         uint32_t minFrames = 1;
         if ((track->sharedBuffer() == 0) && !track->isStopped() && !track->isPausing() &&
@@ -3048,10 +3201,14 @@
 
             mixedTracks++;
 
-            // track->mainBuffer() != mMixBuffer means there is an effect chain
-            // connected to the track
+            // track->mainBuffer() != mSinkBuffer or mMixerBuffer means
+            // there is an effect chain connected to the track
             chain.clear();
-            if (track->mainBuffer() != mMixBuffer) {
+            if (track->mainBuffer() != mSinkBuffer &&
+                    track->mainBuffer() != mMixerBuffer) {
+                if (mEffectBufferEnabled) {
+                    mEffectBufferValid = true; // Later can set directly.
+                }
                 chain = getEffectChain_l(track->sessionId());
                 // Delegate volume control to effect in track effect chain if needed
                 if (chain != 0) {
@@ -3177,10 +3334,41 @@
                 AudioMixer::RESAMPLE,
                 AudioMixer::SAMPLE_RATE,
                 (void *)(uintptr_t)reqSampleRate);
-            mAudioMixer->setParameter(
-                name,
-                AudioMixer::TRACK,
-                AudioMixer::MAIN_BUFFER, (void *)track->mainBuffer());
+            /*
+             * Select the appropriate output buffer for the track.
+             *
+             * Tracks with effects go into their own effects chain buffer
+             * and from there into either mEffectBuffer or mSinkBuffer.
+             *
+             * Other tracks can use mMixerBuffer for higher precision
+             * channel accumulation.  If this buffer is enabled
+             * (mMixerBufferEnabled true), then selected tracks will accumulate
+             * into it.
+             *
+             */
+            if (mMixerBufferEnabled
+                    && (track->mainBuffer() == mSinkBuffer
+                            || track->mainBuffer() == mMixerBuffer)) {
+                mAudioMixer->setParameter(
+                        name,
+                        AudioMixer::TRACK,
+                        AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat);
+                mAudioMixer->setParameter(
+                        name,
+                        AudioMixer::TRACK,
+                        AudioMixer::MAIN_BUFFER, (void *)mMixerBuffer);
+                // TODO: override track->mainBuffer()?
+                mMixerBufferValid = true;
+            } else {
+                mAudioMixer->setParameter(
+                        name,
+                        AudioMixer::TRACK,
+                        AudioMixer::MIXER_FORMAT, (void *)AUDIO_FORMAT_PCM_16_BIT);
+                mAudioMixer->setParameter(
+                        name,
+                        AudioMixer::TRACK,
+                        AudioMixer::MAIN_BUFFER, (void *)track->mainBuffer());
+            }
             mAudioMixer->setParameter(
                 name,
                 AudioMixer::TRACK,
@@ -3294,13 +3482,30 @@
     // remove all the tracks that need to be...
     removeTracks_l(*tracksToRemove);
 
-    // mix buffer must be cleared if all tracks are connected to an
-    // effect chain as in this case the mixer will not write to
-    // mix buffer and track effects will accumulate into it
+    // sink or mix buffer must be cleared if all tracks are connected to an
+    // effect chain as in this case the mixer will not write to the sink or mix buffer
+    // and track effects will accumulate into it
     if ((mBytesRemaining == 0) && ((mixedTracks != 0 && mixedTracks == tracksWithEffect) ||
             (mixedTracks == 0 && fastTracks > 0))) {
         // FIXME as a performance optimization, should remember previous zero status
-        memset(mMixBuffer, 0, mNormalFrameCount * mChannelCount * sizeof(int16_t));
+        if (mMixerBufferValid) {
+            memset(mMixerBuffer, 0, mMixerBufferSize);
+            // TODO: In testing, mSinkBuffer below need not be cleared because
+            // the PlaybackThread::threadLoop() copies mMixerBuffer into mSinkBuffer
+            // after mixing.
+            //
+            // To enforce this guarantee:
+            // ((mixedTracks != 0 && mixedTracks == tracksWithEffect) ||
+            // (mixedTracks == 0 && fastTracks > 0))
+            // must imply MIXER_TRACKS_READY.
+            // Later, we may clear buffers regardless, and skip much of this logic.
+        }
+        // TODO - either mEffectBuffer or mSinkBuffer needs to be cleared.
+        if (mEffectBufferValid) {
+            memset(mEffectBuffer, 0, mEffectBufferSize);
+        }
+        // FIXME as a performance optimization, should remember previous zero status
+        memset(mSinkBuffer, 0, mNormalFrameCount * mChannelCount * sizeof(int16_t));
     }
 
     // if any fast tracks, then status is ready
@@ -3358,6 +3563,7 @@
             if ((audio_format_t) value != AUDIO_FORMAT_PCM_16_BIT) {
                 status = BAD_VALUE;
             } else {
+                // no need to save value, since it's constant
                 reconfig = true;
             }
         }
@@ -3365,6 +3571,7 @@
             if ((audio_channel_mask_t) value != AUDIO_CHANNEL_OUT_STEREO) {
                 status = BAD_VALUE;
             } else {
+                // no need to save value, since it's constant
                 reconfig = true;
             }
         }
@@ -3423,7 +3630,7 @@
                                                        keyValuePair.string());
             }
             if (status == NO_ERROR && reconfig) {
-                readOutputParameters();
+                readOutputParameters_l();
                 delete mAudioMixer;
                 mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
                 for (size_t i = 0; i < mTracks.size() ; i++) {
@@ -3468,9 +3675,7 @@
 
     PlaybackThread::dumpInternals(fd, args);
 
-    snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames());
-    result.append(buffer);
-    write(fd, result.string(), result.size());
+    fdprintf(fd, "  AudioMixer tracks: 0x%08x\n", mAudioMixer->trackNames());
 
     // Make a non-atomic copy of fast mixer dump state so it won't change underneath us
     const FastMixerDumpState copy(mFastMixerDumpState);
@@ -3688,7 +3893,7 @@
 void AudioFlinger::DirectOutputThread::threadLoop_mix()
 {
     size_t frameCount = mFrameCount;
-    int8_t *curBuf = (int8_t *)mMixBuffer;
+    int8_t *curBuf = (int8_t *)mSinkBuffer;
     // output audio to hardware
     while (frameCount) {
         AudioBufferProvider::Buffer buffer;
@@ -3703,7 +3908,7 @@
         curBuf += buffer.frameCount * mFrameSize;
         mActiveTrack->releaseBuffer(&buffer);
     }
-    mCurrentWriteLength = curBuf - (int8_t *)mMixBuffer;
+    mCurrentWriteLength = curBuf - (int8_t *)mSinkBuffer;
     sleepTime = 0;
     standbyTime = systemTime() + standbyDelay;
     mActiveTrack.clear();
@@ -3718,20 +3923,20 @@
             sleepTime = idleSleepTime;
         }
     } else if (mBytesWritten != 0 && audio_is_linear_pcm(mFormat)) {
-        memset(mMixBuffer, 0, mFrameCount * mFrameSize);
+        memset(mSinkBuffer, 0, mFrameCount * mFrameSize);
         sleepTime = 0;
     }
 }
 
 // getTrackName_l() must be called with ThreadBase::mLock held
-int AudioFlinger::DirectOutputThread::getTrackName_l(audio_channel_mask_t channelMask,
-        int sessionId)
+int AudioFlinger::DirectOutputThread::getTrackName_l(audio_channel_mask_t channelMask __unused,
+        int sessionId __unused)
 {
     return 0;
 }
 
 // deleteTrackName_l() must be called with ThreadBase::mLock held
-void AudioFlinger::DirectOutputThread::deleteTrackName_l(int name)
+void AudioFlinger::DirectOutputThread::deleteTrackName_l(int name __unused)
 {
 }
 
@@ -3767,7 +3972,7 @@
                                                        keyValuePair.string());
             }
             if (status == NO_ERROR && reconfig) {
-                readOutputParameters();
+                readOutputParameters_l();
                 sendIoConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
             }
         }
@@ -3984,6 +4189,17 @@
         sp<Track> l = mLatestActiveTrack.promote();
         bool last = l.get() == track;
 
+        if (track->isInvalid()) {
+            ALOGW("An invalidated track shouldn't be in active list");
+            tracksToRemove->add(track);
+            continue;
+        }
+
+        if (track->mState == TrackBase::IDLE) {
+            ALOGW("An idle track shouldn't be in active list");
+            continue;
+        }
+
         if (track->isPausing()) {
             track->setPaused();
             if (last) {
@@ -4002,6 +4218,11 @@
                 mBytesRemaining = 0;    // stop writing
             }
             tracksToRemove->add(track);
+        } else if (track->isFlushPending()) {
+            track->flushAck();
+            if (last) {
+                mFlushPending = true;
+            }
         } else if (track->framesReady() && track->isReady() &&
                 !track->isPaused() && !track->isTerminated() && !track->isStopping_2()) {
             ALOGVV("OffloadThread: track %d s=%08x [OK]", track->name(), cblk->mServer);
@@ -4051,7 +4272,6 @@
                         // seek when resuming.
                         if (previousTrack->sessionId() != track->sessionId()) {
                             previousTrack->invalidate();
-                            mFlushPending = true;
                         }
                     }
                 }
@@ -4127,9 +4347,6 @@
     // if resume is received before pause is executed.
     if (!mStandby && (doHwPause || (mFlushPending && !mHwPaused && (count != 0)))) {
         mOutput->stream->pause(mOutput->stream);
-        if (!doHwPause) {
-            doHwResume = true;
-        }
     }
     if (mFlushPending) {
         flushHw_l();
@@ -4145,11 +4362,6 @@
     return mixerStatus;
 }
 
-void AudioFlinger::OffloadThread::flushOutput_l()
-{
-    mFlushPending = true;
-}
-
 // must be called with thread mutex locked
 bool AudioFlinger::OffloadThread::waitingAsyncCallback_l()
 {
@@ -4164,15 +4376,15 @@
 // must be called with thread mutex locked
 bool AudioFlinger::OffloadThread::shouldStandby_l()
 {
-    bool TrackPaused = false;
+    bool trackPaused = false;
 
     // do not put the HAL in standby when paused. AwesomePlayer clear the offloaded AudioTrack
     // after a timeout and we will enter standby then.
     if (mTracks.size() > 0) {
-        TrackPaused = mTracks[mTracks.size() - 1]->isPaused();
+        trackPaused = mTracks[mTracks.size() - 1]->isPaused();
     }
 
-    return !mStandby && !TrackPaused;
+    return !mStandby && !trackPaused;
 }
 
 
@@ -4190,6 +4402,8 @@
     mBytesRemaining = 0;
     mPausedWriteLength = 0;
     mPausedBytesRemaining = 0;
+    mHwPaused = false;
+
     if (mUseAsyncWrite) {
         // discard any pending drain or write ack by incrementing sequence
         mWriteAckSequence = (mWriteAckSequence + 2) & ~1;
@@ -4200,6 +4414,18 @@
     }
 }
 
+void AudioFlinger::OffloadThread::onAddNewTrack_l()
+{
+    sp<Track> previousTrack = mPreviousTrack.promote();
+    sp<Track> latestTrack = mLatestActiveTrack.promote();
+
+    if (previousTrack != 0 && latestTrack != 0 &&
+        (previousTrack->sessionId() != latestTrack->sessionId())) {
+        mFlushPending = true;
+    }
+    PlaybackThread::onAddNewTrack_l();
+}
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger,
@@ -4224,11 +4450,11 @@
     if (outputsReady(outputTracks)) {
         mAudioMixer->process(AudioBufferProvider::kInvalidPTS);
     } else {
-        memset(mMixBuffer, 0, mixBufferSize);
+        memset(mSinkBuffer, 0, mSinkBufferSize);
     }
     sleepTime = 0;
     writeFrames = mNormalFrameCount;
-    mCurrentWriteLength = mixBufferSize;
+    mCurrentWriteLength = mSinkBufferSize;
     standbyTime = systemTime() + standbyDelay;
 }
 
@@ -4243,7 +4469,7 @@
     } else if (mBytesWritten != 0) {
         if (mMixerStatus == MIXER_TRACKS_ENABLED) {
             writeFrames = mNormalFrameCount;
-            memset(mMixBuffer, 0, mixBufferSize);
+            memset(mSinkBuffer, 0, mSinkBufferSize);
         } else {
             // flush remaining overflow buffers in output tracks
             writeFrames = 0;
@@ -4255,10 +4481,18 @@
 ssize_t AudioFlinger::DuplicatingThread::threadLoop_write()
 {
     for (size_t i = 0; i < outputTracks.size(); i++) {
-        outputTracks[i]->write(mMixBuffer, writeFrames);
+        // We convert the duplicating thread format to AUDIO_FORMAT_PCM_16_BIT
+        // for delivery downstream as needed. This in-place conversion is safe as
+        // AUDIO_FORMAT_PCM_16_BIT is smaller than any other supported format
+        // (AUDIO_FORMAT_PCM_8_BIT is not allowed here).
+        if (mFormat != AUDIO_FORMAT_PCM_16_BIT) {
+            memcpy_by_audio_format(mSinkBuffer, AUDIO_FORMAT_PCM_16_BIT,
+                    mSinkBuffer, mFormat, writeFrames * mChannelCount);
+        }
+        outputTracks[i]->write(reinterpret_cast<int16_t*>(mSinkBuffer), writeFrames);
     }
     mStandby = false;
-    return (ssize_t)mixBufferSize;
+    return (ssize_t)mSinkBufferSize;
 }
 
 void AudioFlinger::DuplicatingThread::threadLoop_standby()
@@ -4284,10 +4518,16 @@
     Mutex::Autolock _l(mLock);
     // FIXME explain this formula
     size_t frameCount = (3 * mNormalFrameCount * mSampleRate) / thread->sampleRate();
+    // OutputTrack is forced to AUDIO_FORMAT_PCM_16_BIT regardless of mFormat
+    // due to current usage case and restrictions on the AudioBufferProvider.
+    // Actual buffer conversion is done in threadLoop_write().
+    //
+    // TODO: This may change in the future, depending on multichannel
+    // (and non int16_t*) support on AF::PlaybackThread::OutputTrack
     OutputTrack *outputTrack = new OutputTrack(thread,
                                             this,
                                             mSampleRate,
-                                            mFormat,
+                                            AUDIO_FORMAT_PCM_16_BIT,
                                             mChannelMask,
                                             frameCount,
                                             IPCThreadState::self()->getCallingUid());
@@ -4369,8 +4609,6 @@
 
 AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
                                          AudioStreamIn *input,
-                                         uint32_t sampleRate,
-                                         audio_channel_mask_t channelMask,
                                          audio_io_handle_t id,
                                          audio_devices_t outDevice,
                                          audio_devices_t inDevice
@@ -4379,27 +4617,24 @@
 #endif
                                          ) :
     ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD),
-    mInput(input), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL),
-    // mRsmpInIndex and mBufferSize set by readInputParameters()
-    mReqChannelCount(popcount(channelMask)),
-    mReqSampleRate(sampleRate)
-    // mBytesRead is only meaningful while active, and so is cleared in start()
-    // (but might be better to also clear here for dump?)
+    mInput(input), mActiveTracksGen(0), mRsmpInBuffer(NULL),
+    // mRsmpInFrames and mRsmpInFramesP2 are set by readInputParameters_l()
+    mRsmpInRear(0)
 #ifdef TEE_SINK
     , mTeeSink(teeSink)
 #endif
 {
     snprintf(mName, kNameLength, "AudioIn_%X", id);
+    mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mName);
 
-    readInputParameters();
+    readInputParameters_l();
 }
 
 
 AudioFlinger::RecordThread::~RecordThread()
 {
+    mAudioFlinger->unregisterWriter(mNBLogWriter);
     delete[] mRsmpInBuffer;
-    delete mResampler;
-    delete[] mRsmpOutBuffer;
 }
 
 void AudioFlinger::RecordThread::onFirstRef()
@@ -4407,230 +4642,393 @@
     run(mName, PRIORITY_URGENT_AUDIO);
 }
 
-status_t AudioFlinger::RecordThread::readyToRun()
-{
-    status_t status = initCheck();
-    ALOGW_IF(status != NO_ERROR,"RecordThread %p could not initialize", this);
-    return status;
-}
-
 bool AudioFlinger::RecordThread::threadLoop()
 {
-    AudioBufferProvider::Buffer buffer;
-    sp<RecordTrack> activeTrack;
-    Vector< sp<EffectChain> > effectChains;
-
     nsecs_t lastWarning = 0;
 
     inputStandBy();
+
+reacquire_wakelock:
+    sp<RecordTrack> activeTrack;
+    int activeTracksGen;
     {
         Mutex::Autolock _l(mLock);
-        activeTrack = mActiveTrack;
-        acquireWakeLock_l(activeTrack != 0 ? activeTrack->uid() : -1);
+        size_t size = mActiveTracks.size();
+        activeTracksGen = mActiveTracksGen;
+        if (size > 0) {
+            // FIXME an arbitrary choice
+            activeTrack = mActiveTracks[0];
+            acquireWakeLock_l(activeTrack->uid());
+            if (size > 1) {
+                SortedVector<int> tmp;
+                for (size_t i = 0; i < size; i++) {
+                    tmp.add(mActiveTracks[i]->uid());
+                }
+                updateWakeLockUids_l(tmp);
+            }
+        } else {
+            acquireWakeLock_l(-1);
+        }
     }
 
-    // used to verify we've read at least once before evaluating how many bytes were read
-    bool readOnce = false;
+    // used to request a deferred sleep, to be executed later while mutex is unlocked
+    uint32_t sleepUs = 0;
 
-    // start recording
-    while (!exitPending()) {
+    // loop while there is work to do
+    for (;;) {
+        Vector< sp<EffectChain> > effectChains;
 
-        processConfigEvents();
+        // sleep with mutex unlocked
+        if (sleepUs > 0) {
+            usleep(sleepUs);
+            sleepUs = 0;
+        }
+
+        // activeTracks accumulates a copy of a subset of mActiveTracks
+        Vector< sp<RecordTrack> > activeTracks;
 
         { // scope for mLock
             Mutex::Autolock _l(mLock);
-            checkForNewParameters_l();
-            if (mActiveTrack != 0 && activeTrack != mActiveTrack) {
-                SortedVector<int> tmp;
-                tmp.add(mActiveTrack->uid());
-                updateWakeLockUids_l(tmp);
+
+            processConfigEvents_l();
+            // return value 'reconfig' is currently unused
+            bool reconfig = checkForNewParameters_l();
+
+            // check exitPending here because checkForNewParameters_l() and
+            // checkForNewParameters_l() can temporarily release mLock
+            if (exitPending()) {
+                break;
             }
-            activeTrack = mActiveTrack;
-            if (mActiveTrack == 0 && mConfigEvents.isEmpty()) {
-                standby();
 
-                if (exitPending()) {
-                    break;
-                }
-
+            // if no active track(s), then standby and release wakelock
+            size_t size = mActiveTracks.size();
+            if (size == 0) {
+                standbyIfNotAlreadyInStandby();
+                // exitPending() can't become true here
                 releaseWakeLock_l();
                 ALOGV("RecordThread: loop stopping");
                 // go to sleep
                 mWaitWorkCV.wait(mLock);
                 ALOGV("RecordThread: loop starting");
-                acquireWakeLock_l(mActiveTrack != 0 ? mActiveTrack->uid() : -1);
+                goto reacquire_wakelock;
+            }
+
+            if (mActiveTracksGen != activeTracksGen) {
+                activeTracksGen = mActiveTracksGen;
+                SortedVector<int> tmp;
+                for (size_t i = 0; i < size; i++) {
+                    tmp.add(mActiveTracks[i]->uid());
+                }
+                updateWakeLockUids_l(tmp);
+            }
+
+            bool doBroadcast = false;
+            for (size_t i = 0; i < size; ) {
+
+                activeTrack = mActiveTracks[i];
+                if (activeTrack->isTerminated()) {
+                    removeTrack_l(activeTrack);
+                    mActiveTracks.remove(activeTrack);
+                    mActiveTracksGen++;
+                    size--;
+                    continue;
+                }
+
+                TrackBase::track_state activeTrackState = activeTrack->mState;
+                switch (activeTrackState) {
+
+                case TrackBase::PAUSING:
+                    mActiveTracks.remove(activeTrack);
+                    mActiveTracksGen++;
+                    doBroadcast = true;
+                    size--;
+                    continue;
+
+                case TrackBase::STARTING_1:
+                    sleepUs = 10000;
+                    i++;
+                    continue;
+
+                case TrackBase::STARTING_2:
+                    doBroadcast = true;
+                    mStandby = false;
+                    activeTrack->mState = TrackBase::ACTIVE;
+                    break;
+
+                case TrackBase::ACTIVE:
+                    break;
+
+                case TrackBase::IDLE:
+                    i++;
+                    continue;
+
+                default:
+                    LOG_FATAL("Unexpected activeTrackState %d", activeTrackState);
+                }
+
+                activeTracks.add(activeTrack);
+                i++;
+
+            }
+            if (doBroadcast) {
+                mStartStopCond.broadcast();
+            }
+
+            // sleep if there are no active tracks to process
+            if (activeTracks.size() == 0) {
+                if (sleepUs == 0) {
+                    sleepUs = kRecordThreadSleepUs;
+                }
                 continue;
             }
-            if (mActiveTrack != 0) {
-                if (mActiveTrack->isTerminated()) {
-                    removeTrack_l(mActiveTrack);
-                    mActiveTrack.clear();
-                } else if (mActiveTrack->mState == TrackBase::PAUSING) {
-                    standby();
-                    mActiveTrack.clear();
-                    mStartStopCond.broadcast();
-                } else if (mActiveTrack->mState == TrackBase::RESUMING) {
-                    if (mReqChannelCount != mActiveTrack->channelCount()) {
-                        mActiveTrack.clear();
-                        mStartStopCond.broadcast();
-                    } else if (readOnce) {
-                        // record start succeeds only if first read from audio input
-                        // succeeds
-                        if (mBytesRead >= 0) {
-                            mActiveTrack->mState = TrackBase::ACTIVE;
-                        } else {
-                            mActiveTrack.clear();
-                        }
-                        mStartStopCond.broadcast();
-                    }
-                    mStandby = false;
-                }
-            }
+            sleepUs = 0;
 
             lockEffectChains_l(effectChains);
         }
 
-        if (mActiveTrack != 0) {
-            if (mActiveTrack->mState != TrackBase::ACTIVE &&
-                mActiveTrack->mState != TrackBase::RESUMING) {
-                unlockEffectChains(effectChains);
-                usleep(kRecordThreadSleepUs);
-                continue;
-            }
-            for (size_t i = 0; i < effectChains.size(); i ++) {
-                effectChains[i]->process_l();
-            }
+        // thread mutex is now unlocked, mActiveTracks unknown, activeTracks.size() > 0
 
-            buffer.frameCount = mFrameCount;
-            status_t status = mActiveTrack->getNextBuffer(&buffer);
-            if (status == NO_ERROR) {
-                readOnce = true;
-                size_t framesOut = buffer.frameCount;
-                if (mResampler == NULL) {
+        size_t size = effectChains.size();
+        for (size_t i = 0; i < size; i++) {
+            // thread mutex is not locked, but effect chain is locked
+            effectChains[i]->process_l();
+        }
+
+        // Read from HAL to keep up with fastest client if multiple active tracks, not slowest one.
+        // Only the client(s) that are too slow will overrun. But if even the fastest client is too
+        // slow, then this RecordThread will overrun by not calling HAL read often enough.
+        // If destination is non-contiguous, first read past the nominal end of buffer, then
+        // copy to the right place.  Permitted because mRsmpInBuffer was over-allocated.
+
+        int32_t rear = mRsmpInRear & (mRsmpInFramesP2 - 1);
+        ssize_t bytesRead = mInput->stream->read(mInput->stream,
+                &mRsmpInBuffer[rear * mChannelCount], mBufferSize);
+        if (bytesRead <= 0) {
+            ALOGE("read failed: bytesRead=%d < %u", bytesRead, mBufferSize);
+            // Force input into standby so that it tries to recover at next read attempt
+            inputStandBy();
+            sleepUs = kRecordThreadSleepUs;
+            continue;
+        }
+        ALOG_ASSERT((size_t) bytesRead <= mBufferSize);
+        size_t framesRead = bytesRead / mFrameSize;
+        ALOG_ASSERT(framesRead > 0);
+        if (mTeeSink != 0) {
+            (void) mTeeSink->write(&mRsmpInBuffer[rear * mChannelCount], framesRead);
+        }
+        // If destination is non-contiguous, we now correct for reading past end of buffer.
+        size_t part1 = mRsmpInFramesP2 - rear;
+        if (framesRead > part1) {
+            memcpy(mRsmpInBuffer, &mRsmpInBuffer[mRsmpInFramesP2 * mChannelCount],
+                    (framesRead - part1) * mFrameSize);
+        }
+        rear = mRsmpInRear += framesRead;
+
+        size = activeTracks.size();
+        // loop over each active track
+        for (size_t i = 0; i < size; i++) {
+            activeTrack = activeTracks[i];
+
+            enum {
+                OVERRUN_UNKNOWN,
+                OVERRUN_TRUE,
+                OVERRUN_FALSE
+            } overrun = OVERRUN_UNKNOWN;
+
+            // loop over getNextBuffer to handle circular sink
+            for (;;) {
+
+                activeTrack->mSink.frameCount = ~0;
+                status_t status = activeTrack->getNextBuffer(&activeTrack->mSink);
+                size_t framesOut = activeTrack->mSink.frameCount;
+                LOG_ALWAYS_FATAL_IF((status == OK) != (framesOut > 0));
+
+                int32_t front = activeTrack->mRsmpInFront;
+                ssize_t filled = rear - front;
+                size_t framesIn;
+
+                if (filled < 0) {
+                    // should not happen, but treat like a massive overrun and re-sync
+                    framesIn = 0;
+                    activeTrack->mRsmpInFront = rear;
+                    overrun = OVERRUN_TRUE;
+                } else if ((size_t) filled <= mRsmpInFrames) {
+                    framesIn = (size_t) filled;
+                } else {
+                    // client is not keeping up with server, but give it latest data
+                    framesIn = mRsmpInFrames;
+                    activeTrack->mRsmpInFront = front = rear - framesIn;
+                    overrun = OVERRUN_TRUE;
+                }
+
+                if (framesOut == 0 || framesIn == 0) {
+                    break;
+                }
+
+                if (activeTrack->mResampler == NULL) {
                     // no resampling
-                    while (framesOut) {
-                        size_t framesIn = mFrameCount - mRsmpInIndex;
-                        if (framesIn) {
-                            int8_t *src = (int8_t *)mRsmpInBuffer + mRsmpInIndex * mFrameSize;
-                            int8_t *dst = buffer.i8 + (buffer.frameCount - framesOut) *
-                                    mActiveTrack->mFrameSize;
-                            if (framesIn > framesOut)
-                                framesIn = framesOut;
-                            mRsmpInIndex += framesIn;
-                            framesOut -= framesIn;
-                            if (mChannelCount == mReqChannelCount) {
-                                memcpy(dst, src, framesIn * mFrameSize);
-                            } else {
-                                if (mChannelCount == 1) {
-                                    upmix_to_stereo_i16_from_mono_i16((int16_t *)dst,
-                                            (int16_t *)src, framesIn);
-                                } else {
-                                    downmix_to_mono_i16_from_stereo_i16((int16_t *)dst,
-                                            (int16_t *)src, framesIn);
-                                }
-                            }
-                        }
-                        if (framesOut && mFrameCount == mRsmpInIndex) {
-                            void *readInto;
-                            if (framesOut == mFrameCount && mChannelCount == mReqChannelCount) {
-                                readInto = buffer.raw;
-                                framesOut = 0;
-                            } else {
-                                readInto = mRsmpInBuffer;
-                                mRsmpInIndex = 0;
-                            }
-                            mBytesRead = mInput->stream->read(mInput->stream, readInto,
-                                    mBufferSize);
-                            if (mBytesRead <= 0) {
-                                if ((mBytesRead < 0) && (mActiveTrack->mState == TrackBase::ACTIVE))
-                                {
-                                    ALOGE("Error reading audio input");
-                                    // Force input into standby so that it tries to
-                                    // recover at next read attempt
-                                    inputStandBy();
-                                    usleep(kRecordThreadSleepUs);
-                                }
-                                mRsmpInIndex = mFrameCount;
-                                framesOut = 0;
-                                buffer.frameCount = 0;
-                            }
-#ifdef TEE_SINK
-                            else if (mTeeSink != 0) {
-                                (void) mTeeSink->write(readInto,
-                                        mBytesRead >> Format_frameBitShift(mTeeSink->format()));
-                            }
-#endif
-                        }
+                    if (framesIn > framesOut) {
+                        framesIn = framesOut;
+                    } else {
+                        framesOut = framesIn;
                     }
+                    int8_t *dst = activeTrack->mSink.i8;
+                    while (framesIn > 0) {
+                        front &= mRsmpInFramesP2 - 1;
+                        size_t part1 = mRsmpInFramesP2 - front;
+                        if (part1 > framesIn) {
+                            part1 = framesIn;
+                        }
+                        int8_t *src = (int8_t *)mRsmpInBuffer + (front * mFrameSize);
+                        if (mChannelCount == activeTrack->mChannelCount) {
+                            memcpy(dst, src, part1 * mFrameSize);
+                        } else if (mChannelCount == 1) {
+                            upmix_to_stereo_i16_from_mono_i16((int16_t *)dst, (int16_t *)src,
+                                    part1);
+                        } else {
+                            downmix_to_mono_i16_from_stereo_i16((int16_t *)dst, (int16_t *)src,
+                                    part1);
+                        }
+                        dst += part1 * activeTrack->mFrameSize;
+                        front += part1;
+                        framesIn -= part1;
+                    }
+                    activeTrack->mRsmpInFront += framesOut;
+
                 } else {
                     // resampling
+                    // FIXME framesInNeeded should really be part of resampler API, and should
+                    //       depend on the SRC ratio
+                    //       to keep mRsmpInBuffer full so resampler always has sufficient input
+                    size_t framesInNeeded;
+                    // FIXME only re-calculate when it changes, and optimize for common ratios
+                    double inOverOut = (double) mSampleRate / activeTrack->mSampleRate;
+                    double outOverIn = (double) activeTrack->mSampleRate / mSampleRate;
+                    framesInNeeded = ceil(framesOut * inOverOut) + 1;
+                    ALOGV("need %u frames in to produce %u out given in/out ratio of %.4g",
+                                framesInNeeded, framesOut, inOverOut);
+                    // Although we theoretically have framesIn in circular buffer, some of those are
+                    // unreleased frames, and thus must be discounted for purpose of budgeting.
+                    size_t unreleased = activeTrack->mRsmpInUnrel;
+                    framesIn = framesIn > unreleased ? framesIn - unreleased : 0;
+                    if (framesIn < framesInNeeded) {
+                        ALOGV("not enough to resample: have %u frames in but need %u in to "
+                                "produce %u out given in/out ratio of %.4g",
+                                framesIn, framesInNeeded, framesOut, inOverOut);
+                        size_t newFramesOut = framesIn > 0 ? floor((framesIn - 1) * outOverIn) : 0;
+                        LOG_ALWAYS_FATAL_IF(newFramesOut >= framesOut);
+                        if (newFramesOut == 0) {
+                            break;
+                        }
+                        framesInNeeded = ceil(newFramesOut * inOverOut) + 1;
+                        ALOGV("now need %u frames in to produce %u out given out/in ratio of %.4g",
+                                framesInNeeded, newFramesOut, outOverIn);
+                        LOG_ALWAYS_FATAL_IF(framesIn < framesInNeeded);
+                        ALOGV("success 2: have %u frames in and need %u in to produce %u out "
+                              "given in/out ratio of %.4g",
+                              framesIn, framesInNeeded, newFramesOut, inOverOut);
+                        framesOut = newFramesOut;
+                    } else {
+                        ALOGV("success 1: have %u in and need %u in to produce %u out "
+                            "given in/out ratio of %.4g",
+                            framesIn, framesInNeeded, framesOut, inOverOut);
+                    }
+
+                    // reallocate mRsmpOutBuffer as needed; we will grow but never shrink
+                    if (activeTrack->mRsmpOutFrameCount < framesOut) {
+                        // FIXME why does each track need it's own mRsmpOutBuffer? can't they share?
+                        delete[] activeTrack->mRsmpOutBuffer;
+                        // resampler always outputs stereo
+                        activeTrack->mRsmpOutBuffer = new int32_t[framesOut * FCC_2];
+                        activeTrack->mRsmpOutFrameCount = framesOut;
+                    }
 
                     // resampler accumulates, but we only have one source track
-                    memset(mRsmpOutBuffer, 0, framesOut * FCC_2 * sizeof(int32_t));
-                    // alter output frame count as if we were expecting stereo samples
-                    if (mChannelCount == 1 && mReqChannelCount == 1) {
-                        framesOut >>= 1;
-                    }
-                    mResampler->resample(mRsmpOutBuffer, framesOut,
-                            this /* AudioBufferProvider* */);
+                    memset(activeTrack->mRsmpOutBuffer, 0, framesOut * FCC_2 * sizeof(int32_t));
+                    activeTrack->mResampler->resample(activeTrack->mRsmpOutBuffer, framesOut,
+                            // FIXME how about having activeTrack implement this interface itself?
+                            activeTrack->mResamplerBufferProvider
+                            /*this*/ /* AudioBufferProvider* */);
                     // ditherAndClamp() works as long as all buffers returned by
-                    // mActiveTrack->getNextBuffer() are 32 bit aligned which should be always true.
-                    if (mChannelCount == 2 && mReqChannelCount == 1) {
+                    // activeTrack->getNextBuffer() are 32 bit aligned which should be always true.
+                    if (activeTrack->mChannelCount == 1) {
                         // temporarily type pun mRsmpOutBuffer from Q19.12 to int16_t
-                        ditherAndClamp(mRsmpOutBuffer, mRsmpOutBuffer, framesOut);
+                        ditherAndClamp(activeTrack->mRsmpOutBuffer, activeTrack->mRsmpOutBuffer,
+                                framesOut);
                         // the resampler always outputs stereo samples:
                         // do post stereo to mono conversion
-                        downmix_to_mono_i16_from_stereo_i16(buffer.i16, (int16_t *)mRsmpOutBuffer,
-                                framesOut);
+                        downmix_to_mono_i16_from_stereo_i16(activeTrack->mSink.i16,
+                                (int16_t *)activeTrack->mRsmpOutBuffer, framesOut);
                     } else {
-                        ditherAndClamp((int32_t *)buffer.raw, mRsmpOutBuffer, framesOut);
+                        ditherAndClamp((int32_t *)activeTrack->mSink.raw,
+                                activeTrack->mRsmpOutBuffer, framesOut);
                     }
                     // now done with mRsmpOutBuffer
 
                 }
-                if (mFramestoDrop == 0) {
-                    mActiveTrack->releaseBuffer(&buffer);
+
+                if (framesOut > 0 && (overrun == OVERRUN_UNKNOWN)) {
+                    overrun = OVERRUN_FALSE;
+                }
+
+                if (activeTrack->mFramesToDrop == 0) {
+                    if (framesOut > 0) {
+                        activeTrack->mSink.frameCount = framesOut;
+                        activeTrack->releaseBuffer(&activeTrack->mSink);
+                    }
                 } else {
-                    if (mFramestoDrop > 0) {
-                        mFramestoDrop -= buffer.frameCount;
-                        if (mFramestoDrop <= 0) {
-                            clearSyncStartEvent();
+                    // FIXME could do a partial drop of framesOut
+                    if (activeTrack->mFramesToDrop > 0) {
+                        activeTrack->mFramesToDrop -= framesOut;
+                        if (activeTrack->mFramesToDrop <= 0) {
+                            activeTrack->clearSyncStartEvent();
                         }
                     } else {
-                        mFramestoDrop += buffer.frameCount;
-                        if (mFramestoDrop >= 0 || mSyncStartEvent == 0 ||
-                                mSyncStartEvent->isCancelled()) {
+                        activeTrack->mFramesToDrop += framesOut;
+                        if (activeTrack->mFramesToDrop >= 0 || activeTrack->mSyncStartEvent == 0 ||
+                                activeTrack->mSyncStartEvent->isCancelled()) {
                             ALOGW("Synced record %s, session %d, trigger session %d",
-                                  (mFramestoDrop >= 0) ? "timed out" : "cancelled",
-                                  mActiveTrack->sessionId(),
-                                  (mSyncStartEvent != 0) ? mSyncStartEvent->triggerSession() : 0);
-                            clearSyncStartEvent();
+                                  (activeTrack->mFramesToDrop >= 0) ? "timed out" : "cancelled",
+                                  activeTrack->sessionId(),
+                                  (activeTrack->mSyncStartEvent != 0) ?
+                                          activeTrack->mSyncStartEvent->triggerSession() : 0);
+                            activeTrack->clearSyncStartEvent();
                         }
                     }
                 }
-                mActiveTrack->clearOverflow();
+
+                if (framesOut == 0) {
+                    break;
+                }
             }
-            // client isn't retrieving buffers fast enough
-            else {
-                if (!mActiveTrack->setOverflow()) {
+
+            switch (overrun) {
+            case OVERRUN_TRUE:
+                // client isn't retrieving buffers fast enough
+                if (!activeTrack->setOverflow()) {
                     nsecs_t now = systemTime();
+                    // FIXME should lastWarning per track?
                     if ((now - lastWarning) > kWarningThrottleNs) {
                         ALOGW("RecordThread: buffer overflow");
                         lastWarning = now;
                     }
                 }
-                // Release the processor for a while before asking for a new buffer.
-                // This will give the application more chance to read from the buffer and
-                // clear the overflow.
-                usleep(kRecordThreadSleepUs);
+                break;
+            case OVERRUN_FALSE:
+                activeTrack->clearOverflow();
+                break;
+            case OVERRUN_UNKNOWN:
+                break;
             }
+
         }
+
         // enable changes in effect chain
         unlockEffectChains(effectChains);
-        effectChains.clear();
+        // effectChains doesn't need to be cleared, since it is cleared by destructor at scope end
     }
 
-    standby();
+    standbyIfNotAlreadyInStandby();
 
     {
         Mutex::Autolock _l(mLock);
@@ -4638,7 +5036,8 @@
             sp<RecordTrack> track = mTracks[i];
             track->invalidate();
         }
-        mActiveTrack.clear();
+        mActiveTracks.clear();
+        mActiveTracksGen++;
         mStartStopCond.broadcast();
     }
 
@@ -4648,7 +5047,7 @@
     return false;
 }
 
-void AudioFlinger::RecordThread::standby()
+void AudioFlinger::RecordThread::standbyIfNotAlreadyInStandby()
 {
     if (!mStandby) {
         inputStandBy();
@@ -4661,26 +5060,23 @@
     mInput->stream->common.standby(&mInput->stream->common);
 }
 
-sp<AudioFlinger::RecordThread::RecordTrack>  AudioFlinger::RecordThread::createRecordTrack_l(
+// RecordThread::createRecordTrack_l() must be called with AudioFlinger::mLock held
+sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRecordTrack_l(
         const sp<AudioFlinger::Client>& client,
         uint32_t sampleRate,
         audio_format_t format,
         audio_channel_mask_t channelMask,
-        size_t frameCount,
+        size_t *pFrameCount,
         int sessionId,
         int uid,
         IAudioFlinger::track_flags_t *flags,
         pid_t tid,
         status_t *status)
 {
+    size_t frameCount = *pFrameCount;
     sp<RecordTrack> track;
     status_t lStatus;
 
-    lStatus = initCheck();
-    if (lStatus != NO_ERROR) {
-        ALOGE("createRecordTrack_l() audio driver not initialized");
-        goto Exit;
-    }
     // client expresses a preference for FAST, but we get the final say
     if (*flags & IAudioFlinger::TRACK_FAST) {
       if (
@@ -4731,8 +5127,13 @@
         }
       }
     }
+    *pFrameCount = frameCount;
 
-    // FIXME use flags and tid similar to createTrack_l()
+    lStatus = initCheck();
+    if (lStatus != NO_ERROR) {
+        ALOGE("createRecordTrack_l() audio driver not initialized");
+        goto Exit;
+    }
 
     { // scope for mLock
         Mutex::Autolock _l(mLock);
@@ -4740,9 +5141,9 @@
         track = new RecordTrack(this, client, sampleRate,
                       format, channelMask, frameCount, sessionId, uid);
 
-        if (track->getCblk() == 0) {
-            ALOGE("createRecordTrack_l() no control block");
-            lStatus = NO_MEMORY;
+        lStatus = track->initCheck();
+        if (lStatus != NO_ERROR) {
+            ALOGE("createRecordTrack_l() initCheck failed %d; no control block?", lStatus);
             // track must be cleared from the caller as the caller has the AF lock
             goto Exit;
         }
@@ -4761,12 +5162,11 @@
             sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp);
         }
     }
+
     lStatus = NO_ERROR;
 
 Exit:
-    if (status) {
-        *status = lStatus;
-    }
+    *status = lStatus;
     return track;
 }
 
@@ -4779,129 +5179,123 @@
     status_t status = NO_ERROR;
 
     if (event == AudioSystem::SYNC_EVENT_NONE) {
-        clearSyncStartEvent();
+        recordTrack->clearSyncStartEvent();
     } else if (event != AudioSystem::SYNC_EVENT_SAME) {
-        mSyncStartEvent = mAudioFlinger->createSyncEvent(event,
+        recordTrack->mSyncStartEvent = mAudioFlinger->createSyncEvent(event,
                                        triggerSession,
                                        recordTrack->sessionId(),
                                        syncStartEventCallback,
-                                       this);
+                                       recordTrack);
         // Sync event can be cancelled by the trigger session if the track is not in a
         // compatible state in which case we start record immediately
-        if (mSyncStartEvent->isCancelled()) {
-            clearSyncStartEvent();
+        if (recordTrack->mSyncStartEvent->isCancelled()) {
+            recordTrack->clearSyncStartEvent();
         } else {
             // do not wait for the event for more than AudioSystem::kSyncRecordStartTimeOutMs
-            mFramestoDrop = - ((AudioSystem::kSyncRecordStartTimeOutMs * mReqSampleRate) / 1000);
+            recordTrack->mFramesToDrop = -
+                    ((AudioSystem::kSyncRecordStartTimeOutMs * recordTrack->mSampleRate) / 1000);
         }
     }
 
     {
+        // This section is a rendezvous between binder thread executing start() and RecordThread
         AutoMutex lock(mLock);
-        if (mActiveTrack != 0) {
-            if (recordTrack != mActiveTrack.get()) {
-                status = -EBUSY;
-            } else if (mActiveTrack->mState == TrackBase::PAUSING) {
-                mActiveTrack->mState = TrackBase::ACTIVE;
+        if (mActiveTracks.indexOf(recordTrack) >= 0) {
+            if (recordTrack->mState == TrackBase::PAUSING) {
+                ALOGV("active record track PAUSING -> ACTIVE");
+                recordTrack->mState = TrackBase::ACTIVE;
+            } else {
+                ALOGV("active record track state %d", recordTrack->mState);
             }
             return status;
         }
 
-        recordTrack->mState = TrackBase::IDLE;
-        mActiveTrack = recordTrack;
+        // TODO consider other ways of handling this, such as changing the state to :STARTING and
+        //      adding the track to mActiveTracks after returning from AudioSystem::startInput(),
+        //      or using a separate command thread
+        recordTrack->mState = TrackBase::STARTING_1;
+        mActiveTracks.add(recordTrack);
+        mActiveTracksGen++;
         mLock.unlock();
         status_t status = AudioSystem::startInput(mId);
         mLock.lock();
+        // FIXME should verify that recordTrack is still in mActiveTracks
         if (status != NO_ERROR) {
-            mActiveTrack.clear();
-            clearSyncStartEvent();
+            mActiveTracks.remove(recordTrack);
+            mActiveTracksGen++;
+            recordTrack->clearSyncStartEvent();
             return status;
         }
-        mRsmpInIndex = mFrameCount;
-        mBytesRead = 0;
-        if (mResampler != NULL) {
-            mResampler->reset();
+        // Catch up with current buffer indices if thread is already running.
+        // This is what makes a new client discard all buffered data.  If the track's mRsmpInFront
+        // was initialized to some value closer to the thread's mRsmpInFront, then the track could
+        // see previously buffered data before it called start(), but with greater risk of overrun.
+
+        recordTrack->mRsmpInFront = mRsmpInRear;
+        recordTrack->mRsmpInUnrel = 0;
+        // FIXME why reset?
+        if (recordTrack->mResampler != NULL) {
+            recordTrack->mResampler->reset();
         }
-        mActiveTrack->mState = TrackBase::RESUMING;
+        recordTrack->mState = TrackBase::STARTING_2;
         // signal thread to start
-        ALOGV("Signal record thread");
         mWaitWorkCV.broadcast();
-        // do not wait for mStartStopCond if exiting
-        if (exitPending()) {
-            mActiveTrack.clear();
-            status = INVALID_OPERATION;
-            goto startError;
-        }
-        mStartStopCond.wait(mLock);
-        if (mActiveTrack == 0) {
+        if (mActiveTracks.indexOf(recordTrack) < 0) {
             ALOGV("Record failed to start");
             status = BAD_VALUE;
             goto startError;
         }
-        ALOGV("Record started OK");
         return status;
     }
 
 startError:
     AudioSystem::stopInput(mId);
-    clearSyncStartEvent();
+    recordTrack->clearSyncStartEvent();
+    // FIXME I wonder why we do not reset the state here?
     return status;
 }
 
-void AudioFlinger::RecordThread::clearSyncStartEvent()
-{
-    if (mSyncStartEvent != 0) {
-        mSyncStartEvent->cancel();
-    }
-    mSyncStartEvent.clear();
-    mFramestoDrop = 0;
-}
-
 void AudioFlinger::RecordThread::syncStartEventCallback(const wp<SyncEvent>& event)
 {
     sp<SyncEvent> strongEvent = event.promote();
 
     if (strongEvent != 0) {
-        RecordThread *me = (RecordThread *)strongEvent->cookie();
-        me->handleSyncStartEvent(strongEvent);
-    }
-}
-
-void AudioFlinger::RecordThread::handleSyncStartEvent(const sp<SyncEvent>& event)
-{
-    if (event == mSyncStartEvent) {
-        // TODO: use actual buffer filling status instead of 2 buffers when info is available
-        // from audio HAL
-        mFramestoDrop = mFrameCount * 2;
+        sp<RefBase> ptr = strongEvent->cookie().promote();
+        if (ptr != 0) {
+            RecordTrack *recordTrack = (RecordTrack *)ptr.get();
+            recordTrack->handleSyncStartEvent(strongEvent);
+        }
     }
 }
 
 bool AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
     ALOGV("RecordThread::stop");
     AutoMutex _l(mLock);
-    if (recordTrack != mActiveTrack.get() || recordTrack->mState == TrackBase::PAUSING) {
+    if (mActiveTracks.indexOf(recordTrack) != 0 || recordTrack->mState == TrackBase::PAUSING) {
         return false;
     }
+    // note that threadLoop may still be processing the track at this point [without lock]
     recordTrack->mState = TrackBase::PAUSING;
     // do not wait for mStartStopCond if exiting
     if (exitPending()) {
         return true;
     }
+    // FIXME incorrect usage of wait: no explicit predicate or loop
     mStartStopCond.wait(mLock);
-    // if we have been restarted, recordTrack == mActiveTrack.get() here
-    if (exitPending() || recordTrack != mActiveTrack.get()) {
+    // if we have been restarted, recordTrack is in mActiveTracks here
+    if (exitPending() || mActiveTracks.indexOf(recordTrack) != 0) {
         ALOGV("Record stopped OK");
         return true;
     }
     return false;
 }
 
-bool AudioFlinger::RecordThread::isValidSyncEvent(const sp<SyncEvent>& event) const
+bool AudioFlinger::RecordThread::isValidSyncEvent(const sp<SyncEvent>& event __unused) const
 {
     return false;
 }
 
-status_t AudioFlinger::RecordThread::setSyncEvent(const sp<SyncEvent>& event)
+status_t AudioFlinger::RecordThread::setSyncEvent(const sp<SyncEvent>& event __unused)
 {
 #if 0   // This branch is currently dead code, but is preserved in case it will be needed in future
     if (!isValidSyncEvent(event)) {
@@ -4932,7 +5326,7 @@
     track->terminate();
     track->mState = TrackBase::STOPPED;
     // active tracks are removed by threadLoop()
-    if (mActiveTrack != track) {
+    if (mActiveTracks.indexOf(track) < 0) {
         removeTrack_l(track);
     }
 }
@@ -4952,104 +5346,119 @@
 
 void AudioFlinger::RecordThread::dumpInternals(int fd, const Vector<String16>& args)
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
+    fdprintf(fd, "\nInput thread %p:\n", this);
 
-    snprintf(buffer, SIZE, "\nInput thread %p internals\n", this);
-    result.append(buffer);
-
-    if (mActiveTrack != 0) {
-        snprintf(buffer, SIZE, "In index: %zu\n", mRsmpInIndex);
-        result.append(buffer);
-        snprintf(buffer, SIZE, "Buffer size: %zu bytes\n", mBufferSize);
-        result.append(buffer);
-        snprintf(buffer, SIZE, "Resampling: %d\n", (mResampler != NULL));
-        result.append(buffer);
-        snprintf(buffer, SIZE, "Out channel count: %u\n", mReqChannelCount);
-        result.append(buffer);
-        snprintf(buffer, SIZE, "Out sample rate: %u\n", mReqSampleRate);
-        result.append(buffer);
+    if (mActiveTracks.size() > 0) {
+        fdprintf(fd, "  Buffer size: %zu bytes\n", mBufferSize);
     } else {
-        result.append("No active record client\n");
+        fdprintf(fd, "  No active record clients\n");
     }
 
-    write(fd, result.string(), result.size());
-
     dumpBase(fd, args);
 }
 
-void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args)
+void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args __unused)
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
 
-    snprintf(buffer, SIZE, "Input thread %p tracks\n", this);
-    result.append(buffer);
-    RecordTrack::appendDumpHeader(result);
-    for (size_t i = 0; i < mTracks.size(); ++i) {
-        sp<RecordTrack> track = mTracks[i];
-        if (track != 0) {
-            track->dump(buffer, SIZE);
-            result.append(buffer);
+    size_t numtracks = mTracks.size();
+    size_t numactive = mActiveTracks.size();
+    size_t numactiveseen = 0;
+    fdprintf(fd, "  %d Tracks", numtracks);
+    if (numtracks) {
+        fdprintf(fd, " of which %d are active\n", numactive);
+        RecordTrack::appendDumpHeader(result);
+        for (size_t i = 0; i < numtracks ; ++i) {
+            sp<RecordTrack> track = mTracks[i];
+            if (track != 0) {
+                bool active = mActiveTracks.indexOf(track) >= 0;
+                if (active) {
+                    numactiveseen++;
+                }
+                track->dump(buffer, SIZE, active);
+                result.append(buffer);
+            }
         }
+    } else {
+        fdprintf(fd, "\n");
     }
 
-    if (mActiveTrack != 0) {
-        snprintf(buffer, SIZE, "\nInput thread %p active tracks\n", this);
+    if (numactiveseen != numactive) {
+        snprintf(buffer, SIZE, "  The following tracks are in the active list but"
+                " not in the track list\n");
         result.append(buffer);
         RecordTrack::appendDumpHeader(result);
-        mActiveTrack->dump(buffer, SIZE);
-        result.append(buffer);
+        for (size_t i = 0; i < numactive; ++i) {
+            sp<RecordTrack> track = mActiveTracks[i];
+            if (mTracks.indexOf(track) < 0) {
+                track->dump(buffer, SIZE, true);
+                result.append(buffer);
+            }
+        }
 
     }
     write(fd, result.string(), result.size());
 }
 
 // AudioBufferProvider interface
-status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts)
+status_t AudioFlinger::RecordThread::ResamplerBufferProvider::getNextBuffer(
+        AudioBufferProvider::Buffer* buffer, int64_t pts __unused)
 {
-    size_t framesReq = buffer->frameCount;
-    size_t framesReady = mFrameCount - mRsmpInIndex;
-    int channelCount;
-
-    if (framesReady == 0) {
-        mBytesRead = mInput->stream->read(mInput->stream, mRsmpInBuffer, mBufferSize);
-        if (mBytesRead <= 0) {
-            if ((mBytesRead < 0) && (mActiveTrack->mState == TrackBase::ACTIVE)) {
-                ALOGE("RecordThread::getNextBuffer() Error reading audio input");
-                // Force input into standby so that it tries to
-                // recover at next read attempt
-                inputStandBy();
-                usleep(kRecordThreadSleepUs);
-            }
-            buffer->raw = NULL;
-            buffer->frameCount = 0;
-            return NOT_ENOUGH_DATA;
-        }
-        mRsmpInIndex = 0;
-        framesReady = mFrameCount;
+    RecordTrack *activeTrack = mRecordTrack;
+    sp<ThreadBase> threadBase = activeTrack->mThread.promote();
+    if (threadBase == 0) {
+        buffer->frameCount = 0;
+        buffer->raw = NULL;
+        return NOT_ENOUGH_DATA;
+    }
+    RecordThread *recordThread = (RecordThread *) threadBase.get();
+    int32_t rear = recordThread->mRsmpInRear;
+    int32_t front = activeTrack->mRsmpInFront;
+    ssize_t filled = rear - front;
+    // FIXME should not be P2 (don't want to increase latency)
+    // FIXME if client not keeping up, discard
+    LOG_ALWAYS_FATAL_IF(!(0 <= filled && (size_t) filled <= recordThread->mRsmpInFrames));
+    // 'filled' may be non-contiguous, so return only the first contiguous chunk
+    front &= recordThread->mRsmpInFramesP2 - 1;
+    size_t part1 = recordThread->mRsmpInFramesP2 - front;
+    if (part1 > (size_t) filled) {
+        part1 = filled;
+    }
+    size_t ask = buffer->frameCount;
+    ALOG_ASSERT(ask > 0);
+    if (part1 > ask) {
+        part1 = ask;
+    }
+    if (part1 == 0) {
+        // Higher-level should keep mRsmpInBuffer full, and not call resampler if empty
+        LOG_ALWAYS_FATAL("RecordThread::getNextBuffer() starved");
+        buffer->raw = NULL;
+        buffer->frameCount = 0;
+        activeTrack->mRsmpInUnrel = 0;
+        return NOT_ENOUGH_DATA;
     }
 
-    if (framesReq > framesReady) {
-        framesReq = framesReady;
-    }
-
-    if (mChannelCount == 1 && mReqChannelCount == 2) {
-        channelCount = 1;
-    } else {
-        channelCount = 2;
-    }
-    buffer->raw = mRsmpInBuffer + mRsmpInIndex * channelCount;
-    buffer->frameCount = framesReq;
+    buffer->raw = recordThread->mRsmpInBuffer + front * recordThread->mChannelCount;
+    buffer->frameCount = part1;
+    activeTrack->mRsmpInUnrel = part1;
     return NO_ERROR;
 }
 
 // AudioBufferProvider interface
-void AudioFlinger::RecordThread::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+void AudioFlinger::RecordThread::ResamplerBufferProvider::releaseBuffer(
+        AudioBufferProvider::Buffer* buffer)
 {
-    mRsmpInIndex += buffer->frameCount;
+    RecordTrack *activeTrack = mRecordTrack;
+    size_t stepCount = buffer->frameCount;
+    if (stepCount == 0) {
+        return;
+    }
+    ALOG_ASSERT(stepCount <= activeTrack->mRsmpInUnrel);
+    activeTrack->mRsmpInUnrel -= stepCount;
+    activeTrack->mRsmpInFront += stepCount;
+    buffer->raw = NULL;
     buffer->frameCount = 0;
 }
 
@@ -5063,11 +5472,14 @@
         AudioParameter param = AudioParameter(keyValuePair);
         int value;
         audio_format_t reqFormat = mFormat;
-        uint32_t reqSamplingRate = mReqSampleRate;
-        uint32_t reqChannelCount = mReqChannelCount;
+        uint32_t samplingRate = mSampleRate;
+        audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(mChannelCount);
 
+        // TODO Investigate when this code runs. Check with audio policy when a sample rate and
+        //      channel count change can be requested. Do we mandate the first client defines the
+        //      HAL sampling rate and channel count or do we allow changes on the fly?
         if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
-            reqSamplingRate = value;
+            samplingRate = value;
             reconfig = true;
         }
         if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
@@ -5079,14 +5491,19 @@
             }
         }
         if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
-            reqChannelCount = popcount(value);
-            reconfig = true;
+            audio_channel_mask_t mask = (audio_channel_mask_t) value;
+            if (mask != AUDIO_CHANNEL_IN_MONO && mask != AUDIO_CHANNEL_IN_STEREO) {
+                status = BAD_VALUE;
+            } else {
+                channelMask = mask;
+                reconfig = true;
+            }
         }
         if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
             // do not accept frame count changes if tracks are open as the track buffer
             // size depends on frame count and correct behavior would not be guaranteed
             // if frame count is changed after track creation
-            if (mActiveTrack != 0) {
+            if (mActiveTracks.size() > 0) {
                 status = INVALID_OPERATION;
             } else {
                 reconfig = true;
@@ -5129,6 +5546,7 @@
             }
             mAudioSource = (audio_source_t)value;
         }
+
         if (status == NO_ERROR) {
             status = mInput->stream->common.set_parameters(&mInput->stream->common,
                     keyValuePair.string());
@@ -5142,14 +5560,15 @@
                     reqFormat == mInput->stream->common.get_format(&mInput->stream->common) &&
                     reqFormat == AUDIO_FORMAT_PCM_16_BIT &&
                     (mInput->stream->common.get_sample_rate(&mInput->stream->common)
-                            <= (2 * reqSamplingRate)) &&
+                            <= (2 * samplingRate)) &&
                     popcount(mInput->stream->common.get_channels(&mInput->stream->common))
                             <= FCC_2 &&
-                    (reqChannelCount <= FCC_2)) {
+                    (channelMask == AUDIO_CHANNEL_IN_MONO ||
+                            channelMask == AUDIO_CHANNEL_IN_STEREO)) {
                     status = NO_ERROR;
                 }
                 if (status == NO_ERROR) {
-                    readInputParameters();
+                    readInputParameters_l();
                     sendIoConfigEvent_l(AudioSystem::INPUT_CONFIG_CHANGED);
                 }
             }
@@ -5179,9 +5598,9 @@
     return out_s8;
 }
 
-void AudioFlinger::RecordThread::audioConfigChanged_l(int event, int param) {
+void AudioFlinger::RecordThread::audioConfigChanged_l(int event, int param __unused) {
     AudioSystem::OutputDescriptor desc;
-    void *param2 = NULL;
+    const void *param2 = NULL;
 
     switch (event) {
     case AudioSystem::INPUT_OPENED:
@@ -5201,53 +5620,35 @@
     mAudioFlinger->audioConfigChanged_l(event, mId, param2);
 }
 
-void AudioFlinger::RecordThread::readInputParameters()
+void AudioFlinger::RecordThread::readInputParameters_l()
 {
-    delete[] mRsmpInBuffer;
-    // mRsmpInBuffer is always assigned a new[] below
-    delete[] mRsmpOutBuffer;
-    mRsmpOutBuffer = NULL;
-    delete mResampler;
-    mResampler = NULL;
-
     mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common);
     mChannelMask = mInput->stream->common.get_channels(&mInput->stream->common);
     mChannelCount = popcount(mChannelMask);
     mFormat = mInput->stream->common.get_format(&mInput->stream->common);
     if (mFormat != AUDIO_FORMAT_PCM_16_BIT) {
-        ALOGE("HAL format %d not supported; must be AUDIO_FORMAT_PCM_16_BIT", mFormat);
+        ALOGE("HAL format %#x not supported; must be AUDIO_FORMAT_PCM_16_BIT", mFormat);
     }
     mFrameSize = audio_stream_frame_size(&mInput->stream->common);
     mBufferSize = mInput->stream->common.get_buffer_size(&mInput->stream->common);
     mFrameCount = mBufferSize / mFrameSize;
-    mRsmpInBuffer = new int16_t[mFrameCount * mChannelCount];
+    // This is the formula for calculating the temporary buffer size.
+    // With 7 HAL buffers, we can guarantee ability to down-sample the input by ratio of 6:1 to
+    // 1 full output buffer, regardless of the alignment of the available input.
+    // The value is somewhat arbitrary, and could probably be even larger.
+    // A larger value should allow more old data to be read after a track calls start(),
+    // without increasing latency.
+    mRsmpInFrames = mFrameCount * 7;
+    mRsmpInFramesP2 = roundup(mRsmpInFrames);
+    delete[] mRsmpInBuffer;
+    // Over-allocate beyond mRsmpInFramesP2 to permit a HAL read past end of buffer
+    mRsmpInBuffer = new int16_t[(mRsmpInFramesP2 + mFrameCount - 1) * mChannelCount];
 
-    if (mSampleRate != mReqSampleRate && mChannelCount <= FCC_2 && mReqChannelCount <= FCC_2)
-    {
-        int channelCount;
-        // optimization: if mono to mono, use the resampler in stereo to stereo mode to avoid
-        // stereo to mono post process as the resampler always outputs stereo.
-        if (mChannelCount == 1 && mReqChannelCount == 2) {
-            channelCount = 1;
-        } else {
-            channelCount = 2;
-        }
-        mResampler = AudioResampler::create(16, channelCount, mReqSampleRate);
-        mResampler->setSampleRate(mSampleRate);
-        mResampler->setVolume(AudioMixer::UNITY_GAIN, AudioMixer::UNITY_GAIN);
-        mRsmpOutBuffer = new int32_t[mFrameCount * FCC_2];
-
-        // optmization: if mono to mono, alter input frame count as if we were inputing
-        // stereo samples
-        if (mChannelCount == 1 && mReqChannelCount == 1) {
-            mFrameCount >>= 1;
-        }
-
-    }
-    mRsmpInIndex = mFrameCount;
+    // AudioRecord mSampleRate and mChannelCount are constant due to AudioRecord API constraints.
+    // But if thread's mSampleRate or mChannelCount changes, how will that affect active tracks?
 }
 
-unsigned int AudioFlinger::RecordThread::getInputFramesLost()
+uint32_t AudioFlinger::RecordThread::getInputFramesLost()
 {
     Mutex::Autolock _l(mLock);
     if (initCheck() != NO_ERROR) {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index a2fb874..59d5c66 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -36,6 +36,8 @@
                 audio_devices_t outDevice, audio_devices_t inDevice, type_t type);
     virtual             ~ThreadBase();
 
+    virtual status_t    readyToRun();
+
     void dumpBase(int fd, const Vector<String16>& args);
     void dumpEffectChains(int fd, const Vector<String16>& args);
 
@@ -63,7 +65,7 @@
     class IoConfigEvent : public ConfigEvent {
     public:
         IoConfigEvent(int event, int param) :
-            ConfigEvent(CFG_EVENT_IO), mEvent(event), mParam(event) {}
+            ConfigEvent(CFG_EVENT_IO), mEvent(event), mParam(param) {}
         virtual ~IoConfigEvent() {}
 
                 int event() const { return mEvent; }
@@ -141,6 +143,7 @@
                 void        sendIoConfigEvent_l(int event, int param = 0);
                 void        sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);
                 void        processConfigEvents();
+                void        processConfigEvents_l();
 
                 // see note at declaration of mStandby, mOutDevice and mInDevice
                 bool        standby() const { return mStandby; }
@@ -156,7 +159,7 @@
                                     int sessionId,
                                     effect_descriptor_t *desc,
                                     int *enabled,
-                                    status_t *status);
+                                    status_t *status /*non-NULL*/);
                 void disconnectEffect(const sp< EffectModule>& effect,
                                       EffectHandle *handle,
                                       bool unpinIfLast);
@@ -198,13 +201,13 @@
                 // effect
                 void removeEffect_l(const sp< EffectModule>& effect);
                 // detach all tracks connected to an auxiliary effect
-    virtual     void detachAuxEffect_l(int effectId) {}
+    virtual     void detachAuxEffect_l(int effectId __unused) {}
                 // returns either EFFECT_SESSION if effects on this audio session exist in one
                 // chain, or TRACK_SESSION if tracks on this audio session exist, or both
                 virtual uint32_t hasAudioSession(int sessionId) const = 0;
                 // the value returned by default implementation is not important as the
                 // strategy is only meaningful for PlaybackThread which implements this method
-                virtual uint32_t getStrategyForSession_l(int sessionId) { return 0; }
+                virtual uint32_t getStrategyForSession_l(int sessionId __unused) { return 0; }
 
                 // suspend or restore effect according to the type of effect passed. a NULL
                 // type pointer means suspend all effects in the session
@@ -267,14 +270,15 @@
 
                 const sp<AudioFlinger>  mAudioFlinger;
 
-                // updated by PlaybackThread::readOutputParameters() or
-                // RecordThread::readInputParameters()
+                // updated by PlaybackThread::readOutputParameters_l() or
+                // RecordThread::readInputParameters_l()
                 uint32_t                mSampleRate;
                 size_t                  mFrameCount;       // output HAL, direct output, record
                 audio_channel_mask_t    mChannelMask;
                 uint32_t                mChannelCount;
                 size_t                  mFrameSize;
                 audio_format_t          mFormat;
+                size_t                  mBufferSize;       // HAL buffer size for read() or write()
 
                 // Parameter sequence by client: binder thread calling setParameters():
                 //  1. Lock mLock
@@ -303,12 +307,12 @@
                 Vector<ConfigEvent *>     mConfigEvents;
 
                 // These fields are written and read by thread itself without lock or barrier,
-                // and read by other threads without lock or barrier via standby() , outDevice()
+                // and read by other threads without lock or barrier via standby(), outDevice()
                 // and inDevice().
                 // Because of the absence of a lock or barrier, any other thread that reads
                 // these fields must use the information in isolation, or be prepared to deal
                 // with possibility that it might be inconsistent with other information.
-                bool                    mStandby;   // Whether thread is currently in standby.
+                bool                    mStandby;     // Whether thread is currently in standby.
                 audio_devices_t         mOutDevice;   // output device
                 audio_devices_t         mInDevice;    // input device
                 audio_source_t          mAudioSource; // (see audio.h, audio_source_t)
@@ -358,7 +362,6 @@
                 void        dump(int fd, const Vector<String16>& args);
 
     // Thread virtuals
-    virtual     status_t    readyToRun();
     virtual     bool        threadLoop();
 
     // RefBase
@@ -391,7 +394,7 @@
     virtual     bool        waitingAsyncCallback();
     virtual     bool        waitingAsyncCallback_l();
     virtual     bool        shouldStandby_l();
-
+    virtual     void        onAddNewTrack_l();
 
     // ThreadBase virtuals
     virtual     void        preExit();
@@ -419,13 +422,13 @@
                                 uint32_t sampleRate,
                                 audio_format_t format,
                                 audio_channel_mask_t channelMask,
-                                size_t frameCount,
+                                size_t *pFrameCount,
                                 const sp<IMemory>& sharedBuffer,
                                 int sessionId,
                                 IAudioFlinger::track_flags_t *flags,
                                 pid_t tid,
                                 int uid,
-                                status_t *status);
+                                status_t *status /*non-NULL*/);
 
                 AudioStreamOut* getOutput() const;
                 AudioStreamOut* clearOutput();
@@ -447,7 +450,11 @@
     virtual     String8     getParameters(const String8& keys);
     virtual     void        audioConfigChanged_l(int event, int param = 0);
                 status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
-                int16_t     *mixBuffer() const { return mMixBuffer; };
+                // FIXME rename mixBuffer() to sinkBuffer() and remove int16_t* dependency.
+                // Consider also removing and passing an explicit mMainBuffer initialization
+                // parameter to AF::PlaybackThread::Track::Track().
+                int16_t     *mixBuffer() const {
+                    return reinterpret_cast<int16_t *>(mSinkBuffer); };
 
     virtual     void detachAuxEffect_l(int effectId);
                 status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track,
@@ -475,11 +482,68 @@
                 status_t         getTimestamp_l(AudioTimestamp& timestamp);
 
 protected:
-    // updated by readOutputParameters()
+    // updated by readOutputParameters_l()
     size_t                          mNormalFrameCount;  // normal mixer and effects
 
-    int16_t*                        mMixBuffer;         // frame size aligned mix buffer
-    int8_t*                         mAllocMixBuffer;    // mixer buffer allocation address
+    void*                           mSinkBuffer;         // frame size aligned sink buffer
+
+    // TODO:
+    // Rearrange the buffer info into a struct/class with
+    // clear, copy, construction, destruction methods.
+    //
+    // mSinkBuffer also has associated with it:
+    //
+    // mSinkBufferSize: Sink Buffer Size
+    // mFormat: Sink Buffer Format
+
+    // Mixer Buffer (mMixerBuffer*)
+    //
+    // In the case of floating point or multichannel data, which is not in the
+    // sink format, it is required to accumulate in a higher precision or greater channel count
+    // buffer before downmixing or data conversion to the sink buffer.
+
+    // Set to "true" to enable the Mixer Buffer otherwise mixer output goes to sink buffer.
+    bool                            mMixerBufferEnabled;
+
+    // Storage, 32 byte aligned (may make this alignment a requirement later).
+    // Due to constraints on mNormalFrameCount, the buffer size is a multiple of 16 frames.
+    void*                           mMixerBuffer;
+
+    // Size of mMixerBuffer in bytes: mNormalFrameCount * #channels * sampsize.
+    size_t                          mMixerBufferSize;
+
+    // The audio format of mMixerBuffer. Set to AUDIO_FORMAT_PCM_(FLOAT|16_BIT) only.
+    audio_format_t                  mMixerBufferFormat;
+
+    // An internal flag set to true by MixerThread::prepareTracks_l()
+    // when mMixerBuffer contains valid data after mixing.
+    bool                            mMixerBufferValid;
+
+    // Effects Buffer (mEffectsBuffer*)
+    //
+    // In the case of effects data, which is not in the sink format,
+    // it is required to accumulate in a different buffer before data conversion
+    // to the sink buffer.
+
+    // Set to "true" to enable the Effects Buffer otherwise effects output goes to sink buffer.
+    bool                            mEffectBufferEnabled;
+
+    // Storage, 32 byte aligned (may make this alignment a requirement later).
+    // Due to constraints on mNormalFrameCount, the buffer size is a multiple of 16 frames.
+    void*                           mEffectBuffer;
+
+    // Size of mEffectsBuffer in bytes: mNormalFrameCount * #channels * sampsize.
+    size_t                          mEffectBufferSize;
+
+    // The audio format of mEffectsBuffer. Set to AUDIO_FORMAT_PCM_16_BIT only.
+    audio_format_t                  mEffectBufferFormat;
+
+    // An internal flag set to true by MixerThread::prepareTracks_l()
+    // when mEffectsBuffer contains valid data after mixing.
+    //
+    // When this is set, all mixer data is routed into the effects buffer
+    // for any processing (including output processing).
+    bool                            mEffectBufferValid;
 
     // suspend count, > 0 means suspended.  While suspended, the thread continues to pull from
     // tracks and mix, but doesn't write to HAL.  A2DP and SCO HAL implementations can't handle
@@ -539,7 +603,7 @@
     void        removeTrack_l(const sp<Track>& track);
     void        broadcast_l();
 
-    void        readOutputParameters();
+    void        readOutputParameters_l();
 
     virtual void dumpInternals(int fd, const Vector<String16>& args);
     void        dumpTracks(int fd, const Vector<String16>& args);
@@ -558,7 +622,7 @@
 
     // FIXME rename these former local variables of threadLoop to standard "m" names
     nsecs_t                         standbyTime;
-    size_t                          mixBufferSize;
+    size_t                          mSinkBufferSize;
 
     // cached copies of activeSleepTimeUs() and idleSleepTimeUs() made by cacheParameters_l()
     uint32_t                        activeSleepTime;
@@ -623,13 +687,12 @@
     sp<NBLog::Writer>       mFastMixerNBLogWriter;
 public:
     virtual     bool        hasFastMixer() const = 0;
-    virtual     FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex) const
+    virtual     FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex __unused) const
                                 { FastTrackUnderruns dummy; return dummy; }
 
 protected:
                 // accessed by both binder threads and within threadLoop(), lock on mutex needed
                 unsigned    mFastTrackAvailMask;    // bit i set if fast track [i] is available
-    virtual     void        flushOutput_l();
 
 private:
     // timestamp latch:
@@ -748,11 +811,11 @@
     // threadLoop snippets
     virtual     mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
     virtual     void        threadLoop_exit();
-    virtual     void        flushOutput_l();
 
     virtual     bool        waitingAsyncCallback();
     virtual     bool        waitingAsyncCallback_l();
     virtual     bool        shouldStandby_l();
+    virtual     void        onAddNewTrack_l();
 
 private:
                 void        flushHw_l();
@@ -838,17 +901,28 @@
 
 
 // record thread
-class RecordThread : public ThreadBase, public AudioBufferProvider
-                        // derives from AudioBufferProvider interface for use by resampler
+class RecordThread : public ThreadBase
 {
 public:
 
+    class RecordTrack;
+    class ResamplerBufferProvider : public AudioBufferProvider
+                        // derives from AudioBufferProvider interface for use by resampler
+    {
+    public:
+        ResamplerBufferProvider(RecordTrack* recordTrack) : mRecordTrack(recordTrack) { }
+        virtual ~ResamplerBufferProvider() { }
+        // AudioBufferProvider interface
+        virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts);
+        virtual void        releaseBuffer(AudioBufferProvider::Buffer* buffer);
+    private:
+        RecordTrack * const mRecordTrack;
+    };
+
 #include "RecordTracks.h"
 
             RecordThread(const sp<AudioFlinger>& audioFlinger,
                     AudioStreamIn *input,
-                    uint32_t sampleRate,
-                    audio_channel_mask_t channelMask,
                     audio_io_handle_t id,
                     audio_devices_t outDevice,
                     audio_devices_t inDevice
@@ -867,23 +941,23 @@
 
     // Thread virtuals
     virtual bool        threadLoop();
-    virtual status_t    readyToRun();
 
     // RefBase
     virtual void        onFirstRef();
 
     virtual status_t    initCheck() const { return (mInput == NULL) ? NO_INIT : NO_ERROR; }
+
             sp<AudioFlinger::RecordThread::RecordTrack>  createRecordTrack_l(
                     const sp<AudioFlinger::Client>& client,
                     uint32_t sampleRate,
                     audio_format_t format,
                     audio_channel_mask_t channelMask,
-                    size_t frameCount,
+                    size_t *pFrameCount,
                     int sessionId,
                     int uid,
                     IAudioFlinger::track_flags_t *flags,
                     pid_t tid,
-                    status_t *status);
+                    status_t *status /*non-NULL*/);
 
             status_t    start(RecordTrack* recordTrack,
                               AudioSystem::sync_event_t event,
@@ -897,15 +971,12 @@
             AudioStreamIn* clearInput();
             virtual audio_stream_t* stream() const;
 
-    // AudioBufferProvider interface
-    virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts);
-    virtual void        releaseBuffer(AudioBufferProvider::Buffer* buffer);
 
     virtual bool        checkForNewParameters_l();
     virtual String8     getParameters(const String8& keys);
     virtual void        audioConfigChanged_l(int event, int param = 0);
-            void        readInputParameters();
-    virtual unsigned int  getInputFramesLost();
+            void        readInputParameters_l();
+    virtual uint32_t    getInputFramesLost();
 
     virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
     virtual size_t removeEffectChain_l(const sp<EffectChain>& chain);
@@ -920,44 +991,33 @@
     virtual bool     isValidSyncEvent(const sp<SyncEvent>& event) const;
 
     static void syncStartEventCallback(const wp<SyncEvent>& event);
-           void handleSyncStartEvent(const sp<SyncEvent>& event);
 
     virtual size_t      frameCount() const { return mFrameCount; }
             bool        hasFastRecorder() const { return false; }
 
 private:
-            void clearSyncStartEvent();
-
             // Enter standby if not already in standby, and set mStandby flag
-            void standby();
+            void    standbyIfNotAlreadyInStandby();
 
             // Call the HAL standby method unconditionally, and don't change mStandby flag
-            void inputStandBy();
+            void    inputStandBy();
 
             AudioStreamIn                       *mInput;
             SortedVector < sp<RecordTrack> >    mTracks;
-            // mActiveTrack has dual roles:  it indicates the current active track, and
+            // mActiveTracks has dual roles:  it indicates the current active track(s), and
             // is used together with mStartStopCond to indicate start()/stop() progress
-            sp<RecordTrack>                     mActiveTrack;
+            SortedVector< sp<RecordTrack> >     mActiveTracks;
+            // generation counter for mActiveTracks
+            int                                 mActiveTracksGen;
             Condition                           mStartStopCond;
 
-            // updated by RecordThread::readInputParameters()
-            AudioResampler                      *mResampler;
-            // interleaved stereo pairs of fixed-point signed Q19.12
-            int32_t                             *mRsmpOutBuffer;
-            int16_t                             *mRsmpInBuffer; // [mFrameCount * mChannelCount]
-            size_t                              mRsmpInIndex;
-            size_t                              mBufferSize;    // stream buffer size for read()
-            const uint32_t                      mReqChannelCount;
-            const uint32_t                      mReqSampleRate;
-            ssize_t                             mBytesRead;
-            // sync event triggering actual audio capture. Frames read before this event will
-            // be dropped and therefore not read by the application.
-            sp<SyncEvent>                       mSyncStartEvent;
-            // number of captured frames to drop after the start sync event has been received.
-            // when < 0, maximum frames to drop before starting capture even if sync event is
-            // not received
-            ssize_t                             mFramestoDrop;
+            // resampler converts input at HAL Hz to output at AudioRecord client Hz
+            int16_t                             *mRsmpInBuffer; // see new[] for details on the size
+            size_t                              mRsmpInFrames;  // size of resampler input in frames
+            size_t                              mRsmpInFramesP2;// size rounded up to a power-of-2
+
+            // rolling index that is never cleared
+            int32_t                             mRsmpInRear;    // last filled frame + 1
 
             // For dumpsys
             const sp<NBAIO_Sink>                mTeeSink;
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index cd201d9..58705c4 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -34,7 +34,9 @@
         RESUMING,
         ACTIVE,
         PAUSING,
-        PAUSED
+        PAUSED,
+        STARTING_1,     // for RecordTrack only
+        STARTING_2,     // for RecordTrack only
     };
 
                         TrackBase(ThreadBase *thread,
@@ -48,6 +50,7 @@
                                 int uid,
                                 bool isOut);
     virtual             ~TrackBase();
+    virtual status_t    initCheck() const { return getCblk() != 0 ? NO_ERROR : NO_MEMORY; }
 
     virtual status_t    start(AudioSystem::sync_event_t event,
                              int triggerSession) = 0;
@@ -78,15 +81,6 @@
 
     virtual uint32_t sampleRate() const { return mSampleRate; }
 
-    // Return a pointer to the start of a contiguous slice of the track buffer.
-    // Parameter 'offset' is the requested start position, expressed in
-    // monotonically increasing frame units relative to the track epoch.
-    // Parameter 'frames' is the requested length, also in frame units.
-    // Always returns non-NULL.  It is the caller's responsibility to
-    // verify that this will be successful; the result of calling this
-    // function with invalid 'offset' or 'frames' is undefined.
-    void* getBuffer(uint32_t offset, uint32_t frames) const;
-
     bool isStopped() const {
         return (mState == STOPPED || mState == FLUSHED);
     }
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 813ec8a..f19cd88 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -116,12 +116,11 @@
 
     if (client != 0) {
         mCblkMemory = client->heap()->allocate(size);
-        if (mCblkMemory != 0) {
-            mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer());
-            // can't assume mCblk != NULL
-        } else {
+        if (mCblkMemory == 0 ||
+                (mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer())) == NULL) {
             ALOGE("not enough memory for AudioTrack size=%u", size);
             client->heap()->dump("AudioTrack");
+            mCblkMemory.clear();
             return;
         }
     } else {
@@ -134,7 +133,6 @@
     if (mCblk != NULL) {
         new(mCblk) audio_track_cblk_t();
         // clear all buffers
-        mCblk->frameCount_ = frameCount;
         if (sharedBuffer == 0) {
             mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
             memset(mBuffer, 0, bufferSize);
@@ -148,7 +146,7 @@
 #ifdef TEE_SINK
         if (mTeeSinkTrackEnabled) {
             NBAIO_Format pipeFormat = Format_from_SR_C(mSampleRate, mChannelCount);
-            if (pipeFormat != Format_Invalid) {
+            if (Format_isValid(pipeFormat)) {
                 Pipe *pipe = new Pipe(mTeeSinkTrackFrames, pipeFormat);
                 size_t numCounterOffers = 0;
                 const NBAIO_Format offers[1] = {pipeFormat};
@@ -275,6 +273,11 @@
     if (!mTrack->isTimedTrack())
         return INVALID_OPERATION;
 
+    if (buffer == 0 || buffer->pointer() == NULL) {
+        ALOGE("queueTimedBuffer() buffer is 0 or has NULL pointer()");
+        return BAD_VALUE;
+    }
+
     PlaybackThread::TimedTrack* tt =
             reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get());
     return tt->queueTimedBuffer(buffer, pts);
@@ -344,41 +347,42 @@
     mCachedVolume(1.0),
     mIsInvalid(false),
     mAudioTrackServerProxy(NULL),
-    mResumeToStopping(false)
+    mResumeToStopping(false),
+    mFlushHwPending(false)
 {
-    if (mCblk != NULL) {
-        if (sharedBuffer == 0) {
-            mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount,
-                    mFrameSize);
-        } else {
-            mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount,
-                    mFrameSize);
-        }
-        mServerProxy = mAudioTrackServerProxy;
-        // to avoid leaking a track name, do not allocate one unless there is an mCblk
-        mName = thread->getTrackName_l(channelMask, sessionId);
-        if (mName < 0) {
-            ALOGE("no more track names available");
-            return;
-        }
-        // only allocate a fast track index if we were able to allocate a normal track name
-        if (flags & IAudioFlinger::TRACK_FAST) {
-            mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads();
-            ALOG_ASSERT(thread->mFastTrackAvailMask != 0);
-            int i = __builtin_ctz(thread->mFastTrackAvailMask);
-            ALOG_ASSERT(0 < i && i < (int)FastMixerState::kMaxFastTracks);
-            // FIXME This is too eager.  We allocate a fast track index before the
-            //       fast track becomes active.  Since fast tracks are a scarce resource,
-            //       this means we are potentially denying other more important fast tracks from
-            //       being created.  It would be better to allocate the index dynamically.
-            mFastIndex = i;
-            // Read the initial underruns because this field is never cleared by the fast mixer
-            mObservedUnderruns = thread->getFastTrackUnderruns(i);
-            thread->mFastTrackAvailMask &= ~(1 << i);
-        }
+    if (mCblk == NULL) {
+        return;
     }
-    ALOGV("Track constructor name %d, calling pid %d", mName,
-            IPCThreadState::self()->getCallingPid());
+
+    if (sharedBuffer == 0) {
+        mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount,
+                mFrameSize);
+    } else {
+        mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount,
+                mFrameSize);
+    }
+    mServerProxy = mAudioTrackServerProxy;
+
+    mName = thread->getTrackName_l(channelMask, sessionId);
+    if (mName < 0) {
+        ALOGE("no more track names available");
+        return;
+    }
+    // only allocate a fast track index if we were able to allocate a normal track name
+    if (flags & IAudioFlinger::TRACK_FAST) {
+        mAudioTrackServerProxy->framesReadyIsCalledByMultipleThreads();
+        ALOG_ASSERT(thread->mFastTrackAvailMask != 0);
+        int i = __builtin_ctz(thread->mFastTrackAvailMask);
+        ALOG_ASSERT(0 < i && i < (int)FastMixerState::kMaxFastTracks);
+        // FIXME This is too eager.  We allocate a fast track index before the
+        //       fast track becomes active.  Since fast tracks are a scarce resource,
+        //       this means we are potentially denying other more important fast tracks from
+        //       being created.  It would be better to allocate the index dynamically.
+        mFastIndex = i;
+        // Read the initial underruns because this field is never cleared by the fast mixer
+        mObservedUnderruns = thread->getFastTrackUnderruns(i);
+        thread->mFastTrackAvailMask &= ~(1 << i);
+    }
 }
 
 AudioFlinger::PlaybackThread::Track::~Track()
@@ -396,6 +400,15 @@
     }
 }
 
+status_t AudioFlinger::PlaybackThread::Track::initCheck() const
+{
+    status_t status = TrackBase::initCheck();
+    if (status == NO_ERROR && mName < 0) {
+        status = NO_MEMORY;
+    }
+    return status;
+}
+
 void AudioFlinger::PlaybackThread::Track::destroy()
 {
     // NOTE: destroyTrack_l() can remove a strong reference to this Track
@@ -422,17 +435,19 @@
 
 /*static*/ void AudioFlinger::PlaybackThread::Track::appendDumpHeader(String8& result)
 {
-    result.append("   Name Client Type      Fmt Chn mask Session fCount S F SRate  "
+    result.append("    Name Active Client Type      Fmt Chn mask Session fCount S F SRate  "
                   "L dB  R dB    Server Main buf  Aux Buf Flags UndFrmCnt\n");
 }
 
-void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size)
+void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size, bool active)
 {
     uint32_t vlr = mAudioTrackServerProxy->getVolumeLR();
     if (isFastTrack()) {
-        sprintf(buffer, "   F %2d", mFastIndex);
+        sprintf(buffer, "    F %2d", mFastIndex);
+    } else if (mName >= AudioMixer::TRACK0) {
+        sprintf(buffer, "    %4d", mName - AudioMixer::TRACK0);
     } else {
-        sprintf(buffer, "   %4d", mName - AudioMixer::TRACK0);
+        sprintf(buffer, "    none");
     }
     track_state state = mState;
     char stateChar;
@@ -487,8 +502,9 @@
         nowInUnderrun = '?';
         break;
     }
-    snprintf(&buffer[7], size-7, " %6u %4u %08X %08X %7u %6zu %1c %1d %5u %5.2g %5.2g  "
+    snprintf(&buffer[8], size-8, " %6s %6u %4u %08X %08X %7u %6zu %1c %1d %5u %5.2g %5.2g  "
                                  "%08X %p %p 0x%03X %9u%c\n",
+            active ? "yes" : "no",
             (mClient == 0) ? getpid_cached : mClient->pid(),
             mStreamType,
             mFormat,
@@ -514,7 +530,7 @@
 
 // AudioBufferProvider interface
 status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(
-        AudioBufferProvider::Buffer* buffer, int64_t pts)
+        AudioBufferProvider::Buffer* buffer, int64_t pts __unused)
 {
     ServerProxy::Buffer buf;
     size_t desiredFrames = buffer->frameCount;
@@ -564,8 +580,8 @@
     return false;
 }
 
-status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t event,
-                                                    int triggerSession)
+status_t AudioFlinger::PlaybackThread::Track::start(AudioSystem::sync_event_t event __unused,
+                                                    int triggerSession __unused)
 {
     status_t status = NO_ERROR;
     ALOGV("start(%d), calling pid %d session %d",
@@ -719,6 +735,7 @@
                 mRetryCount = PlaybackThread::kMaxTrackRetriesOffload;
             }
 
+            mFlushHwPending = true;
             mResumeToStopping = false;
         } else {
             if (mState != STOPPING_1 && mState != STOPPING_2 && mState != STOPPED &&
@@ -739,11 +756,19 @@
         // Prevent flush being lost if the track is flushed and then resumed
         // before mixer thread can run. This is important when offloading
         // because the hardware buffer could hold a large amount of audio
-        playbackThread->flushOutput_l();
         playbackThread->broadcast_l();
     }
 }
 
+// must be called with thread lock held
+void AudioFlinger::PlaybackThread::Track::flushAck()
+{
+    if (!isOffloaded())
+        return;
+
+    mFlushHwPending = false;
+}
+
 void AudioFlinger::PlaybackThread::Track::reset()
 {
     // Do not reset twice to avoid discarding data written just after a flush and before
@@ -979,7 +1004,8 @@
             size_t frameCount,
             const sp<IMemory>& sharedBuffer,
             int sessionId,
-            int uid) {
+            int uid)
+{
     if (!client->reserveTimedTrack())
         return 0;
 
@@ -1045,15 +1071,14 @@
 
         mTimedMemoryDealer = new MemoryDealer(kTimedBufferHeapSize,
                                               "AudioFlingerTimed");
-        if (mTimedMemoryDealer == NULL)
+        if (mTimedMemoryDealer == NULL) {
             return NO_MEMORY;
+        }
     }
 
     sp<IMemory> newBuffer = mTimedMemoryDealer->allocate(size);
-    if (newBuffer == NULL) {
-        newBuffer = mTimedMemoryDealer->allocate(size);
-        if (newBuffer == NULL)
-            return NO_MEMORY;
+    if (newBuffer == 0 || newBuffer->pointer() == NULL) {
+        return NO_MEMORY;
     }
 
     *buffer = newBuffer;
@@ -1152,7 +1177,7 @@
 
 void AudioFlinger::PlaybackThread::TimedTrack::updateFramesPendingAfterTrim_l(
         const TimedBuffer& buf,
-        const char* logTag) {
+        const char* logTag __unused) {
     uint32_t bufBytes        = buf.buffer()->size();
     uint32_t consumedAlready = buf.position();
 
@@ -1504,9 +1529,9 @@
         mOutBuffer.frameCount = 0;
         playbackThread->mTracks.add(this);
         ALOGV("OutputTrack constructor mCblk %p, mBuffer %p, "
-                "mCblk->frameCount_ %u, mChannelMask 0x%08x",
+                "frameCount %u, mChannelMask 0x%08x",
                 mCblk, mBuffer,
-                mCblk->frameCount_, mChannelMask);
+                frameCount, mChannelMask);
         // since client and server are in the same process,
         // the buffer has the same virtual address on both sides
         mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize);
@@ -1748,7 +1773,7 @@
 
 // ----------------------------------------------------------------------------
 
-// RecordTrack constructor must be called with AudioFlinger::mLock held
+// RecordTrack constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held
 AudioFlinger::RecordThread::RecordTrack::RecordTrack(
             RecordThread *thread,
             const sp<Client>& client,
@@ -1760,24 +1785,40 @@
             int uid)
     :   TrackBase(thread, client, sampleRate, format,
                   channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, uid, false /*isOut*/),
-        mOverflow(false)
+        mOverflow(false), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpOutFrameCount(0),
+        // See real initialization of mRsmpInFront at RecordThread::start()
+        mRsmpInUnrel(0), mRsmpInFront(0), mFramesToDrop(0), mResamplerBufferProvider(NULL)
 {
-    ALOGV("RecordTrack constructor");
-    if (mCblk != NULL) {
-        mAudioRecordServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount,
-                mFrameSize);
-        mServerProxy = mAudioRecordServerProxy;
+    if (mCblk == NULL) {
+        return;
+    }
+
+    mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount, mFrameSize);
+
+    uint32_t channelCount = popcount(channelMask);
+    // FIXME I don't understand either of the channel count checks
+    if (thread->mSampleRate != sampleRate && thread->mChannelCount <= FCC_2 &&
+            channelCount <= FCC_2) {
+        // sink SR
+        mResampler = AudioResampler::create(16, thread->mChannelCount, sampleRate);
+        // source SR
+        mResampler->setSampleRate(thread->mSampleRate);
+        mResampler->setVolume(AudioMixer::UNITY_GAIN, AudioMixer::UNITY_GAIN);
+        mResamplerBufferProvider = new ResamplerBufferProvider(this);
     }
 }
 
 AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
 {
     ALOGV("%s", __func__);
+    delete mResampler;
+    delete[] mRsmpOutBuffer;
+    delete mResamplerBufferProvider;
 }
 
 // AudioBufferProvider interface
 status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer,
-        int64_t pts)
+        int64_t pts __unused)
 {
     ServerProxy::Buffer buf;
     buf.mFrameCount = buffer->frameCount;
@@ -1845,19 +1886,45 @@
 
 /*static*/ void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result)
 {
-    result.append("Client Fmt Chn mask Session S   Server fCount\n");
+    result.append("    Active Client Fmt Chn mask Session S   Server fCount Resampling\n");
 }
 
-void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size)
+void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size, bool active)
 {
-    snprintf(buffer, size, "%6u %3u %08X %7u %1d %08X %6zu\n",
+    snprintf(buffer, size, "    %6s %6u %3u %08X %7u %1d %08X %6zu %10d\n",
+            active ? "yes" : "no",
             (mClient == 0) ? getpid_cached : mClient->pid(),
             mFormat,
             mChannelMask,
             mSessionId,
             mState,
             mCblk->mServer,
-            mFrameCount);
+            mFrameCount,
+            mResampler != NULL);
+
+}
+
+void AudioFlinger::RecordThread::RecordTrack::handleSyncStartEvent(const sp<SyncEvent>& event)
+{
+    if (event == mSyncStartEvent) {
+        ssize_t framesToDrop = 0;
+        sp<ThreadBase> threadBase = mThread.promote();
+        if (threadBase != 0) {
+            // TODO: use actual buffer filling status instead of 2 buffers when info is available
+            // from audio HAL
+            framesToDrop = threadBase->mFrameCount * 2;
+        }
+        mFramesToDrop = framesToDrop;
+    }
+}
+
+void AudioFlinger::RecordThread::RecordTrack::clearSyncStartEvent()
+{
+    if (mSyncStartEvent != 0) {
+        mSyncStartEvent->cancel();
+        mSyncStartEvent.clear();
+    }
+    mFramesToDrop = 0;
 }
 
 }; // namespace android
diff --git a/services/audioflinger/test-resample.cpp b/services/audioflinger/test-resample.cpp
index 7a314cf..3ab3ba9 100644
--- a/services/audioflinger/test-resample.cpp
+++ b/services/audioflinger/test-resample.cpp
@@ -26,77 +26,104 @@
 #include <errno.h>
 #include <time.h>
 #include <math.h>
+#include <audio_utils/sndfile.h>
+#include <utils/Vector.h>
 
 using namespace android;
 
-struct HeaderWav {
-    HeaderWav(size_t size, int nc, int sr, int bits) {
-        strncpy(RIFF, "RIFF", 4);
-        chunkSize = size + sizeof(HeaderWav);
-        strncpy(WAVE, "WAVE", 4);
-        strncpy(fmt,  "fmt ", 4);
-        fmtSize = 16;
-        audioFormat = 1;
-        numChannels = nc;
-        samplesRate = sr;
-        byteRate = sr * numChannels * (bits/8);
-        align = nc*(bits/8);
-        bitsPerSample = bits;
-        strncpy(data, "data", 4);
-        dataSize = size;
-    }
-
-    char RIFF[4];           // RIFF
-    uint32_t chunkSize;     // File size
-    char WAVE[4];        // WAVE
-    char fmt[4];            // fmt\0
-    uint32_t fmtSize;       // fmt size
-    uint16_t audioFormat;   // 1=PCM
-    uint16_t numChannels;   // num channels
-    uint32_t samplesRate;   // sample rate in hz
-    uint32_t byteRate;      // Bps
-    uint16_t align;         // 2=16-bit mono, 4=16-bit stereo
-    uint16_t bitsPerSample; // bits per sample
-    char data[4];           // "data"
-    uint32_t dataSize;      // size
-};
+bool gVerbose = false;
 
 static int usage(const char* name) {
-    fprintf(stderr,"Usage: %s [-p] [-h] [-s] [-q {dq|lq|mq|hq|vhq}] [-i input-sample-rate] "
-                   "[-o output-sample-rate] [<input-file>] <output-file>\n", name);
+    fprintf(stderr,"Usage: %s [-p] [-h] [-v] [-s] [-q {dq|lq|mq|hq|vhq|dlq|dmq|dhq}]"
+                   " [-i input-sample-rate] [-o output-sample-rate] [-O csv] [-P csv] [<input-file>]"
+                   " <output-file>\n", name);
     fprintf(stderr,"    -p    enable profiling\n");
     fprintf(stderr,"    -h    create wav file\n");
-    fprintf(stderr,"    -s    stereo\n");
+    fprintf(stderr,"    -v    verbose : log buffer provider calls\n");
+    fprintf(stderr,"    -s    stereo (ignored if input file is specified)\n");
     fprintf(stderr,"    -q    resampler quality\n");
     fprintf(stderr,"              dq  : default quality\n");
     fprintf(stderr,"              lq  : low quality\n");
     fprintf(stderr,"              mq  : medium quality\n");
     fprintf(stderr,"              hq  : high quality\n");
     fprintf(stderr,"              vhq : very high quality\n");
-    fprintf(stderr,"    -i    input file sample rate\n");
+    fprintf(stderr,"              dlq : dynamic low quality\n");
+    fprintf(stderr,"              dmq : dynamic medium quality\n");
+    fprintf(stderr,"              dhq : dynamic high quality\n");
+    fprintf(stderr,"    -i    input file sample rate (ignored if input file is specified)\n");
     fprintf(stderr,"    -o    output file sample rate\n");
+    fprintf(stderr,"    -O    # frames output per call to resample() in CSV format\n");
+    fprintf(stderr,"    -P    # frames provided per call to resample() in CSV format\n");
     return -1;
 }
 
+// Convert a list of integers in CSV format to a Vector of those values.
+// Returns the number of elements in the list, or -1 on error.
+int parseCSV(const char *string, Vector<int>& values)
+{
+    // pass 1: count the number of values and do syntax check
+    size_t numValues = 0;
+    bool hadDigit = false;
+    for (const char *p = string; ; ) {
+        switch (*p++) {
+        case '0': case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+            hadDigit = true;
+            break;
+        case '\0':
+            if (hadDigit) {
+                // pass 2: allocate and initialize vector of values
+                values.resize(++numValues);
+                values.editItemAt(0) = atoi(p = optarg);
+                for (size_t i = 1; i < numValues; ) {
+                    if (*p++ == ',') {
+                        values.editItemAt(i++) = atoi(p);
+                    }
+                }
+                return numValues;
+            }
+            // fall through
+        case ',':
+            if (hadDigit) {
+                hadDigit = false;
+                numValues++;
+                break;
+            }
+            // fall through
+        default:
+            return -1;
+        }
+    }
+}
+
 int main(int argc, char* argv[]) {
 
     const char* const progname = argv[0];
-    bool profiling = false;
+    bool profileResample = false;
+    bool profileFilter = false;
     bool writeHeader = false;
     int channels = 1;
     int input_freq = 0;
     int output_freq = 0;
     AudioResampler::src_quality quality = AudioResampler::DEFAULT_QUALITY;
+    Vector<int> Ovalues;
+    Vector<int> Pvalues;
 
     int ch;
-    while ((ch = getopt(argc, argv, "phsq:i:o:")) != -1) {
+    while ((ch = getopt(argc, argv, "pfhvsq:i:o:O:P:")) != -1) {
         switch (ch) {
         case 'p':
-            profiling = true;
+            profileResample = true;
+            break;
+        case 'f':
+            profileFilter = true;
             break;
         case 'h':
             writeHeader = true;
             break;
+        case 'v':
+            gVerbose = true;
+            break;
         case 's':
             channels = 2;
             break;
@@ -111,6 +138,12 @@
                 quality = AudioResampler::HIGH_QUALITY;
             else if (!strcmp(optarg, "vhq"))
                 quality = AudioResampler::VERY_HIGH_QUALITY;
+            else if (!strcmp(optarg, "dlq"))
+                quality = AudioResampler::DYN_LOW_QUALITY;
+            else if (!strcmp(optarg, "dmq"))
+                quality = AudioResampler::DYN_MED_QUALITY;
+            else if (!strcmp(optarg, "dhq"))
+                quality = AudioResampler::DYN_HIGH_QUALITY;
             else {
                 usage(progname);
                 return -1;
@@ -122,6 +155,18 @@
         case 'o':
             output_freq = atoi(optarg);
             break;
+        case 'O':
+            if (parseCSV(optarg, Ovalues) < 0) {
+                fprintf(stderr, "incorrect syntax for -O option\n");
+                return -1;
+            }
+            break;
+        case 'P':
+            if (parseCSV(optarg, Pvalues) < 0) {
+                fprintf(stderr, "incorrect syntax for -P option\n");
+                return -1;
+            }
+            break;
         case '?':
         default:
             usage(progname);
@@ -148,25 +193,22 @@
     size_t input_size;
     void* input_vaddr;
     if (argc == 2) {
-        struct stat st;
-        if (stat(file_in, &st) < 0) {
-            fprintf(stderr, "stat: %s\n", strerror(errno));
-            return -1;
+        SF_INFO info;
+        info.format = 0;
+        SNDFILE *sf = sf_open(file_in, SFM_READ, &info);
+        if (sf == NULL) {
+            perror(file_in);
+            return EXIT_FAILURE;
         }
-
-        int input_fd = open(file_in, O_RDONLY);
-        if (input_fd < 0) {
-            fprintf(stderr, "open: %s\n", strerror(errno));
-            return -1;
-        }
-
-        input_size = st.st_size;
-        input_vaddr = mmap(0, input_size, PROT_READ, MAP_PRIVATE, input_fd, 0);
-        if (input_vaddr == MAP_FAILED ) {
-            fprintf(stderr, "mmap: %s\n", strerror(errno));
-            return -1;
-        }
+        input_size = info.frames * info.channels * sizeof(short);
+        input_vaddr = malloc(input_size);
+        (void) sf_readf_short(sf, (short *) input_vaddr, info.frames);
+        sf_close(sf);
+        channels = info.channels;
+        input_freq = info.samplerate;
     } else {
+        // data for testing is exactly (input sampling rate/1000)/2 seconds
+        // so 44.1khz input is 22.05 seconds
         double k = 1000; // Hz / s
         double time = (input_freq / 2) / k;
         size_t input_frames = size_t(input_freq * time);
@@ -178,7 +220,7 @@
             double y = sin(M_PI * k * t * t);
             int16_t yi = floor(y * 32767.0 + 0.5);
             for (size_t j=0 ; j<(size_t)channels ; j++) {
-                in[i*channels + j] = yi / (1+j);
+                in[i*channels + j] = yi / (1+j); // right ch. 1/2 left ch.
             }
         }
     }
@@ -186,89 +228,263 @@
     // ----------------------------------------------------------
 
     class Provider: public AudioBufferProvider {
-        int16_t* mAddr;
-        size_t mNumFrames;
+        int16_t* const  mAddr;      // base address
+        const size_t    mNumFrames; // total frames
+        const int       mChannels;
+        size_t          mNextFrame; // index of next frame to provide
+        size_t          mUnrel;     // number of frames not yet released
+        const Vector<int> mPvalues; // number of frames provided per call
+        size_t          mNextPidx;  // index of next entry in mPvalues to use
     public:
-        Provider(const void* addr, size_t size, int channels) {
-            mAddr = (int16_t*) addr;
-            mNumFrames = size / (channels*sizeof(int16_t));
+        Provider(const void* addr, size_t size, int channels, const Vector<int>& Pvalues)
+          : mAddr((int16_t*) addr),
+            mNumFrames(size / (channels*sizeof(int16_t))),
+            mChannels(channels),
+            mNextFrame(0), mUnrel(0), mPvalues(Pvalues), mNextPidx(0) {
         }
         virtual status_t getNextBuffer(Buffer* buffer,
                 int64_t pts = kInvalidPTS) {
-            buffer->frameCount = mNumFrames;
-            buffer->i16 = mAddr;
-            return NO_ERROR;
+            (void)pts; // suppress warning
+            size_t requestedFrames = buffer->frameCount;
+            if (requestedFrames > mNumFrames - mNextFrame) {
+                buffer->frameCount = mNumFrames - mNextFrame;
+            }
+            if (!mPvalues.isEmpty()) {
+                size_t provided = mPvalues[mNextPidx++];
+                printf("mPvalue[%d]=%u not %u\n", mNextPidx-1, provided, buffer->frameCount);
+                if (provided < buffer->frameCount) {
+                    buffer->frameCount = provided;
+                }
+                if (mNextPidx >= mPvalues.size()) {
+                    mNextPidx = 0;
+                }
+            }
+            if (gVerbose) {
+                printf("getNextBuffer() requested %u frames out of %u frames available,"
+                        " and returned %u frames\n",
+                        requestedFrames, mNumFrames - mNextFrame, buffer->frameCount);
+            }
+            mUnrel = buffer->frameCount;
+            if (buffer->frameCount > 0) {
+                buffer->i16 = &mAddr[mChannels * mNextFrame];
+                return NO_ERROR;
+            } else {
+                buffer->i16 = NULL;
+                return NOT_ENOUGH_DATA;
+            }
         }
         virtual void releaseBuffer(Buffer* buffer) {
+            if (buffer->frameCount > mUnrel) {
+                fprintf(stderr, "ERROR releaseBuffer() released %u frames but only %u available "
+                        "to release\n", buffer->frameCount, mUnrel);
+                mNextFrame += mUnrel;
+                mUnrel = 0;
+            } else {
+                if (gVerbose) {
+                    printf("releaseBuffer() released %u frames out of %u frames available "
+                            "to release\n", buffer->frameCount, mUnrel);
+                }
+                mNextFrame += buffer->frameCount;
+                mUnrel -= buffer->frameCount;
+            }
+            buffer->frameCount = 0;
+            buffer->i16 = NULL;
         }
-    } provider(input_vaddr, input_size, channels);
+        void reset() {
+            mNextFrame = 0;
+        }
+    } provider(input_vaddr, input_size, channels, Pvalues);
 
     size_t input_frames = input_size / (channels * sizeof(int16_t));
+    if (gVerbose) {
+        printf("%u input frames\n", input_frames);
+    }
     size_t output_size = 2 * 4 * ((int64_t) input_frames * output_freq) / input_freq;
     output_size &= ~7; // always stereo, 32-bits
 
-    void* output_vaddr = malloc(output_size);
-
-    if (profiling) {
+    if (profileFilter) {
+        // Check how fast sample rate changes are that require filter changes.
+        // The delta sample rate changes must indicate a downsampling ratio,
+        // and must be larger than 10% changes.
+        //
+        // On fast devices, filters should be generated between 0.1ms - 1ms.
+        // (single threaded).
         AudioResampler* resampler = AudioResampler::create(16, channels,
-                output_freq, quality);
-
-        size_t out_frames = output_size/8;
-        resampler->setSampleRate(input_freq);
-        resampler->setVolume(0x1000, 0x1000);
-
-        memset(output_vaddr, 0, output_size);
+                8000, quality);
+        int looplimit = 100;
         timespec start, end;
         clock_gettime(CLOCK_MONOTONIC, &start);
-        resampler->resample((int*) output_vaddr, out_frames, &provider);
-        resampler->resample((int*) output_vaddr, out_frames, &provider);
-        resampler->resample((int*) output_vaddr, out_frames, &provider);
-        resampler->resample((int*) output_vaddr, out_frames, &provider);
+        for (int i = 0; i < looplimit; ++i) {
+            resampler->setSampleRate(9000);
+            resampler->setSampleRate(12000);
+            resampler->setSampleRate(20000);
+            resampler->setSampleRate(30000);
+        }
         clock_gettime(CLOCK_MONOTONIC, &end);
         int64_t start_ns = start.tv_sec * 1000000000LL + start.tv_nsec;
         int64_t end_ns = end.tv_sec * 1000000000LL + end.tv_nsec;
-        int64_t time = (end_ns - start_ns)/4;
-        printf("%f Mspl/s\n", out_frames/(time/1e9)/1e6);
+        int64_t time = end_ns - start_ns;
+        printf("%.2f sample rate changes with filter calculation/sec\n",
+                looplimit * 4 / (time / 1e9));
 
+        // Check how fast sample rate changes are without filter changes.
+        // This should be very fast, probably 0.1us - 1us per sample rate
+        // change.
+        resampler->setSampleRate(1000);
+        looplimit = 1000;
+        clock_gettime(CLOCK_MONOTONIC, &start);
+        for (int i = 0; i < looplimit; ++i) {
+            resampler->setSampleRate(1000+i);
+        }
+        clock_gettime(CLOCK_MONOTONIC, &end);
+        start_ns = start.tv_sec * 1000000000LL + start.tv_nsec;
+        end_ns = end.tv_sec * 1000000000LL + end.tv_nsec;
+        time = end_ns - start_ns;
+        printf("%.2f sample rate changes without filter calculation/sec\n",
+                looplimit / (time / 1e9));
+        resampler->reset();
         delete resampler;
     }
 
+    void* output_vaddr = malloc(output_size);
     AudioResampler* resampler = AudioResampler::create(16, channels,
             output_freq, quality);
     size_t out_frames = output_size/8;
+
+    /* set volume precision to 12 bits, so the volume scale is 1<<12.
+     * This means the "integer" part fits in the Q19.12 precision
+     * representation of output int32_t.
+     *
+     * Generally 0 < volumePrecision <= 14 (due to the limits of
+     * int16_t values for Volume). volumePrecision cannot be 0 due
+     * to rounding and shifts.
+     */
+    const int volumePrecision = 12; // in bits
+
     resampler->setSampleRate(input_freq);
-    resampler->setVolume(0x1000, 0x1000);
+    resampler->setVolume(1 << volumePrecision, 1 << volumePrecision);
+
+    if (profileResample) {
+        /*
+         * For profiling on mobile devices, upon experimentation
+         * it is better to run a few trials with a shorter loop limit,
+         * and take the minimum time.
+         *
+         * Long tests can cause CPU temperature to build up and thermal throttling
+         * to reduce CPU frequency.
+         *
+         * For frequency checks (index=0, or 1, etc.):
+         * "cat /sys/devices/system/cpu/cpu${index}/cpufreq/scaling_*_freq"
+         *
+         * For temperature checks (index=0, or 1, etc.):
+         * "cat /sys/class/thermal/thermal_zone${index}/temp"
+         *
+         * Another way to avoid thermal throttling is to fix the CPU frequency
+         * at a lower level which prevents excessive temperatures.
+         */
+        const int trials = 4;
+        const int looplimit = 4;
+        timespec start, end;
+        int64_t time;
+
+        for (int n = 0; n < trials; ++n) {
+            clock_gettime(CLOCK_MONOTONIC, &start);
+            for (int i = 0; i < looplimit; ++i) {
+                resampler->resample((int*) output_vaddr, out_frames, &provider);
+                provider.reset(); //  during benchmarking reset only the provider
+            }
+            clock_gettime(CLOCK_MONOTONIC, &end);
+            int64_t start_ns = start.tv_sec * 1000000000LL + start.tv_nsec;
+            int64_t end_ns = end.tv_sec * 1000000000LL + end.tv_nsec;
+            int64_t diff_ns = end_ns - start_ns;
+            if (n == 0 || diff_ns < time) {
+                time = diff_ns;   // save the best out of our trials.
+            }
+        }
+        // Mfrms/s is "Millions of output frames per second".
+        printf("quality: %d  channels: %d  msec: %lld  Mfrms/s: %.2lf\n",
+                quality, channels, time/1000000, out_frames * looplimit / (time / 1e9) / 1e6);
+        resampler->reset();
+    }
 
     memset(output_vaddr, 0, output_size);
-    resampler->resample((int*) output_vaddr, out_frames, &provider);
+    if (gVerbose) {
+        printf("resample() %u output frames\n", out_frames);
+    }
+    if (Ovalues.isEmpty()) {
+        Ovalues.push(out_frames);
+    }
+    for (size_t i = 0, j = 0; i < out_frames; ) {
+        size_t thisFrames = Ovalues[j++];
+        if (j >= Ovalues.size()) {
+            j = 0;
+        }
+        if (thisFrames == 0 || thisFrames > out_frames - i) {
+            thisFrames = out_frames - i;
+        }
+        resampler->resample((int*) output_vaddr + 2*i, thisFrames, &provider);
+        i += thisFrames;
+    }
+    if (gVerbose) {
+        printf("resample() complete\n");
+    }
+    resampler->reset();
+    if (gVerbose) {
+        printf("reset() complete\n");
+    }
+    delete resampler;
+    resampler = NULL;
 
-    // down-mix (we just truncate and keep the left channel)
+    // mono takes left channel only
+    // stereo right channel is half amplitude of stereo left channel (due to input creation)
     int32_t* out = (int32_t*) output_vaddr;
     int16_t* convert = (int16_t*) malloc(out_frames * channels * sizeof(int16_t));
+
+    // round to half towards zero and saturate at int16 (non-dithered)
+    const int roundVal = (1<<(volumePrecision-1)) - 1; // volumePrecision > 0
+
     for (size_t i = 0; i < out_frames; i++) {
-        for (int j=0 ; j<channels ; j++) {
-            int32_t s = out[i * 2 + j] >> 12;
-            if (s > 32767)       s =  32767;
-            else if (s < -32768) s = -32768;
+        for (int j = 0; j < channels; j++) {
+            int32_t s = out[i * 2 + j] + roundVal; // add offset here
+            if (s < 0) {
+                s = (s + 1) >> volumePrecision; // round to 0
+                if (s < -32768) {
+                    s = -32768;
+                }
+            } else {
+                s = s >> volumePrecision;
+                if (s > 32767) {
+                    s = 32767;
+                }
+            }
             convert[i * channels + j] = int16_t(s);
         }
     }
 
     // write output to disk
-    int output_fd = open(file_out, O_WRONLY | O_CREAT | O_TRUNC,
-            S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-    if (output_fd < 0) {
-        fprintf(stderr, "open: %s\n", strerror(errno));
-        return -1;
-    }
-
     if (writeHeader) {
-        HeaderWav wav(out_frames * channels * sizeof(int16_t), channels, output_freq, 16);
-        write(output_fd, &wav, sizeof(wav));
+        SF_INFO info;
+        info.frames = 0;
+        info.samplerate = output_freq;
+        info.channels = channels;
+        info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+        SNDFILE *sf = sf_open(file_out, SFM_WRITE, &info);
+        if (sf == NULL) {
+            perror(file_out);
+            return EXIT_FAILURE;
+        }
+        (void) sf_writef_short(sf, convert, out_frames);
+        sf_close(sf);
+    } else {
+        int output_fd = open(file_out, O_WRONLY | O_CREAT | O_TRUNC,
+                S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+        if (output_fd < 0) {
+            perror(file_out);
+            return EXIT_FAILURE;
+        }
+        write(output_fd, convert, out_frames * channels * sizeof(int16_t));
+        close(output_fd);
     }
 
-    write(output_fd, convert, out_frames * channels * sizeof(int16_t));
-    close(output_fd);
-
-    return 0;
+    return EXIT_SUCCESS;
 }
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
new file mode 100644
index 0000000..84565bb
--- /dev/null
+++ b/services/audiopolicy/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    AudioPolicyService.cpp \
+    AudioPolicyInterfaceImpl.cpp \
+    AudioPolicyClientImpl.cpp
+
+LOCAL_C_INCLUDES := \
+    $(TOPDIR)frameworks/av/services/audioflinger \
+    $(call include-path-for, audio-effects) \
+    $(call include-path-for, audio-utils)
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    libutils \
+    liblog \
+    libbinder \
+    libmedia \
+    libhardware \
+    libhardware_legacy
+
+LOCAL_STATIC_LIBRARIES := \
+    libmedia_helper \
+    libserviceutility
+
+LOCAL_MODULE:= libaudiopolicy
+
+LOCAL_CFLAGS += -fvisibility=hidden
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audiopolicy/AudioPolicyClientImpl.cpp b/services/audiopolicy/AudioPolicyClientImpl.cpp
new file mode 100644
index 0000000..53f3e2d
--- /dev/null
+++ b/services/audiopolicy/AudioPolicyClientImpl.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioPolicyService"
+//#define LOG_NDEBUG 0
+
+#include "Configuration.h"
+#undef __STRICT_ANSI__
+#define __STDINT_LIMITS
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+
+#include <sys/time.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <binder/IPCThreadState.h>
+#include <utils/String16.h>
+#include <utils/threads.h>
+#include "AudioPolicyService.h"
+#include "ServiceUtilities.h"
+#include <hardware_legacy/power.h>
+#include <media/AudioEffect.h>
+#include <media/EffectsFactoryApi.h>
+//#include <media/IAudioFlinger.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <hardware/audio_policy.h>
+#include <audio_effects/audio_effects_conf.h>
+#include <media/AudioParameter.h>
+
+
+namespace android {
+
+/* implementation of the interface to the policy manager */
+extern "C" {
+
+audio_module_handle_t aps_load_hw_module(void *service __unused,
+                                             const char *name)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        ALOGW("%s: could not get AudioFlinger", __func__);
+        return 0;
+    }
+
+    return af->loadHwModule(name);
+}
+
+// deprecated: replaced by aps_open_output_on_module()
+audio_io_handle_t aps_open_output(void *service __unused,
+                                         audio_devices_t *pDevices,
+                                         uint32_t *pSamplingRate,
+                                         audio_format_t *pFormat,
+                                         audio_channel_mask_t *pChannelMask,
+                                         uint32_t *pLatencyMs,
+                                         audio_output_flags_t flags)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        ALOGW("%s: could not get AudioFlinger", __func__);
+        return 0;
+    }
+
+    return af->openOutput((audio_module_handle_t)0, pDevices, pSamplingRate, pFormat, pChannelMask,
+                          pLatencyMs, flags);
+}
+
+audio_io_handle_t aps_open_output_on_module(void *service __unused,
+                                                   audio_module_handle_t module,
+                                                   audio_devices_t *pDevices,
+                                                   uint32_t *pSamplingRate,
+                                                   audio_format_t *pFormat,
+                                                   audio_channel_mask_t *pChannelMask,
+                                                   uint32_t *pLatencyMs,
+                                                   audio_output_flags_t flags,
+                                                   const audio_offload_info_t *offloadInfo)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        ALOGW("%s: could not get AudioFlinger", __func__);
+        return 0;
+    }
+    return af->openOutput(module, pDevices, pSamplingRate, pFormat, pChannelMask,
+                          pLatencyMs, flags, offloadInfo);
+}
+
+audio_io_handle_t aps_open_dup_output(void *service __unused,
+                                                 audio_io_handle_t output1,
+                                                 audio_io_handle_t output2)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        ALOGW("%s: could not get AudioFlinger", __func__);
+        return 0;
+    }
+    return af->openDuplicateOutput(output1, output2);
+}
+
+int aps_close_output(void *service __unused, audio_io_handle_t output)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        return PERMISSION_DENIED;
+    }
+
+    return af->closeOutput(output);
+}
+
+int aps_suspend_output(void *service __unused, audio_io_handle_t output)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        ALOGW("%s: could not get AudioFlinger", __func__);
+        return PERMISSION_DENIED;
+    }
+
+    return af->suspendOutput(output);
+}
+
+int aps_restore_output(void *service __unused, audio_io_handle_t output)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        ALOGW("%s: could not get AudioFlinger", __func__);
+        return PERMISSION_DENIED;
+    }
+
+    return af->restoreOutput(output);
+}
+
+// deprecated: replaced by aps_open_input_on_module(), and acoustics parameter is ignored
+audio_io_handle_t aps_open_input(void *service __unused,
+                                        audio_devices_t *pDevices,
+                                        uint32_t *pSamplingRate,
+                                        audio_format_t *pFormat,
+                                        audio_channel_mask_t *pChannelMask,
+                                        audio_in_acoustics_t acoustics __unused)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        ALOGW("%s: could not get AudioFlinger", __func__);
+        return 0;
+    }
+
+    return af->openInput((audio_module_handle_t)0, pDevices, pSamplingRate, pFormat, pChannelMask);
+}
+
+audio_io_handle_t aps_open_input_on_module(void *service __unused,
+                                                  audio_module_handle_t module,
+                                                  audio_devices_t *pDevices,
+                                                  uint32_t *pSamplingRate,
+                                                  audio_format_t *pFormat,
+                                                  audio_channel_mask_t *pChannelMask)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        ALOGW("%s: could not get AudioFlinger", __func__);
+        return 0;
+    }
+
+    return af->openInput(module, pDevices, pSamplingRate, pFormat, pChannelMask);
+}
+
+int aps_close_input(void *service __unused, audio_io_handle_t input)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        return PERMISSION_DENIED;
+    }
+
+    return af->closeInput(input);
+}
+
+int aps_invalidate_stream(void *service __unused, audio_stream_type_t stream)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        return PERMISSION_DENIED;
+    }
+
+    return af->invalidateStream(stream);
+}
+
+int aps_move_effects(void *service __unused, int session,
+                                audio_io_handle_t src_output,
+                                audio_io_handle_t dst_output)
+{
+    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+    if (af == 0) {
+        return PERMISSION_DENIED;
+    }
+
+    return af->moveEffects(session, src_output, dst_output);
+}
+
+char * aps_get_parameters(void *service __unused, audio_io_handle_t io_handle,
+                                     const char *keys)
+{
+    String8 result = AudioSystem::getParameters(io_handle, String8(keys));
+    return strdup(result.string());
+}
+
+void aps_set_parameters(void *service, audio_io_handle_t io_handle,
+                                   const char *kv_pairs, int delay_ms)
+{
+    AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
+
+    audioPolicyService->setParameters(io_handle, kv_pairs, delay_ms);
+}
+
+int aps_set_stream_volume(void *service, audio_stream_type_t stream,
+                                     float volume, audio_io_handle_t output,
+                                     int delay_ms)
+{
+    AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
+
+    return audioPolicyService->setStreamVolume(stream, volume, output,
+                                               delay_ms);
+}
+
+int aps_start_tone(void *service, audio_policy_tone_t tone,
+                              audio_stream_type_t stream)
+{
+    AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
+
+    return audioPolicyService->startTone(tone, stream);
+}
+
+int aps_stop_tone(void *service)
+{
+    AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
+
+    return audioPolicyService->stopTone();
+}
+
+int aps_set_voice_volume(void *service, float volume, int delay_ms)
+{
+    AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
+
+    return audioPolicyService->setVoiceVolume(volume, delay_ms);
+}
+
+}; // extern "C"
+
+}; // namespace android
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
new file mode 100644
index 0000000..768b13e
--- /dev/null
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIOPOLICYINTERFACE_H
+#define ANDROID_AUDIOPOLICYINTERFACE_H
+
+#include <media/AudioSystem.h>
+#include <utils/String8.h>
+
+#include <hardware/audio_policy.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+// The AudioPolicyInterface and AudioPolicyClientInterface classes define the communication interfaces
+// between the platform specific audio policy manager and Android generic audio policy manager.
+// The platform specific audio policy manager must implement methods of the AudioPolicyInterface class.
+// This implementation makes use of the AudioPolicyClientInterface to control the activity and
+// configuration of audio input and output streams.
+//
+// The platform specific audio policy manager is in charge of the audio routing and volume control
+// policies for a given platform.
+// The main roles of this module are:
+//   - keep track of current system state (removable device connections, phone state, user requests...).
+//   System state changes and user actions are notified to audio policy manager with methods of the AudioPolicyInterface.
+//   - process getOutput() queries received when AudioTrack objects are created: Those queries
+//   return a handler on an output that has been selected, configured and opened by the audio policy manager and that
+//   must be used by the AudioTrack when registering to the AudioFlinger with the createTrack() method.
+//   When the AudioTrack object is released, a putOutput() query is received and the audio policy manager can decide
+//   to close or reconfigure the output depending on other streams using this output and current system state.
+//   - similarly process getInput() and putInput() queries received from AudioRecord objects and configure audio inputs.
+//   - process volume control requests: the stream volume is converted from an index value (received from UI) to a float value
+//   applicable to each output as a function of platform specific settings and current output route (destination device). It
+//   also make sure that streams are not muted if not allowed (e.g. camera shutter sound in some countries).
+//
+// The platform specific audio policy manager is provided as a shared library by platform vendors (as for libaudio.so)
+// and is linked with libaudioflinger.so
+
+
+//    Audio Policy Manager Interface
+class AudioPolicyInterface
+{
+
+public:
+    virtual ~AudioPolicyInterface() {}
+    //
+    // configuration functions
+    //
+
+    // indicate a change in device connection status
+    virtual status_t setDeviceConnectionState(audio_devices_t device,
+                                              audio_policy_dev_state_t state,
+                                          const char *device_address) = 0;
+    // retrieve a device connection status
+    virtual audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device,
+                                                                          const char *device_address) = 0;
+    // indicate a change in phone state. Valid phones states are defined by audio_mode_t
+    virtual void setPhoneState(audio_mode_t state) = 0;
+    // force using a specific device category for the specified usage
+    virtual void setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config) = 0;
+    // retrieve current device category forced for a given usage
+    virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) = 0;
+    // set a system property (e.g. camera sound always audible)
+    virtual void setSystemProperty(const char* property, const char* value) = 0;
+    // check proper initialization
+    virtual status_t initCheck() = 0;
+
+    //
+    // Audio routing query functions
+    //
+
+    // request an output appropriate for playback of the supplied stream type and parameters
+    virtual audio_io_handle_t getOutput(audio_stream_type_t stream,
+                                        uint32_t samplingRate,
+                                        audio_format_t format,
+                                        audio_channel_mask_t channelMask,
+                                        audio_output_flags_t flags,
+                                        const audio_offload_info_t *offloadInfo) = 0;
+    // indicates to the audio policy manager that the output starts being used by corresponding stream.
+    virtual status_t startOutput(audio_io_handle_t output,
+                                 audio_stream_type_t stream,
+                                 int session = 0) = 0;
+    // indicates to the audio policy manager that the output stops being used by corresponding stream.
+    virtual status_t stopOutput(audio_io_handle_t output,
+                                audio_stream_type_t stream,
+                                int session = 0) = 0;
+    // releases the output.
+    virtual void releaseOutput(audio_io_handle_t output) = 0;
+
+    // request an input appropriate for record from the supplied device with supplied parameters.
+    virtual audio_io_handle_t getInput(audio_source_t inputSource,
+                                    uint32_t samplingRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t channelMask,
+                                    audio_in_acoustics_t acoustics) = 0;
+    // indicates to the audio policy manager that the input starts being used.
+    virtual status_t startInput(audio_io_handle_t input) = 0;
+    // indicates to the audio policy manager that the input stops being used.
+    virtual status_t stopInput(audio_io_handle_t input) = 0;
+    // releases the input.
+    virtual void releaseInput(audio_io_handle_t input) = 0;
+
+    //
+    // volume control functions
+    //
+
+    // initialises stream volume conversion parameters by specifying volume index range.
+    virtual void initStreamVolume(audio_stream_type_t stream,
+                                      int indexMin,
+                                      int indexMax) = 0;
+
+    // sets the new stream volume at a level corresponding to the supplied index for the
+    // supplied device. By convention, specifying AUDIO_DEVICE_OUT_DEFAULT means
+    // setting volume for all devices
+    virtual status_t setStreamVolumeIndex(audio_stream_type_t stream,
+                                          int index,
+                                          audio_devices_t device) = 0;
+
+    // retrieve current volume index for the specified stream and the
+    // specified device. By convention, specifying AUDIO_DEVICE_OUT_DEFAULT means
+    // querying the volume of the active device.
+    virtual status_t getStreamVolumeIndex(audio_stream_type_t stream,
+                                          int *index,
+                                          audio_devices_t device) = 0;
+
+    // return the strategy corresponding to a given stream type
+    virtual uint32_t getStrategyForStream(audio_stream_type_t stream) = 0;
+
+    // return the enabled output devices for the given stream type
+    virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream) = 0;
+
+    // Audio effect management
+    virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc) = 0;
+    virtual status_t registerEffect(const effect_descriptor_t *desc,
+                                    audio_io_handle_t io,
+                                    uint32_t strategy,
+                                    int session,
+                                    int id) = 0;
+    virtual status_t unregisterEffect(int id) = 0;
+    virtual status_t setEffectEnabled(int id, bool enabled) = 0;
+
+    virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const = 0;
+    virtual bool isStreamActiveRemotely(audio_stream_type_t stream,
+                                        uint32_t inPastMs = 0) const = 0;
+    virtual bool isSourceActive(audio_source_t source) const = 0;
+
+    //dump state
+    virtual status_t    dump(int fd) = 0;
+
+    virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo) = 0;
+};
+
+
+// Audio Policy client Interface
+class AudioPolicyClientInterface
+{
+public:
+    virtual ~AudioPolicyClientInterface() {}
+
+    //
+    // Audio HW module functions
+    //
+
+    // loads a HW module.
+    virtual audio_module_handle_t loadHwModule(const char *name) = 0;
+
+    //
+    // Audio output Control functions
+    //
+
+    // opens an audio output with the requested parameters. The parameter values can indicate to use the default values
+    // in case the audio policy manager has no specific requirements for the output being opened.
+    // When the function returns, the parameter values reflect the actual values used by the audio hardware output stream.
+    // The audio policy manager can check if the proposed parameters are suitable or not and act accordingly.
+    virtual audio_io_handle_t openOutput(audio_module_handle_t module,
+                                         audio_devices_t *pDevices,
+                                         uint32_t *pSamplingRate,
+                                         audio_format_t *pFormat,
+                                         audio_channel_mask_t *pChannelMask,
+                                         uint32_t *pLatencyMs,
+                                         audio_output_flags_t flags,
+                                         const audio_offload_info_t *offloadInfo = NULL) = 0;
+    // creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by
+    // a special mixer thread in the AudioFlinger.
+    virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2) = 0;
+    // closes the output stream
+    virtual status_t closeOutput(audio_io_handle_t output) = 0;
+    // suspends the output. When an output is suspended, the corresponding audio hardware output stream is placed in
+    // standby and the AudioTracks attached to the mixer thread are still processed but the output mix is discarded.
+    virtual status_t suspendOutput(audio_io_handle_t output) = 0;
+    // restores a suspended output.
+    virtual status_t restoreOutput(audio_io_handle_t output) = 0;
+
+    //
+    // Audio input Control functions
+    //
+
+    // opens an audio input
+    virtual audio_io_handle_t openInput(audio_module_handle_t module,
+                                        audio_devices_t *pDevices,
+                                        uint32_t *pSamplingRate,
+                                        audio_format_t *pFormat,
+                                        audio_channel_mask_t *pChannelMask) = 0;
+    // closes an audio input
+    virtual status_t closeInput(audio_io_handle_t input) = 0;
+    //
+    // misc control functions
+    //
+
+    // set a stream volume for a particular output. For the same user setting, a given stream type can have different volumes
+    // for each output (destination device) it is attached to.
+    virtual status_t setStreamVolume(audio_stream_type_t stream, float volume, audio_io_handle_t output, int delayMs = 0) = 0;
+
+    // invalidate a stream type, causing a reroute to an unspecified new output
+    virtual status_t invalidateStream(audio_stream_type_t stream) = 0;
+
+    // function enabling to send proprietary informations directly from audio policy manager to audio hardware interface.
+    virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs = 0) = 0;
+    // function enabling to receive proprietary informations directly from audio hardware interface to audio policy manager.
+    virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) = 0;
+
+    // request the playback of a tone on the specified stream: used for instance to replace notification sounds when playing
+    // over a telephony device during a phone call.
+    virtual status_t startTone(audio_policy_tone_t tone, audio_stream_type_t stream) = 0;
+    virtual status_t stopTone() = 0;
+
+    // set down link audio volume.
+    virtual status_t setVoiceVolume(float volume, int delayMs = 0) = 0;
+
+    // move effect to the specified output
+    virtual status_t moveEffects(int session,
+                                     audio_io_handle_t srcOutput,
+                                     audio_io_handle_t dstOutput) = 0;
+
+};
+
+extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface);
+extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface);
+
+
+}; // namespace android
+
+#endif // ANDROID_AUDIOPOLICYINTERFACE_H
diff --git a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
new file mode 100644
index 0000000..bb62ab3
--- /dev/null
+++ b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp
@@ -0,0 +1,489 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioPolicyService"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include "AudioPolicyService.h"
+#include "ServiceUtilities.h"
+
+#include <system/audio.h>
+#include <system/audio_policy.h>
+#include <hardware/audio_policy.h>
+
+namespace android {
+
+
+// ----------------------------------------------------------------------------
+
+status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,
+                                                  audio_policy_dev_state_t state,
+                                                  const char *device_address)
+{
+    if (mpAudioPolicy == NULL) {
+        return NO_INIT;
+    }
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    if (!audio_is_output_device(device) && !audio_is_input_device(device)) {
+        return BAD_VALUE;
+    }
+    if (state != AUDIO_POLICY_DEVICE_STATE_AVAILABLE &&
+            state != AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
+        return BAD_VALUE;
+    }
+
+    ALOGV("setDeviceConnectionState()");
+    Mutex::Autolock _l(mLock);
+    return mpAudioPolicy->set_device_connection_state(mpAudioPolicy, device,
+                                                      state, device_address);
+}
+
+audio_policy_dev_state_t AudioPolicyService::getDeviceConnectionState(
+                                                              audio_devices_t device,
+                                                              const char *device_address)
+{
+    if (mpAudioPolicy == NULL) {
+        return AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE;
+    }
+    return mpAudioPolicy->get_device_connection_state(mpAudioPolicy, device,
+                                                      device_address);
+}
+
+status_t AudioPolicyService::setPhoneState(audio_mode_t state)
+{
+    if (mpAudioPolicy == NULL) {
+        return NO_INIT;
+    }
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    if (uint32_t(state) >= AUDIO_MODE_CNT) {
+        return BAD_VALUE;
+    }
+
+    ALOGV("setPhoneState()");
+
+    // TODO: check if it is more appropriate to do it in platform specific policy manager
+    AudioSystem::setMode(state);
+
+    Mutex::Autolock _l(mLock);
+    mpAudioPolicy->set_phone_state(mpAudioPolicy, state);
+    return NO_ERROR;
+}
+
+status_t AudioPolicyService::setForceUse(audio_policy_force_use_t usage,
+                                         audio_policy_forced_cfg_t config)
+{
+    if (mpAudioPolicy == NULL) {
+        return NO_INIT;
+    }
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    if (usage < 0 || usage >= AUDIO_POLICY_FORCE_USE_CNT) {
+        return BAD_VALUE;
+    }
+    if (config < 0 || config >= AUDIO_POLICY_FORCE_CFG_CNT) {
+        return BAD_VALUE;
+    }
+    ALOGV("setForceUse()");
+    Mutex::Autolock _l(mLock);
+    mpAudioPolicy->set_force_use(mpAudioPolicy, usage, config);
+    return NO_ERROR;
+}
+
+audio_policy_forced_cfg_t AudioPolicyService::getForceUse(audio_policy_force_use_t usage)
+{
+    if (mpAudioPolicy == NULL) {
+        return AUDIO_POLICY_FORCE_NONE;
+    }
+    if (usage < 0 || usage >= AUDIO_POLICY_FORCE_USE_CNT) {
+        return AUDIO_POLICY_FORCE_NONE;
+    }
+    return mpAudioPolicy->get_force_use(mpAudioPolicy, usage);
+}
+
+audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream,
+                                    uint32_t samplingRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t channelMask,
+                                    audio_output_flags_t flags,
+                                    const audio_offload_info_t *offloadInfo)
+{
+    if (mpAudioPolicy == NULL) {
+        return 0;
+    }
+    ALOGV("getOutput()");
+    Mutex::Autolock _l(mLock);
+    return mpAudioPolicy->get_output(mpAudioPolicy, stream, samplingRate,
+                                    format, channelMask, flags, offloadInfo);
+}
+
+status_t AudioPolicyService::startOutput(audio_io_handle_t output,
+                                         audio_stream_type_t stream,
+                                         int session)
+{
+    if (mpAudioPolicy == NULL) {
+        return NO_INIT;
+    }
+    ALOGV("startOutput()");
+    Mutex::Autolock _l(mLock);
+    return mpAudioPolicy->start_output(mpAudioPolicy, output, stream, session);
+}
+
+status_t AudioPolicyService::stopOutput(audio_io_handle_t output,
+                                        audio_stream_type_t stream,
+                                        int session)
+{
+    if (mpAudioPolicy == NULL) {
+        return NO_INIT;
+    }
+    ALOGV("stopOutput()");
+    mOutputCommandThread->stopOutputCommand(output, stream, session);
+    return NO_ERROR;
+}
+
+status_t  AudioPolicyService::doStopOutput(audio_io_handle_t output,
+                                      audio_stream_type_t stream,
+                                      int session)
+{
+    ALOGV("doStopOutput from tid %d", gettid());
+    Mutex::Autolock _l(mLock);
+    return mpAudioPolicy->stop_output(mpAudioPolicy, output, stream, session);
+}
+
+void AudioPolicyService::releaseOutput(audio_io_handle_t output)
+{
+    if (mpAudioPolicy == NULL) {
+        return;
+    }
+    ALOGV("releaseOutput()");
+    mOutputCommandThread->releaseOutputCommand(output);
+}
+
+void AudioPolicyService::doReleaseOutput(audio_io_handle_t output)
+{
+    ALOGV("doReleaseOutput from tid %d", gettid());
+    Mutex::Autolock _l(mLock);
+    mpAudioPolicy->release_output(mpAudioPolicy, output);
+}
+
+audio_io_handle_t AudioPolicyService::getInput(audio_source_t inputSource,
+                                    uint32_t samplingRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t channelMask,
+                                    int audioSession)
+{
+    if (mpAudioPolicy == NULL) {
+        return 0;
+    }
+    // already checked by client, but double-check in case the client wrapper is bypassed
+    if (inputSource >= AUDIO_SOURCE_CNT && inputSource != AUDIO_SOURCE_HOTWORD) {
+        return 0;
+    }
+
+    if ((inputSource == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) {
+        return 0;
+    }
+
+    Mutex::Autolock _l(mLock);
+    // the audio_in_acoustics_t parameter is ignored by get_input()
+    audio_io_handle_t input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate,
+                                                   format, channelMask, (audio_in_acoustics_t) 0);
+
+    if (input == 0) {
+        return input;
+    }
+    // create audio pre processors according to input source
+    audio_source_t aliasSource = (inputSource == AUDIO_SOURCE_HOTWORD) ?
+                                    AUDIO_SOURCE_VOICE_RECOGNITION : inputSource;
+
+    ssize_t index = mInputSources.indexOfKey(aliasSource);
+    if (index < 0) {
+        return input;
+    }
+    ssize_t idx = mInputs.indexOfKey(input);
+    InputDesc *inputDesc;
+    if (idx < 0) {
+        inputDesc = new InputDesc(audioSession);
+        mInputs.add(input, inputDesc);
+    } else {
+        inputDesc = mInputs.valueAt(idx);
+    }
+
+    Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
+    for (size_t i = 0; i < effects.size(); i++) {
+        EffectDesc *effect = effects[i];
+        sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0, audioSession, input);
+        status_t status = fx->initCheck();
+        if (status != NO_ERROR && status != ALREADY_EXISTS) {
+            ALOGW("Failed to create Fx %s on input %d", effect->mName, input);
+            // fx goes out of scope and strong ref on AudioEffect is released
+            continue;
+        }
+        for (size_t j = 0; j < effect->mParams.size(); j++) {
+            fx->setParameter(effect->mParams[j]);
+        }
+        inputDesc->mEffects.add(fx);
+    }
+    setPreProcessorEnabled(inputDesc, true);
+    return input;
+}
+
+status_t AudioPolicyService::startInput(audio_io_handle_t input)
+{
+    if (mpAudioPolicy == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+
+    return mpAudioPolicy->start_input(mpAudioPolicy, input);
+}
+
+status_t AudioPolicyService::stopInput(audio_io_handle_t input)
+{
+    if (mpAudioPolicy == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+
+    return mpAudioPolicy->stop_input(mpAudioPolicy, input);
+}
+
+void AudioPolicyService::releaseInput(audio_io_handle_t input)
+{
+    if (mpAudioPolicy == NULL) {
+        return;
+    }
+    Mutex::Autolock _l(mLock);
+    mpAudioPolicy->release_input(mpAudioPolicy, input);
+
+    ssize_t index = mInputs.indexOfKey(input);
+    if (index < 0) {
+        return;
+    }
+    InputDesc *inputDesc = mInputs.valueAt(index);
+    setPreProcessorEnabled(inputDesc, false);
+    delete inputDesc;
+    mInputs.removeItemsAt(index);
+}
+
+status_t AudioPolicyService::initStreamVolume(audio_stream_type_t stream,
+                                            int indexMin,
+                                            int indexMax)
+{
+    if (mpAudioPolicy == NULL) {
+        return NO_INIT;
+    }
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+        return BAD_VALUE;
+    }
+    Mutex::Autolock _l(mLock);
+    mpAudioPolicy->init_stream_volume(mpAudioPolicy, stream, indexMin, indexMax);
+    return NO_ERROR;
+}
+
+status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream,
+                                                  int index,
+                                                  audio_devices_t device)
+{
+    if (mpAudioPolicy == NULL) {
+        return NO_INIT;
+    }
+    if (!settingsAllowed()) {
+        return PERMISSION_DENIED;
+    }
+    if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+        return BAD_VALUE;
+    }
+    Mutex::Autolock _l(mLock);
+    if (mpAudioPolicy->set_stream_volume_index_for_device) {
+        return mpAudioPolicy->set_stream_volume_index_for_device(mpAudioPolicy,
+                                                                stream,
+                                                                index,
+                                                                device);
+    } else {
+        return mpAudioPolicy->set_stream_volume_index(mpAudioPolicy, stream, index);
+    }
+}
+
+status_t AudioPolicyService::getStreamVolumeIndex(audio_stream_type_t stream,
+                                                  int *index,
+                                                  audio_devices_t device)
+{
+    if (mpAudioPolicy == NULL) {
+        return NO_INIT;
+    }
+    if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
+        return BAD_VALUE;
+    }
+    Mutex::Autolock _l(mLock);
+    if (mpAudioPolicy->get_stream_volume_index_for_device) {
+        return mpAudioPolicy->get_stream_volume_index_for_device(mpAudioPolicy,
+                                                                stream,
+                                                                index,
+                                                                device);
+    } else {
+        return mpAudioPolicy->get_stream_volume_index(mpAudioPolicy, stream, index);
+    }
+}
+
+uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream)
+{
+    if (mpAudioPolicy == NULL) {
+        return 0;
+    }
+    return mpAudioPolicy->get_strategy_for_stream(mpAudioPolicy, stream);
+}
+
+//audio policy: use audio_device_t appropriately
+
+audio_devices_t AudioPolicyService::getDevicesForStream(audio_stream_type_t stream)
+{
+    if (mpAudioPolicy == NULL) {
+        return (audio_devices_t)0;
+    }
+    return mpAudioPolicy->get_devices_for_stream(mpAudioPolicy, stream);
+}
+
+audio_io_handle_t AudioPolicyService::getOutputForEffect(const effect_descriptor_t *desc)
+{
+    // FIXME change return type to status_t, and return NO_INIT here
+    if (mpAudioPolicy == NULL) {
+        return 0;
+    }
+    Mutex::Autolock _l(mLock);
+    return mpAudioPolicy->get_output_for_effect(mpAudioPolicy, desc);
+}
+
+status_t AudioPolicyService::registerEffect(const effect_descriptor_t *desc,
+                                audio_io_handle_t io,
+                                uint32_t strategy,
+                                int session,
+                                int id)
+{
+    if (mpAudioPolicy == NULL) {
+        return NO_INIT;
+    }
+    return mpAudioPolicy->register_effect(mpAudioPolicy, desc, io, strategy, session, id);
+}
+
+status_t AudioPolicyService::unregisterEffect(int id)
+{
+    if (mpAudioPolicy == NULL) {
+        return NO_INIT;
+    }
+    return mpAudioPolicy->unregister_effect(mpAudioPolicy, id);
+}
+
+status_t AudioPolicyService::setEffectEnabled(int id, bool enabled)
+{
+    if (mpAudioPolicy == NULL) {
+        return NO_INIT;
+    }
+    return mpAudioPolicy->set_effect_enabled(mpAudioPolicy, id, enabled);
+}
+
+bool AudioPolicyService::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
+{
+    if (mpAudioPolicy == NULL) {
+        return 0;
+    }
+    Mutex::Autolock _l(mLock);
+    return mpAudioPolicy->is_stream_active(mpAudioPolicy, stream, inPastMs);
+}
+
+bool AudioPolicyService::isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const
+{
+    if (mpAudioPolicy == NULL) {
+        return 0;
+    }
+    Mutex::Autolock _l(mLock);
+    return mpAudioPolicy->is_stream_active_remotely(mpAudioPolicy, stream, inPastMs);
+}
+
+bool AudioPolicyService::isSourceActive(audio_source_t source) const
+{
+    if (mpAudioPolicy == NULL) {
+        return false;
+    }
+    if (mpAudioPolicy->is_source_active == 0) {
+        return false;
+    }
+    Mutex::Autolock _l(mLock);
+    return mpAudioPolicy->is_source_active(mpAudioPolicy, source);
+}
+
+status_t AudioPolicyService::queryDefaultPreProcessing(int audioSession,
+                                                       effect_descriptor_t *descriptors,
+                                                       uint32_t *count)
+{
+
+    if (mpAudioPolicy == NULL) {
+        *count = 0;
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    status_t status = NO_ERROR;
+
+    size_t index;
+    for (index = 0; index < mInputs.size(); index++) {
+        if (mInputs.valueAt(index)->mSessionId == audioSession) {
+            break;
+        }
+    }
+    if (index == mInputs.size()) {
+        *count = 0;
+        return BAD_VALUE;
+    }
+    Vector< sp<AudioEffect> > effects = mInputs.valueAt(index)->mEffects;
+
+    for (size_t i = 0; i < effects.size(); i++) {
+        effect_descriptor_t desc = effects[i]->descriptor();
+        if (i < *count) {
+            descriptors[i] = desc;
+        }
+    }
+    if (effects.size() > *count) {
+        status = NO_MEMORY;
+    }
+    *count = effects.size();
+    return status;
+}
+
+bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info)
+{
+    if (mpAudioPolicy == NULL) {
+        ALOGV("mpAudioPolicy == NULL");
+        return false;
+    }
+
+    if (mpAudioPolicy->is_offload_supported == NULL) {
+        ALOGV("HAL does not implement is_offload_supported");
+        return false;
+    }
+
+    return mpAudioPolicy->is_offload_supported(mpAudioPolicy, &info);
+}
+
+
+}; // namespace android
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
new file mode 100644
index 0000000..5ac9d9e
--- /dev/null
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -0,0 +1,4104 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioPolicyManager"
+//#define LOG_NDEBUG 0
+
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+// A device mask for all audio input devices that are considered "virtual" when evaluating
+// active inputs in getActiveInput()
+#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL  AUDIO_DEVICE_IN_REMOTE_SUBMIX
+// A device mask for all audio output devices that are considered "remote" when evaluating
+// active output devices in isStreamActiveRemotely()
+#define APM_AUDIO_OUT_DEVICE_REMOTE_ALL  AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+
+#include <utils/Log.h>
+#include "AudioPolicyManager.h"
+#include <hardware/audio_effect.h>
+#include <hardware/audio.h>
+#include <math.h>
+#include <hardware_legacy/audio_policy_conf.h>
+#include <cutils/properties.h>
+#include <media/AudioParameter.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+// AudioPolicyInterface implementation
+// ----------------------------------------------------------------------------
+
+
+status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
+                                                          audio_policy_dev_state_t state,
+                                                  const char *device_address)
+{
+    SortedVector <audio_io_handle_t> outputs;
+
+    ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);
+
+    // connect/disconnect only 1 device at a time
+    if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
+
+    if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
+        ALOGE("setDeviceConnectionState() invalid address: %s", device_address);
+        return BAD_VALUE;
+    }
+
+    // handle output devices
+    if (audio_is_output_device(device)) {
+
+        if (!mHasA2dp && audio_is_a2dp_device(device)) {
+            ALOGE("setDeviceConnectionState() invalid A2DP device: %x", device);
+            return BAD_VALUE;
+        }
+        if (!mHasUsb && audio_is_usb_device(device)) {
+            ALOGE("setDeviceConnectionState() invalid USB audio device: %x", device);
+            return BAD_VALUE;
+        }
+        if (!mHasRemoteSubmix && audio_is_remote_submix_device((audio_devices_t)device)) {
+            ALOGE("setDeviceConnectionState() invalid remote submix audio device: %x", device);
+            return BAD_VALUE;
+        }
+
+        // save a copy of the opened output descriptors before any output is opened or closed
+        // by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies()
+        mPreviousOutputs = mOutputs;
+        String8 paramStr;
+        switch (state)
+        {
+        // handle output device connection
+        case AUDIO_POLICY_DEVICE_STATE_AVAILABLE:
+            if (mAvailableOutputDevices & device) {
+                ALOGW("setDeviceConnectionState() device already connected: %x", device);
+                return INVALID_OPERATION;
+            }
+            ALOGV("setDeviceConnectionState() connecting device %x", device);
+
+            if (mHasA2dp && audio_is_a2dp_device(device)) {
+                // handle A2DP device connection
+                AudioParameter param;
+                param.add(String8(AUDIO_PARAMETER_A2DP_SINK_ADDRESS), String8(device_address));
+                paramStr = param.toString();
+            } else if (mHasUsb && audio_is_usb_device(device)) {
+                // handle USB device connection
+                paramStr = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+            }
+
+            if (checkOutputsForDevice(device, state, outputs, paramStr) != NO_ERROR) {
+                return INVALID_OPERATION;
+            }
+            ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %d outputs",
+                  outputs.size());
+            // register new device as available
+            mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | device);
+
+            if (mHasA2dp && audio_is_a2dp_device(device)) {
+                // handle A2DP device connection
+                mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+                mA2dpSuspended = false;
+            } else if (audio_is_bluetooth_sco_device(device)) {
+                // handle SCO device connection
+                mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+            } else if (mHasUsb && audio_is_usb_device(device)) {
+                // handle USB device connection
+                mUsbCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+            }
+
+            break;
+        // handle output device disconnection
+        case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: {
+            if (!(mAvailableOutputDevices & device)) {
+                ALOGW("setDeviceConnectionState() device not connected: %x", device);
+                return INVALID_OPERATION;
+            }
+
+            ALOGV("setDeviceConnectionState() disconnecting device %x", device);
+            // remove device from available output devices
+            mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device);
+
+            checkOutputsForDevice(device, state, outputs, paramStr);
+            if (mHasA2dp && audio_is_a2dp_device(device)) {
+                // handle A2DP device disconnection
+                mA2dpDeviceAddress = "";
+                mA2dpSuspended = false;
+            } else if (audio_is_bluetooth_sco_device(device)) {
+                // handle SCO device disconnection
+                mScoDeviceAddress = "";
+            } else if (mHasUsb && audio_is_usb_device(device)) {
+                // handle USB device disconnection
+                mUsbCardAndDevice = "";
+            }
+            // not currently handling multiple simultaneous submixes: ignoring remote submix
+            //   case and address
+            } break;
+
+        default:
+            ALOGE("setDeviceConnectionState() invalid state: %x", state);
+            return BAD_VALUE;
+        }
+
+        checkA2dpSuspend();
+        checkOutputForAllStrategies();
+        // outputs must be closed after checkOutputForAllStrategies() is executed
+        if (!outputs.isEmpty()) {
+            for (size_t i = 0; i < outputs.size(); i++) {
+                AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]);
+                // close unused outputs after device disconnection or direct outputs that have been
+                // opened by checkOutputsForDevice() to query dynamic parameters
+                if ((state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) ||
+                        (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) &&
+                         (desc->mDirectOpenCount == 0))) {
+                    closeOutput(outputs[i]);
+                }
+            }
+        }
+
+        updateDevicesAndOutputs();
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            // do not force device change on duplicated output because if device is 0, it will
+            // also force a device 0 for the two outputs it is duplicated to which may override
+            // a valid device selection on those outputs.
+            setOutputDevice(mOutputs.keyAt(i),
+                            getNewDevice(mOutputs.keyAt(i), true /*fromCache*/),
+                            !mOutputs.valueAt(i)->isDuplicated(),
+                            0);
+        }
+
+        if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+            device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+        } else if (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO ||
+                   device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
+                   device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
+            device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+        } else {
+            return NO_ERROR;
+        }
+    }
+    // handle input devices
+    if (audio_is_input_device(device)) {
+
+        switch (state)
+        {
+        // handle input device connection
+        case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: {
+            if (mAvailableInputDevices & device) {
+                ALOGW("setDeviceConnectionState() device already connected: %d", device);
+                return INVALID_OPERATION;
+            }
+            mAvailableInputDevices = mAvailableInputDevices | (device & ~AUDIO_DEVICE_BIT_IN);
+            }
+            break;
+
+        // handle input device disconnection
+        case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: {
+            if (!(mAvailableInputDevices & device)) {
+                ALOGW("setDeviceConnectionState() device not connected: %d", device);
+                return INVALID_OPERATION;
+            }
+            mAvailableInputDevices = (audio_devices_t) (mAvailableInputDevices & ~device);
+            } break;
+
+        default:
+            ALOGE("setDeviceConnectionState() invalid state: %x", state);
+            return BAD_VALUE;
+        }
+
+        audio_io_handle_t activeInput = getActiveInput();
+        if (activeInput != 0) {
+            AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+            audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+            if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
+                ALOGV("setDeviceConnectionState() changing device from %x to %x for input %d",
+                        inputDesc->mDevice, newDevice, activeInput);
+                inputDesc->mDevice = newDevice;
+                AudioParameter param = AudioParameter();
+                param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+                mpClientInterface->setParameters(activeInput, param.toString());
+            }
+        }
+
+        return NO_ERROR;
+    }
+
+    ALOGW("setDeviceConnectionState() invalid device: %x", device);
+    return BAD_VALUE;
+}
+
+audio_policy_dev_state_t AudioPolicyManager::getDeviceConnectionState(audio_devices_t device,
+                                                  const char *device_address)
+{
+    audio_policy_dev_state_t state = AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE;
+    String8 address = String8(device_address);
+    if (audio_is_output_device(device)) {
+        if (device & mAvailableOutputDevices) {
+            if (audio_is_a2dp_device(device) &&
+                (!mHasA2dp || (address != "" && mA2dpDeviceAddress != address))) {
+                return state;
+            }
+            if (audio_is_bluetooth_sco_device(device) &&
+                address != "" && mScoDeviceAddress != address) {
+                return state;
+            }
+            if (audio_is_usb_device(device) &&
+                (!mHasUsb || (address != "" && mUsbCardAndDevice != address))) {
+                ALOGE("getDeviceConnectionState() invalid device: %x", device);
+                return state;
+            }
+            if (audio_is_remote_submix_device((audio_devices_t)device) && !mHasRemoteSubmix) {
+                return state;
+            }
+            state = AUDIO_POLICY_DEVICE_STATE_AVAILABLE;
+        }
+    } else if (audio_is_input_device(device)) {
+        if (device & mAvailableInputDevices) {
+            state = AUDIO_POLICY_DEVICE_STATE_AVAILABLE;
+        }
+    }
+
+    return state;
+}
+
+void AudioPolicyManager::setPhoneState(audio_mode_t state)
+{
+    ALOGV("setPhoneState() state %d", state);
+    audio_devices_t newDevice = AUDIO_DEVICE_NONE;
+    if (state < 0 || state >= AUDIO_MODE_CNT) {
+        ALOGW("setPhoneState() invalid state %d", state);
+        return;
+    }
+
+    if (state == mPhoneState ) {
+        ALOGW("setPhoneState() setting same state %d", state);
+        return;
+    }
+
+    // if leaving call state, handle special case of active streams
+    // pertaining to sonification strategy see handleIncallSonification()
+    if (isInCall()) {
+        ALOGV("setPhoneState() in call state management: new state is %d", state);
+        for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) {
+            handleIncallSonification((audio_stream_type_t)stream, false, true);
+        }
+    }
+
+    // store previous phone state for management of sonification strategy below
+    int oldState = mPhoneState;
+    mPhoneState = state;
+    bool force = false;
+
+    // are we entering or starting a call
+    if (!isStateInCall(oldState) && isStateInCall(state)) {
+        ALOGV("  Entering call in setPhoneState()");
+        // force routing command to audio hardware when starting a call
+        // even if no device change is needed
+        force = true;
+        for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+            mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] =
+                    sVolumeProfiles[AUDIO_STREAM_VOICE_CALL][j];
+        }
+    } else if (isStateInCall(oldState) && !isStateInCall(state)) {
+        ALOGV("  Exiting call in setPhoneState()");
+        // force routing command to audio hardware when exiting a call
+        // even if no device change is needed
+        force = true;
+        for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+            mStreams[AUDIO_STREAM_DTMF].mVolumeCurve[j] =
+                    sVolumeProfiles[AUDIO_STREAM_DTMF][j];
+        }
+    } else if (isStateInCall(state) && (state != oldState)) {
+        ALOGV("  Switching between telephony and VoIP in setPhoneState()");
+        // force routing command to audio hardware when switching between telephony and VoIP
+        // even if no device change is needed
+        force = true;
+    }
+
+    // check for device and output changes triggered by new phone state
+    newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/);
+    checkA2dpSuspend();
+    checkOutputForAllStrategies();
+    updateDevicesAndOutputs();
+
+    AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mPrimaryOutput);
+
+    // force routing command to audio hardware when ending call
+    // even if no device change is needed
+    if (isStateInCall(oldState) && newDevice == AUDIO_DEVICE_NONE) {
+        newDevice = hwOutputDesc->device();
+    }
+
+    int delayMs = 0;
+    if (isStateInCall(state)) {
+        nsecs_t sysTime = systemTime();
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+            // mute media and sonification strategies and delay device switch by the largest
+            // latency of any output where either strategy is active.
+            // This avoid sending the ring tone or music tail into the earpiece or headset.
+            if ((desc->isStrategyActive(STRATEGY_MEDIA,
+                                     SONIFICATION_HEADSET_MUSIC_DELAY,
+                                     sysTime) ||
+                    desc->isStrategyActive(STRATEGY_SONIFICATION,
+                                         SONIFICATION_HEADSET_MUSIC_DELAY,
+                                         sysTime)) &&
+                    (delayMs < (int)desc->mLatency*2)) {
+                delayMs = desc->mLatency*2;
+            }
+            setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i));
+            setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS,
+                getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/));
+            setStrategyMute(STRATEGY_SONIFICATION, true, mOutputs.keyAt(i));
+            setStrategyMute(STRATEGY_SONIFICATION, false, mOutputs.keyAt(i), MUTE_TIME_MS,
+                getDeviceForStrategy(STRATEGY_SONIFICATION, true /*fromCache*/));
+        }
+    }
+
+    // change routing is necessary
+    setOutputDevice(mPrimaryOutput, newDevice, force, delayMs);
+
+    // if entering in call state, handle special case of active streams
+    // pertaining to sonification strategy see handleIncallSonification()
+    if (isStateInCall(state)) {
+        ALOGV("setPhoneState() in call state management: new state is %d", state);
+        for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) {
+            handleIncallSonification((audio_stream_type_t)stream, true, true);
+        }
+    }
+
+    // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE
+    if (state == AUDIO_MODE_RINGTONE &&
+        isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)) {
+        mLimitRingtoneVolume = true;
+    } else {
+        mLimitRingtoneVolume = false;
+    }
+}
+
+void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage,
+                                         audio_policy_forced_cfg_t config)
+{
+    ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);
+
+    bool forceVolumeReeval = false;
+    switch(usage) {
+    case AUDIO_POLICY_FORCE_FOR_COMMUNICATION:
+        if (config != AUDIO_POLICY_FORCE_SPEAKER && config != AUDIO_POLICY_FORCE_BT_SCO &&
+            config != AUDIO_POLICY_FORCE_NONE) {
+            ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
+            return;
+        }
+        forceVolumeReeval = true;
+        mForceUse[usage] = config;
+        break;
+    case AUDIO_POLICY_FORCE_FOR_MEDIA:
+        if (config != AUDIO_POLICY_FORCE_HEADPHONES && config != AUDIO_POLICY_FORCE_BT_A2DP &&
+            config != AUDIO_POLICY_FORCE_WIRED_ACCESSORY &&
+            config != AUDIO_POLICY_FORCE_ANALOG_DOCK &&
+            config != AUDIO_POLICY_FORCE_DIGITAL_DOCK && config != AUDIO_POLICY_FORCE_NONE &&
+            config != AUDIO_POLICY_FORCE_NO_BT_A2DP) {
+            ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
+            return;
+        }
+        mForceUse[usage] = config;
+        break;
+    case AUDIO_POLICY_FORCE_FOR_RECORD:
+        if (config != AUDIO_POLICY_FORCE_BT_SCO && config != AUDIO_POLICY_FORCE_WIRED_ACCESSORY &&
+            config != AUDIO_POLICY_FORCE_NONE) {
+            ALOGW("setForceUse() invalid config %d for FOR_RECORD", config);
+            return;
+        }
+        mForceUse[usage] = config;
+        break;
+    case AUDIO_POLICY_FORCE_FOR_DOCK:
+        if (config != AUDIO_POLICY_FORCE_NONE && config != AUDIO_POLICY_FORCE_BT_CAR_DOCK &&
+            config != AUDIO_POLICY_FORCE_BT_DESK_DOCK &&
+            config != AUDIO_POLICY_FORCE_WIRED_ACCESSORY &&
+            config != AUDIO_POLICY_FORCE_ANALOG_DOCK &&
+            config != AUDIO_POLICY_FORCE_DIGITAL_DOCK) {
+            ALOGW("setForceUse() invalid config %d for FOR_DOCK", config);
+        }
+        forceVolumeReeval = true;
+        mForceUse[usage] = config;
+        break;
+    case AUDIO_POLICY_FORCE_FOR_SYSTEM:
+        if (config != AUDIO_POLICY_FORCE_NONE &&
+            config != AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
+            ALOGW("setForceUse() invalid config %d for FOR_SYSTEM", config);
+        }
+        forceVolumeReeval = true;
+        mForceUse[usage] = config;
+        break;
+    default:
+        ALOGW("setForceUse() invalid usage %d", usage);
+        break;
+    }
+
+    // check for device and output changes triggered by new force usage
+    checkA2dpSuspend();
+    checkOutputForAllStrategies();
+    updateDevicesAndOutputs();
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        audio_io_handle_t output = mOutputs.keyAt(i);
+        audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/);
+        setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE));
+        if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) {
+            applyStreamVolumes(output, newDevice, 0, true);
+        }
+    }
+
+    audio_io_handle_t activeInput = getActiveInput();
+    if (activeInput != 0) {
+        AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+        audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+        if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
+            ALOGV("setForceUse() changing device from %x to %x for input %d",
+                    inputDesc->mDevice, newDevice, activeInput);
+            inputDesc->mDevice = newDevice;
+            AudioParameter param = AudioParameter();
+            param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+            mpClientInterface->setParameters(activeInput, param.toString());
+        }
+    }
+
+}
+
+audio_policy_forced_cfg_t AudioPolicyManager::getForceUse(audio_policy_force_use_t usage)
+{
+    return mForceUse[usage];
+}
+
+void AudioPolicyManager::setSystemProperty(const char* property, const char* value)
+{
+    ALOGV("setSystemProperty() property %s, value %s", property, value);
+}
+
+// Find a direct output profile compatible with the parameters passed, even if the input flags do
+// not explicitly request a direct output
+AudioPolicyManager::IOProfile *AudioPolicyManager::getProfileForDirectOutput(
+                                                               audio_devices_t device,
+                                                               uint32_t samplingRate,
+                                                               audio_format_t format,
+                                                               audio_channel_mask_t channelMask,
+                                                               audio_output_flags_t flags)
+{
+    for (size_t i = 0; i < mHwModules.size(); i++) {
+        if (mHwModules[i]->mHandle == 0) {
+            continue;
+        }
+        for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
+            IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
+            if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+                if (profile->isCompatibleProfile(device, samplingRate, format,
+                                           channelMask,
+                                           AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
+                    if (mAvailableOutputDevices & profile->mSupportedDevices) {
+                        return mHwModules[i]->mOutputProfiles[j];
+                    }
+                }
+            } else {
+                if (profile->isCompatibleProfile(device, samplingRate, format,
+                                           channelMask,
+                                           AUDIO_OUTPUT_FLAG_DIRECT)) {
+                    if (mAvailableOutputDevices & profile->mSupportedDevices) {
+                        return mHwModules[i]->mOutputProfiles[j];
+                    }
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream,
+                                    uint32_t samplingRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t channelMask,
+                                    audio_output_flags_t flags,
+                                    const audio_offload_info_t *offloadInfo)
+{
+    audio_io_handle_t output = 0;
+    uint32_t latency = 0;
+    routing_strategy strategy = getStrategy(stream);
+    audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
+    ALOGV("getOutput() device %d, stream %d, samplingRate %d, format %x, channelMask %x, flags %x",
+          device, stream, samplingRate, format, channelMask, flags);
+
+#ifdef AUDIO_POLICY_TEST
+    if (mCurOutput != 0) {
+        ALOGV("getOutput() test output mCurOutput %d, samplingRate %d, format %d, channelMask %x, mDirectOutput %d",
+                mCurOutput, mTestSamplingRate, mTestFormat, mTestChannels, mDirectOutput);
+
+        if (mTestOutputs[mCurOutput] == 0) {
+            ALOGV("getOutput() opening test output");
+            AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(NULL);
+            outputDesc->mDevice = mTestDevice;
+            outputDesc->mSamplingRate = mTestSamplingRate;
+            outputDesc->mFormat = mTestFormat;
+            outputDesc->mChannelMask = mTestChannels;
+            outputDesc->mLatency = mTestLatencyMs;
+            outputDesc->mFlags =
+                    (audio_output_flags_t)(mDirectOutput ? AUDIO_OUTPUT_FLAG_DIRECT : 0);
+            outputDesc->mRefCount[stream] = 0;
+            mTestOutputs[mCurOutput] = mpClientInterface->openOutput(0, &outputDesc->mDevice,
+                                            &outputDesc->mSamplingRate,
+                                            &outputDesc->mFormat,
+                                            &outputDesc->mChannelMask,
+                                            &outputDesc->mLatency,
+                                            outputDesc->mFlags,
+                                            offloadInfo);
+            if (mTestOutputs[mCurOutput]) {
+                AudioParameter outputCmd = AudioParameter();
+                outputCmd.addInt(String8("set_id"),mCurOutput);
+                mpClientInterface->setParameters(mTestOutputs[mCurOutput],outputCmd.toString());
+                addOutput(mTestOutputs[mCurOutput], outputDesc);
+            }
+        }
+        return mTestOutputs[mCurOutput];
+    }
+#endif //AUDIO_POLICY_TEST
+
+    // open a direct output if required by specified parameters
+    //force direct flag if offload flag is set: offloading implies a direct output stream
+    // and all common behaviors are driven by checking only the direct flag
+    // this should normally be set appropriately in the policy configuration file
+    if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+        flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT);
+    }
+
+    // Do not allow offloading if one non offloadable effect is enabled. This prevents from
+    // creating an offloaded track and tearing it down immediately after start when audioflinger
+    // detects there is an active non offloadable effect.
+    // FIXME: We should check the audio session here but we do not have it in this context.
+    // This may prevent offloading in rare situations where effects are left active by apps
+    // in the background.
+    IOProfile *profile = NULL;
+    if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
+            !isNonOffloadableEffectEnabled()) {
+        profile = getProfileForDirectOutput(device,
+                                           samplingRate,
+                                           format,
+                                           channelMask,
+                                           (audio_output_flags_t)flags);
+    }
+
+    if (profile != NULL) {
+        AudioOutputDescriptor *outputDesc = NULL;
+
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+            if (!desc->isDuplicated() && (profile == desc->mProfile)) {
+                outputDesc = desc;
+                // reuse direct output if currently open and configured with same parameters
+                if ((samplingRate == outputDesc->mSamplingRate) &&
+                        (format == outputDesc->mFormat) &&
+                        (channelMask == outputDesc->mChannelMask)) {
+                    outputDesc->mDirectOpenCount++;
+                    ALOGV("getOutput() reusing direct output %d", mOutputs.keyAt(i));
+                    return mOutputs.keyAt(i);
+                }
+            }
+        }
+        // close direct output if currently open and configured with different parameters
+        if (outputDesc != NULL) {
+            closeOutput(outputDesc->mId);
+        }
+        outputDesc = new AudioOutputDescriptor(profile);
+        outputDesc->mDevice = device;
+        outputDesc->mSamplingRate = samplingRate;
+        outputDesc->mFormat = format;
+        outputDesc->mChannelMask = channelMask;
+        outputDesc->mLatency = 0;
+        outputDesc->mFlags =(audio_output_flags_t) (outputDesc->mFlags | flags);
+        outputDesc->mRefCount[stream] = 0;
+        outputDesc->mStopTime[stream] = 0;
+        outputDesc->mDirectOpenCount = 1;
+        output = mpClientInterface->openOutput(profile->mModule->mHandle,
+                                        &outputDesc->mDevice,
+                                        &outputDesc->mSamplingRate,
+                                        &outputDesc->mFormat,
+                                        &outputDesc->mChannelMask,
+                                        &outputDesc->mLatency,
+                                        outputDesc->mFlags,
+                                        offloadInfo);
+
+        // only accept an output with the requested parameters
+        if (output == 0 ||
+            (samplingRate != 0 && samplingRate != outputDesc->mSamplingRate) ||
+            (format != AUDIO_FORMAT_DEFAULT && format != outputDesc->mFormat) ||
+            (channelMask != 0 && channelMask != outputDesc->mChannelMask)) {
+            ALOGV("getOutput() failed opening direct output: output %d samplingRate %d %d,"
+                    "format %d %d, channelMask %04x %04x", output, samplingRate,
+                    outputDesc->mSamplingRate, format, outputDesc->mFormat, channelMask,
+                    outputDesc->mChannelMask);
+            if (output != 0) {
+                mpClientInterface->closeOutput(output);
+            }
+            delete outputDesc;
+            return 0;
+        }
+        audio_io_handle_t srcOutput = getOutputForEffect();
+        addOutput(output, outputDesc);
+        audio_io_handle_t dstOutput = getOutputForEffect();
+        if (dstOutput == output) {
+            mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, srcOutput, dstOutput);
+        }
+        mPreviousOutputs = mOutputs;
+        ALOGV("getOutput() returns new direct output %d", output);
+        return output;
+    }
+
+    // ignoring channel mask due to downmix capability in mixer
+
+    // open a non direct output
+
+    // for non direct outputs, only PCM is supported
+    if (audio_is_linear_pcm(format)) {
+        // get which output is suitable for the specified stream. The actual
+        // routing change will happen when startOutput() will be called
+        SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
+
+        output = selectOutput(outputs, flags);
+    }
+    ALOGW_IF((output == 0), "getOutput() could not find output for stream %d, samplingRate %d,"
+            "format %d, channels %x, flags %x", stream, samplingRate, format, channelMask, flags);
+
+    ALOGV("getOutput() returns output %d", output);
+
+    return output;
+}
+
+audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_handle_t>& outputs,
+                                                       audio_output_flags_t flags)
+{
+    // select one output among several that provide a path to a particular device or set of
+    // devices (the list was previously build by getOutputsForDevice()).
+    // The priority is as follows:
+    // 1: the output with the highest number of requested policy flags
+    // 2: the primary output
+    // 3: the first output in the list
+
+    if (outputs.size() == 0) {
+        return 0;
+    }
+    if (outputs.size() == 1) {
+        return outputs[0];
+    }
+
+    int maxCommonFlags = 0;
+    audio_io_handle_t outputFlags = 0;
+    audio_io_handle_t outputPrimary = 0;
+
+    for (size_t i = 0; i < outputs.size(); i++) {
+        AudioOutputDescriptor *outputDesc = mOutputs.valueFor(outputs[i]);
+        if (!outputDesc->isDuplicated()) {
+            int commonFlags = popcount(outputDesc->mProfile->mFlags & flags);
+            if (commonFlags > maxCommonFlags) {
+                outputFlags = outputs[i];
+                maxCommonFlags = commonFlags;
+                ALOGV("selectOutput() commonFlags for output %d, %04x", outputs[i], commonFlags);
+            }
+            if (outputDesc->mProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+                outputPrimary = outputs[i];
+            }
+        }
+    }
+
+    if (outputFlags != 0) {
+        return outputFlags;
+    }
+    if (outputPrimary != 0) {
+        return outputPrimary;
+    }
+
+    return outputs[0];
+}
+
+status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
+                                             audio_stream_type_t stream,
+                                             int session)
+{
+    ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session);
+    ssize_t index = mOutputs.indexOfKey(output);
+    if (index < 0) {
+        ALOGW("startOutput() unknown output %d", output);
+        return BAD_VALUE;
+    }
+
+    AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+    // increment usage count for this stream on the requested output:
+    // NOTE that the usage count is the same for duplicated output and hardware output which is
+    // necessary for a correct control of hardware output routing by startOutput() and stopOutput()
+    outputDesc->changeRefCount(stream, 1);
+
+    if (outputDesc->mRefCount[stream] == 1) {
+        audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+        routing_strategy strategy = getStrategy(stream);
+        bool shouldWait = (strategy == STRATEGY_SONIFICATION) ||
+                            (strategy == STRATEGY_SONIFICATION_RESPECTFUL);
+        uint32_t waitMs = 0;
+        bool force = false;
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+            if (desc != outputDesc) {
+                // force a device change if any other output is managed by the same hw
+                // module and has a current device selection that differs from selected device.
+                // In this case, the audio HAL must receive the new device selection so that it can
+                // change the device currently selected by the other active output.
+                if (outputDesc->sharesHwModuleWith(desc) &&
+                    desc->device() != newDevice) {
+                    force = true;
+                }
+                // wait for audio on other active outputs to be presented when starting
+                // a notification so that audio focus effect can propagate.
+                uint32_t latency = desc->latency();
+                if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
+                    waitMs = latency;
+                }
+            }
+        }
+        uint32_t muteWaitMs = setOutputDevice(output, newDevice, force);
+
+        // handle special case for sonification while in call
+        if (isInCall()) {
+            handleIncallSonification(stream, true, false);
+        }
+
+        // apply volume rules for current stream and device if necessary
+        checkAndSetVolume(stream,
+                          mStreams[stream].getVolumeIndex(newDevice),
+                          output,
+                          newDevice);
+
+        // update the outputs if starting an output with a stream that can affect notification
+        // routing
+        handleNotificationRoutingForStream(stream);
+        if (waitMs > muteWaitMs) {
+            usleep((waitMs - muteWaitMs) * 2 * 1000);
+        }
+    }
+    return NO_ERROR;
+}
+
+
+status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
+                                            audio_stream_type_t stream,
+                                            int session)
+{
+    ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
+    ssize_t index = mOutputs.indexOfKey(output);
+    if (index < 0) {
+        ALOGW("stopOutput() unknown output %d", output);
+        return BAD_VALUE;
+    }
+
+    AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+    // handle special case for sonification while in call
+    if (isInCall()) {
+        handleIncallSonification(stream, false, false);
+    }
+
+    if (outputDesc->mRefCount[stream] > 0) {
+        // decrement usage count of this stream on the output
+        outputDesc->changeRefCount(stream, -1);
+        // store time at which the stream was stopped - see isStreamActive()
+        if (outputDesc->mRefCount[stream] == 0) {
+            outputDesc->mStopTime[stream] = systemTime();
+            audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+            // delay the device switch by twice the latency because stopOutput() is executed when
+            // the track stop() command is received and at that time the audio track buffer can
+            // still contain data that needs to be drained. The latency only covers the audio HAL
+            // and kernel buffers. Also the latency does not always include additional delay in the
+            // audio path (audio DSP, CODEC ...)
+            setOutputDevice(output, newDevice, false, outputDesc->mLatency*2);
+
+            // force restoring the device selection on other active outputs if it differs from the
+            // one being selected for this output
+            for (size_t i = 0; i < mOutputs.size(); i++) {
+                audio_io_handle_t curOutput = mOutputs.keyAt(i);
+                AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+                if (curOutput != output &&
+                        desc->isActive() &&
+                        outputDesc->sharesHwModuleWith(desc) &&
+                        (newDevice != desc->device())) {
+                    setOutputDevice(curOutput,
+                                    getNewDevice(curOutput, false /*fromCache*/),
+                                    true,
+                                    outputDesc->mLatency*2);
+                }
+            }
+            // update the outputs if stopping one with a stream that can affect notification routing
+            handleNotificationRoutingForStream(stream);
+        }
+        return NO_ERROR;
+    } else {
+        ALOGW("stopOutput() refcount is already 0 for output %d", output);
+        return INVALID_OPERATION;
+    }
+}
+
+void AudioPolicyManager::releaseOutput(audio_io_handle_t output)
+{
+    ALOGV("releaseOutput() %d", output);
+    ssize_t index = mOutputs.indexOfKey(output);
+    if (index < 0) {
+        ALOGW("releaseOutput() releasing unknown output %d", output);
+        return;
+    }
+
+#ifdef AUDIO_POLICY_TEST
+    int testIndex = testOutputIndex(output);
+    if (testIndex != 0) {
+        AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+        if (outputDesc->isActive()) {
+            mpClientInterface->closeOutput(output);
+            delete mOutputs.valueAt(index);
+            mOutputs.removeItem(output);
+            mTestOutputs[testIndex] = 0;
+        }
+        return;
+    }
+#endif //AUDIO_POLICY_TEST
+
+    AudioOutputDescriptor *desc = mOutputs.valueAt(index);
+    if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
+        if (desc->mDirectOpenCount <= 0) {
+            ALOGW("releaseOutput() invalid open count %d for output %d",
+                                                              desc->mDirectOpenCount, output);
+            return;
+        }
+        if (--desc->mDirectOpenCount == 0) {
+            closeOutput(output);
+            // If effects where present on the output, audioflinger moved them to the primary
+            // output by default: move them back to the appropriate output.
+            audio_io_handle_t dstOutput = getOutputForEffect();
+            if (dstOutput != mPrimaryOutput) {
+                mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, mPrimaryOutput, dstOutput);
+            }
+        }
+    }
+}
+
+
+audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource,
+                                    uint32_t samplingRate,
+                                    audio_format_t format,
+                                    audio_channel_mask_t channelMask,
+                                    audio_in_acoustics_t acoustics)
+{
+    audio_io_handle_t input = 0;
+    audio_devices_t device = getDeviceForInputSource(inputSource);
+
+    ALOGV("getInput() inputSource %d, samplingRate %d, format %d, channelMask %x, acoustics %x",
+          inputSource, samplingRate, format, channelMask, acoustics);
+
+    if (device == AUDIO_DEVICE_NONE) {
+        ALOGW("getInput() could not find device for inputSource %d", inputSource);
+        return 0;
+    }
+
+    // adapt channel selection to input source
+    switch(inputSource) {
+    case AUDIO_SOURCE_VOICE_UPLINK:
+        channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK;
+        break;
+    case AUDIO_SOURCE_VOICE_DOWNLINK:
+        channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK;
+        break;
+    case AUDIO_SOURCE_VOICE_CALL:
+        channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK;
+        break;
+    default:
+        break;
+    }
+
+    IOProfile *profile = getInputProfile(device,
+                                         samplingRate,
+                                         format,
+                                         channelMask);
+    if (profile == NULL) {
+        ALOGW("getInput() could not find profile for device %04x, samplingRate %d, format %d, "
+                "channelMask %04x",
+                device, samplingRate, format, channelMask);
+        return 0;
+    }
+
+    if (profile->mModule->mHandle == 0) {
+        ALOGE("getInput(): HW module %s not opened", profile->mModule->mName);
+        return 0;
+    }
+
+    AudioInputDescriptor *inputDesc = new AudioInputDescriptor(profile);
+
+    inputDesc->mInputSource = inputSource;
+    inputDesc->mDevice = device;
+    inputDesc->mSamplingRate = samplingRate;
+    inputDesc->mFormat = format;
+    inputDesc->mChannelMask = channelMask;
+    inputDesc->mRefCount = 0;
+    input = mpClientInterface->openInput(profile->mModule->mHandle,
+                                    &inputDesc->mDevice,
+                                    &inputDesc->mSamplingRate,
+                                    &inputDesc->mFormat,
+                                    &inputDesc->mChannelMask);
+
+    // only accept input with the exact requested set of parameters
+    if (input == 0 ||
+        (samplingRate != inputDesc->mSamplingRate) ||
+        (format != inputDesc->mFormat) ||
+        (channelMask != inputDesc->mChannelMask)) {
+        ALOGI("getInput() failed opening input: samplingRate %d, format %d, channelMask %x",
+                samplingRate, format, channelMask);
+        if (input != 0) {
+            mpClientInterface->closeInput(input);
+        }
+        delete inputDesc;
+        return 0;
+    }
+    mInputs.add(input, inputDesc);
+    return input;
+}
+
+status_t AudioPolicyManager::startInput(audio_io_handle_t input)
+{
+    ALOGV("startInput() input %d", input);
+    ssize_t index = mInputs.indexOfKey(input);
+    if (index < 0) {
+        ALOGW("startInput() unknown input %d", input);
+        return BAD_VALUE;
+    }
+    AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+#ifdef AUDIO_POLICY_TEST
+    if (mTestInput == 0)
+#endif //AUDIO_POLICY_TEST
+    {
+        // refuse 2 active AudioRecord clients at the same time except if the active input
+        // uses AUDIO_SOURCE_HOTWORD in which case it is closed.
+        audio_io_handle_t activeInput = getActiveInput();
+        if (!isVirtualInputDevice(inputDesc->mDevice) && activeInput != 0) {
+            AudioInputDescriptor *activeDesc = mInputs.valueFor(activeInput);
+            if (activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) {
+                ALOGW("startInput() preempting already started low-priority input %d", activeInput);
+                stopInput(activeInput);
+                releaseInput(activeInput);
+            } else {
+                ALOGW("startInput() input %d failed: other input already started", input);
+                return INVALID_OPERATION;
+            }
+        }
+    }
+
+    audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+    if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
+        inputDesc->mDevice = newDevice;
+    }
+
+    // automatically enable the remote submix output when input is started
+    if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+        setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+                AUDIO_POLICY_DEVICE_STATE_AVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
+    }
+
+    AudioParameter param = AudioParameter();
+    param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice);
+
+    int aliasSource = (inputDesc->mInputSource == AUDIO_SOURCE_HOTWORD) ?
+                                        AUDIO_SOURCE_VOICE_RECOGNITION : inputDesc->mInputSource;
+
+    param.addInt(String8(AudioParameter::keyInputSource), aliasSource);
+    ALOGV("AudioPolicyManager::startInput() input source = %d", inputDesc->mInputSource);
+
+    mpClientInterface->setParameters(input, param.toString());
+
+    inputDesc->mRefCount = 1;
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::stopInput(audio_io_handle_t input)
+{
+    ALOGV("stopInput() input %d", input);
+    ssize_t index = mInputs.indexOfKey(input);
+    if (index < 0) {
+        ALOGW("stopInput() unknown input %d", input);
+        return BAD_VALUE;
+    }
+    AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+    if (inputDesc->mRefCount == 0) {
+        ALOGW("stopInput() input %d already stopped", input);
+        return INVALID_OPERATION;
+    } else {
+        // automatically disable the remote submix output when input is stopped
+        if (audio_is_remote_submix_device(inputDesc->mDevice)) {
+            setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+                    AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS);
+        }
+
+        AudioParameter param = AudioParameter();
+        param.addInt(String8(AudioParameter::keyRouting), 0);
+        mpClientInterface->setParameters(input, param.toString());
+        inputDesc->mRefCount = 0;
+        return NO_ERROR;
+    }
+}
+
+void AudioPolicyManager::releaseInput(audio_io_handle_t input)
+{
+    ALOGV("releaseInput() %d", input);
+    ssize_t index = mInputs.indexOfKey(input);
+    if (index < 0) {
+        ALOGW("releaseInput() releasing unknown input %d", input);
+        return;
+    }
+    mpClientInterface->closeInput(input);
+    delete mInputs.valueAt(index);
+    mInputs.removeItem(input);
+    ALOGV("releaseInput() exit");
+}
+
+void AudioPolicyManager::initStreamVolume(audio_stream_type_t stream,
+                                            int indexMin,
+                                            int indexMax)
+{
+    ALOGV("initStreamVolume() stream %d, min %d, max %d", stream , indexMin, indexMax);
+    if (indexMin < 0 || indexMin >= indexMax) {
+        ALOGW("initStreamVolume() invalid index limits for stream %d, min %d, max %d", stream , indexMin, indexMax);
+        return;
+    }
+    mStreams[stream].mIndexMin = indexMin;
+    mStreams[stream].mIndexMax = indexMax;
+}
+
+status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
+                                                      int index,
+                                                      audio_devices_t device)
+{
+
+    if ((index < mStreams[stream].mIndexMin) || (index > mStreams[stream].mIndexMax)) {
+        return BAD_VALUE;
+    }
+    if (!audio_is_output_device(device)) {
+        return BAD_VALUE;
+    }
+
+    // Force max volume if stream cannot be muted
+    if (!mStreams[stream].mCanBeMuted) index = mStreams[stream].mIndexMax;
+
+    ALOGV("setStreamVolumeIndex() stream %d, device %04x, index %d",
+          stream, device, index);
+
+    // if device is AUDIO_DEVICE_OUT_DEFAULT set default value and
+    // clear all device specific values
+    if (device == AUDIO_DEVICE_OUT_DEFAULT) {
+        mStreams[stream].mIndexCur.clear();
+    }
+    mStreams[stream].mIndexCur.add(device, index);
+
+    // compute and apply stream volume on all outputs according to connected device
+    status_t status = NO_ERROR;
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        audio_devices_t curDevice =
+                getDeviceForVolume(mOutputs.valueAt(i)->device());
+        if ((device == AUDIO_DEVICE_OUT_DEFAULT) || (device == curDevice)) {
+            status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice);
+            if (volStatus != NO_ERROR) {
+                status = volStatus;
+            }
+        }
+    }
+    return status;
+}
+
+status_t AudioPolicyManager::getStreamVolumeIndex(audio_stream_type_t stream,
+                                                      int *index,
+                                                      audio_devices_t device)
+{
+    if (index == NULL) {
+        return BAD_VALUE;
+    }
+    if (!audio_is_output_device(device)) {
+        return BAD_VALUE;
+    }
+    // if device is AUDIO_DEVICE_OUT_DEFAULT, return volume for device corresponding to
+    // the strategy the stream belongs to.
+    if (device == AUDIO_DEVICE_OUT_DEFAULT) {
+        device = getDeviceForStrategy(getStrategy(stream), true /*fromCache*/);
+    }
+    device = getDeviceForVolume(device);
+
+    *index =  mStreams[stream].getVolumeIndex(device);
+    ALOGV("getStreamVolumeIndex() stream %d device %08x index %d", stream, device, *index);
+    return NO_ERROR;
+}
+
+audio_io_handle_t AudioPolicyManager::selectOutputForEffects(
+                                            const SortedVector<audio_io_handle_t>& outputs)
+{
+    // select one output among several suitable for global effects.
+    // The priority is as follows:
+    // 1: An offloaded output. If the effect ends up not being offloadable,
+    //    AudioFlinger will invalidate the track and the offloaded output
+    //    will be closed causing the effect to be moved to a PCM output.
+    // 2: A deep buffer output
+    // 3: the first output in the list
+
+    if (outputs.size() == 0) {
+        return 0;
+    }
+
+    audio_io_handle_t outputOffloaded = 0;
+    audio_io_handle_t outputDeepBuffer = 0;
+
+    for (size_t i = 0; i < outputs.size(); i++) {
+        AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]);
+        ALOGV("selectOutputForEffects outputs[%d] flags %x", i, desc->mFlags);
+        if ((desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+            outputOffloaded = outputs[i];
+        }
+        if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) {
+            outputDeepBuffer = outputs[i];
+        }
+    }
+
+    ALOGV("selectOutputForEffects outputOffloaded %d outputDeepBuffer %d",
+          outputOffloaded, outputDeepBuffer);
+    if (outputOffloaded != 0) {
+        return outputOffloaded;
+    }
+    if (outputDeepBuffer != 0) {
+        return outputDeepBuffer;
+    }
+
+    return outputs[0];
+}
+
+audio_io_handle_t AudioPolicyManager::getOutputForEffect(const effect_descriptor_t *desc)
+{
+    // apply simple rule where global effects are attached to the same output as MUSIC streams
+
+    routing_strategy strategy = getStrategy(AUDIO_STREAM_MUSIC);
+    audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
+    SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(device, mOutputs);
+
+    audio_io_handle_t output = selectOutputForEffects(dstOutputs);
+    ALOGV("getOutputForEffect() got output %d for fx %s flags %x",
+          output, (desc == NULL) ? "unspecified" : desc->name,  (desc == NULL) ? 0 : desc->flags);
+
+    return output;
+}
+
+status_t AudioPolicyManager::registerEffect(const effect_descriptor_t *desc,
+                                audio_io_handle_t io,
+                                uint32_t strategy,
+                                int session,
+                                int id)
+{
+    ssize_t index = mOutputs.indexOfKey(io);
+    if (index < 0) {
+        index = mInputs.indexOfKey(io);
+        if (index < 0) {
+            ALOGW("registerEffect() unknown io %d", io);
+            return INVALID_OPERATION;
+        }
+    }
+
+    if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) {
+        ALOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB",
+                desc->name, desc->memoryUsage);
+        return INVALID_OPERATION;
+    }
+    mTotalEffectsMemory += desc->memoryUsage;
+    ALOGV("registerEffect() effect %s, io %d, strategy %d session %d id %d",
+            desc->name, io, strategy, session, id);
+    ALOGV("registerEffect() memory %d, total memory %d", desc->memoryUsage, mTotalEffectsMemory);
+
+    EffectDescriptor *pDesc = new EffectDescriptor();
+    memcpy (&pDesc->mDesc, desc, sizeof(effect_descriptor_t));
+    pDesc->mIo = io;
+    pDesc->mStrategy = (routing_strategy)strategy;
+    pDesc->mSession = session;
+    pDesc->mEnabled = false;
+
+    mEffects.add(id, pDesc);
+
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::unregisterEffect(int id)
+{
+    ssize_t index = mEffects.indexOfKey(id);
+    if (index < 0) {
+        ALOGW("unregisterEffect() unknown effect ID %d", id);
+        return INVALID_OPERATION;
+    }
+
+    EffectDescriptor *pDesc = mEffects.valueAt(index);
+
+    setEffectEnabled(pDesc, false);
+
+    if (mTotalEffectsMemory < pDesc->mDesc.memoryUsage) {
+        ALOGW("unregisterEffect() memory %d too big for total %d",
+                pDesc->mDesc.memoryUsage, mTotalEffectsMemory);
+        pDesc->mDesc.memoryUsage = mTotalEffectsMemory;
+    }
+    mTotalEffectsMemory -= pDesc->mDesc.memoryUsage;
+    ALOGV("unregisterEffect() effect %s, ID %d, memory %d total memory %d",
+            pDesc->mDesc.name, id, pDesc->mDesc.memoryUsage, mTotalEffectsMemory);
+
+    mEffects.removeItem(id);
+    delete pDesc;
+
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::setEffectEnabled(int id, bool enabled)
+{
+    ssize_t index = mEffects.indexOfKey(id);
+    if (index < 0) {
+        ALOGW("unregisterEffect() unknown effect ID %d", id);
+        return INVALID_OPERATION;
+    }
+
+    return setEffectEnabled(mEffects.valueAt(index), enabled);
+}
+
+status_t AudioPolicyManager::setEffectEnabled(EffectDescriptor *pDesc, bool enabled)
+{
+    if (enabled == pDesc->mEnabled) {
+        ALOGV("setEffectEnabled(%s) effect already %s",
+             enabled?"true":"false", enabled?"enabled":"disabled");
+        return INVALID_OPERATION;
+    }
+
+    if (enabled) {
+        if (mTotalEffectsCpuLoad + pDesc->mDesc.cpuLoad > getMaxEffectsCpuLoad()) {
+            ALOGW("setEffectEnabled(true) CPU Load limit exceeded for Fx %s, CPU %f MIPS",
+                 pDesc->mDesc.name, (float)pDesc->mDesc.cpuLoad/10);
+            return INVALID_OPERATION;
+        }
+        mTotalEffectsCpuLoad += pDesc->mDesc.cpuLoad;
+        ALOGV("setEffectEnabled(true) total CPU %d", mTotalEffectsCpuLoad);
+    } else {
+        if (mTotalEffectsCpuLoad < pDesc->mDesc.cpuLoad) {
+            ALOGW("setEffectEnabled(false) CPU load %d too high for total %d",
+                    pDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad);
+            pDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad;
+        }
+        mTotalEffectsCpuLoad -= pDesc->mDesc.cpuLoad;
+        ALOGV("setEffectEnabled(false) total CPU %d", mTotalEffectsCpuLoad);
+    }
+    pDesc->mEnabled = enabled;
+    return NO_ERROR;
+}
+
+bool AudioPolicyManager::isNonOffloadableEffectEnabled()
+{
+    for (size_t i = 0; i < mEffects.size(); i++) {
+        const EffectDescriptor * const pDesc = mEffects.valueAt(i);
+        if (pDesc->mEnabled && (pDesc->mStrategy == STRATEGY_MEDIA) &&
+                ((pDesc->mDesc.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) == 0)) {
+            ALOGV("isNonOffloadableEffectEnabled() non offloadable effect %s enabled on session %d",
+                  pDesc->mDesc.name, pDesc->mSession);
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioPolicyManager::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
+{
+    nsecs_t sysTime = systemTime();
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        const AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+        if (outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioPolicyManager::isStreamActiveRemotely(audio_stream_type_t stream,
+                                                    uint32_t inPastMs) const
+{
+    nsecs_t sysTime = systemTime();
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        const AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+        if (((outputDesc->device() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) &&
+                outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioPolicyManager::isSourceActive(audio_source_t source) const
+{
+    for (size_t i = 0; i < mInputs.size(); i++) {
+        const AudioInputDescriptor * inputDescriptor = mInputs.valueAt(i);
+        if ((inputDescriptor->mInputSource == (int)source ||
+                (source == AUDIO_SOURCE_VOICE_RECOGNITION &&
+                 inputDescriptor->mInputSource == AUDIO_SOURCE_HOTWORD))
+             && (inputDescriptor->mRefCount > 0)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+
+status_t AudioPolicyManager::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "\nAudioPolicyManager Dump: %p\n", this);
+    result.append(buffer);
+
+    snprintf(buffer, SIZE, " Primary Output: %d\n", mPrimaryOutput);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " A2DP device address: %s\n", mA2dpDeviceAddress.string());
+    result.append(buffer);
+    snprintf(buffer, SIZE, " SCO device address: %s\n", mScoDeviceAddress.string());
+    result.append(buffer);
+    snprintf(buffer, SIZE, " USB audio ALSA %s\n", mUsbCardAndDevice.string());
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Output devices: %08x\n", mAvailableOutputDevices);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Input devices: %08x\n", mAvailableInputDevices);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Phone state: %d\n", mPhoneState);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Force use for communications %d\n",
+             mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Force use for media %d\n", mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA]);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Force use for record %d\n", mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD]);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Force use for dock %d\n", mForceUse[AUDIO_POLICY_FORCE_FOR_DOCK]);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Force use for system %d\n", mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM]);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+
+
+    snprintf(buffer, SIZE, "\nHW Modules dump:\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < mHwModules.size(); i++) {
+        snprintf(buffer, SIZE, "- HW Module %d:\n", i + 1);
+        write(fd, buffer, strlen(buffer));
+        mHwModules[i]->dump(fd);
+    }
+
+    snprintf(buffer, SIZE, "\nOutputs dump:\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        snprintf(buffer, SIZE, "- Output %d dump:\n", mOutputs.keyAt(i));
+        write(fd, buffer, strlen(buffer));
+        mOutputs.valueAt(i)->dump(fd);
+    }
+
+    snprintf(buffer, SIZE, "\nInputs dump:\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < mInputs.size(); i++) {
+        snprintf(buffer, SIZE, "- Input %d dump:\n", mInputs.keyAt(i));
+        write(fd, buffer, strlen(buffer));
+        mInputs.valueAt(i)->dump(fd);
+    }
+
+    snprintf(buffer, SIZE, "\nStreams dump:\n");
+    write(fd, buffer, strlen(buffer));
+    snprintf(buffer, SIZE,
+             " Stream  Can be muted  Index Min  Index Max  Index Cur [device : index]...\n");
+    write(fd, buffer, strlen(buffer));
+    for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
+        snprintf(buffer, SIZE, " %02d      ", i);
+        write(fd, buffer, strlen(buffer));
+        mStreams[i].dump(fd);
+    }
+
+    snprintf(buffer, SIZE, "\nTotal Effects CPU: %f MIPS, Total Effects memory: %d KB\n",
+            (float)mTotalEffectsCpuLoad/10, mTotalEffectsMemory);
+    write(fd, buffer, strlen(buffer));
+
+    snprintf(buffer, SIZE, "Registered effects:\n");
+    write(fd, buffer, strlen(buffer));
+    for (size_t i = 0; i < mEffects.size(); i++) {
+        snprintf(buffer, SIZE, "- Effect %d dump:\n", mEffects.keyAt(i));
+        write(fd, buffer, strlen(buffer));
+        mEffects.valueAt(i)->dump(fd);
+    }
+
+
+    return NO_ERROR;
+}
+
+// This function checks for the parameters which can be offloaded.
+// This can be enhanced depending on the capability of the DSP and policy
+// of the system.
+bool AudioPolicyManager::isOffloadSupported(const audio_offload_info_t& offloadInfo)
+{
+    ALOGV("isOffloadSupported: SR=%u, CM=0x%x, Format=0x%x, StreamType=%d,"
+     " BitRate=%u, duration=%lld us, has_video=%d",
+     offloadInfo.sample_rate, offloadInfo.channel_mask,
+     offloadInfo.format,
+     offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
+     offloadInfo.has_video);
+
+    // Check if offload has been disabled
+    char propValue[PROPERTY_VALUE_MAX];
+    if (property_get("audio.offload.disable", propValue, "0")) {
+        if (atoi(propValue) != 0) {
+            ALOGV("offload disabled by audio.offload.disable=%s", propValue );
+            return false;
+        }
+    }
+
+    // Check if stream type is music, then only allow offload as of now.
+    if (offloadInfo.stream_type != AUDIO_STREAM_MUSIC)
+    {
+        ALOGV("isOffloadSupported: stream_type != MUSIC, returning false");
+        return false;
+    }
+
+    //TODO: enable audio offloading with video when ready
+    if (offloadInfo.has_video)
+    {
+        ALOGV("isOffloadSupported: has_video == true, returning false");
+        return false;
+    }
+
+    //If duration is less than minimum value defined in property, return false
+    if (property_get("audio.offload.min.duration.secs", propValue, NULL)) {
+        if (offloadInfo.duration_us < (atoi(propValue) * 1000000 )) {
+            ALOGV("Offload denied by duration < audio.offload.min.duration.secs(=%s)", propValue);
+            return false;
+        }
+    } else if (offloadInfo.duration_us < OFFLOAD_DEFAULT_MIN_DURATION_SECS * 1000000) {
+        ALOGV("Offload denied by duration < default min(=%u)", OFFLOAD_DEFAULT_MIN_DURATION_SECS);
+        return false;
+    }
+
+    // Do not allow offloading if one non offloadable effect is enabled. This prevents from
+    // creating an offloaded track and tearing it down immediately after start when audioflinger
+    // detects there is an active non offloadable effect.
+    // FIXME: We should check the audio session here but we do not have it in this context.
+    // This may prevent offloading in rare situations where effects are left active by apps
+    // in the background.
+    if (isNonOffloadableEffectEnabled()) {
+        return false;
+    }
+
+    // See if there is a profile to support this.
+    // AUDIO_DEVICE_NONE
+    IOProfile *profile = getProfileForDirectOutput(AUDIO_DEVICE_NONE /*ignore device */,
+                                            offloadInfo.sample_rate,
+                                            offloadInfo.format,
+                                            offloadInfo.channel_mask,
+                                            AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+    ALOGV("isOffloadSupported() profile %sfound", profile != NULL ? "" : "NOT ");
+    return (profile != NULL);
+}
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManager
+// ----------------------------------------------------------------------------
+
+AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+    :
+#ifdef AUDIO_POLICY_TEST
+    Thread(false),
+#endif //AUDIO_POLICY_TEST
+    mPrimaryOutput((audio_io_handle_t)0),
+    mAvailableOutputDevices(AUDIO_DEVICE_NONE),
+    mPhoneState(AUDIO_MODE_NORMAL),
+    mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
+    mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0),
+    mA2dpSuspended(false), mHasA2dp(false), mHasUsb(false), mHasRemoteSubmix(false),
+    mSpeakerDrcEnabled(false)
+{
+    mpClientInterface = clientInterface;
+
+    for (int i = 0; i < AUDIO_POLICY_FORCE_USE_CNT; i++) {
+        mForceUse[i] = AUDIO_POLICY_FORCE_NONE;
+    }
+
+    mA2dpDeviceAddress = String8("");
+    mScoDeviceAddress = String8("");
+    mUsbCardAndDevice = String8("");
+
+    if (loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE) != NO_ERROR) {
+        if (loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE) != NO_ERROR) {
+            ALOGE("could not load audio policy configuration file, setting defaults");
+            defaultAudioPolicyConfig();
+        }
+    }
+
+    // must be done after reading the policy
+    initializeVolumeCurves();
+
+    // open all output streams needed to access attached devices
+    for (size_t i = 0; i < mHwModules.size(); i++) {
+        mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);
+        if (mHwModules[i]->mHandle == 0) {
+            ALOGW("could not open HW module %s", mHwModules[i]->mName);
+            continue;
+        }
+        // open all output streams needed to access attached devices
+        // except for direct output streams that are only opened when they are actually
+        // required by an app.
+        for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
+        {
+            const IOProfile *outProfile = mHwModules[i]->mOutputProfiles[j];
+
+            if ((outProfile->mSupportedDevices & mAttachedOutputDevices) &&
+                    ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0)) {
+                AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(outProfile);
+                outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice &
+                                                            outProfile->mSupportedDevices);
+                audio_io_handle_t output = mpClientInterface->openOutput(
+                                                outProfile->mModule->mHandle,
+                                                &outputDesc->mDevice,
+                                                &outputDesc->mSamplingRate,
+                                                &outputDesc->mFormat,
+                                                &outputDesc->mChannelMask,
+                                                &outputDesc->mLatency,
+                                                outputDesc->mFlags);
+                if (output == 0) {
+                    delete outputDesc;
+                } else {
+                    mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices |
+                                            (outProfile->mSupportedDevices & mAttachedOutputDevices));
+                    if (mPrimaryOutput == 0 &&
+                            outProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+                        mPrimaryOutput = output;
+                    }
+                    addOutput(output, outputDesc);
+                    setOutputDevice(output,
+                                    (audio_devices_t)(mDefaultOutputDevice &
+                                                        outProfile->mSupportedDevices),
+                                    true);
+                }
+            }
+        }
+    }
+
+    ALOGE_IF((mAttachedOutputDevices & ~mAvailableOutputDevices),
+             "Not output found for attached devices %08x",
+             (mAttachedOutputDevices & ~mAvailableOutputDevices));
+
+    ALOGE_IF((mPrimaryOutput == 0), "Failed to open primary output");
+
+    updateDevicesAndOutputs();
+
+#ifdef AUDIO_POLICY_TEST
+    if (mPrimaryOutput != 0) {
+        AudioParameter outputCmd = AudioParameter();
+        outputCmd.addInt(String8("set_id"), 0);
+        mpClientInterface->setParameters(mPrimaryOutput, outputCmd.toString());
+
+        mTestDevice = AUDIO_DEVICE_OUT_SPEAKER;
+        mTestSamplingRate = 44100;
+        mTestFormat = AUDIO_FORMAT_PCM_16_BIT;
+        mTestChannels =  AUDIO_CHANNEL_OUT_STEREO;
+        mTestLatencyMs = 0;
+        mCurOutput = 0;
+        mDirectOutput = false;
+        for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+            mTestOutputs[i] = 0;
+        }
+
+        const size_t SIZE = 256;
+        char buffer[SIZE];
+        snprintf(buffer, SIZE, "AudioPolicyManagerTest");
+        run(buffer, ANDROID_PRIORITY_AUDIO);
+    }
+#endif //AUDIO_POLICY_TEST
+}
+
+AudioPolicyManager::~AudioPolicyManager()
+{
+#ifdef AUDIO_POLICY_TEST
+    exit();
+#endif //AUDIO_POLICY_TEST
+   for (size_t i = 0; i < mOutputs.size(); i++) {
+        mpClientInterface->closeOutput(mOutputs.keyAt(i));
+        delete mOutputs.valueAt(i);
+   }
+   for (size_t i = 0; i < mInputs.size(); i++) {
+        mpClientInterface->closeInput(mInputs.keyAt(i));
+        delete mInputs.valueAt(i);
+   }
+   for (size_t i = 0; i < mHwModules.size(); i++) {
+        delete mHwModules[i];
+   }
+}
+
+status_t AudioPolicyManager::initCheck()
+{
+    return (mPrimaryOutput == 0) ? NO_INIT : NO_ERROR;
+}
+
+#ifdef AUDIO_POLICY_TEST
+bool AudioPolicyManager::threadLoop()
+{
+    ALOGV("entering threadLoop()");
+    while (!exitPending())
+    {
+        String8 command;
+        int valueInt;
+        String8 value;
+
+        Mutex::Autolock _l(mLock);
+        mWaitWorkCV.waitRelative(mLock, milliseconds(50));
+
+        command = mpClientInterface->getParameters(0, String8("test_cmd_policy"));
+        AudioParameter param = AudioParameter(command);
+
+        if (param.getInt(String8("test_cmd_policy"), valueInt) == NO_ERROR &&
+            valueInt != 0) {
+            ALOGV("Test command %s received", command.string());
+            String8 target;
+            if (param.get(String8("target"), target) != NO_ERROR) {
+                target = "Manager";
+            }
+            if (param.getInt(String8("test_cmd_policy_output"), valueInt) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_output"));
+                mCurOutput = valueInt;
+            }
+            if (param.get(String8("test_cmd_policy_direct"), value) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_direct"));
+                if (value == "false") {
+                    mDirectOutput = false;
+                } else if (value == "true") {
+                    mDirectOutput = true;
+                }
+            }
+            if (param.getInt(String8("test_cmd_policy_input"), valueInt) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_input"));
+                mTestInput = valueInt;
+            }
+
+            if (param.get(String8("test_cmd_policy_format"), value) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_format"));
+                int format = AUDIO_FORMAT_INVALID;
+                if (value == "PCM 16 bits") {
+                    format = AUDIO_FORMAT_PCM_16_BIT;
+                } else if (value == "PCM 8 bits") {
+                    format = AUDIO_FORMAT_PCM_8_BIT;
+                } else if (value == "Compressed MP3") {
+                    format = AUDIO_FORMAT_MP3;
+                }
+                if (format != AUDIO_FORMAT_INVALID) {
+                    if (target == "Manager") {
+                        mTestFormat = format;
+                    } else if (mTestOutputs[mCurOutput] != 0) {
+                        AudioParameter outputParam = AudioParameter();
+                        outputParam.addInt(String8("format"), format);
+                        mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+                    }
+                }
+            }
+            if (param.get(String8("test_cmd_policy_channels"), value) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_channels"));
+                int channels = 0;
+
+                if (value == "Channels Stereo") {
+                    channels =  AUDIO_CHANNEL_OUT_STEREO;
+                } else if (value == "Channels Mono") {
+                    channels =  AUDIO_CHANNEL_OUT_MONO;
+                }
+                if (channels != 0) {
+                    if (target == "Manager") {
+                        mTestChannels = channels;
+                    } else if (mTestOutputs[mCurOutput] != 0) {
+                        AudioParameter outputParam = AudioParameter();
+                        outputParam.addInt(String8("channels"), channels);
+                        mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+                    }
+                }
+            }
+            if (param.getInt(String8("test_cmd_policy_sampleRate"), valueInt) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_sampleRate"));
+                if (valueInt >= 0 && valueInt <= 96000) {
+                    int samplingRate = valueInt;
+                    if (target == "Manager") {
+                        mTestSamplingRate = samplingRate;
+                    } else if (mTestOutputs[mCurOutput] != 0) {
+                        AudioParameter outputParam = AudioParameter();
+                        outputParam.addInt(String8("sampling_rate"), samplingRate);
+                        mpClientInterface->setParameters(mTestOutputs[mCurOutput], outputParam.toString());
+                    }
+                }
+            }
+
+            if (param.get(String8("test_cmd_policy_reopen"), value) == NO_ERROR) {
+                param.remove(String8("test_cmd_policy_reopen"));
+
+                AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mPrimaryOutput);
+                mpClientInterface->closeOutput(mPrimaryOutput);
+
+                audio_module_handle_t moduleHandle = outputDesc->mModule->mHandle;
+
+                delete mOutputs.valueFor(mPrimaryOutput);
+                mOutputs.removeItem(mPrimaryOutput);
+
+                AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor(NULL);
+                outputDesc->mDevice = AUDIO_DEVICE_OUT_SPEAKER;
+                mPrimaryOutput = mpClientInterface->openOutput(moduleHandle,
+                                                &outputDesc->mDevice,
+                                                &outputDesc->mSamplingRate,
+                                                &outputDesc->mFormat,
+                                                &outputDesc->mChannelMask,
+                                                &outputDesc->mLatency,
+                                                outputDesc->mFlags);
+                if (mPrimaryOutput == 0) {
+                    ALOGE("Failed to reopen hardware output stream, samplingRate: %d, format %d, channels %d",
+                            outputDesc->mSamplingRate, outputDesc->mFormat, outputDesc->mChannelMask);
+                } else {
+                    AudioParameter outputCmd = AudioParameter();
+                    outputCmd.addInt(String8("set_id"), 0);
+                    mpClientInterface->setParameters(mPrimaryOutput, outputCmd.toString());
+                    addOutput(mPrimaryOutput, outputDesc);
+                }
+            }
+
+
+            mpClientInterface->setParameters(0, String8("test_cmd_policy="));
+        }
+    }
+    return false;
+}
+
+void AudioPolicyManager::exit()
+{
+    {
+        AutoMutex _l(mLock);
+        requestExit();
+        mWaitWorkCV.signal();
+    }
+    requestExitAndWait();
+}
+
+int AudioPolicyManager::testOutputIndex(audio_io_handle_t output)
+{
+    for (int i = 0; i < NUM_TEST_OUTPUTS; i++) {
+        if (output == mTestOutputs[i]) return i;
+    }
+    return 0;
+}
+#endif //AUDIO_POLICY_TEST
+
+// ---
+
+void AudioPolicyManager::addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc)
+{
+    outputDesc->mId = id;
+    mOutputs.add(id, outputDesc);
+}
+
+
+status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
+                                                       audio_policy_dev_state_t state,
+                                                       SortedVector<audio_io_handle_t>& outputs,
+                                                       const String8 paramStr)
+{
+    AudioOutputDescriptor *desc;
+
+    if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
+        // first list already open outputs that can be routed to this device
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            desc = mOutputs.valueAt(i);
+            if (!desc->isDuplicated() && (desc->mProfile->mSupportedDevices & device)) {
+                ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i));
+                outputs.add(mOutputs.keyAt(i));
+            }
+        }
+        // then look for output profiles that can be routed to this device
+        SortedVector<IOProfile *> profiles;
+        for (size_t i = 0; i < mHwModules.size(); i++)
+        {
+            if (mHwModules[i]->mHandle == 0) {
+                continue;
+            }
+            for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
+            {
+                if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices & device) {
+                    ALOGV("checkOutputsForDevice(): adding profile %d from module %d", j, i);
+                    profiles.add(mHwModules[i]->mOutputProfiles[j]);
+                }
+            }
+        }
+
+        if (profiles.isEmpty() && outputs.isEmpty()) {
+            ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
+            return BAD_VALUE;
+        }
+
+        // open outputs for matching profiles if needed. Direct outputs are also opened to
+        // query for dynamic parameters and will be closed later by setDeviceConnectionState()
+        for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
+            IOProfile *profile = profiles[profile_index];
+
+            // nothing to do if one output is already opened for this profile
+            size_t j;
+            for (j = 0; j < mOutputs.size(); j++) {
+                desc = mOutputs.valueAt(j);
+                if (!desc->isDuplicated() && desc->mProfile == profile) {
+                    break;
+                }
+            }
+            if (j != mOutputs.size()) {
+                continue;
+            }
+
+            ALOGV("opening output for device %08x with params %s", device, paramStr.string());
+            desc = new AudioOutputDescriptor(profile);
+            desc->mDevice = device;
+            audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
+            offloadInfo.sample_rate = desc->mSamplingRate;
+            offloadInfo.format = desc->mFormat;
+            offloadInfo.channel_mask = desc->mChannelMask;
+
+            audio_io_handle_t output = mpClientInterface->openOutput(profile->mModule->mHandle,
+                                                                       &desc->mDevice,
+                                                                       &desc->mSamplingRate,
+                                                                       &desc->mFormat,
+                                                                       &desc->mChannelMask,
+                                                                       &desc->mLatency,
+                                                                       desc->mFlags,
+                                                                       &offloadInfo);
+            if (output != 0) {
+                if (!paramStr.isEmpty()) {
+                    mpClientInterface->setParameters(output, paramStr);
+                }
+
+                if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
+                    String8 reply;
+                    char *value;
+                    if (profile->mSamplingRates[0] == 0) {
+                        reply = mpClientInterface->getParameters(output,
+                                                String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
+                        ALOGV("checkOutputsForDevice() direct output sup sampling rates %s",
+                                  reply.string());
+                        value = strpbrk((char *)reply.string(), "=");
+                        if (value != NULL) {
+                            loadSamplingRates(value + 1, profile);
+                        }
+                    }
+                    if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+                        reply = mpClientInterface->getParameters(output,
+                                                       String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+                        ALOGV("checkOutputsForDevice() direct output sup formats %s",
+                                  reply.string());
+                        value = strpbrk((char *)reply.string(), "=");
+                        if (value != NULL) {
+                            loadFormats(value + 1, profile);
+                        }
+                    }
+                    if (profile->mChannelMasks[0] == 0) {
+                        reply = mpClientInterface->getParameters(output,
+                                                      String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
+                        ALOGV("checkOutputsForDevice() direct output sup channel masks %s",
+                                  reply.string());
+                        value = strpbrk((char *)reply.string(), "=");
+                        if (value != NULL) {
+                            loadOutChannels(value + 1, profile);
+                        }
+                    }
+                    if (((profile->mSamplingRates[0] == 0) &&
+                             (profile->mSamplingRates.size() < 2)) ||
+                         ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) &&
+                             (profile->mFormats.size() < 2)) ||
+                         ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) &&
+                             (profile->mChannelMasks.size() < 2))) {
+                        ALOGW("checkOutputsForDevice() direct output missing param");
+                        mpClientInterface->closeOutput(output);
+                        output = 0;
+                    } else {
+                        addOutput(output, desc);
+                    }
+                } else {
+                    audio_io_handle_t duplicatedOutput = 0;
+                    // add output descriptor
+                    addOutput(output, desc);
+                    // set initial stream volume for device
+                    applyStreamVolumes(output, device, 0, true);
+
+                    //TODO: configure audio effect output stage here
+
+                    // open a duplicating output thread for the new output and the primary output
+                    duplicatedOutput = mpClientInterface->openDuplicateOutput(output,
+                                                                              mPrimaryOutput);
+                    if (duplicatedOutput != 0) {
+                        // add duplicated output descriptor
+                        AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(NULL);
+                        dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput);
+                        dupOutputDesc->mOutput2 = mOutputs.valueFor(output);
+                        dupOutputDesc->mSamplingRate = desc->mSamplingRate;
+                        dupOutputDesc->mFormat = desc->mFormat;
+                        dupOutputDesc->mChannelMask = desc->mChannelMask;
+                        dupOutputDesc->mLatency = desc->mLatency;
+                        addOutput(duplicatedOutput, dupOutputDesc);
+                        applyStreamVolumes(duplicatedOutput, device, 0, true);
+                    } else {
+                        ALOGW("checkOutputsForDevice() could not open dup output for %d and %d",
+                                mPrimaryOutput, output);
+                        mpClientInterface->closeOutput(output);
+                        mOutputs.removeItem(output);
+                        output = 0;
+                    }
+                }
+            }
+            if (output == 0) {
+                ALOGW("checkOutputsForDevice() could not open output for device %x", device);
+                delete desc;
+                profiles.removeAt(profile_index);
+                profile_index--;
+            } else {
+                outputs.add(output);
+                ALOGV("checkOutputsForDevice(): adding output %d", output);
+            }
+        }
+
+        if (profiles.isEmpty()) {
+            ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
+            return BAD_VALUE;
+        }
+    } else {
+        // check if one opened output is not needed any more after disconnecting one device
+        for (size_t i = 0; i < mOutputs.size(); i++) {
+            desc = mOutputs.valueAt(i);
+            if (!desc->isDuplicated() &&
+                    !(desc->mProfile->mSupportedDevices & mAvailableOutputDevices)) {
+                ALOGV("checkOutputsForDevice(): disconnecting adding output %d", mOutputs.keyAt(i));
+                outputs.add(mOutputs.keyAt(i));
+            }
+        }
+        for (size_t i = 0; i < mHwModules.size(); i++)
+        {
+            if (mHwModules[i]->mHandle == 0) {
+                continue;
+            }
+            for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
+            {
+                IOProfile *profile = mHwModules[i]->mOutputProfiles[j];
+                if ((profile->mSupportedDevices & device) &&
+                        (profile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
+                    ALOGV("checkOutputsForDevice(): clearing direct output profile %d on module %d",
+                          j, i);
+                    if (profile->mSamplingRates[0] == 0) {
+                        profile->mSamplingRates.clear();
+                        profile->mSamplingRates.add(0);
+                    }
+                    if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
+                        profile->mFormats.clear();
+                        profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
+                    }
+                    if (profile->mChannelMasks[0] == 0) {
+                        profile->mChannelMasks.clear();
+                        profile->mChannelMasks.add(0);
+                    }
+                }
+            }
+        }
+    }
+    return NO_ERROR;
+}
+
+void AudioPolicyManager::closeOutput(audio_io_handle_t output)
+{
+    ALOGV("closeOutput(%d)", output);
+
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    if (outputDesc == NULL) {
+        ALOGW("closeOutput() unknown output %d", output);
+        return;
+    }
+
+    // look for duplicated outputs connected to the output being removed.
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        AudioOutputDescriptor *dupOutputDesc = mOutputs.valueAt(i);
+        if (dupOutputDesc->isDuplicated() &&
+                (dupOutputDesc->mOutput1 == outputDesc ||
+                dupOutputDesc->mOutput2 == outputDesc)) {
+            AudioOutputDescriptor *outputDesc2;
+            if (dupOutputDesc->mOutput1 == outputDesc) {
+                outputDesc2 = dupOutputDesc->mOutput2;
+            } else {
+                outputDesc2 = dupOutputDesc->mOutput1;
+            }
+            // As all active tracks on duplicated output will be deleted,
+            // and as they were also referenced on the other output, the reference
+            // count for their stream type must be adjusted accordingly on
+            // the other output.
+            for (int j = 0; j < AUDIO_STREAM_CNT; j++) {
+                int refCount = dupOutputDesc->mRefCount[j];
+                outputDesc2->changeRefCount((audio_stream_type_t)j,-refCount);
+            }
+            audio_io_handle_t duplicatedOutput = mOutputs.keyAt(i);
+            ALOGV("closeOutput() closing also duplicated output %d", duplicatedOutput);
+
+            mpClientInterface->closeOutput(duplicatedOutput);
+            delete mOutputs.valueFor(duplicatedOutput);
+            mOutputs.removeItem(duplicatedOutput);
+        }
+    }
+
+    AudioParameter param;
+    param.add(String8("closing"), String8("true"));
+    mpClientInterface->setParameters(output, param.toString());
+
+    mpClientInterface->closeOutput(output);
+    delete outputDesc;
+    mOutputs.removeItem(output);
+    mPreviousOutputs = mOutputs;
+}
+
+SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice(audio_devices_t device,
+                        DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> openOutputs)
+{
+    SortedVector<audio_io_handle_t> outputs;
+
+    ALOGVV("getOutputsForDevice() device %04x", device);
+    for (size_t i = 0; i < openOutputs.size(); i++) {
+        ALOGVV("output %d isDuplicated=%d device=%04x",
+                i, openOutputs.valueAt(i)->isDuplicated(), openOutputs.valueAt(i)->supportedDevices());
+        if ((device & openOutputs.valueAt(i)->supportedDevices()) == device) {
+            ALOGVV("getOutputsForDevice() found output %d", openOutputs.keyAt(i));
+            outputs.add(openOutputs.keyAt(i));
+        }
+    }
+    return outputs;
+}
+
+bool AudioPolicyManager::vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
+                                   SortedVector<audio_io_handle_t>& outputs2)
+{
+    if (outputs1.size() != outputs2.size()) {
+        return false;
+    }
+    for (size_t i = 0; i < outputs1.size(); i++) {
+        if (outputs1[i] != outputs2[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy)
+{
+    audio_devices_t oldDevice = getDeviceForStrategy(strategy, true /*fromCache*/);
+    audio_devices_t newDevice = getDeviceForStrategy(strategy, false /*fromCache*/);
+    SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevice(oldDevice, mPreviousOutputs);
+    SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(newDevice, mOutputs);
+
+    if (!vectorsEqual(srcOutputs,dstOutputs)) {
+        ALOGV("checkOutputForStrategy() strategy %d, moving from output %d to output %d",
+              strategy, srcOutputs[0], dstOutputs[0]);
+        // mute strategy while moving tracks from one output to another
+        for (size_t i = 0; i < srcOutputs.size(); i++) {
+            AudioOutputDescriptor *desc = mOutputs.valueFor(srcOutputs[i]);
+            if (desc->isStrategyActive(strategy)) {
+                setStrategyMute(strategy, true, srcOutputs[i]);
+                setStrategyMute(strategy, false, srcOutputs[i], MUTE_TIME_MS, newDevice);
+            }
+        }
+
+        // Move effects associated to this strategy from previous output to new output
+        if (strategy == STRATEGY_MEDIA) {
+            audio_io_handle_t fxOutput = selectOutputForEffects(dstOutputs);
+            SortedVector<audio_io_handle_t> moved;
+            for (size_t i = 0; i < mEffects.size(); i++) {
+                EffectDescriptor *desc = mEffects.valueAt(i);
+                if (desc->mSession == AUDIO_SESSION_OUTPUT_MIX &&
+                        desc->mIo != fxOutput) {
+                    if (moved.indexOf(desc->mIo) < 0) {
+                        ALOGV("checkOutputForStrategy() moving effect %d to output %d",
+                              mEffects.keyAt(i), fxOutput);
+                        mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, desc->mIo,
+                                                       fxOutput);
+                        moved.add(desc->mIo);
+                    }
+                    desc->mIo = fxOutput;
+                }
+            }
+        }
+        // Move tracks associated to this strategy from previous output to new output
+        for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
+            if (getStrategy((audio_stream_type_t)i) == strategy) {
+                mpClientInterface->invalidateStream((audio_stream_type_t)i);
+            }
+        }
+    }
+}
+
+void AudioPolicyManager::checkOutputForAllStrategies()
+{
+    checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
+    checkOutputForStrategy(STRATEGY_PHONE);
+    checkOutputForStrategy(STRATEGY_SONIFICATION);
+    checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
+    checkOutputForStrategy(STRATEGY_MEDIA);
+    checkOutputForStrategy(STRATEGY_DTMF);
+}
+
+audio_io_handle_t AudioPolicyManager::getA2dpOutput()
+{
+    if (!mHasA2dp) {
+        return 0;
+    }
+
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        AudioOutputDescriptor *outputDesc = mOutputs.valueAt(i);
+        if (!outputDesc->isDuplicated() && outputDesc->device() & AUDIO_DEVICE_OUT_ALL_A2DP) {
+            return mOutputs.keyAt(i);
+        }
+    }
+
+    return 0;
+}
+
+void AudioPolicyManager::checkA2dpSuspend()
+{
+    if (!mHasA2dp) {
+        return;
+    }
+    audio_io_handle_t a2dpOutput = getA2dpOutput();
+    if (a2dpOutput == 0) {
+        return;
+    }
+
+    // suspend A2DP output if:
+    //      (NOT already suspended) &&
+    //      ((SCO device is connected &&
+    //       (forced usage for communication || for record is SCO))) ||
+    //      (phone state is ringing || in call)
+    //
+    // restore A2DP output if:
+    //      (Already suspended) &&
+    //      ((SCO device is NOT connected ||
+    //       (forced usage NOT for communication && NOT for record is SCO))) &&
+    //      (phone state is NOT ringing && NOT in call)
+    //
+    if (mA2dpSuspended) {
+        if (((mScoDeviceAddress == "") ||
+             ((mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION] != AUDIO_POLICY_FORCE_BT_SCO) &&
+              (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] != AUDIO_POLICY_FORCE_BT_SCO))) &&
+             ((mPhoneState != AUDIO_MODE_IN_CALL) &&
+              (mPhoneState != AUDIO_MODE_RINGTONE))) {
+
+            mpClientInterface->restoreOutput(a2dpOutput);
+            mA2dpSuspended = false;
+        }
+    } else {
+        if (((mScoDeviceAddress != "") &&
+             ((mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION] == AUDIO_POLICY_FORCE_BT_SCO) ||
+              (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO))) ||
+             ((mPhoneState == AUDIO_MODE_IN_CALL) ||
+              (mPhoneState == AUDIO_MODE_RINGTONE))) {
+
+            mpClientInterface->suspendOutput(a2dpOutput);
+            mA2dpSuspended = true;
+        }
+    }
+}
+
+audio_devices_t AudioPolicyManager::getNewDevice(audio_io_handle_t output, bool fromCache)
+{
+    audio_devices_t device = AUDIO_DEVICE_NONE;
+
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    // check the following by order of priority to request a routing change if necessary:
+    // 1: the strategy enforced audible is active on the output:
+    //      use device for strategy enforced audible
+    // 2: we are in call or the strategy phone is active on the output:
+    //      use device for strategy phone
+    // 3: the strategy sonification is active on the output:
+    //      use device for strategy sonification
+    // 4: the strategy "respectful" sonification is active on the output:
+    //      use device for strategy "respectful" sonification
+    // 5: the strategy media is active on the output:
+    //      use device for strategy media
+    // 6: the strategy DTMF is active on the output:
+    //      use device for strategy DTMF
+    if (outputDesc->isStrategyActive(STRATEGY_ENFORCED_AUDIBLE)) {
+        device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
+    } else if (isInCall() ||
+                    outputDesc->isStrategyActive(STRATEGY_PHONE)) {
+        device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
+    } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION)) {
+        device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
+    } else if (outputDesc->isStrategyActive(STRATEGY_SONIFICATION_RESPECTFUL)) {
+        device = getDeviceForStrategy(STRATEGY_SONIFICATION_RESPECTFUL, fromCache);
+    } else if (outputDesc->isStrategyActive(STRATEGY_MEDIA)) {
+        device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
+    } else if (outputDesc->isStrategyActive(STRATEGY_DTMF)) {
+        device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
+    }
+
+    ALOGV("getNewDevice() selected device %x", device);
+    return device;
+}
+
+uint32_t AudioPolicyManager::getStrategyForStream(audio_stream_type_t stream) {
+    return (uint32_t)getStrategy(stream);
+}
+
+audio_devices_t AudioPolicyManager::getDevicesForStream(audio_stream_type_t stream) {
+    audio_devices_t devices;
+    // By checking the range of stream before calling getStrategy, we avoid
+    // getStrategy's behavior for invalid streams.  getStrategy would do a ALOGE
+    // and then return STRATEGY_MEDIA, but we want to return the empty set.
+    if (stream < (audio_stream_type_t) 0 || stream >= AUDIO_STREAM_CNT) {
+        devices = AUDIO_DEVICE_NONE;
+    } else {
+        AudioPolicyManager::routing_strategy strategy = getStrategy(stream);
+        devices = getDeviceForStrategy(strategy, true /*fromCache*/);
+    }
+    return devices;
+}
+
+AudioPolicyManager::routing_strategy AudioPolicyManager::getStrategy(
+        audio_stream_type_t stream) {
+    // stream to strategy mapping
+    switch (stream) {
+    case AUDIO_STREAM_VOICE_CALL:
+    case AUDIO_STREAM_BLUETOOTH_SCO:
+        return STRATEGY_PHONE;
+    case AUDIO_STREAM_RING:
+    case AUDIO_STREAM_ALARM:
+        return STRATEGY_SONIFICATION;
+    case AUDIO_STREAM_NOTIFICATION:
+        return STRATEGY_SONIFICATION_RESPECTFUL;
+    case AUDIO_STREAM_DTMF:
+        return STRATEGY_DTMF;
+    default:
+        ALOGE("unknown stream type");
+    case AUDIO_STREAM_SYSTEM:
+        // NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
+        // while key clicks are played produces a poor result
+    case AUDIO_STREAM_TTS:
+    case AUDIO_STREAM_MUSIC:
+        return STRATEGY_MEDIA;
+    case AUDIO_STREAM_ENFORCED_AUDIBLE:
+        return STRATEGY_ENFORCED_AUDIBLE;
+    }
+}
+
+void AudioPolicyManager::handleNotificationRoutingForStream(audio_stream_type_t stream) {
+    switch(stream) {
+    case AUDIO_STREAM_MUSIC:
+        checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
+        updateDevicesAndOutputs();
+        break;
+    default:
+        break;
+    }
+}
+
+audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,
+                                                             bool fromCache)
+{
+    uint32_t device = AUDIO_DEVICE_NONE;
+
+    if (fromCache) {
+        ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x",
+              strategy, mDeviceForStrategy[strategy]);
+        return mDeviceForStrategy[strategy];
+    }
+
+    switch (strategy) {
+
+    case STRATEGY_SONIFICATION_RESPECTFUL:
+        if (isInCall()) {
+            device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+        } else if (isStreamActiveRemotely(AUDIO_STREAM_MUSIC,
+                SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+            // while media is playing on a remote device, use the the sonification behavior.
+            // Note that we test this usecase before testing if media is playing because
+            //   the isStreamActive() method only informs about the activity of a stream, not
+            //   if it's for local playback. Note also that we use the same delay between both tests
+            device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+        } else if (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+            // while media is playing (or has recently played), use the same device
+            device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+        } else {
+            // when media is not playing anymore, fall back on the sonification behavior
+            device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+        }
+
+        break;
+
+    case STRATEGY_DTMF:
+        if (!isInCall()) {
+            // when off call, DTMF strategy follows the same rules as MEDIA strategy
+            device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+            break;
+        }
+        // when in call, DTMF and PHONE strategies follow the same rules
+        // FALL THROUGH
+
+    case STRATEGY_PHONE:
+        // for phone strategy, we first consider the forced use and then the available devices by order
+        // of priority
+        switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) {
+        case AUDIO_POLICY_FORCE_BT_SCO:
+            if (!isInCall() || strategy != STRATEGY_DTMF) {
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+                if (device) break;
+            }
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+            if (device) break;
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+            if (device) break;
+            // if SCO device is requested but no SCO device is available, fall back to default case
+            // FALL THROUGH
+
+        default:    // FORCE_NONE
+            // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
+            if (mHasA2dp && !isInCall() &&
+                    (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
+                    (getA2dpOutput() != 0) && !mA2dpSuspended) {
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+                if (device) break;
+            }
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+            if (device) break;
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+            if (device) break;
+            if (mPhoneState != AUDIO_MODE_IN_CALL) {
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+                if (device) break;
+            }
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_EARPIECE;
+            if (device) break;
+            device = mDefaultOutputDevice;
+            if (device == AUDIO_DEVICE_NONE) {
+                ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
+            }
+            break;
+
+        case AUDIO_POLICY_FORCE_SPEAKER:
+            // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
+            // A2DP speaker when forcing to speaker output
+            if (mHasA2dp && !isInCall() &&
+                    (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
+                    (getA2dpOutput() != 0) && !mA2dpSuspended) {
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+                if (device) break;
+            }
+            if (mPhoneState != AUDIO_MODE_IN_CALL) {
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+                if (device) break;
+                device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+                if (device) break;
+            }
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+            if (device) break;
+            device = mDefaultOutputDevice;
+            if (device == AUDIO_DEVICE_NONE) {
+                ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
+            }
+            break;
+        }
+    break;
+
+    case STRATEGY_SONIFICATION:
+
+        // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
+        // handleIncallSonification().
+        if (isInCall()) {
+            device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/);
+            break;
+        }
+        // FALL THROUGH
+
+    case STRATEGY_ENFORCED_AUDIBLE:
+        // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION
+        // except:
+        //   - when in call where it doesn't default to STRATEGY_PHONE behavior
+        //   - in countries where not enforced in which case it follows STRATEGY_MEDIA
+
+        if ((strategy == STRATEGY_SONIFICATION) ||
+                (mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)) {
+            device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+            if (device == AUDIO_DEVICE_NONE) {
+                ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION");
+            }
+        }
+        // The second device used for sonification is the same as the device used by media strategy
+        // FALL THROUGH
+
+    case STRATEGY_MEDIA: {
+        uint32_t device2 = AUDIO_DEVICE_NONE;
+        if (strategy != STRATEGY_SONIFICATION) {
+            // no sonification on remote submix (e.g. WFD)
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+        }
+        if ((device2 == AUDIO_DEVICE_NONE) &&
+                mHasA2dp &&
+                (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
+                (getA2dpOutput() != 0) && !mA2dpSuspended) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+            if (device2 == AUDIO_DEVICE_NONE) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+            }
+            if (device2 == AUDIO_DEVICE_NONE) {
+                device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+            }
+        }
+        if (device2 == AUDIO_DEVICE_NONE) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+        }
+        if (device2 == AUDIO_DEVICE_NONE) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+        }
+        if (device2 == AUDIO_DEVICE_NONE) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+        }
+        if (device2 == AUDIO_DEVICE_NONE) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+        }
+        if (device2 == AUDIO_DEVICE_NONE) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+        }
+        if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {
+            // no sonification on aux digital (e.g. HDMI)
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+        }
+        if ((device2 == AUDIO_DEVICE_NONE) &&
+                (mForceUse[AUDIO_POLICY_FORCE_FOR_DOCK] == AUDIO_POLICY_FORCE_ANALOG_DOCK)) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+        }
+        if (device2 == AUDIO_DEVICE_NONE) {
+            device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+        }
+
+        // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
+        // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
+        device |= device2;
+        if (device) break;
+        device = mDefaultOutputDevice;
+        if (device == AUDIO_DEVICE_NONE) {
+            ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA");
+        }
+        } break;
+
+    default:
+        ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
+        break;
+    }
+
+    ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
+    return device;
+}
+
+void AudioPolicyManager::updateDevicesAndOutputs()
+{
+    for (int i = 0; i < NUM_STRATEGIES; i++) {
+        mDeviceForStrategy[i] = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
+    }
+    mPreviousOutputs = mOutputs;
+}
+
+uint32_t AudioPolicyManager::checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
+                                                       audio_devices_t prevDevice,
+                                                       uint32_t delayMs)
+{
+    // mute/unmute strategies using an incompatible device combination
+    // if muting, wait for the audio in pcm buffer to be drained before proceeding
+    // if unmuting, unmute only after the specified delay
+    if (outputDesc->isDuplicated()) {
+        return 0;
+    }
+
+    uint32_t muteWaitMs = 0;
+    audio_devices_t device = outputDesc->device();
+    bool shouldMute = outputDesc->isActive() && (popcount(device) >= 2);
+    // temporary mute output if device selection changes to avoid volume bursts due to
+    // different per device volumes
+    bool tempMute = outputDesc->isActive() && (device != prevDevice);
+
+    for (size_t i = 0; i < NUM_STRATEGIES; i++) {
+        audio_devices_t curDevice = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/);
+        bool mute = shouldMute && (curDevice & device) && (curDevice != device);
+        bool doMute = false;
+
+        if (mute && !outputDesc->mStrategyMutedByDevice[i]) {
+            doMute = true;
+            outputDesc->mStrategyMutedByDevice[i] = true;
+        } else if (!mute && outputDesc->mStrategyMutedByDevice[i]){
+            doMute = true;
+            outputDesc->mStrategyMutedByDevice[i] = false;
+        }
+        if (doMute || tempMute) {
+            for (size_t j = 0; j < mOutputs.size(); j++) {
+                AudioOutputDescriptor *desc = mOutputs.valueAt(j);
+                // skip output if it does not share any device with current output
+                if ((desc->supportedDevices() & outputDesc->supportedDevices())
+                        == AUDIO_DEVICE_NONE) {
+                    continue;
+                }
+                audio_io_handle_t curOutput = mOutputs.keyAt(j);
+                ALOGVV("checkDeviceMuteStrategies() %s strategy %d (curDevice %04x) on output %d",
+                      mute ? "muting" : "unmuting", i, curDevice, curOutput);
+                setStrategyMute((routing_strategy)i, mute, curOutput, mute ? 0 : delayMs);
+                if (desc->isStrategyActive((routing_strategy)i)) {
+                    // do tempMute only for current output
+                    if (tempMute && (desc == outputDesc)) {
+                        setStrategyMute((routing_strategy)i, true, curOutput);
+                        setStrategyMute((routing_strategy)i, false, curOutput,
+                                            desc->latency() * 2, device);
+                    }
+                    if ((tempMute && (desc == outputDesc)) || mute) {
+                        if (muteWaitMs < desc->latency()) {
+                            muteWaitMs = desc->latency();
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // FIXME: should not need to double latency if volume could be applied immediately by the
+    // audioflinger mixer. We must account for the delay between now and the next time
+    // the audioflinger thread for this output will process a buffer (which corresponds to
+    // one buffer size, usually 1/2 or 1/4 of the latency).
+    muteWaitMs *= 2;
+    // wait for the PCM output buffers to empty before proceeding with the rest of the command
+    if (muteWaitMs > delayMs) {
+        muteWaitMs -= delayMs;
+        usleep(muteWaitMs * 1000);
+        return muteWaitMs;
+    }
+    return 0;
+}
+
+uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output,
+                                             audio_devices_t device,
+                                             bool force,
+                                             int delayMs)
+{
+    ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs);
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    AudioParameter param;
+    uint32_t muteWaitMs;
+
+    if (outputDesc->isDuplicated()) {
+        muteWaitMs = setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
+        muteWaitMs += setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
+        return muteWaitMs;
+    }
+    // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
+    // output profile
+    if ((device != AUDIO_DEVICE_NONE) &&
+            ((device & outputDesc->mProfile->mSupportedDevices) == 0)) {
+        return 0;
+    }
+
+    // filter devices according to output selected
+    device = (audio_devices_t)(device & outputDesc->mProfile->mSupportedDevices);
+
+    audio_devices_t prevDevice = outputDesc->mDevice;
+
+    ALOGV("setOutputDevice() prevDevice %04x", prevDevice);
+
+    if (device != AUDIO_DEVICE_NONE) {
+        outputDesc->mDevice = device;
+    }
+    muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+
+    // Do not change the routing if:
+    //  - the requested device is AUDIO_DEVICE_NONE
+    //  - the requested device is the same as current device and force is not specified.
+    // Doing this check here allows the caller to call setOutputDevice() without conditions
+    if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force) {
+        ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output);
+        return muteWaitMs;
+    }
+
+    ALOGV("setOutputDevice() changing device");
+    // do the routing
+    param.addInt(String8(AudioParameter::keyRouting), (int)device);
+    mpClientInterface->setParameters(output, param.toString(), delayMs);
+
+    // update stream volumes according to new device
+    applyStreamVolumes(output, device, delayMs);
+
+    return muteWaitMs;
+}
+
+AudioPolicyManager::IOProfile *AudioPolicyManager::getInputProfile(audio_devices_t device,
+                                                   uint32_t samplingRate,
+                                                   audio_format_t format,
+                                                   audio_channel_mask_t channelMask)
+{
+    // Choose an input profile based on the requested capture parameters: select the first available
+    // profile supporting all requested parameters.
+
+    for (size_t i = 0; i < mHwModules.size(); i++)
+    {
+        if (mHwModules[i]->mHandle == 0) {
+            continue;
+        }
+        for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
+        {
+            IOProfile *profile = mHwModules[i]->mInputProfiles[j];
+            if (profile->isCompatibleProfile(device, samplingRate, format,
+                                             channelMask, AUDIO_OUTPUT_FLAG_NONE)) {
+                return profile;
+            }
+        }
+    }
+    return NULL;
+}
+
+audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource)
+{
+    uint32_t device = AUDIO_DEVICE_NONE;
+
+    switch (inputSource) {
+    case AUDIO_SOURCE_VOICE_UPLINK:
+      if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
+          device = AUDIO_DEVICE_IN_VOICE_CALL;
+          break;
+      }
+      // FALL THROUGH
+
+    case AUDIO_SOURCE_DEFAULT:
+    case AUDIO_SOURCE_MIC:
+    case AUDIO_SOURCE_VOICE_RECOGNITION:
+    case AUDIO_SOURCE_HOTWORD:
+    case AUDIO_SOURCE_VOICE_COMMUNICATION:
+        if (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO &&
+            mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+            device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+            device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+        }
+        break;
+    case AUDIO_SOURCE_CAMCORDER:
+        if (mAvailableInputDevices & AUDIO_DEVICE_IN_BACK_MIC) {
+            device = AUDIO_DEVICE_IN_BACK_MIC;
+        } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+            device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+        }
+        break;
+    case AUDIO_SOURCE_VOICE_DOWNLINK:
+    case AUDIO_SOURCE_VOICE_CALL:
+        if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
+            device = AUDIO_DEVICE_IN_VOICE_CALL;
+        }
+        break;
+    case AUDIO_SOURCE_REMOTE_SUBMIX:
+        if (mAvailableInputDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+            device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+        }
+        break;
+    default:
+        ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
+        break;
+    }
+    ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
+    return device;
+}
+
+bool AudioPolicyManager::isVirtualInputDevice(audio_devices_t device)
+{
+    if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+        device &= ~AUDIO_DEVICE_BIT_IN;
+        if ((popcount(device) == 1) && ((device & ~APM_AUDIO_IN_DEVICE_VIRTUAL_ALL) == 0))
+            return true;
+    }
+    return false;
+}
+
+audio_io_handle_t AudioPolicyManager::getActiveInput(bool ignoreVirtualInputs)
+{
+    for (size_t i = 0; i < mInputs.size(); i++) {
+        const AudioInputDescriptor * input_descriptor = mInputs.valueAt(i);
+        if ((input_descriptor->mRefCount > 0)
+                && (!ignoreVirtualInputs || !isVirtualInputDevice(input_descriptor->mDevice))) {
+            return mInputs.keyAt(i);
+        }
+    }
+    return 0;
+}
+
+
+audio_devices_t AudioPolicyManager::getDeviceForVolume(audio_devices_t device)
+{
+    if (device == AUDIO_DEVICE_NONE) {
+        // this happens when forcing a route update and no track is active on an output.
+        // In this case the returned category is not important.
+        device =  AUDIO_DEVICE_OUT_SPEAKER;
+    } else if (popcount(device) > 1) {
+        // Multiple device selection is either:
+        //  - speaker + one other device: give priority to speaker in this case.
+        //  - one A2DP device + another device: happens with duplicated output. In this case
+        // retain the device on the A2DP output as the other must not correspond to an active
+        // selection if not the speaker.
+        if (device & AUDIO_DEVICE_OUT_SPEAKER) {
+            device = AUDIO_DEVICE_OUT_SPEAKER;
+        } else {
+            device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
+        }
+    }
+
+    ALOGW_IF(popcount(device) != 1,
+            "getDeviceForVolume() invalid device combination: %08x",
+            device);
+
+    return device;
+}
+
+AudioPolicyManager::device_category AudioPolicyManager::getDeviceCategory(audio_devices_t device)
+{
+    switch(getDeviceForVolume(device)) {
+        case AUDIO_DEVICE_OUT_EARPIECE:
+            return DEVICE_CATEGORY_EARPIECE;
+        case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+        case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+            return DEVICE_CATEGORY_HEADSET;
+        case AUDIO_DEVICE_OUT_SPEAKER:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+        case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+        case AUDIO_DEVICE_OUT_AUX_DIGITAL:
+        case AUDIO_DEVICE_OUT_USB_ACCESSORY:
+        case AUDIO_DEVICE_OUT_USB_DEVICE:
+        case AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
+        default:
+            return DEVICE_CATEGORY_SPEAKER;
+    }
+}
+
+float AudioPolicyManager::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
+        int indexInUi)
+{
+    device_category deviceCategory = getDeviceCategory(device);
+    const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory];
+
+    // the volume index in the UI is relative to the min and max volume indices for this stream type
+    int nbSteps = 1 + curve[VOLMAX].mIndex -
+            curve[VOLMIN].mIndex;
+    int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) /
+            (streamDesc.mIndexMax - streamDesc.mIndexMin);
+
+    // find what part of the curve this index volume belongs to, or if it's out of bounds
+    int segment = 0;
+    if (volIdx < curve[VOLMIN].mIndex) {         // out of bounds
+        return 0.0f;
+    } else if (volIdx < curve[VOLKNEE1].mIndex) {
+        segment = 0;
+    } else if (volIdx < curve[VOLKNEE2].mIndex) {
+        segment = 1;
+    } else if (volIdx <= curve[VOLMAX].mIndex) {
+        segment = 2;
+    } else {                                                               // out of bounds
+        return 1.0f;
+    }
+
+    // linear interpolation in the attenuation table in dB
+    float decibels = curve[segment].mDBAttenuation +
+            ((float)(volIdx - curve[segment].mIndex)) *
+                ( (curve[segment+1].mDBAttenuation -
+                        curve[segment].mDBAttenuation) /
+                    ((float)(curve[segment+1].mIndex -
+                            curve[segment].mIndex)) );
+
+    float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
+
+    ALOGVV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f] ampl=%.5f",
+            curve[segment].mIndex, volIdx,
+            curve[segment+1].mIndex,
+            curve[segment].mDBAttenuation,
+            decibels,
+            curve[segment+1].mDBAttenuation,
+            amplification);
+
+    return amplification;
+}
+
+const AudioPolicyManager::VolumeCurvePoint
+    AudioPolicyManager::sDefaultVolumeCurve[AudioPolicyManager::VOLCNT] = {
+    {1, -49.5f}, {33, -33.5f}, {66, -17.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManager::VolumeCurvePoint
+    AudioPolicyManager::sDefaultMediaVolumeCurve[AudioPolicyManager::VOLCNT] = {
+    {1, -58.0f}, {20, -40.0f}, {60, -17.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManager::VolumeCurvePoint
+    AudioPolicyManager::sSpeakerMediaVolumeCurve[AudioPolicyManager::VOLCNT] = {
+    {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManager::VolumeCurvePoint
+    AudioPolicyManager::sSpeakerSonificationVolumeCurve[AudioPolicyManager::VOLCNT] = {
+    {1, -29.7f}, {33, -20.1f}, {66, -10.2f}, {100, 0.0f}
+};
+
+const AudioPolicyManager::VolumeCurvePoint
+    AudioPolicyManager::sSpeakerSonificationVolumeCurveDrc[AudioPolicyManager::VOLCNT] = {
+    {1, -35.7f}, {33, -26.1f}, {66, -13.2f}, {100, 0.0f}
+};
+
+// AUDIO_STREAM_SYSTEM, AUDIO_STREAM_ENFORCED_AUDIBLE and AUDIO_STREAM_DTMF volume tracks
+// AUDIO_STREAM_RING on phones and AUDIO_STREAM_MUSIC on tablets.
+// AUDIO_STREAM_DTMF tracks AUDIO_STREAM_VOICE_CALL while in call (See AudioService.java).
+// The range is constrained between -24dB and -6dB over speaker and -30dB and -18dB over headset.
+
+const AudioPolicyManager::VolumeCurvePoint
+    AudioPolicyManager::sDefaultSystemVolumeCurve[AudioPolicyManager::VOLCNT] = {
+    {1, -24.0f}, {33, -18.0f}, {66, -12.0f}, {100, -6.0f}
+};
+
+const AudioPolicyManager::VolumeCurvePoint
+    AudioPolicyManager::sDefaultSystemVolumeCurveDrc[AudioPolicyManager::VOLCNT] = {
+    {1, -34.0f}, {33, -24.0f}, {66, -15.0f}, {100, -6.0f}
+};
+
+const AudioPolicyManager::VolumeCurvePoint
+    AudioPolicyManager::sHeadsetSystemVolumeCurve[AudioPolicyManager::VOLCNT] = {
+    {1, -30.0f}, {33, -26.0f}, {66, -22.0f}, {100, -18.0f}
+};
+
+const AudioPolicyManager::VolumeCurvePoint
+    AudioPolicyManager::sDefaultVoiceVolumeCurve[AudioPolicyManager::VOLCNT] = {
+    {0, -42.0f}, {33, -28.0f}, {66, -14.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManager::VolumeCurvePoint
+    AudioPolicyManager::sSpeakerVoiceVolumeCurve[AudioPolicyManager::VOLCNT] = {
+    {0, -24.0f}, {33, -16.0f}, {66, -8.0f}, {100, 0.0f}
+};
+
+const AudioPolicyManager::VolumeCurvePoint
+            *AudioPolicyManager::sVolumeProfiles[AUDIO_STREAM_CNT]
+                                                   [AudioPolicyManager::DEVICE_CATEGORY_CNT] = {
+    { // AUDIO_STREAM_VOICE_CALL
+        sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultVoiceVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    { // AUDIO_STREAM_SYSTEM
+        sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultSystemVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    { // AUDIO_STREAM_RING
+        sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    { // AUDIO_STREAM_MUSIC
+        sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    { // AUDIO_STREAM_ALARM
+        sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    { // AUDIO_STREAM_NOTIFICATION
+        sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    { // AUDIO_STREAM_BLUETOOTH_SCO
+        sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultVoiceVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    { // AUDIO_STREAM_ENFORCED_AUDIBLE
+        sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultSystemVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    {  // AUDIO_STREAM_DTMF
+        sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultSystemVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+    { // AUDIO_STREAM_TTS
+        sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET
+        sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER
+        sDefaultMediaVolumeCurve  // DEVICE_CATEGORY_EARPIECE
+    },
+};
+
+void AudioPolicyManager::initializeVolumeCurves()
+{
+    for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
+        for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+            mStreams[i].mVolumeCurve[j] =
+                    sVolumeProfiles[i][j];
+        }
+    }
+
+    // Check availability of DRC on speaker path: if available, override some of the speaker curves
+    if (mSpeakerDrcEnabled) {
+        mStreams[AUDIO_STREAM_SYSTEM].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+                sDefaultSystemVolumeCurveDrc;
+        mStreams[AUDIO_STREAM_RING].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+                sSpeakerSonificationVolumeCurveDrc;
+        mStreams[AUDIO_STREAM_ALARM].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+                sSpeakerSonificationVolumeCurveDrc;
+        mStreams[AUDIO_STREAM_NOTIFICATION].mVolumeCurve[DEVICE_CATEGORY_SPEAKER] =
+                sSpeakerSonificationVolumeCurveDrc;
+    }
+}
+
+float AudioPolicyManager::computeVolume(audio_stream_type_t stream,
+                                            int index,
+                                            audio_io_handle_t output,
+                                            audio_devices_t device)
+{
+    float volume = 1.0;
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    StreamDescriptor &streamDesc = mStreams[stream];
+
+    if (device == AUDIO_DEVICE_NONE) {
+        device = outputDesc->device();
+    }
+
+    // if volume is not 0 (not muted), force media volume to max on digital output
+    if (stream == AUDIO_STREAM_MUSIC &&
+        index != mStreams[stream].mIndexMin &&
+        (device == AUDIO_DEVICE_OUT_AUX_DIGITAL ||
+         device == AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET ||
+         device == AUDIO_DEVICE_OUT_USB_ACCESSORY ||
+         device == AUDIO_DEVICE_OUT_USB_DEVICE)) {
+        return 1.0;
+    }
+
+    volume = volIndexToAmpl(device, streamDesc, index);
+
+    // if a headset is connected, apply the following rules to ring tones and notifications
+    // to avoid sound level bursts in user's ears:
+    // - always attenuate ring tones and notifications volume by 6dB
+    // - if music is playing, always limit the volume to current music volume,
+    // with a minimum threshold at -36dB so that notification is always perceived.
+    const routing_strategy stream_strategy = getStrategy(stream);
+    if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
+            AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+            AUDIO_DEVICE_OUT_WIRED_HEADSET |
+            AUDIO_DEVICE_OUT_WIRED_HEADPHONE)) &&
+        ((stream_strategy == STRATEGY_SONIFICATION)
+                || (stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL)
+                || (stream == AUDIO_STREAM_SYSTEM)
+                || ((stream_strategy == STRATEGY_ENFORCED_AUDIBLE) &&
+                    (mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_NONE))) &&
+        streamDesc.mCanBeMuted) {
+        volume *= SONIFICATION_HEADSET_VOLUME_FACTOR;
+        // when the phone is ringing we must consider that music could have been paused just before
+        // by the music application and behave as if music was active if the last music track was
+        // just stopped
+        if (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY) ||
+                mLimitRingtoneVolume) {
+            audio_devices_t musicDevice = getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/);
+            float musicVol = computeVolume(AUDIO_STREAM_MUSIC,
+                               mStreams[AUDIO_STREAM_MUSIC].getVolumeIndex(musicDevice),
+                               output,
+                               musicDevice);
+            float minVol = (musicVol > SONIFICATION_HEADSET_VOLUME_MIN) ?
+                                musicVol : SONIFICATION_HEADSET_VOLUME_MIN;
+            if (volume > minVol) {
+                volume = minVol;
+                ALOGV("computeVolume limiting volume to %f musicVol %f", minVol, musicVol);
+            }
+        }
+    }
+
+    return volume;
+}
+
+status_t AudioPolicyManager::checkAndSetVolume(audio_stream_type_t stream,
+                                                   int index,
+                                                   audio_io_handle_t output,
+                                                   audio_devices_t device,
+                                                   int delayMs,
+                                                   bool force)
+{
+
+    // do not change actual stream volume if the stream is muted
+    if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) {
+        ALOGVV("checkAndSetVolume() stream %d muted count %d",
+              stream, mOutputs.valueFor(output)->mMuteCount[stream]);
+        return NO_ERROR;
+    }
+
+    // do not change in call volume if bluetooth is connected and vice versa
+    if ((stream == AUDIO_STREAM_VOICE_CALL &&
+            mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION] == AUDIO_POLICY_FORCE_BT_SCO) ||
+        (stream == AUDIO_STREAM_BLUETOOTH_SCO &&
+                mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION] != AUDIO_POLICY_FORCE_BT_SCO)) {
+        ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
+             stream, mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]);
+        return INVALID_OPERATION;
+    }
+
+    float volume = computeVolume(stream, index, output, device);
+    // We actually change the volume if:
+    // - the float value returned by computeVolume() changed
+    // - the force flag is set
+    if (volume != mOutputs.valueFor(output)->mCurVolume[stream] ||
+            force) {
+        mOutputs.valueFor(output)->mCurVolume[stream] = volume;
+        ALOGVV("checkAndSetVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
+        // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is
+        // enabled
+        if (stream == AUDIO_STREAM_BLUETOOTH_SCO) {
+            mpClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL, volume, output, delayMs);
+        }
+        mpClientInterface->setStreamVolume(stream, volume, output, delayMs);
+    }
+
+    if (stream == AUDIO_STREAM_VOICE_CALL ||
+        stream == AUDIO_STREAM_BLUETOOTH_SCO) {
+        float voiceVolume;
+        // Force voice volume to max for bluetooth SCO as volume is managed by the headset
+        if (stream == AUDIO_STREAM_VOICE_CALL) {
+            voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+        } else {
+            voiceVolume = 1.0;
+        }
+
+        if (voiceVolume != mLastVoiceVolume && output == mPrimaryOutput) {
+            mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+            mLastVoiceVolume = voiceVolume;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+void AudioPolicyManager::applyStreamVolumes(audio_io_handle_t output,
+                                                audio_devices_t device,
+                                                int delayMs,
+                                                bool force)
+{
+    ALOGVV("applyStreamVolumes() for output %d and device %x", output, device);
+
+    for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) {
+        checkAndSetVolume((audio_stream_type_t)stream,
+                          mStreams[stream].getVolumeIndex(device),
+                          output,
+                          device,
+                          delayMs,
+                          force);
+    }
+}
+
+void AudioPolicyManager::setStrategyMute(routing_strategy strategy,
+                                             bool on,
+                                             audio_io_handle_t output,
+                                             int delayMs,
+                                             audio_devices_t device)
+{
+    ALOGVV("setStrategyMute() strategy %d, mute %d, output %d", strategy, on, output);
+    for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) {
+        if (getStrategy((audio_stream_type_t)stream) == strategy) {
+            setStreamMute((audio_stream_type_t)stream, on, output, delayMs, device);
+        }
+    }
+}
+
+void AudioPolicyManager::setStreamMute(audio_stream_type_t stream,
+                                           bool on,
+                                           audio_io_handle_t output,
+                                           int delayMs,
+                                           audio_devices_t device)
+{
+    StreamDescriptor &streamDesc = mStreams[stream];
+    AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+    if (device == AUDIO_DEVICE_NONE) {
+        device = outputDesc->device();
+    }
+
+    ALOGVV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d device %04x",
+          stream, on, output, outputDesc->mMuteCount[stream], device);
+
+    if (on) {
+        if (outputDesc->mMuteCount[stream] == 0) {
+            if (streamDesc.mCanBeMuted &&
+                    ((stream != AUDIO_STREAM_ENFORCED_AUDIBLE) ||
+                     (mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_NONE))) {
+                checkAndSetVolume(stream, 0, output, device, delayMs);
+            }
+        }
+        // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored
+        outputDesc->mMuteCount[stream]++;
+    } else {
+        if (outputDesc->mMuteCount[stream] == 0) {
+            ALOGV("setStreamMute() unmuting non muted stream!");
+            return;
+        }
+        if (--outputDesc->mMuteCount[stream] == 0) {
+            checkAndSetVolume(stream,
+                              streamDesc.getVolumeIndex(device),
+                              output,
+                              device,
+                              delayMs);
+        }
+    }
+}
+
+void AudioPolicyManager::handleIncallSonification(audio_stream_type_t stream,
+                                                      bool starting, bool stateChange)
+{
+    // if the stream pertains to sonification strategy and we are in call we must
+    // mute the stream if it is low visibility. If it is high visibility, we must play a tone
+    // in the device used for phone strategy and play the tone if the selected device does not
+    // interfere with the device used for phone strategy
+    // if stateChange is true, we are called from setPhoneState() and we must mute or unmute as
+    // many times as there are active tracks on the output
+    const routing_strategy stream_strategy = getStrategy(stream);
+    if ((stream_strategy == STRATEGY_SONIFICATION) ||
+            ((stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL))) {
+        AudioOutputDescriptor *outputDesc = mOutputs.valueFor(mPrimaryOutput);
+        ALOGV("handleIncallSonification() stream %d starting %d device %x stateChange %d",
+                stream, starting, outputDesc->mDevice, stateChange);
+        if (outputDesc->mRefCount[stream]) {
+            int muteCount = 1;
+            if (stateChange) {
+                muteCount = outputDesc->mRefCount[stream];
+            }
+            if (audio_is_low_visibility(stream)) {
+                ALOGV("handleIncallSonification() low visibility, muteCount %d", muteCount);
+                for (int i = 0; i < muteCount; i++) {
+                    setStreamMute(stream, starting, mPrimaryOutput);
+                }
+            } else {
+                ALOGV("handleIncallSonification() high visibility");
+                if (outputDesc->device() &
+                        getDeviceForStrategy(STRATEGY_PHONE, true /*fromCache*/)) {
+                    ALOGV("handleIncallSonification() high visibility muted, muteCount %d", muteCount);
+                    for (int i = 0; i < muteCount; i++) {
+                        setStreamMute(stream, starting, mPrimaryOutput);
+                    }
+                }
+                if (starting) {
+                    mpClientInterface->startTone(AUDIO_POLICY_TONE_IN_CALL_NOTIFICATION,
+                                                 AUDIO_STREAM_VOICE_CALL);
+                } else {
+                    mpClientInterface->stopTone();
+                }
+            }
+        }
+    }
+}
+
+bool AudioPolicyManager::isInCall()
+{
+    return isStateInCall(mPhoneState);
+}
+
+bool AudioPolicyManager::isStateInCall(int state) {
+    return ((state == AUDIO_MODE_IN_CALL) ||
+            (state == AUDIO_MODE_IN_COMMUNICATION));
+}
+
+uint32_t AudioPolicyManager::getMaxEffectsCpuLoad()
+{
+    return MAX_EFFECTS_CPU_LOAD;
+}
+
+uint32_t AudioPolicyManager::getMaxEffectsMemory()
+{
+    return MAX_EFFECTS_MEMORY;
+}
+
+// --- AudioOutputDescriptor class implementation
+
+AudioPolicyManager::AudioOutputDescriptor::AudioOutputDescriptor(
+        const IOProfile *profile)
+    : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT),
+      mChannelMask(0), mLatency(0),
+    mFlags((audio_output_flags_t)0), mDevice(AUDIO_DEVICE_NONE),
+    mOutput1(0), mOutput2(0), mProfile(profile), mDirectOpenCount(0)
+{
+    // clear usage count for all stream types
+    for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
+        mRefCount[i] = 0;
+        mCurVolume[i] = -1.0;
+        mMuteCount[i] = 0;
+        mStopTime[i] = 0;
+    }
+    for (int i = 0; i < NUM_STRATEGIES; i++) {
+        mStrategyMutedByDevice[i] = false;
+    }
+    if (profile != NULL) {
+        mSamplingRate = profile->mSamplingRates[0];
+        mFormat = profile->mFormats[0];
+        mChannelMask = profile->mChannelMasks[0];
+        mFlags = profile->mFlags;
+    }
+}
+
+audio_devices_t AudioPolicyManager::AudioOutputDescriptor::device() const
+{
+    if (isDuplicated()) {
+        return (audio_devices_t)(mOutput1->mDevice | mOutput2->mDevice);
+    } else {
+        return mDevice;
+    }
+}
+
+uint32_t AudioPolicyManager::AudioOutputDescriptor::latency()
+{
+    if (isDuplicated()) {
+        return (mOutput1->mLatency > mOutput2->mLatency) ? mOutput1->mLatency : mOutput2->mLatency;
+    } else {
+        return mLatency;
+    }
+}
+
+bool AudioPolicyManager::AudioOutputDescriptor::sharesHwModuleWith(
+        const AudioOutputDescriptor *outputDesc)
+{
+    if (isDuplicated()) {
+        return mOutput1->sharesHwModuleWith(outputDesc) || mOutput2->sharesHwModuleWith(outputDesc);
+    } else if (outputDesc->isDuplicated()){
+        return sharesHwModuleWith(outputDesc->mOutput1) || sharesHwModuleWith(outputDesc->mOutput2);
+    } else {
+        return (mProfile->mModule == outputDesc->mProfile->mModule);
+    }
+}
+
+void AudioPolicyManager::AudioOutputDescriptor::changeRefCount(audio_stream_type_t stream,
+                                                                   int delta)
+{
+    // forward usage count change to attached outputs
+    if (isDuplicated()) {
+        mOutput1->changeRefCount(stream, delta);
+        mOutput2->changeRefCount(stream, delta);
+    }
+    if ((delta + (int)mRefCount[stream]) < 0) {
+        ALOGW("changeRefCount() invalid delta %d for stream %d, refCount %d",
+              delta, stream, mRefCount[stream]);
+        mRefCount[stream] = 0;
+        return;
+    }
+    mRefCount[stream] += delta;
+    ALOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
+}
+
+audio_devices_t AudioPolicyManager::AudioOutputDescriptor::supportedDevices()
+{
+    if (isDuplicated()) {
+        return (audio_devices_t)(mOutput1->supportedDevices() | mOutput2->supportedDevices());
+    } else {
+        return mProfile->mSupportedDevices ;
+    }
+}
+
+bool AudioPolicyManager::AudioOutputDescriptor::isActive(uint32_t inPastMs) const
+{
+    return isStrategyActive(NUM_STRATEGIES, inPastMs);
+}
+
+bool AudioPolicyManager::AudioOutputDescriptor::isStrategyActive(routing_strategy strategy,
+                                                                       uint32_t inPastMs,
+                                                                       nsecs_t sysTime) const
+{
+    if ((sysTime == 0) && (inPastMs != 0)) {
+        sysTime = systemTime();
+    }
+    for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
+        if (((getStrategy((audio_stream_type_t)i) == strategy) ||
+                (NUM_STRATEGIES == strategy)) &&
+                isStreamActive((audio_stream_type_t)i, inPastMs, sysTime)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioPolicyManager::AudioOutputDescriptor::isStreamActive(audio_stream_type_t stream,
+                                                                       uint32_t inPastMs,
+                                                                       nsecs_t sysTime) const
+{
+    if (mRefCount[stream] != 0) {
+        return true;
+    }
+    if (inPastMs == 0) {
+        return false;
+    }
+    if (sysTime == 0) {
+        sysTime = systemTime();
+    }
+    if (ns2ms(sysTime - mStopTime[stream]) < inPastMs) {
+        return true;
+    }
+    return false;
+}
+
+
+status_t AudioPolicyManager::AudioOutputDescriptor::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Format: %08x\n", mFormat);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Latency: %d\n", mLatency);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Flags %08x\n", mFlags);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Devices %08x\n", device());
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Stream volume refCount muteCount\n");
+    result.append(buffer);
+    for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
+        snprintf(buffer, SIZE, " %02d     %.03f     %02d       %02d\n",
+                 i, mCurVolume[i], mRefCount[i], mMuteCount[i]);
+        result.append(buffer);
+    }
+    write(fd, result.string(), result.size());
+
+    return NO_ERROR;
+}
+
+// --- AudioInputDescriptor class implementation
+
+AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const IOProfile *profile)
+    : mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0),
+      mDevice(AUDIO_DEVICE_NONE), mRefCount(0),
+      mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile)
+{
+}
+
+status_t AudioPolicyManager::AudioInputDescriptor::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Format: %d\n", mFormat);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+
+    return NO_ERROR;
+}
+
+// --- StreamDescriptor class implementation
+
+AudioPolicyManager::StreamDescriptor::StreamDescriptor()
+    :   mIndexMin(0), mIndexMax(1), mCanBeMuted(true)
+{
+    mIndexCur.add(AUDIO_DEVICE_OUT_DEFAULT, 0);
+}
+
+int AudioPolicyManager::StreamDescriptor::getVolumeIndex(audio_devices_t device)
+{
+    device = AudioPolicyManager::getDeviceForVolume(device);
+    // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT
+    if (mIndexCur.indexOfKey(device) < 0) {
+        device = AUDIO_DEVICE_OUT_DEFAULT;
+    }
+    return mIndexCur.valueFor(device);
+}
+
+void AudioPolicyManager::StreamDescriptor::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "%s         %02d         %02d         ",
+             mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax);
+    result.append(buffer);
+    for (size_t i = 0; i < mIndexCur.size(); i++) {
+        snprintf(buffer, SIZE, "%04x : %02d, ",
+                 mIndexCur.keyAt(i),
+                 mIndexCur.valueAt(i));
+        result.append(buffer);
+    }
+    result.append("\n");
+
+    write(fd, result.string(), result.size());
+}
+
+// --- EffectDescriptor class implementation
+
+status_t AudioPolicyManager::EffectDescriptor::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, " I/O: %d\n", mIo);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Strategy: %d\n", mStrategy);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Session: %d\n", mSession);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " Name: %s\n",  mDesc.name);
+    result.append(buffer);
+    snprintf(buffer, SIZE, " %s\n",  mEnabled ? "Enabled" : "Disabled");
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+
+    return NO_ERROR;
+}
+
+// --- IOProfile class implementation
+
+AudioPolicyManager::HwModule::HwModule(const char *name)
+    : mName(strndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN)), mHandle(0)
+{
+}
+
+AudioPolicyManager::HwModule::~HwModule()
+{
+    for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+         delete mOutputProfiles[i];
+    }
+    for (size_t i = 0; i < mInputProfiles.size(); i++) {
+         delete mInputProfiles[i];
+    }
+    free((void *)mName);
+}
+
+void AudioPolicyManager::HwModule::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "  - name: %s\n", mName);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "  - handle: %d\n", mHandle);
+    result.append(buffer);
+    write(fd, result.string(), result.size());
+    if (mOutputProfiles.size()) {
+        write(fd, "  - outputs:\n", strlen("  - outputs:\n"));
+        for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+            snprintf(buffer, SIZE, "    output %d:\n", i);
+            write(fd, buffer, strlen(buffer));
+            mOutputProfiles[i]->dump(fd);
+        }
+    }
+    if (mInputProfiles.size()) {
+        write(fd, "  - inputs:\n", strlen("  - inputs:\n"));
+        for (size_t i = 0; i < mInputProfiles.size(); i++) {
+            snprintf(buffer, SIZE, "    input %d:\n", i);
+            write(fd, buffer, strlen(buffer));
+            mInputProfiles[i]->dump(fd);
+        }
+    }
+}
+
+AudioPolicyManager::IOProfile::IOProfile(HwModule *module)
+    : mFlags((audio_output_flags_t)0), mModule(module)
+{
+}
+
+AudioPolicyManager::IOProfile::~IOProfile()
+{
+}
+
+// checks if the IO profile is compatible with specified parameters.
+// Sampling rate, format and channel mask must be specified in order to
+// get a valid a match
+bool AudioPolicyManager::IOProfile::isCompatibleProfile(audio_devices_t device,
+                                                            uint32_t samplingRate,
+                                                            audio_format_t format,
+                                                            audio_channel_mask_t channelMask,
+                                                            audio_output_flags_t flags) const
+{
+    if (samplingRate == 0 || !audio_is_valid_format(format) || channelMask == 0) {
+         return false;
+     }
+
+     if ((mSupportedDevices & device) != device) {
+         return false;
+     }
+     if ((mFlags & flags) != flags) {
+         return false;
+     }
+     size_t i;
+     for (i = 0; i < mSamplingRates.size(); i++)
+     {
+         if (mSamplingRates[i] == samplingRate) {
+             break;
+         }
+     }
+     if (i == mSamplingRates.size()) {
+         return false;
+     }
+     for (i = 0; i < mFormats.size(); i++)
+     {
+         if (mFormats[i] == format) {
+             break;
+         }
+     }
+     if (i == mFormats.size()) {
+         return false;
+     }
+     for (i = 0; i < mChannelMasks.size(); i++)
+     {
+         if (mChannelMasks[i] == channelMask) {
+             break;
+         }
+     }
+     if (i == mChannelMasks.size()) {
+         return false;
+     }
+     return true;
+}
+
+void AudioPolicyManager::IOProfile::dump(int fd)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "    - sampling rates: ");
+    result.append(buffer);
+    for (size_t i = 0; i < mSamplingRates.size(); i++) {
+        snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
+        result.append(buffer);
+        result.append(i == (mSamplingRates.size() - 1) ? "\n" : ", ");
+    }
+
+    snprintf(buffer, SIZE, "    - channel masks: ");
+    result.append(buffer);
+    for (size_t i = 0; i < mChannelMasks.size(); i++) {
+        snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
+        result.append(buffer);
+        result.append(i == (mChannelMasks.size() - 1) ? "\n" : ", ");
+    }
+
+    snprintf(buffer, SIZE, "    - formats: ");
+    result.append(buffer);
+    for (size_t i = 0; i < mFormats.size(); i++) {
+        snprintf(buffer, SIZE, "0x%08x", mFormats[i]);
+        result.append(buffer);
+        result.append(i == (mFormats.size() - 1) ? "\n" : ", ");
+    }
+
+    snprintf(buffer, SIZE, "    - devices: 0x%04x\n", mSupportedDevices);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "    - flags: 0x%04x\n", mFlags);
+    result.append(buffer);
+
+    write(fd, result.string(), result.size());
+}
+
+// --- audio_policy.conf file parsing
+
+struct StringToEnum {
+    const char *name;
+    uint32_t value;
+};
+
+#define STRING_TO_ENUM(string) { #string, string }
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+const struct StringToEnum sDeviceNameToEnumTable[] = {
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_EARPIECE),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADSET),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_SCO),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_A2DP),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_DIGITAL),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_DEVICE),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_ACCESSORY),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_USB),
+    STRING_TO_ENUM(AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_VOICE_CALL),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
+    STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
+};
+
+const struct StringToEnum sFlagNameToEnumTable[] = {
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
+    STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
+};
+
+const struct StringToEnum sFormatNameToEnumTable[] = {
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_32_BIT),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_FLOAT),
+    STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
+    STRING_TO_ENUM(AUDIO_FORMAT_MP3),
+    STRING_TO_ENUM(AUDIO_FORMAT_AAC),
+    STRING_TO_ENUM(AUDIO_FORMAT_VORBIS),
+};
+
+const struct StringToEnum sOutChannelsNameToEnumTable[] = {
+    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_MONO),
+    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
+    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
+    STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
+};
+
+const struct StringToEnum sInChannelsNameToEnumTable[] = {
+    STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
+    STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
+    STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
+};
+
+
+uint32_t AudioPolicyManager::stringToEnum(const struct StringToEnum *table,
+                                              size_t size,
+                                              const char *name)
+{
+    for (size_t i = 0; i < size; i++) {
+        if (strcmp(table[i].name, name) == 0) {
+            ALOGV("stringToEnum() found %s", table[i].name);
+            return table[i].value;
+        }
+    }
+    return 0;
+}
+
+bool AudioPolicyManager::stringToBool(const char *value)
+{
+    return ((strcasecmp("true", value) == 0) || (strcmp("1", value) == 0));
+}
+
+audio_output_flags_t AudioPolicyManager::parseFlagNames(char *name)
+{
+    uint32_t flag = 0;
+
+    // it is OK to cast name to non const here as we are not going to use it after
+    // strtok() modifies it
+    char *flagName = strtok(name, "|");
+    while (flagName != NULL) {
+        if (strlen(flagName) != 0) {
+            flag |= stringToEnum(sFlagNameToEnumTable,
+                               ARRAY_SIZE(sFlagNameToEnumTable),
+                               flagName);
+        }
+        flagName = strtok(NULL, "|");
+    }
+    //force direct flag if offload flag is set: offloading implies a direct output stream
+    // and all common behaviors are driven by checking only the direct flag
+    // this should normally be set appropriately in the policy configuration file
+    if ((flag & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+        flag |= AUDIO_OUTPUT_FLAG_DIRECT;
+    }
+
+    return (audio_output_flags_t)flag;
+}
+
+audio_devices_t AudioPolicyManager::parseDeviceNames(char *name)
+{
+    uint32_t device = 0;
+
+    char *devName = strtok(name, "|");
+    while (devName != NULL) {
+        if (strlen(devName) != 0) {
+            device |= stringToEnum(sDeviceNameToEnumTable,
+                                 ARRAY_SIZE(sDeviceNameToEnumTable),
+                                 devName);
+        }
+        devName = strtok(NULL, "|");
+    }
+    return device;
+}
+
+void AudioPolicyManager::loadSamplingRates(char *name, IOProfile *profile)
+{
+    char *str = strtok(name, "|");
+
+    // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
+    // rates should be read from the output stream after it is opened for the first time
+    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+        profile->mSamplingRates.add(0);
+        return;
+    }
+
+    while (str != NULL) {
+        uint32_t rate = atoi(str);
+        if (rate != 0) {
+            ALOGV("loadSamplingRates() adding rate %d", rate);
+            profile->mSamplingRates.add(rate);
+        }
+        str = strtok(NULL, "|");
+    }
+    return;
+}
+
+void AudioPolicyManager::loadFormats(char *name, IOProfile *profile)
+{
+    char *str = strtok(name, "|");
+
+    // by convention, "0' in the first entry in mFormats indicates the supported formats
+    // should be read from the output stream after it is opened for the first time
+    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+        profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
+        return;
+    }
+
+    while (str != NULL) {
+        audio_format_t format = (audio_format_t)stringToEnum(sFormatNameToEnumTable,
+                                                             ARRAY_SIZE(sFormatNameToEnumTable),
+                                                             str);
+        if (format != AUDIO_FORMAT_DEFAULT) {
+            profile->mFormats.add(format);
+        }
+        str = strtok(NULL, "|");
+    }
+    return;
+}
+
+void AudioPolicyManager::loadInChannels(char *name, IOProfile *profile)
+{
+    const char *str = strtok(name, "|");
+
+    ALOGV("loadInChannels() %s", name);
+
+    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+        profile->mChannelMasks.add(0);
+        return;
+    }
+
+    while (str != NULL) {
+        audio_channel_mask_t channelMask =
+                (audio_channel_mask_t)stringToEnum(sInChannelsNameToEnumTable,
+                                                   ARRAY_SIZE(sInChannelsNameToEnumTable),
+                                                   str);
+        if (channelMask != 0) {
+            ALOGV("loadInChannels() adding channelMask %04x", channelMask);
+            profile->mChannelMasks.add(channelMask);
+        }
+        str = strtok(NULL, "|");
+    }
+    return;
+}
+
+void AudioPolicyManager::loadOutChannels(char *name, IOProfile *profile)
+{
+    const char *str = strtok(name, "|");
+
+    ALOGV("loadOutChannels() %s", name);
+
+    // by convention, "0' in the first entry in mChannelMasks indicates the supported channel
+    // masks should be read from the output stream after it is opened for the first time
+    if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
+        profile->mChannelMasks.add(0);
+        return;
+    }
+
+    while (str != NULL) {
+        audio_channel_mask_t channelMask =
+                (audio_channel_mask_t)stringToEnum(sOutChannelsNameToEnumTable,
+                                                   ARRAY_SIZE(sOutChannelsNameToEnumTable),
+                                                   str);
+        if (channelMask != 0) {
+            profile->mChannelMasks.add(channelMask);
+        }
+        str = strtok(NULL, "|");
+    }
+    return;
+}
+
+status_t AudioPolicyManager::loadInput(cnode *root, HwModule *module)
+{
+    cnode *node = root->first_child;
+
+    IOProfile *profile = new IOProfile(module);
+
+    while (node) {
+        if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
+            loadSamplingRates((char *)node->value, profile);
+        } else if (strcmp(node->name, FORMATS_TAG) == 0) {
+            loadFormats((char *)node->value, profile);
+        } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
+            loadInChannels((char *)node->value, profile);
+        } else if (strcmp(node->name, DEVICES_TAG) == 0) {
+            profile->mSupportedDevices = parseDeviceNames((char *)node->value);
+        }
+        node = node->next;
+    }
+    ALOGW_IF(profile->mSupportedDevices == AUDIO_DEVICE_NONE,
+            "loadInput() invalid supported devices");
+    ALOGW_IF(profile->mChannelMasks.size() == 0,
+            "loadInput() invalid supported channel masks");
+    ALOGW_IF(profile->mSamplingRates.size() == 0,
+            "loadInput() invalid supported sampling rates");
+    ALOGW_IF(profile->mFormats.size() == 0,
+            "loadInput() invalid supported formats");
+    if ((profile->mSupportedDevices != AUDIO_DEVICE_NONE) &&
+            (profile->mChannelMasks.size() != 0) &&
+            (profile->mSamplingRates.size() != 0) &&
+            (profile->mFormats.size() != 0)) {
+
+        ALOGV("loadInput() adding input mSupportedDevices %04x", profile->mSupportedDevices);
+
+        module->mInputProfiles.add(profile);
+        return NO_ERROR;
+    } else {
+        delete profile;
+        return BAD_VALUE;
+    }
+}
+
+status_t AudioPolicyManager::loadOutput(cnode *root, HwModule *module)
+{
+    cnode *node = root->first_child;
+
+    IOProfile *profile = new IOProfile(module);
+
+    while (node) {
+        if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
+            loadSamplingRates((char *)node->value, profile);
+        } else if (strcmp(node->name, FORMATS_TAG) == 0) {
+            loadFormats((char *)node->value, profile);
+        } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
+            loadOutChannels((char *)node->value, profile);
+        } else if (strcmp(node->name, DEVICES_TAG) == 0) {
+            profile->mSupportedDevices = parseDeviceNames((char *)node->value);
+        } else if (strcmp(node->name, FLAGS_TAG) == 0) {
+            profile->mFlags = parseFlagNames((char *)node->value);
+        }
+        node = node->next;
+    }
+    ALOGW_IF(profile->mSupportedDevices == AUDIO_DEVICE_NONE,
+            "loadOutput() invalid supported devices");
+    ALOGW_IF(profile->mChannelMasks.size() == 0,
+            "loadOutput() invalid supported channel masks");
+    ALOGW_IF(profile->mSamplingRates.size() == 0,
+            "loadOutput() invalid supported sampling rates");
+    ALOGW_IF(profile->mFormats.size() == 0,
+            "loadOutput() invalid supported formats");
+    if ((profile->mSupportedDevices != AUDIO_DEVICE_NONE) &&
+            (profile->mChannelMasks.size() != 0) &&
+            (profile->mSamplingRates.size() != 0) &&
+            (profile->mFormats.size() != 0)) {
+
+        ALOGV("loadOutput() adding output mSupportedDevices %04x, mFlags %04x",
+              profile->mSupportedDevices, profile->mFlags);
+
+        module->mOutputProfiles.add(profile);
+        return NO_ERROR;
+    } else {
+        delete profile;
+        return BAD_VALUE;
+    }
+}
+
+void AudioPolicyManager::loadHwModule(cnode *root)
+{
+    cnode *node = config_find(root, OUTPUTS_TAG);
+    status_t status = NAME_NOT_FOUND;
+
+    HwModule *module = new HwModule(root->name);
+
+    if (node != NULL) {
+        if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_A2DP) == 0) {
+            mHasA2dp = true;
+        } else if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_USB) == 0) {
+            mHasUsb = true;
+        } else if (strcmp(root->name, AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX) == 0) {
+            mHasRemoteSubmix = true;
+        }
+
+        node = node->first_child;
+        while (node) {
+            ALOGV("loadHwModule() loading output %s", node->name);
+            status_t tmpStatus = loadOutput(node, module);
+            if (status == NAME_NOT_FOUND || status == NO_ERROR) {
+                status = tmpStatus;
+            }
+            node = node->next;
+        }
+    }
+    node = config_find(root, INPUTS_TAG);
+    if (node != NULL) {
+        node = node->first_child;
+        while (node) {
+            ALOGV("loadHwModule() loading input %s", node->name);
+            status_t tmpStatus = loadInput(node, module);
+            if (status == NAME_NOT_FOUND || status == NO_ERROR) {
+                status = tmpStatus;
+            }
+            node = node->next;
+        }
+    }
+    if (status == NO_ERROR) {
+        mHwModules.add(module);
+    } else {
+        delete module;
+    }
+}
+
+void AudioPolicyManager::loadHwModules(cnode *root)
+{
+    cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);
+    if (node == NULL) {
+        return;
+    }
+
+    node = node->first_child;
+    while (node) {
+        ALOGV("loadHwModules() loading module %s", node->name);
+        loadHwModule(node);
+        node = node->next;
+    }
+}
+
+void AudioPolicyManager::loadGlobalConfig(cnode *root)
+{
+    cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
+    if (node == NULL) {
+        return;
+    }
+    node = node->first_child;
+    while (node) {
+        if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
+            mAttachedOutputDevices = parseDeviceNames((char *)node->value);
+            ALOGW_IF(mAttachedOutputDevices == AUDIO_DEVICE_NONE,
+                    "loadGlobalConfig() no attached output devices");
+            ALOGV("loadGlobalConfig() mAttachedOutputDevices %04x", mAttachedOutputDevices);
+        } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) {
+            mDefaultOutputDevice = (audio_devices_t)stringToEnum(sDeviceNameToEnumTable,
+                                              ARRAY_SIZE(sDeviceNameToEnumTable),
+                                              (char *)node->value);
+            ALOGW_IF(mDefaultOutputDevice == AUDIO_DEVICE_NONE,
+                    "loadGlobalConfig() default device not specified");
+            ALOGV("loadGlobalConfig() mDefaultOutputDevice %04x", mDefaultOutputDevice);
+        } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
+            mAvailableInputDevices = parseDeviceNames((char *)node->value) & ~AUDIO_DEVICE_BIT_IN;
+            ALOGV("loadGlobalConfig() mAvailableInputDevices %04x", mAvailableInputDevices);
+        } else if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
+            mSpeakerDrcEnabled = stringToBool((char *)node->value);
+            ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", mSpeakerDrcEnabled);
+        }
+        node = node->next;
+    }
+}
+
+status_t AudioPolicyManager::loadAudioPolicyConfig(const char *path)
+{
+    cnode *root;
+    char *data;
+
+    data = (char *)load_file(path, NULL);
+    if (data == NULL) {
+        return -ENODEV;
+    }
+    root = config_node("", "");
+    config_load(root, data);
+
+    loadGlobalConfig(root);
+    loadHwModules(root);
+
+    config_free(root);
+    free(root);
+    free(data);
+
+    ALOGI("loadAudioPolicyConfig() loaded %s\n", path);
+
+    return NO_ERROR;
+}
+
+void AudioPolicyManager::defaultAudioPolicyConfig(void)
+{
+    HwModule *module;
+    IOProfile *profile;
+
+    mDefaultOutputDevice = AUDIO_DEVICE_OUT_SPEAKER;
+    mAttachedOutputDevices = AUDIO_DEVICE_OUT_SPEAKER;
+    mAvailableInputDevices = AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN;
+
+    module = new HwModule("primary");
+
+    profile = new IOProfile(module);
+    profile->mSamplingRates.add(44100);
+    profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
+    profile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO);
+    profile->mSupportedDevices = AUDIO_DEVICE_OUT_SPEAKER;
+    profile->mFlags = AUDIO_OUTPUT_FLAG_PRIMARY;
+    module->mOutputProfiles.add(profile);
+
+    profile = new IOProfile(module);
+    profile->mSamplingRates.add(8000);
+    profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
+    profile->mChannelMasks.add(AUDIO_CHANNEL_IN_MONO);
+    profile->mSupportedDevices = AUDIO_DEVICE_IN_BUILTIN_MIC;
+    module->mInputProfiles.add(profile);
+
+    mHwModules.add(module);
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
new file mode 100644
index 0000000..e00d8ab
--- /dev/null
+++ b/services/audiopolicy/AudioPolicyManager.h
@@ -0,0 +1,582 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <cutils/config_utils.h>
+#include <cutils/misc.h>
+#include <utils/Timers.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
+#include "AudioPolicyInterface.h"
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+#define MAX_DEVICE_ADDRESS_LEN 20
+// Attenuation applied to STRATEGY_SONIFICATION streams when a headset is connected: 6dB
+#define SONIFICATION_HEADSET_VOLUME_FACTOR 0.5
+// Min volume for STRATEGY_SONIFICATION streams when limited by music volume: -36dB
+#define SONIFICATION_HEADSET_VOLUME_MIN  0.016
+// Time in milliseconds during which we consider that music is still active after a music
+// track was stopped - see computeVolume()
+#define SONIFICATION_HEADSET_MUSIC_DELAY  5000
+// Time in milliseconds after media stopped playing during which we consider that the
+// sonification should be as unobtrusive as during the time media was playing.
+#define SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY 5000
+// Time in milliseconds during witch some streams are muted while the audio path
+// is switched
+#define MUTE_TIME_MS 2000
+
+#define NUM_TEST_OUTPUTS 5
+
+#define NUM_VOL_CURVE_KNEES 2
+
+// Default minimum length allowed for offloading a compressed track
+// Can be overridden by the audio.offload.min.duration.secs property
+#define OFFLOAD_DEFAULT_MIN_DURATION_SECS 60
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManager implements audio policy manager behavior common to all platforms.
+// ----------------------------------------------------------------------------
+
+class AudioPolicyManager: public AudioPolicyInterface
+#ifdef AUDIO_POLICY_TEST
+    , public Thread
+#endif //AUDIO_POLICY_TEST
+{
+
+public:
+                AudioPolicyManager(AudioPolicyClientInterface *clientInterface);
+        virtual ~AudioPolicyManager();
+
+        // AudioPolicyInterface
+        virtual status_t setDeviceConnectionState(audio_devices_t device,
+                                                          audio_policy_dev_state_t state,
+                                                          const char *device_address);
+        virtual audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device,
+                                                                              const char *device_address);
+        virtual void setPhoneState(audio_mode_t state);
+        virtual void setForceUse(audio_policy_force_use_t usage,
+                                 audio_policy_forced_cfg_t config);
+        virtual audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage);
+        virtual void setSystemProperty(const char* property, const char* value);
+        virtual status_t initCheck();
+        virtual audio_io_handle_t getOutput(audio_stream_type_t stream,
+                                            uint32_t samplingRate,
+                                            audio_format_t format,
+                                            audio_channel_mask_t channelMask,
+                                            audio_output_flags_t flags,
+                                            const audio_offload_info_t *offloadInfo);
+        virtual status_t startOutput(audio_io_handle_t output,
+                                     audio_stream_type_t stream,
+                                     int session = 0);
+        virtual status_t stopOutput(audio_io_handle_t output,
+                                    audio_stream_type_t stream,
+                                    int session = 0);
+        virtual void releaseOutput(audio_io_handle_t output);
+        virtual audio_io_handle_t getInput(audio_source_t inputSource,
+                                            uint32_t samplingRate,
+                                            audio_format_t format,
+                                            audio_channel_mask_t channelMask,
+                                            audio_in_acoustics_t acoustics);
+
+        // indicates to the audio policy manager that the input starts being used.
+        virtual status_t startInput(audio_io_handle_t input);
+
+        // indicates to the audio policy manager that the input stops being used.
+        virtual status_t stopInput(audio_io_handle_t input);
+        virtual void releaseInput(audio_io_handle_t input);
+        virtual void initStreamVolume(audio_stream_type_t stream,
+                                                    int indexMin,
+                                                    int indexMax);
+        virtual status_t setStreamVolumeIndex(audio_stream_type_t stream,
+                                              int index,
+                                              audio_devices_t device);
+        virtual status_t getStreamVolumeIndex(audio_stream_type_t stream,
+                                              int *index,
+                                              audio_devices_t device);
+
+        // return the strategy corresponding to a given stream type
+        virtual uint32_t getStrategyForStream(audio_stream_type_t stream);
+
+        // return the enabled output devices for the given stream type
+        virtual audio_devices_t getDevicesForStream(audio_stream_type_t stream);
+
+        virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t *desc = NULL);
+        virtual status_t registerEffect(const effect_descriptor_t *desc,
+                                        audio_io_handle_t io,
+                                        uint32_t strategy,
+                                        int session,
+                                        int id);
+        virtual status_t unregisterEffect(int id);
+        virtual status_t setEffectEnabled(int id, bool enabled);
+
+        virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
+        // return whether a stream is playing remotely, override to change the definition of
+        //   local/remote playback, used for instance by notification manager to not make
+        //   media players lose audio focus when not playing locally
+        virtual bool isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
+        virtual bool isSourceActive(audio_source_t source) const;
+
+        virtual status_t dump(int fd);
+
+        virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo);
+
+protected:
+
+        enum routing_strategy {
+            STRATEGY_MEDIA,
+            STRATEGY_PHONE,
+            STRATEGY_SONIFICATION,
+            STRATEGY_SONIFICATION_RESPECTFUL,
+            STRATEGY_DTMF,
+            STRATEGY_ENFORCED_AUDIBLE,
+            NUM_STRATEGIES
+        };
+
+        // 4 points to define the volume attenuation curve, each characterized by the volume
+        // index (from 0 to 100) at which they apply, and the attenuation in dB at that index.
+        // we use 100 steps to avoid rounding errors when computing the volume in volIndexToAmpl()
+
+        enum { VOLMIN = 0, VOLKNEE1 = 1, VOLKNEE2 = 2, VOLMAX = 3, VOLCNT = 4};
+
+        class VolumeCurvePoint
+        {
+        public:
+            int mIndex;
+            float mDBAttenuation;
+        };
+
+        // device categories used for volume curve management.
+        enum device_category {
+            DEVICE_CATEGORY_HEADSET,
+            DEVICE_CATEGORY_SPEAKER,
+            DEVICE_CATEGORY_EARPIECE,
+            DEVICE_CATEGORY_CNT
+        };
+
+        class IOProfile;
+
+        class HwModule {
+        public:
+                    HwModule(const char *name);
+                    ~HwModule();
+
+            void dump(int fd);
+
+            const char *const mName; // base name of the audio HW module (primary, a2dp ...)
+            audio_module_handle_t mHandle;
+            Vector <IOProfile *> mOutputProfiles; // output profiles exposed by this module
+            Vector <IOProfile *> mInputProfiles;  // input profiles exposed by this module
+        };
+
+        // the IOProfile class describes the capabilities of an output or input stream.
+        // It is currently assumed that all combination of listed parameters are supported.
+        // It is used by the policy manager to determine if an output or input is suitable for
+        // a given use case,  open/close it accordingly and connect/disconnect audio tracks
+        // to/from it.
+        class IOProfile
+        {
+        public:
+            IOProfile(HwModule *module);
+            ~IOProfile();
+
+            bool isCompatibleProfile(audio_devices_t device,
+                                     uint32_t samplingRate,
+                                     audio_format_t format,
+                                     audio_channel_mask_t channelMask,
+                                     audio_output_flags_t flags) const;
+
+            void dump(int fd);
+
+            // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
+            // indicates the supported parameters should be read from the output stream
+            // after it is opened for the first time
+            Vector <uint32_t> mSamplingRates; // supported sampling rates
+            Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks
+            Vector <audio_format_t> mFormats; // supported audio formats
+            audio_devices_t mSupportedDevices; // supported devices (devices this output can be
+                                               // routed to)
+            audio_output_flags_t mFlags; // attribute flags (e.g primary output,
+                                                // direct output...). For outputs only.
+            HwModule *mModule;                     // audio HW module exposing this I/O stream
+        };
+
+        // default volume curve
+        static const VolumeCurvePoint sDefaultVolumeCurve[AudioPolicyManager::VOLCNT];
+        // default volume curve for media strategy
+        static const VolumeCurvePoint sDefaultMediaVolumeCurve[AudioPolicyManager::VOLCNT];
+        // volume curve for media strategy on speakers
+        static const VolumeCurvePoint sSpeakerMediaVolumeCurve[AudioPolicyManager::VOLCNT];
+        // volume curve for sonification strategy on speakers
+        static const VolumeCurvePoint sSpeakerSonificationVolumeCurve[AudioPolicyManager::VOLCNT];
+        static const VolumeCurvePoint sSpeakerSonificationVolumeCurveDrc[AudioPolicyManager::VOLCNT];
+        static const VolumeCurvePoint sDefaultSystemVolumeCurve[AudioPolicyManager::VOLCNT];
+        static const VolumeCurvePoint sDefaultSystemVolumeCurveDrc[AudioPolicyManager::VOLCNT];
+        static const VolumeCurvePoint sHeadsetSystemVolumeCurve[AudioPolicyManager::VOLCNT];
+        static const VolumeCurvePoint sDefaultVoiceVolumeCurve[AudioPolicyManager::VOLCNT];
+        static const VolumeCurvePoint sSpeakerVoiceVolumeCurve[AudioPolicyManager::VOLCNT];
+        // default volume curves per stream and device category. See initializeVolumeCurves()
+        static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][DEVICE_CATEGORY_CNT];
+
+        // descriptor for audio outputs. Used to maintain current configuration of each opened audio output
+        // and keep track of the usage of this output by each audio stream type.
+        class AudioOutputDescriptor
+        {
+        public:
+            AudioOutputDescriptor(const IOProfile *profile);
+
+            status_t    dump(int fd);
+
+            audio_devices_t device() const;
+            void changeRefCount(audio_stream_type_t stream, int delta);
+
+            bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); }
+            audio_devices_t supportedDevices();
+            uint32_t latency();
+            bool sharesHwModuleWith(const AudioOutputDescriptor *outputDesc);
+            bool isActive(uint32_t inPastMs = 0) const;
+            bool isStreamActive(audio_stream_type_t stream,
+                                uint32_t inPastMs = 0,
+                                nsecs_t sysTime = 0) const;
+            bool isStrategyActive(routing_strategy strategy,
+                             uint32_t inPastMs = 0,
+                             nsecs_t sysTime = 0) const;
+
+            audio_io_handle_t mId;              // output handle
+            uint32_t mSamplingRate;             //
+            audio_format_t mFormat;             //
+            audio_channel_mask_t mChannelMask;     // output configuration
+            uint32_t mLatency;                  //
+            audio_output_flags_t mFlags;   //
+            audio_devices_t mDevice;                   // current device this output is routed to
+            uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output
+            nsecs_t mStopTime[AUDIO_STREAM_CNT];
+            AudioOutputDescriptor *mOutput1;    // used by duplicated outputs: first output
+            AudioOutputDescriptor *mOutput2;    // used by duplicated outputs: second output
+            float mCurVolume[AUDIO_STREAM_CNT];   // current stream volume
+            int mMuteCount[AUDIO_STREAM_CNT];     // mute request counter
+            const IOProfile *mProfile;          // I/O profile this output derives from
+            bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible
+                                                // device selection. See checkDeviceMuteStrategies()
+            uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only)
+        };
+
+        // descriptor for audio inputs. Used to maintain current configuration of each opened audio input
+        // and keep track of the usage of this input.
+        class AudioInputDescriptor
+        {
+        public:
+            AudioInputDescriptor(const IOProfile *profile);
+
+            status_t    dump(int fd);
+
+            uint32_t mSamplingRate;                     //
+            audio_format_t mFormat;                     // input configuration
+            audio_channel_mask_t mChannelMask;             //
+            audio_devices_t mDevice;                    // current device this input is routed to
+            uint32_t mRefCount;                         // number of AudioRecord clients using this output
+            audio_source_t mInputSource;                // input source selected by application (mediarecorder.h)
+            const IOProfile *mProfile;                  // I/O profile this output derives from
+        };
+
+        // stream descriptor used for volume control
+        class StreamDescriptor
+        {
+        public:
+            StreamDescriptor();
+
+            int getVolumeIndex(audio_devices_t device);
+            void dump(int fd);
+
+            int mIndexMin;      // min volume index
+            int mIndexMax;      // max volume index
+            KeyedVector<audio_devices_t, int> mIndexCur;   // current volume index per device
+            bool mCanBeMuted;   // true is the stream can be muted
+
+            const VolumeCurvePoint *mVolumeCurve[DEVICE_CATEGORY_CNT];
+        };
+
+        // stream descriptor used for volume control
+        class EffectDescriptor
+        {
+        public:
+
+            status_t dump(int fd);
+
+            int mIo;                // io the effect is attached to
+            routing_strategy mStrategy; // routing strategy the effect is associated to
+            int mSession;               // audio session the effect is on
+            effect_descriptor_t mDesc;  // effect descriptor
+            bool mEnabled;              // enabled state: CPU load being used or not
+        };
+
+        void addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc);
+
+        // return the strategy corresponding to a given stream type
+        static routing_strategy getStrategy(audio_stream_type_t stream);
+
+        // return appropriate device for streams handled by the specified strategy according to current
+        // phone state, connected devices...
+        // if fromCache is true, the device is returned from mDeviceForStrategy[],
+        // otherwise it is determine by current state
+        // (device connected,phone state, force use, a2dp output...)
+        // This allows to:
+        //  1 speed up process when the state is stable (when starting or stopping an output)
+        //  2 access to either current device selection (fromCache == true) or
+        // "future" device selection (fromCache == false) when called from a context
+        //  where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
+        //  before updateDevicesAndOutputs() is called.
+        virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy,
+                                                     bool fromCache);
+
+        // change the route of the specified output. Returns the number of ms we have slept to
+        // allow new routing to take effect in certain cases.
+        uint32_t setOutputDevice(audio_io_handle_t output,
+                             audio_devices_t device,
+                             bool force = false,
+                             int delayMs = 0);
+
+        // select input device corresponding to requested audio source
+        virtual audio_devices_t getDeviceForInputSource(audio_source_t inputSource);
+
+        // return io handle of active input or 0 if no input is active
+        //    Only considers inputs from physical devices (e.g. main mic, headset mic) when
+        //    ignoreVirtualInputs is true.
+        audio_io_handle_t getActiveInput(bool ignoreVirtualInputs = true);
+
+        // initialize volume curves for each strategy and device category
+        void initializeVolumeCurves();
+
+        // compute the actual volume for a given stream according to the requested index and a particular
+        // device
+        virtual float computeVolume(audio_stream_type_t stream, int index,
+                                    audio_io_handle_t output, audio_devices_t device);
+
+        // check that volume change is permitted, compute and send new volume to audio hardware
+        status_t checkAndSetVolume(audio_stream_type_t stream, int index, audio_io_handle_t output,
+                                   audio_devices_t device, int delayMs = 0, bool force = false);
+
+        // apply all stream volumes to the specified output and device
+        void applyStreamVolumes(audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false);
+
+        // Mute or unmute all streams handled by the specified strategy on the specified output
+        void setStrategyMute(routing_strategy strategy,
+                             bool on,
+                             audio_io_handle_t output,
+                             int delayMs = 0,
+                             audio_devices_t device = (audio_devices_t)0);
+
+        // Mute or unmute the stream on the specified output
+        void setStreamMute(audio_stream_type_t stream,
+                           bool on,
+                           audio_io_handle_t output,
+                           int delayMs = 0,
+                           audio_devices_t device = (audio_devices_t)0);
+
+        // handle special cases for sonification strategy while in call: mute streams or replace by
+        // a special tone in the device used for communication
+        void handleIncallSonification(audio_stream_type_t stream, bool starting, bool stateChange);
+
+        // true if device is in a telephony or VoIP call
+        virtual bool isInCall();
+
+        // true if given state represents a device in a telephony or VoIP call
+        virtual bool isStateInCall(int state);
+
+        // when a device is connected, checks if an open output can be routed
+        // to this device. If none is open, tries to open one of the available outputs.
+        // Returns an output suitable to this device or 0.
+        // when a device is disconnected, checks if an output is not used any more and
+        // returns its handle if any.
+        // transfers the audio tracks and effects from one output thread to another accordingly.
+        status_t checkOutputsForDevice(audio_devices_t device,
+                                       audio_policy_dev_state_t state,
+                                       SortedVector<audio_io_handle_t>& outputs,
+                                       const String8 paramStr);
+
+        // close an output and its companion duplicating output.
+        void closeOutput(audio_io_handle_t output);
+
+        // checks and if necessary changes outputs used for all strategies.
+        // must be called every time a condition that affects the output choice for a given strategy
+        // changes: connected device, phone state, force use...
+        // Must be called before updateDevicesAndOutputs()
+        void checkOutputForStrategy(routing_strategy strategy);
+
+        // Same as checkOutputForStrategy() but for a all strategies in order of priority
+        void checkOutputForAllStrategies();
+
+        // manages A2DP output suspend/restore according to phone state and BT SCO usage
+        void checkA2dpSuspend();
+
+        // returns the A2DP output handle if it is open or 0 otherwise
+        audio_io_handle_t getA2dpOutput();
+
+        // selects the most appropriate device on output for current state
+        // must be called every time a condition that affects the device choice for a given output is
+        // changed: connected device, phone state, force use, output start, output stop..
+        // see getDeviceForStrategy() for the use of fromCache parameter
+
+        audio_devices_t getNewDevice(audio_io_handle_t output, bool fromCache);
+        // updates cache of device used by all strategies (mDeviceForStrategy[])
+        // must be called every time a condition that affects the device choice for a given strategy is
+        // changed: connected device, phone state, force use...
+        // cached values are used by getDeviceForStrategy() if parameter fromCache is true.
+         // Must be called after checkOutputForAllStrategies()
+
+        void updateDevicesAndOutputs();
+
+        virtual uint32_t getMaxEffectsCpuLoad();
+        virtual uint32_t getMaxEffectsMemory();
+#ifdef AUDIO_POLICY_TEST
+        virtual     bool        threadLoop();
+                    void        exit();
+        int testOutputIndex(audio_io_handle_t output);
+#endif //AUDIO_POLICY_TEST
+
+        status_t setEffectEnabled(EffectDescriptor *pDesc, bool enabled);
+
+        // returns the category the device belongs to with regard to volume curve management
+        static device_category getDeviceCategory(audio_devices_t device);
+
+        // extract one device relevant for volume control from multiple device selection
+        static audio_devices_t getDeviceForVolume(audio_devices_t device);
+
+        SortedVector<audio_io_handle_t> getOutputsForDevice(audio_devices_t device,
+                        DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> openOutputs);
+        bool vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
+                                           SortedVector<audio_io_handle_t>& outputs2);
+
+        // mute/unmute strategies using an incompatible device combination
+        // if muting, wait for the audio in pcm buffer to be drained before proceeding
+        // if unmuting, unmute only after the specified delay
+        // Returns the number of ms waited
+        uint32_t  checkDeviceMuteStrategies(AudioOutputDescriptor *outputDesc,
+                                            audio_devices_t prevDevice,
+                                            uint32_t delayMs);
+
+        audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& outputs,
+                                       audio_output_flags_t flags);
+        IOProfile *getInputProfile(audio_devices_t device,
+                                   uint32_t samplingRate,
+                                   audio_format_t format,
+                                   audio_channel_mask_t channelMask);
+        IOProfile *getProfileForDirectOutput(audio_devices_t device,
+                                                       uint32_t samplingRate,
+                                                       audio_format_t format,
+                                                       audio_channel_mask_t channelMask,
+                                                       audio_output_flags_t flags);
+
+        audio_io_handle_t selectOutputForEffects(const SortedVector<audio_io_handle_t>& outputs);
+
+        bool isNonOffloadableEffectEnabled();
+
+        //
+        // Audio policy configuration file parsing (audio_policy.conf)
+        //
+        static uint32_t stringToEnum(const struct StringToEnum *table,
+                                     size_t size,
+                                     const char *name);
+        static bool stringToBool(const char *value);
+        static audio_output_flags_t parseFlagNames(char *name);
+        static audio_devices_t parseDeviceNames(char *name);
+        void loadSamplingRates(char *name, IOProfile *profile);
+        void loadFormats(char *name, IOProfile *profile);
+        void loadOutChannels(char *name, IOProfile *profile);
+        void loadInChannels(char *name, IOProfile *profile);
+        status_t loadOutput(cnode *root,  HwModule *module);
+        status_t loadInput(cnode *root,  HwModule *module);
+        void loadHwModule(cnode *root);
+        void loadHwModules(cnode *root);
+        void loadGlobalConfig(cnode *root);
+        status_t loadAudioPolicyConfig(const char *path);
+        void defaultAudioPolicyConfig(void);
+
+
+        AudioPolicyClientInterface *mpClientInterface;  // audio policy client interface
+        audio_io_handle_t mPrimaryOutput;              // primary output handle
+        // list of descriptors for outputs currently opened
+        DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mOutputs;
+        // copy of mOutputs before setDeviceConnectionState() opens new outputs
+        // reset to mOutputs when updateDevicesAndOutputs() is called.
+        DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mPreviousOutputs;
+        DefaultKeyedVector<audio_io_handle_t, AudioInputDescriptor *> mInputs;     // list of input descriptors
+        audio_devices_t mAvailableOutputDevices; // bit field of all available output devices
+        audio_devices_t mAvailableInputDevices; // bit field of all available input devices
+                                                // without AUDIO_DEVICE_BIT_IN to allow direct bit
+                                                // field comparisons
+        int mPhoneState;                                                    // current phone state
+        audio_policy_forced_cfg_t mForceUse[AUDIO_POLICY_FORCE_USE_CNT];   // current forced use configuration
+
+        StreamDescriptor mStreams[AUDIO_STREAM_CNT];           // stream descriptors for volume control
+        String8 mA2dpDeviceAddress;                                         // A2DP device MAC address
+        String8 mScoDeviceAddress;                                          // SCO device MAC address
+        String8 mUsbCardAndDevice; // USB audio ALSA card and device numbers:
+                                   // card=<card_number>;device=<><device_number>
+        bool    mLimitRingtoneVolume;                                       // limit ringtone volume to music volume if headset connected
+        audio_devices_t mDeviceForStrategy[NUM_STRATEGIES];
+        float   mLastVoiceVolume;                                           // last voice volume value sent to audio HAL
+
+        // Maximum CPU load allocated to audio effects in 0.1 MIPS (ARMv5TE, 0 WS memory) units
+        static const uint32_t MAX_EFFECTS_CPU_LOAD = 1000;
+        // Maximum memory allocated to audio effects in KB
+        static const uint32_t MAX_EFFECTS_MEMORY = 512;
+        uint32_t mTotalEffectsCpuLoad; // current CPU load used by effects
+        uint32_t mTotalEffectsMemory;  // current memory used by effects
+        KeyedVector<int, EffectDescriptor *> mEffects;  // list of registered audio effects
+        bool    mA2dpSuspended;  // true if A2DP output is suspended
+        bool mHasA2dp; // true on platforms with support for bluetooth A2DP
+        bool mHasUsb; // true on platforms with support for USB audio
+        bool mHasRemoteSubmix; // true on platforms with support for remote presentation of a submix
+        audio_devices_t mAttachedOutputDevices; // output devices always available on the platform
+        audio_devices_t mDefaultOutputDevice; // output device selected by default at boot time
+                                              // (must be in mAttachedOutputDevices)
+        bool mSpeakerDrcEnabled;// true on devices that use DRC on the DEVICE_CATEGORY_SPEAKER path
+                                // to boost soft sounds, used to adjust volume curves accordingly
+
+        Vector <HwModule *> mHwModules;
+
+#ifdef AUDIO_POLICY_TEST
+        Mutex   mLock;
+        Condition mWaitWorkCV;
+
+        int             mCurOutput;
+        bool            mDirectOutput;
+        audio_io_handle_t mTestOutputs[NUM_TEST_OUTPUTS];
+        int             mTestInput;
+        uint32_t        mTestDevice;
+        uint32_t        mTestSamplingRate;
+        uint32_t        mTestFormat;
+        uint32_t        mTestChannels;
+        uint32_t        mTestLatencyMs;
+#endif //AUDIO_POLICY_TEST
+
+private:
+        static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
+                int indexInUi);
+        // updates device caching and output for streams that can influence the
+        //    routing of notifications
+        void handleNotificationRoutingForStream(audio_stream_type_t stream);
+        static bool isVirtualInputDevice(audio_devices_t device);
+};
+
+};
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audiopolicy/AudioPolicyService.cpp
similarity index 63%
rename from services/audioflinger/AudioPolicyService.cpp
rename to services/audiopolicy/AudioPolicyService.cpp
index 646a317..49145a5 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audiopolicy/AudioPolicyService.cpp
@@ -60,7 +60,7 @@
 // ----------------------------------------------------------------------------
 
 AudioPolicyService::AudioPolicyService()
-    : BnAudioPolicyService() , mpAudioPolicyDev(NULL) , mpAudioPolicy(NULL)
+    : BnAudioPolicyService(), mpAudioPolicyDev(NULL), mpAudioPolicy(NULL)
 {
     char value[PROPERTY_VALUE_MAX];
     const struct hw_module_t *module;
@@ -77,24 +77,28 @@
     mOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this);
     /* instantiate the audio policy manager */
     rc = hw_get_module(AUDIO_POLICY_HARDWARE_MODULE_ID, &module);
-    if (rc)
+    if (rc) {
         return;
+    }
 
     rc = audio_policy_dev_open(module, &mpAudioPolicyDev);
     ALOGE_IF(rc, "couldn't open audio policy device (%s)", strerror(-rc));
-    if (rc)
+    if (rc) {
         return;
+    }
 
     rc = mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this,
                                                &mpAudioPolicy);
     ALOGE_IF(rc, "couldn't create audio policy (%s)", strerror(-rc));
-    if (rc)
+    if (rc) {
         return;
+    }
 
     rc = mpAudioPolicy->init_check(mpAudioPolicy);
     ALOGE_IF(rc, "couldn't init_check the audio policy (%s)", strerror(-rc));
-    if (rc)
+    if (rc) {
         return;
+    }
 
     ALOGI("Loaded audio policy from %s (%s)", module->name, module->id);
 
@@ -126,450 +130,14 @@
     }
     mInputs.clear();
 
-    if (mpAudioPolicy != NULL && mpAudioPolicyDev != NULL)
+    if (mpAudioPolicy != NULL && mpAudioPolicyDev != NULL) {
         mpAudioPolicyDev->destroy_audio_policy(mpAudioPolicyDev, mpAudioPolicy);
-    if (mpAudioPolicyDev != NULL)
+    }
+    if (mpAudioPolicyDev != NULL) {
         audio_policy_dev_close(mpAudioPolicyDev);
-}
-
-status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,
-                                                  audio_policy_dev_state_t state,
-                                                  const char *device_address)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    if (!settingsAllowed()) {
-        return PERMISSION_DENIED;
-    }
-    if (!audio_is_output_device(device) && !audio_is_input_device(device)) {
-        return BAD_VALUE;
-    }
-    if (state != AUDIO_POLICY_DEVICE_STATE_AVAILABLE &&
-            state != AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
-        return BAD_VALUE;
-    }
-
-    ALOGV("setDeviceConnectionState()");
-    Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->set_device_connection_state(mpAudioPolicy, device,
-                                                      state, device_address);
-}
-
-audio_policy_dev_state_t AudioPolicyService::getDeviceConnectionState(
-                                                              audio_devices_t device,
-                                                              const char *device_address)
-{
-    if (mpAudioPolicy == NULL) {
-        return AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE;
-    }
-    return mpAudioPolicy->get_device_connection_state(mpAudioPolicy, device,
-                                                      device_address);
-}
-
-status_t AudioPolicyService::setPhoneState(audio_mode_t state)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    if (!settingsAllowed()) {
-        return PERMISSION_DENIED;
-    }
-    if (uint32_t(state) >= AUDIO_MODE_CNT) {
-        return BAD_VALUE;
-    }
-
-    ALOGV("setPhoneState()");
-
-    // TODO: check if it is more appropriate to do it in platform specific policy manager
-    AudioSystem::setMode(state);
-
-    Mutex::Autolock _l(mLock);
-    mpAudioPolicy->set_phone_state(mpAudioPolicy, state);
-    return NO_ERROR;
-}
-
-status_t AudioPolicyService::setForceUse(audio_policy_force_use_t usage,
-                                         audio_policy_forced_cfg_t config)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    if (!settingsAllowed()) {
-        return PERMISSION_DENIED;
-    }
-    if (usage < 0 || usage >= AUDIO_POLICY_FORCE_USE_CNT) {
-        return BAD_VALUE;
-    }
-    if (config < 0 || config >= AUDIO_POLICY_FORCE_CFG_CNT) {
-        return BAD_VALUE;
-    }
-    ALOGV("setForceUse()");
-    Mutex::Autolock _l(mLock);
-    mpAudioPolicy->set_force_use(mpAudioPolicy, usage, config);
-    return NO_ERROR;
-}
-
-audio_policy_forced_cfg_t AudioPolicyService::getForceUse(audio_policy_force_use_t usage)
-{
-    if (mpAudioPolicy == NULL) {
-        return AUDIO_POLICY_FORCE_NONE;
-    }
-    if (usage < 0 || usage >= AUDIO_POLICY_FORCE_USE_CNT) {
-        return AUDIO_POLICY_FORCE_NONE;
-    }
-    return mpAudioPolicy->get_force_use(mpAudioPolicy, usage);
-}
-
-audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream,
-                                    uint32_t samplingRate,
-                                    audio_format_t format,
-                                    audio_channel_mask_t channelMask,
-                                    audio_output_flags_t flags,
-                                    const audio_offload_info_t *offloadInfo)
-{
-    if (mpAudioPolicy == NULL) {
-        return 0;
-    }
-    ALOGV("getOutput()");
-    Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->get_output(mpAudioPolicy, stream, samplingRate,
-                                    format, channelMask, flags, offloadInfo);
-}
-
-status_t AudioPolicyService::startOutput(audio_io_handle_t output,
-                                         audio_stream_type_t stream,
-                                         int session)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    ALOGV("startOutput()");
-    Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->start_output(mpAudioPolicy, output, stream, session);
-}
-
-status_t AudioPolicyService::stopOutput(audio_io_handle_t output,
-                                        audio_stream_type_t stream,
-                                        int session)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    ALOGV("stopOutput()");
-    mOutputCommandThread->stopOutputCommand(output, stream, session);
-    return NO_ERROR;
-}
-
-status_t  AudioPolicyService::doStopOutput(audio_io_handle_t output,
-                                      audio_stream_type_t stream,
-                                      int session)
-{
-    ALOGV("doStopOutput from tid %d", gettid());
-    Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->stop_output(mpAudioPolicy, output, stream, session);
-}
-
-void AudioPolicyService::releaseOutput(audio_io_handle_t output)
-{
-    if (mpAudioPolicy == NULL) {
-        return;
-    }
-    ALOGV("releaseOutput()");
-    mOutputCommandThread->releaseOutputCommand(output);
-}
-
-void AudioPolicyService::doReleaseOutput(audio_io_handle_t output)
-{
-    ALOGV("doReleaseOutput from tid %d", gettid());
-    Mutex::Autolock _l(mLock);
-    mpAudioPolicy->release_output(mpAudioPolicy, output);
-}
-
-audio_io_handle_t AudioPolicyService::getInput(audio_source_t inputSource,
-                                    uint32_t samplingRate,
-                                    audio_format_t format,
-                                    audio_channel_mask_t channelMask,
-                                    int audioSession)
-{
-    if (mpAudioPolicy == NULL) {
-        return 0;
-    }
-    // already checked by client, but double-check in case the client wrapper is bypassed
-    if (inputSource >= AUDIO_SOURCE_CNT && inputSource != AUDIO_SOURCE_HOTWORD) {
-        return 0;
-    }
-
-    if ((inputSource == AUDIO_SOURCE_HOTWORD) && !captureHotwordAllowed()) {
-        return 0;
-    }
-
-    Mutex::Autolock _l(mLock);
-    // the audio_in_acoustics_t parameter is ignored by get_input()
-    audio_io_handle_t input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate,
-                                                   format, channelMask, (audio_in_acoustics_t) 0);
-
-    if (input == 0) {
-        return input;
-    }
-    // create audio pre processors according to input source
-    audio_source_t aliasSource = (inputSource == AUDIO_SOURCE_HOTWORD) ?
-                                    AUDIO_SOURCE_VOICE_RECOGNITION : inputSource;
-
-    ssize_t index = mInputSources.indexOfKey(aliasSource);
-    if (index < 0) {
-        return input;
-    }
-    ssize_t idx = mInputs.indexOfKey(input);
-    InputDesc *inputDesc;
-    if (idx < 0) {
-        inputDesc = new InputDesc(audioSession);
-        mInputs.add(input, inputDesc);
-    } else {
-        inputDesc = mInputs.valueAt(idx);
-    }
-
-    Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
-    for (size_t i = 0; i < effects.size(); i++) {
-        EffectDesc *effect = effects[i];
-        sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0, audioSession, input);
-        status_t status = fx->initCheck();
-        if (status != NO_ERROR && status != ALREADY_EXISTS) {
-            ALOGW("Failed to create Fx %s on input %d", effect->mName, input);
-            // fx goes out of scope and strong ref on AudioEffect is released
-            continue;
-        }
-        for (size_t j = 0; j < effect->mParams.size(); j++) {
-            fx->setParameter(effect->mParams[j]);
-        }
-        inputDesc->mEffects.add(fx);
-    }
-    setPreProcessorEnabled(inputDesc, true);
-    return input;
-}
-
-status_t AudioPolicyService::startInput(audio_io_handle_t input)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    Mutex::Autolock _l(mLock);
-
-    return mpAudioPolicy->start_input(mpAudioPolicy, input);
-}
-
-status_t AudioPolicyService::stopInput(audio_io_handle_t input)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    Mutex::Autolock _l(mLock);
-
-    return mpAudioPolicy->stop_input(mpAudioPolicy, input);
-}
-
-void AudioPolicyService::releaseInput(audio_io_handle_t input)
-{
-    if (mpAudioPolicy == NULL) {
-        return;
-    }
-    Mutex::Autolock _l(mLock);
-    mpAudioPolicy->release_input(mpAudioPolicy, input);
-
-    ssize_t index = mInputs.indexOfKey(input);
-    if (index < 0) {
-        return;
-    }
-    InputDesc *inputDesc = mInputs.valueAt(index);
-    setPreProcessorEnabled(inputDesc, false);
-    delete inputDesc;
-    mInputs.removeItemsAt(index);
-}
-
-status_t AudioPolicyService::initStreamVolume(audio_stream_type_t stream,
-                                            int indexMin,
-                                            int indexMax)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    if (!settingsAllowed()) {
-        return PERMISSION_DENIED;
-    }
-    if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
-        return BAD_VALUE;
-    }
-    Mutex::Autolock _l(mLock);
-    mpAudioPolicy->init_stream_volume(mpAudioPolicy, stream, indexMin, indexMax);
-    return NO_ERROR;
-}
-
-status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream,
-                                                  int index,
-                                                  audio_devices_t device)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    if (!settingsAllowed()) {
-        return PERMISSION_DENIED;
-    }
-    if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
-        return BAD_VALUE;
-    }
-    Mutex::Autolock _l(mLock);
-    if (mpAudioPolicy->set_stream_volume_index_for_device) {
-        return mpAudioPolicy->set_stream_volume_index_for_device(mpAudioPolicy,
-                                                                stream,
-                                                                index,
-                                                                device);
-    } else {
-        return mpAudioPolicy->set_stream_volume_index(mpAudioPolicy, stream, index);
     }
 }
 
-status_t AudioPolicyService::getStreamVolumeIndex(audio_stream_type_t stream,
-                                                  int *index,
-                                                  audio_devices_t device)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
-        return BAD_VALUE;
-    }
-    Mutex::Autolock _l(mLock);
-    if (mpAudioPolicy->get_stream_volume_index_for_device) {
-        return mpAudioPolicy->get_stream_volume_index_for_device(mpAudioPolicy,
-                                                                stream,
-                                                                index,
-                                                                device);
-    } else {
-        return mpAudioPolicy->get_stream_volume_index(mpAudioPolicy, stream, index);
-    }
-}
-
-uint32_t AudioPolicyService::getStrategyForStream(audio_stream_type_t stream)
-{
-    if (mpAudioPolicy == NULL) {
-        return 0;
-    }
-    return mpAudioPolicy->get_strategy_for_stream(mpAudioPolicy, stream);
-}
-
-//audio policy: use audio_device_t appropriately
-
-audio_devices_t AudioPolicyService::getDevicesForStream(audio_stream_type_t stream)
-{
-    if (mpAudioPolicy == NULL) {
-        return (audio_devices_t)0;
-    }
-    return mpAudioPolicy->get_devices_for_stream(mpAudioPolicy, stream);
-}
-
-audio_io_handle_t AudioPolicyService::getOutputForEffect(const effect_descriptor_t *desc)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->get_output_for_effect(mpAudioPolicy, desc);
-}
-
-status_t AudioPolicyService::registerEffect(const effect_descriptor_t *desc,
-                                audio_io_handle_t io,
-                                uint32_t strategy,
-                                int session,
-                                int id)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    return mpAudioPolicy->register_effect(mpAudioPolicy, desc, io, strategy, session, id);
-}
-
-status_t AudioPolicyService::unregisterEffect(int id)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    return mpAudioPolicy->unregister_effect(mpAudioPolicy, id);
-}
-
-status_t AudioPolicyService::setEffectEnabled(int id, bool enabled)
-{
-    if (mpAudioPolicy == NULL) {
-        return NO_INIT;
-    }
-    return mpAudioPolicy->set_effect_enabled(mpAudioPolicy, id, enabled);
-}
-
-bool AudioPolicyService::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
-{
-    if (mpAudioPolicy == NULL) {
-        return 0;
-    }
-    Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->is_stream_active(mpAudioPolicy, stream, inPastMs);
-}
-
-bool AudioPolicyService::isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const
-{
-    if (mpAudioPolicy == NULL) {
-        return 0;
-    }
-    Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->is_stream_active_remotely(mpAudioPolicy, stream, inPastMs);
-}
-
-bool AudioPolicyService::isSourceActive(audio_source_t source) const
-{
-    if (mpAudioPolicy == NULL) {
-        return false;
-    }
-    if (mpAudioPolicy->is_source_active == 0) {
-        return false;
-    }
-    Mutex::Autolock _l(mLock);
-    return mpAudioPolicy->is_source_active(mpAudioPolicy, source);
-}
-
-status_t AudioPolicyService::queryDefaultPreProcessing(int audioSession,
-                                                       effect_descriptor_t *descriptors,
-                                                       uint32_t *count)
-{
-
-    if (mpAudioPolicy == NULL) {
-        *count = 0;
-        return NO_INIT;
-    }
-    Mutex::Autolock _l(mLock);
-    status_t status = NO_ERROR;
-
-    size_t index;
-    for (index = 0; index < mInputs.size(); index++) {
-        if (mInputs.valueAt(index)->mSessionId == audioSession) {
-            break;
-        }
-    }
-    if (index == mInputs.size()) {
-        *count = 0;
-        return BAD_VALUE;
-    }
-    Vector< sp<AudioEffect> > effects = mInputs.valueAt(index)->mEffects;
-
-    for (size_t i = 0; i < effects.size(); i++) {
-        effect_descriptor_t desc = effects[i]->descriptor();
-        if (i < *count) {
-            descriptors[i] = desc;
-        }
-    }
-    if (effects.size() > *count) {
-        status = NO_MEMORY;
-    }
-    *count = effects.size();
-    return status;
-}
 
 void AudioPolicyService::binderDied(const wp<IBinder>& who) {
     ALOGW("binderDied() %p, calling pid %d", who.unsafe_get(),
@@ -606,7 +174,7 @@
     return NO_ERROR;
 }
 
-status_t AudioPolicyService::dump(int fd, const Vector<String16>& args)
+status_t AudioPolicyService::dump(int fd, const Vector<String16>& args __unused)
 {
     if (!dumpAllowed()) {
         dumpPermissionDenial(fd);
@@ -1114,11 +682,13 @@
 int AudioPolicyService::startTone(audio_policy_tone_t tone,
                                   audio_stream_type_t stream)
 {
-    if (tone != AUDIO_POLICY_TONE_IN_CALL_NOTIFICATION)
+    if (tone != AUDIO_POLICY_TONE_IN_CALL_NOTIFICATION) {
         ALOGE("startTone: illegal tone requested (%d)", tone);
-    if (stream != AUDIO_STREAM_VOICE_CALL)
+    }
+    if (stream != AUDIO_STREAM_VOICE_CALL) {
         ALOGE("startTone: illegal stream (%d) requested for tone %d", stream,
             tone);
+    }
     mTonePlaybackThread->startToneCommand(ToneGenerator::TONE_SUP_CALL_WAITING,
                                           AUDIO_STREAM_VOICE_CALL);
     return 0;
@@ -1135,21 +705,6 @@
     return (int)mAudioCommandThread->voiceVolumeCommand(volume, delayMs);
 }
 
-bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info)
-{
-    if (mpAudioPolicy == NULL) {
-        ALOGV("mpAudioPolicy == NULL");
-        return false;
-    }
-
-    if (mpAudioPolicy->is_offload_supported == NULL) {
-        ALOGV("HAL does not implement is_offload_supported");
-        return false;
-    }
-
-    return mpAudioPolicy->is_offload_supported(mpAudioPolicy, &info);
-}
-
 // ----------------------------------------------------------------------------
 // Audio pre-processing configuration
 // ----------------------------------------------------------------------------
@@ -1448,42 +1003,18 @@
     return NO_ERROR;
 }
 
-/* implementation of the interface to the policy manager */
 extern "C" {
-
-
-static audio_module_handle_t aps_load_hw_module(void *service,
-                                             const char *name)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        ALOGW("%s: could not get AudioFlinger", __func__);
-        return 0;
-    }
-
-    return af->loadHwModule(name);
-}
-
-// deprecated: replaced by aps_open_output_on_module()
-static audio_io_handle_t aps_open_output(void *service,
+audio_module_handle_t aps_load_hw_module(void *service __unused,
+                                             const char *name);
+audio_io_handle_t aps_open_output(void *service __unused,
                                          audio_devices_t *pDevices,
                                          uint32_t *pSamplingRate,
                                          audio_format_t *pFormat,
                                          audio_channel_mask_t *pChannelMask,
                                          uint32_t *pLatencyMs,
-                                         audio_output_flags_t flags)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        ALOGW("%s: could not get AudioFlinger", __func__);
-        return 0;
-    }
+                                         audio_output_flags_t flags);
 
-    return af->openOutput((audio_module_handle_t)0, pDevices, pSamplingRate, pFormat, pChannelMask,
-                          pLatencyMs, flags);
-}
-
-static audio_io_handle_t aps_open_output_on_module(void *service,
+audio_io_handle_t aps_open_output_on_module(void *service __unused,
                                                    audio_module_handle_t module,
                                                    audio_devices_t *pDevices,
                                                    uint32_t *pSamplingRate,
@@ -1491,192 +1022,63 @@
                                                    audio_channel_mask_t *pChannelMask,
                                                    uint32_t *pLatencyMs,
                                                    audio_output_flags_t flags,
-                                                   const audio_offload_info_t *offloadInfo)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        ALOGW("%s: could not get AudioFlinger", __func__);
-        return 0;
-    }
-    return af->openOutput(module, pDevices, pSamplingRate, pFormat, pChannelMask,
-                          pLatencyMs, flags, offloadInfo);
-}
-
-static audio_io_handle_t aps_open_dup_output(void *service,
+                                                   const audio_offload_info_t *offloadInfo);
+audio_io_handle_t aps_open_dup_output(void *service __unused,
                                                  audio_io_handle_t output1,
-                                                 audio_io_handle_t output2)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        ALOGW("%s: could not get AudioFlinger", __func__);
-        return 0;
-    }
-    return af->openDuplicateOutput(output1, output2);
-}
-
-static int aps_close_output(void *service, audio_io_handle_t output)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0)
-        return PERMISSION_DENIED;
-
-    return af->closeOutput(output);
-}
-
-static int aps_suspend_output(void *service, audio_io_handle_t output)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        ALOGW("%s: could not get AudioFlinger", __func__);
-        return PERMISSION_DENIED;
-    }
-
-    return af->suspendOutput(output);
-}
-
-static int aps_restore_output(void *service, audio_io_handle_t output)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        ALOGW("%s: could not get AudioFlinger", __func__);
-        return PERMISSION_DENIED;
-    }
-
-    return af->restoreOutput(output);
-}
-
-// deprecated: replaced by aps_open_input_on_module(), and acoustics parameter is ignored
-static audio_io_handle_t aps_open_input(void *service,
+                                                 audio_io_handle_t output2);
+int aps_close_output(void *service __unused, audio_io_handle_t output);
+int aps_suspend_output(void *service __unused, audio_io_handle_t output);
+int aps_restore_output(void *service __unused, audio_io_handle_t output);
+audio_io_handle_t aps_open_input(void *service __unused,
                                         audio_devices_t *pDevices,
                                         uint32_t *pSamplingRate,
                                         audio_format_t *pFormat,
                                         audio_channel_mask_t *pChannelMask,
-                                        audio_in_acoustics_t acoustics)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        ALOGW("%s: could not get AudioFlinger", __func__);
-        return 0;
-    }
-
-    return af->openInput((audio_module_handle_t)0, pDevices, pSamplingRate, pFormat, pChannelMask);
-}
-
-static audio_io_handle_t aps_open_input_on_module(void *service,
+                                        audio_in_acoustics_t acoustics __unused);
+audio_io_handle_t aps_open_input_on_module(void *service __unused,
                                                   audio_module_handle_t module,
                                                   audio_devices_t *pDevices,
                                                   uint32_t *pSamplingRate,
                                                   audio_format_t *pFormat,
-                                                  audio_channel_mask_t *pChannelMask)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0) {
-        ALOGW("%s: could not get AudioFlinger", __func__);
-        return 0;
-    }
-
-    return af->openInput(module, pDevices, pSamplingRate, pFormat, pChannelMask);
-}
-
-static int aps_close_input(void *service, audio_io_handle_t input)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0)
-        return PERMISSION_DENIED;
-
-    return af->closeInput(input);
-}
-
-static int aps_set_stream_output(void *service, audio_stream_type_t stream,
-                                     audio_io_handle_t output)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0)
-        return PERMISSION_DENIED;
-
-    return af->setStreamOutput(stream, output);
-}
-
-static int aps_move_effects(void *service, int session,
+                                                  audio_channel_mask_t *pChannelMask);
+int aps_close_input(void *service __unused, audio_io_handle_t input);
+int aps_invalidate_stream(void *service __unused, audio_stream_type_t stream);
+int aps_move_effects(void *service __unused, int session,
                                 audio_io_handle_t src_output,
-                                audio_io_handle_t dst_output)
-{
-    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
-    if (af == 0)
-        return PERMISSION_DENIED;
-
-    return af->moveEffects(session, src_output, dst_output);
-}
-
-static char * aps_get_parameters(void *service, audio_io_handle_t io_handle,
-                                     const char *keys)
-{
-    String8 result = AudioSystem::getParameters(io_handle, String8(keys));
-    return strdup(result.string());
-}
-
-static void aps_set_parameters(void *service, audio_io_handle_t io_handle,
-                                   const char *kv_pairs, int delay_ms)
-{
-    AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
-
-    audioPolicyService->setParameters(io_handle, kv_pairs, delay_ms);
-}
-
-static int aps_set_stream_volume(void *service, audio_stream_type_t stream,
+                                audio_io_handle_t dst_output);
+char * aps_get_parameters(void *service __unused, audio_io_handle_t io_handle,
+                                     const char *keys);
+void aps_set_parameters(void *service, audio_io_handle_t io_handle,
+                                   const char *kv_pairs, int delay_ms);
+int aps_set_stream_volume(void *service, audio_stream_type_t stream,
                                      float volume, audio_io_handle_t output,
-                                     int delay_ms)
-{
-    AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
-
-    return audioPolicyService->setStreamVolume(stream, volume, output,
-                                               delay_ms);
-}
-
-static int aps_start_tone(void *service, audio_policy_tone_t tone,
-                              audio_stream_type_t stream)
-{
-    AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
-
-    return audioPolicyService->startTone(tone, stream);
-}
-
-static int aps_stop_tone(void *service)
-{
-    AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
-
-    return audioPolicyService->stopTone();
-}
-
-static int aps_set_voice_volume(void *service, float volume, int delay_ms)
-{
-    AudioPolicyService *audioPolicyService = (AudioPolicyService *)service;
-
-    return audioPolicyService->setVoiceVolume(volume, delay_ms);
-}
-
-}; // extern "C"
+                                     int delay_ms);
+int aps_start_tone(void *service, audio_policy_tone_t tone,
+                              audio_stream_type_t stream);
+int aps_stop_tone(void *service);
+int aps_set_voice_volume(void *service, float volume, int delay_ms);
+};
 
 namespace {
     struct audio_policy_service_ops aps_ops = {
-        open_output           : aps_open_output,
-        open_duplicate_output : aps_open_dup_output,
-        close_output          : aps_close_output,
-        suspend_output        : aps_suspend_output,
-        restore_output        : aps_restore_output,
-        open_input            : aps_open_input,
-        close_input           : aps_close_input,
-        set_stream_volume     : aps_set_stream_volume,
-        set_stream_output     : aps_set_stream_output,
-        set_parameters        : aps_set_parameters,
-        get_parameters        : aps_get_parameters,
-        start_tone            : aps_start_tone,
-        stop_tone             : aps_stop_tone,
-        set_voice_volume      : aps_set_voice_volume,
-        move_effects          : aps_move_effects,
-        load_hw_module        : aps_load_hw_module,
-        open_output_on_module : aps_open_output_on_module,
-        open_input_on_module  : aps_open_input_on_module,
+        .open_output           = aps_open_output,
+        .open_duplicate_output = aps_open_dup_output,
+        .close_output          = aps_close_output,
+        .suspend_output        = aps_suspend_output,
+        .restore_output        = aps_restore_output,
+        .open_input            = aps_open_input,
+        .close_input           = aps_close_input,
+        .set_stream_volume     = aps_set_stream_volume,
+        .invalidate_stream     = aps_invalidate_stream,
+        .set_parameters        = aps_set_parameters,
+        .get_parameters        = aps_get_parameters,
+        .start_tone            = aps_start_tone,
+        .stop_tone             = aps_stop_tone,
+        .set_voice_volume      = aps_set_voice_volume,
+        .move_effects          = aps_move_effects,
+        .load_hw_module        = aps_load_hw_module,
+        .open_output_on_module = aps_open_output_on_module,
+        .open_input_on_module  = aps_open_input_on_module,
     };
 }; // namespace <unnamed>
 
diff --git a/services/audioflinger/AudioPolicyService.h b/services/audiopolicy/AudioPolicyService.h
similarity index 100%
rename from services/audioflinger/AudioPolicyService.h
rename to services/audiopolicy/AudioPolicyService.h
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 4352b17..4e2272d 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -1,3 +1,17 @@
+# Copyright 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
 LOCAL_PATH:= $(call my-dir)
 
 #
@@ -53,6 +67,7 @@
 
 LOCAL_C_INCLUDES += \
     system/media/camera/include \
+    system/media/private/camera/include \
     external/jpeg
 
 
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index f512db2..b83c315 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1,24 +1,24 @@
 /*
-**
-** Copyright (C) 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.
-*/
+ * Copyright (C) 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 "CameraService"
 //#define LOG_NDEBUG 0
 
 #include <stdio.h>
+#include <string.h>
 #include <sys/types.h>
 #include <pthread.h>
 
@@ -32,10 +32,13 @@
 #include <gui/Surface.h>
 #include <hardware/hardware.h>
 #include <media/AudioSystem.h>
+#include <media/IMediaHTTPService.h>
 #include <media/mediaplayer.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <utils/String16.h>
+#include <utils/Trace.h>
+#include <system/camera_vendor_tags.h>
 
 #include "CameraService.h"
 #include "api1/CameraClient.h"
@@ -130,6 +133,12 @@
             mModule->set_callbacks(this);
         }
 
+        VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+
+        if (mModule->common.module_api_version >= CAMERA_MODULE_API_VERSION_2_2) {
+            setUpVendorTags();
+        }
+
         CameraDeviceFactory::registerService(this);
     }
 }
@@ -141,6 +150,7 @@
         }
     }
 
+    VendorTagDescriptor::clearGlobalVendorTagDescriptor();
     gCameraService = NULL;
 }
 
@@ -269,6 +279,22 @@
     return ret;
 }
 
+status_t CameraService::getCameraVendorTagDescriptor(/*out*/sp<VendorTagDescriptor>& desc) {
+    if (!mModule) {
+        ALOGE("%s: camera hardware module doesn't exist", __FUNCTION__);
+        return -ENODEV;
+    }
+
+    if (mModule->common.module_api_version < CAMERA_MODULE_API_VERSION_2_2) {
+        // TODO: Remove this check once HAL1 shim is in place.
+        ALOGW("%s: Only HAL module version V2.2 or higher supports vendor tags", __FUNCTION__);
+        return -EOPNOTSUPP;
+    }
+
+    desc = VendorTagDescriptor::getGlobalVendorTagDescriptor();
+    return OK;
+}
+
 int CameraService::getDeviceVersion(int cameraId, int* facing) {
     struct camera_info info;
     if (mModule->get_camera_info(cameraId, &info) != OK) {
@@ -306,6 +332,44 @@
     return false;
 }
 
+bool CameraService::setUpVendorTags() {
+    vendor_tag_ops_t vOps = vendor_tag_ops_t();
+
+    // Check if vendor operations have been implemented
+    if (mModule->get_vendor_tag_ops == NULL) {
+        ALOGI("%s: No vendor tags defined for this device.", __FUNCTION__);
+        return false;
+    }
+
+    ATRACE_BEGIN("camera3->get_metadata_vendor_tag_ops");
+    mModule->get_vendor_tag_ops(&vOps);
+    ATRACE_END();
+
+    // Ensure all vendor operations are present
+    if (vOps.get_tag_count == NULL || vOps.get_all_tags == NULL ||
+            vOps.get_section_name == NULL || vOps.get_tag_name == NULL ||
+            vOps.get_tag_type == NULL) {
+        ALOGE("%s: Vendor tag operations not fully defined. Ignoring definitions."
+               , __FUNCTION__);
+        return false;
+    }
+
+    // Read all vendor tag definitions into a descriptor
+    sp<VendorTagDescriptor> desc;
+    status_t res;
+    if ((res = VendorTagDescriptor::createDescriptorFromOps(&vOps, /*out*/desc))
+            != OK) {
+        ALOGE("%s: Could not generate descriptor from vendor tag operations,"
+              "received error %s (%d). Camera clients will not be able to use"
+              "vendor tags", __FUNCTION__, strerror(res), res);
+        return false;
+    }
+
+    // Set the global descriptor to use with camera metadata
+    VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
+    return true;
+}
+
 status_t CameraService::validateConnect(int cameraId,
                                     /*inout*/
                                     int& clientUid) const {
@@ -876,7 +940,7 @@
 
 MediaPlayer* CameraService::newMediaPlayer(const char *file) {
     MediaPlayer* mp = new MediaPlayer();
-    if (mp->setDataSource(file, NULL) == NO_ERROR) {
+    if (mp->setDataSource(NULL /* httpService */, file, NULL) == NO_ERROR) {
         mp->setAudioStreamType(AUDIO_STREAM_ENFORCED_AUDIBLE);
         mp->prepare();
     } else {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index ad6a582..8853e48 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -1,19 +1,18 @@
 /*
-**
-** Copyright (C) 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.
-*/
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 #ifndef ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
 #define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
@@ -31,6 +30,7 @@
 #include <camera/IProCameraCallbacks.h>
 #include <camera/camera2/ICameraDeviceUser.h>
 #include <camera/camera2/ICameraDeviceCallbacks.h>
+#include <camera/VendorTagDescriptor.h>
 
 #include <camera/ICameraServiceListener.h>
 
@@ -73,6 +73,7 @@
                                       struct CameraInfo* cameraInfo);
     virtual status_t    getCameraCharacteristics(int cameraId,
                                                  CameraMetadata* cameraInfo);
+    virtual status_t    getCameraVendorTagDescriptor(/*out*/ sp<VendorTagDescriptor>& desc);
 
     virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
             const String16& clientPackageName, int clientUid,
@@ -387,6 +388,8 @@
     // Helpers
 
     bool                isValidCameraId(int cameraId);
+
+    bool                setUpVendorTags();
 };
 
 } // namespace android
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index af23557..80b7cd4 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -238,7 +238,7 @@
 
     result.append("    Scene mode: ");
     switch (p.sceneMode) {
-        case ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED:
+        case ANDROID_CONTROL_SCENE_MODE_DISABLED:
             result.append("AUTO\n"); break;
         CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_ACTION)
         CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_PORTRAIT)
@@ -816,6 +816,8 @@
             return res;
         }
         outputStreams.push(getZslStreamId());
+    } else {
+        mZslProcessor->deleteStream();
     }
 
     outputStreams.push(getPreviewStreamId());
@@ -1162,7 +1164,7 @@
          * Handle quirk mode for AF in scene modes
          */
         if (l.mParameters.quirks.triggerAfWithAuto &&
-                l.mParameters.sceneMode != ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED &&
+                l.mParameters.sceneMode != ANDROID_CONTROL_SCENE_MODE_DISABLED &&
                 l.mParameters.focusMode != Parameters::FOCUS_MODE_AUTO &&
                 !l.mParameters.focusingAreas[0].isEmpty()) {
             ALOGV("%s: Quirk: Switching from focusMode %d to AUTO",
diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
index d2ac79c..c266213 100644
--- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
@@ -110,11 +110,13 @@
     if (!mCallbackToApp && mCallbackConsumer == 0) {
         // Create CPU buffer queue endpoint, since app hasn't given us one
         // Make it async to avoid disconnect deadlocks
-        sp<BufferQueue> bq = new BufferQueue();
-        mCallbackConsumer = new CpuConsumer(bq, kCallbackHeapCount);
+        sp<IGraphicBufferProducer> producer;
+        sp<IGraphicBufferConsumer> consumer;
+        BufferQueue::createBufferQueue(&producer, &consumer);
+        mCallbackConsumer = new CpuConsumer(consumer, kCallbackHeapCount);
         mCallbackConsumer->setFrameAvailableListener(this);
         mCallbackConsumer->setName(String8("Camera2Client::CallbackConsumer"));
-        mCallbackWindow = new Surface(bq);
+        mCallbackWindow = new Surface(producer);
     }
 
     if (mCallbackStreamId != NO_STREAM) {
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index ec81456..fb8bd27 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -83,11 +83,13 @@
 
     if (mCaptureConsumer == 0) {
         // Create CPU buffer queue endpoint
-        sp<BufferQueue> bq = new BufferQueue();
-        mCaptureConsumer = new CpuConsumer(bq, 1);
+        sp<IGraphicBufferProducer> producer;
+        sp<IGraphicBufferConsumer> consumer;
+        BufferQueue::createBufferQueue(&producer, &consumer);
+        mCaptureConsumer = new CpuConsumer(consumer, 1);
         mCaptureConsumer->setFrameAvailableListener(this);
         mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer"));
-        mCaptureWindow = new Surface(bq);
+        mCaptureWindow = new Surface(producer);
         // Create memory for API consumption
         mCaptureHeap = new MemoryHeapBase(maxJpegSize.data.i32[0], 0,
                                        "Camera2Client::CaptureHeap");
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 5196e09..2cf0d29 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -466,7 +466,7 @@
                 supportedAntibanding);
     }
 
-    sceneMode = ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED;
+    sceneMode = ANDROID_CONTROL_SCENE_MODE_DISABLED;
     params.set(CameraParameters::KEY_SCENE_MODE,
             CameraParameters::SCENE_MODE_AUTO);
 
@@ -482,7 +482,7 @@
             if (addComma) supportedSceneModes += ",";
             addComma = true;
             switch (availableSceneModes.data.u8[i]) {
-                case ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED:
+                case ANDROID_CONTROL_SCENE_MODE_DISABLED:
                     noSceneModes = true;
                     break;
                 case ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY:
@@ -664,13 +664,13 @@
     focusState = ANDROID_CONTROL_AF_STATE_INACTIVE;
     shadowFocusMode = FOCUS_MODE_INVALID;
 
-    camera_metadata_ro_entry_t max3aRegions =
-        staticInfo(ANDROID_CONTROL_MAX_REGIONS, 1, 1);
-    if (!max3aRegions.count) return NO_INIT;
+    camera_metadata_ro_entry_t max3aRegions = staticInfo(ANDROID_CONTROL_MAX_REGIONS,
+            Parameters::NUM_REGION, Parameters::NUM_REGION);
+    if (max3aRegions.count != Parameters::NUM_REGION) return NO_INIT;
 
     int32_t maxNumFocusAreas = 0;
     if (focusMode != Parameters::FOCUS_MODE_FIXED) {
-        maxNumFocusAreas = max3aRegions.data.i32[0];
+        maxNumFocusAreas = max3aRegions.data.i32[Parameters::REGION_AF];
     }
     params.set(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS, maxNumFocusAreas);
     params.set(CameraParameters::KEY_FOCUS_AREAS,
@@ -730,7 +730,7 @@
 
     meteringAreas.add(Parameters::Area(0, 0, 0, 0, 0));
     params.set(CameraParameters::KEY_MAX_NUM_METERING_AREAS,
-            max3aRegions.data.i32[0]);
+            max3aRegions.data.i32[Parameters::REGION_AE]);
     params.set(CameraParameters::KEY_METERING_AREAS,
             "(0,0,0,0,0)");
 
@@ -1446,7 +1446,7 @@
         newParams.get(CameraParameters::KEY_SCENE_MODE) );
     if (validatedParams.sceneMode != sceneMode &&
             validatedParams.sceneMode !=
-            ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED) {
+            ANDROID_CONTROL_SCENE_MODE_DISABLED) {
         camera_metadata_ro_entry_t availableSceneModes =
             staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
         for (i = 0; i < availableSceneModes.count; i++) {
@@ -1461,7 +1461,7 @@
         }
     }
     bool sceneModeSet =
-            validatedParams.sceneMode != ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED;
+            validatedParams.sceneMode != ANDROID_CONTROL_SCENE_MODE_DISABLED;
 
     // FLASH_MODE
     if (sceneModeSet) {
@@ -1591,10 +1591,11 @@
     // FOCUS_AREAS
     res = parseAreas(newParams.get(CameraParameters::KEY_FOCUS_AREAS),
             &validatedParams.focusingAreas);
-    size_t max3aRegions =
-        (size_t)staticInfo(ANDROID_CONTROL_MAX_REGIONS, 1, 1).data.i32[0];
+    size_t maxAfRegions = (size_t)staticInfo(ANDROID_CONTROL_MAX_REGIONS,
+              Parameters::NUM_REGION, Parameters::NUM_REGION).
+              data.i32[Parameters::REGION_AF];
     if (res == OK) res = validateAreas(validatedParams.focusingAreas,
-            max3aRegions, AREA_KIND_FOCUS);
+            maxAfRegions, AREA_KIND_FOCUS);
     if (res != OK) {
         ALOGE("%s: Requested focus areas are malformed: %s",
                 __FUNCTION__, newParams.get(CameraParameters::KEY_FOCUS_AREAS));
@@ -1624,10 +1625,13 @@
         newParams.get(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK));
 
     // METERING_AREAS
+    size_t maxAeRegions = (size_t)staticInfo(ANDROID_CONTROL_MAX_REGIONS,
+            Parameters::NUM_REGION, Parameters::NUM_REGION).
+            data.i32[Parameters::REGION_AE];
     res = parseAreas(newParams.get(CameraParameters::KEY_METERING_AREAS),
             &validatedParams.meteringAreas);
     if (res == OK) {
-        res = validateAreas(validatedParams.meteringAreas, max3aRegions,
+        res = validateAreas(validatedParams.meteringAreas, maxAeRegions,
                             AREA_KIND_METERING);
     }
     if (res != OK) {
@@ -1776,7 +1780,7 @@
     // (face detection statistics and face priority scene mode). Map from other
     // to the other.
     bool sceneModeActive =
-            sceneMode != (uint8_t)ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED;
+            sceneMode != (uint8_t)ANDROID_CONTROL_SCENE_MODE_DISABLED;
     uint8_t reqControlMode = ANDROID_CONTROL_MODE_AUTO;
     if (enableFaceDetect || sceneModeActive) {
         reqControlMode = ANDROID_CONTROL_MODE_USE_SCENE_MODE;
@@ -1788,7 +1792,7 @@
     uint8_t reqSceneMode =
             sceneModeActive ? sceneMode :
             enableFaceDetect ? (uint8_t)ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY :
-            (uint8_t)ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED;
+            (uint8_t)ANDROID_CONTROL_SCENE_MODE_DISABLED;
     res = request->update(ANDROID_CONTROL_SCENE_MODE,
             &reqSceneMode, 1);
     if (res != OK) return res;
@@ -1909,6 +1913,23 @@
             reqMeteringAreas, reqMeteringAreasSize);
     if (res != OK) return res;
 
+    // Set awb regions to be the same as the metering regions if allowed
+    size_t maxAwbRegions = (size_t)staticInfo(ANDROID_CONTROL_MAX_REGIONS,
+            Parameters::NUM_REGION, Parameters::NUM_REGION).
+            data.i32[Parameters::REGION_AWB];
+    if (maxAwbRegions > 0) {
+        if (maxAwbRegions >= meteringAreas.size()) {
+            res = request->update(ANDROID_CONTROL_AWB_REGIONS,
+                    reqMeteringAreas, reqMeteringAreasSize);
+        } else {
+            // Ensure the awb regions are zeroed if the region count is too high.
+            int32_t zeroedAwbAreas[5] = {0, 0, 0, 0, 0};
+            res = request->update(ANDROID_CONTROL_AWB_REGIONS,
+                    zeroedAwbAreas, sizeof(zeroedAwbAreas)/sizeof(int32_t));
+        }
+        if (res != OK) return res;
+    }
+
     delete[] reqMeteringAreas;
 
     /* don't include jpeg thumbnail size - it's valid for
@@ -2149,9 +2170,9 @@
 int Parameters::sceneModeStringToEnum(const char *sceneMode) {
     return
         !sceneMode ?
-            ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED :
+            ANDROID_CONTROL_SCENE_MODE_DISABLED :
         !strcmp(sceneMode, CameraParameters::SCENE_MODE_AUTO) ?
-            ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED :
+            ANDROID_CONTROL_SCENE_MODE_DISABLED :
         !strcmp(sceneMode, CameraParameters::SCENE_MODE_ACTION) ?
             ANDROID_CONTROL_SCENE_MODE_ACTION :
         !strcmp(sceneMode, CameraParameters::SCENE_MODE_PORTRAIT) ?
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 32dbd42..60c4687 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -113,6 +113,14 @@
     bool autoExposureLock;
     bool autoWhiteBalanceLock;
 
+    // 3A region types, for use with ANDROID_CONTROL_MAX_REGIONS
+    enum region_t {
+        REGION_AE = 0,
+        REGION_AWB,
+        REGION_AF,
+        NUM_REGION // Number of region types
+    } region;
+
     Vector<Area> meteringAreas;
 
     int zoom;
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index 6076dae..1844ea3 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -319,13 +319,15 @@
         // Create CPU buffer queue endpoint. We need one more buffer here so that we can
         // always acquire and free a buffer when the heap is full; otherwise the consumer
         // will have buffers in flight we'll never clear out.
-        sp<BufferQueue> bq = new BufferQueue();
-        mRecordingConsumer = new BufferItemConsumer(bq,
+        sp<IGraphicBufferProducer> producer;
+        sp<IGraphicBufferConsumer> consumer;
+        BufferQueue::createBufferQueue(&producer, &consumer);
+        mRecordingConsumer = new BufferItemConsumer(consumer,
                 GRALLOC_USAGE_HW_VIDEO_ENCODER,
                 mRecordingHeapCount + 1);
         mRecordingConsumer->setFrameAvailableListener(this);
         mRecordingConsumer->setName(String8("Camera2-RecordingConsumer"));
-        mRecordingWindow = new Surface(bq);
+        mRecordingWindow = new Surface(producer);
         newConsumer = true;
         // Allocate memory later, since we don't know buffer size until receipt
     }
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 453d54c..07381ae 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -128,13 +128,15 @@
 
     if (mZslConsumer == 0) {
         // Create CPU buffer queue endpoint
-        sp<BufferQueue> bq = new BufferQueue();
-        mZslConsumer = new BufferItemConsumer(bq,
+        sp<IGraphicBufferProducer> producer;
+        sp<IGraphicBufferConsumer> consumer;
+        BufferQueue::createBufferQueue(&producer, &consumer);
+        mZslConsumer = new BufferItemConsumer(consumer,
             GRALLOC_USAGE_HW_CAMERA_ZSL,
             kZslBufferDepth);
         mZslConsumer->setFrameAvailableListener(this);
         mZslConsumer->setName(String8("Camera2Client::ZslConsumer"));
-        mZslWindow = new Surface(bq);
+        mZslWindow = new Surface(producer);
     }
 
     if (mZslStreamId != NO_STREAM) {
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
index 6b4e57a..c1d0496 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
@@ -273,6 +273,15 @@
             return INVALID_OPERATION;
         }
 
+        // Flush device to clear out all in-flight requests pending in HAL.
+        res = client->getCameraDevice()->flush();
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Failed to flush device: "
+                "%s (%d)",
+                __FUNCTION__, client->getCameraId(), strerror(-res), res);
+            return res;
+        }
+
         // Update JPEG settings
         {
             SharedParameters::Lock l(client->getParameters());
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 1cdf8dc..187220e 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -635,26 +635,56 @@
         return INVALID_OPERATION;
     }
 
+    camera_metadata_ro_entry_t entryFacing = staticInfo.find(ANDROID_LENS_FACING);
+    if (entry.count == 0) {
+        ALOGE("%s: Camera %d: Can't find android.lens.facing in "
+                "static metadata!", __FUNCTION__, mCameraId);
+        return INVALID_OPERATION;
+    }
+
     int32_t& flags = *transform;
 
+    bool mirror = (entryFacing.data.u8[0] == ANDROID_LENS_FACING_FRONT);
     int orientation = entry.data.i32[0];
-    switch (orientation) {
-        case 0:
-            flags = 0;
-            break;
-        case 90:
-            flags = NATIVE_WINDOW_TRANSFORM_ROT_90;
-            break;
-        case 180:
-            flags = NATIVE_WINDOW_TRANSFORM_ROT_180;
-            break;
-        case 270:
-            flags = NATIVE_WINDOW_TRANSFORM_ROT_270;
-            break;
-        default:
-            ALOGE("%s: Invalid HAL android.sensor.orientation value: %d",
-                  __FUNCTION__, orientation);
-            return INVALID_OPERATION;
+    if (!mirror) {
+        switch (orientation) {
+            case 0:
+                flags = 0;
+                break;
+            case 90:
+                flags = NATIVE_WINDOW_TRANSFORM_ROT_90;
+                break;
+            case 180:
+                flags = NATIVE_WINDOW_TRANSFORM_ROT_180;
+                break;
+            case 270:
+                flags = NATIVE_WINDOW_TRANSFORM_ROT_270;
+                break;
+            default:
+                ALOGE("%s: Invalid HAL android.sensor.orientation value: %d",
+                      __FUNCTION__, orientation);
+                return INVALID_OPERATION;
+        }
+    } else {
+        switch (orientation) {
+            case 0:
+                flags = HAL_TRANSFORM_FLIP_H;
+                break;
+            case 90:
+                flags = HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90;
+                break;
+            case 180:
+                flags = HAL_TRANSFORM_FLIP_V;
+                break;
+            case 270:
+                flags = HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
+                break;
+            default:
+                ALOGE("%s: Invalid HAL android.sensor.orientation value: %d",
+                      __FUNCTION__, orientation);
+                return INVALID_OPERATION;
+        }
+
     }
 
     /**
diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp
index dc97c47..f60ca98 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.cpp
+++ b/services/camera/libcameraservice/device2/Camera2Device.cpp
@@ -112,20 +112,6 @@
         return res;
     }
 
-    res = device->ops->get_metadata_vendor_tag_ops(device, &mVendorTagOps);
-    if (res != OK ) {
-        ALOGE("%s: Camera %d: Unable to retrieve tag ops from device: %s (%d)",
-                __FUNCTION__, mId, strerror(-res), res);
-        device->common.close(&device->common);
-        return res;
-    }
-    res = set_camera_metadata_vendor_tag_ops(mVendorTagOps);
-    if (res != OK) {
-        ALOGE("%s: Camera %d: Unable to set tag ops: %s (%d)",
-            __FUNCTION__, mId, strerror(-res), res);
-        device->common.close(&device->common);
-        return res;
-    }
     res = device->ops->set_notify_callback(device, notificationCallback,
             NULL);
     if (res != OK) {
diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h
index 1f53c56..5b91f88 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.h
+++ b/services/camera/libcameraservice/device2/Camera2Device.h
@@ -78,7 +78,6 @@
     camera2_device_t *mHal2Device;
 
     CameraMetadata mDeviceInfo;
-    vendor_tag_query_ops_t *mVendorTagOps;
 
     /**
      * Queue class for both sending requests to a camera2 device, and for
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 3dbc1b0..08e03ce 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -100,8 +100,10 @@
 
     camera3_device_t *device;
 
+    ATRACE_BEGIN("camera3->open");
     res = module->common.methods->open(&module->common, deviceName.string(),
             reinterpret_cast<hw_device_t**>(&device));
+    ATRACE_END();
 
     if (res != OK) {
         SET_ERR_L("Could not open camera: %s (%d)", strerror(-res), res);
@@ -144,24 +146,6 @@
         return BAD_VALUE;
     }
 
-    /** Get vendor metadata tags */
-
-    mVendorTagOps.get_camera_vendor_section_name = NULL;
-
-    ATRACE_BEGIN("camera3->get_metadata_vendor_tag_ops");
-    device->ops->get_metadata_vendor_tag_ops(device, &mVendorTagOps);
-    ATRACE_END();
-
-    if (mVendorTagOps.get_camera_vendor_section_name != NULL) {
-        res = set_camera_metadata_vendor_tag_ops(&mVendorTagOps);
-        if (res != OK) {
-            SET_ERR_L("Unable to set tag ops: %s (%d)",
-                    strerror(-res), res);
-            device->common.close(&device->common);
-            return res;
-        }
-    }
-
     /** Start up status tracker thread */
     mStatusTracker = new StatusTracker(this);
     res = mStatusTracker->run(String8::format("C3Dev-%d-Status", mId).string());
@@ -269,7 +253,9 @@
         mStatusTracker.clear();
 
         if (mHal3Device != NULL) {
+            ATRACE_BEGIN("camera3->close");
             mHal3Device->common.close(&mHal3Device->common);
+            ATRACE_END();
             mHal3Device = NULL;
         }
 
@@ -836,16 +822,20 @@
     }
 
     sp<Camera3StreamInterface> deletedStream;
+    ssize_t outputStreamIdx = mOutputStreams.indexOfKey(id);
     if (mInputStream != NULL && id == mInputStream->getId()) {
         deletedStream = mInputStream;
         mInputStream.clear();
     } else {
-        ssize_t idx = mOutputStreams.indexOfKey(id);
-        if (idx == NAME_NOT_FOUND) {
+        if (outputStreamIdx == NAME_NOT_FOUND) {
             CLOGE("Stream %d does not exist", id);
             return BAD_VALUE;
         }
-        deletedStream = mOutputStreams.editValueAt(idx);
+    }
+
+    // Delete output stream or the output part of a bi-directional stream.
+    if (outputStreamIdx != NAME_NOT_FOUND) {
+        deletedStream = mOutputStreams.editValueAt(outputStreamIdx);
         mOutputStreams.removeItem(id);
     }
 
@@ -1120,7 +1110,14 @@
     Mutex::Autolock l(mLock);
 
     mRequestThread->clear();
-    return mHal3Device->ops->flush(mHal3Device);
+    status_t res;
+    if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) {
+        res = mHal3Device->ops->flush(mHal3Device);
+    } else {
+        res = waitUntilDrained();
+    }
+
+    return res;
 }
 
 /**
@@ -1664,8 +1661,10 @@
             return;
         }
 
-        // Check if everything has arrived for this result (buffers and metadata)
-        if (request.haveResultMetadata && request.numBuffersLeft == 0) {
+        // Check if everything has arrived for this result (buffers and metadata), remove it from
+        // InFlightMap if both arrived or HAL reports error for this request (i.e. during flush).
+        if ((request.requestStatus != OK) ||
+                (request.haveResultMetadata && request.numBuffersLeft == 0)) {
             ATRACE_ASYNC_END("frame capture", frameNumber);
             mInFlightMap.removeItemsAt(idx, 1);
         }
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 468f641..9007a9b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -157,7 +157,6 @@
     camera3_device_t          *mHal3Device;
 
     CameraMetadata             mDeviceInfo;
-    vendor_tag_query_ops_t     mVendorTagOps;
 
     enum Status {
         STATUS_ERROR,
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index 5aa9a3e..dd7fb6c 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -199,14 +199,36 @@
     assert(mMaxSize == 0);
     assert(camera3_stream::format != HAL_PIXEL_FORMAT_BLOB);
 
-    mTotalBufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS +
-                        camera3_stream::max_buffers;
     mDequeuedBufferCount = 0;
     mFrameCount = 0;
 
     if (mConsumer.get() == 0) {
-        sp<BufferQueue> bq = new BufferQueue();
-        mConsumer = new BufferItemConsumer(bq, camera3_stream::usage,
+        sp<IGraphicBufferProducer> producer;
+        sp<IGraphicBufferConsumer> consumer;
+        BufferQueue::createBufferQueue(&producer, &consumer);
+
+        int minUndequeuedBuffers = 0;
+        res = producer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers);
+        if (res != OK || minUndequeuedBuffers < 0) {
+            ALOGE("%s: Stream %d: Could not query min undequeued buffers (error %d, bufCount %d)",
+                  __FUNCTION__, mId, res, minUndequeuedBuffers);
+            return res;
+        }
+        size_t minBufs = static_cast<size_t>(minUndequeuedBuffers);
+        /*
+         * We promise never to 'acquire' more than camera3_stream::max_buffers
+         * at any one time.
+         *
+         * Boost the number up to meet the minimum required buffer count.
+         *
+         * (Note that this sets consumer-side buffer count only,
+         * and not the sum of producer+consumer side as in other camera streams).
+         */
+        mTotalBufferCount = camera3_stream::max_buffers > minBufs ?
+            camera3_stream::max_buffers : minBufs;
+        // TODO: somehow set the total buffer count when producer connects?
+
+        mConsumer = new BufferItemConsumer(consumer, camera3_stream::usage,
                                            mTotalBufferCount);
         mConsumer->setName(String8::format("Camera3-InputStream-%d", mId));
     }
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.h b/services/camera/libcameraservice/device3/Camera3InputStream.h
index 681d684..ae49467 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.h
@@ -44,6 +44,8 @@
 
     virtual void     dump(int fd, const Vector<String16> &args) const;
 
+    // TODO: expose an interface to get the IGraphicBufferProducer
+
   private:
 
     typedef BufferItemConsumer::BufferItem BufferItem;
diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
index 1a54923..04deac5 100644
--- a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
@@ -109,15 +109,17 @@
 } // namespace anonymous
 
 Camera3ZslStream::Camera3ZslStream(int id, uint32_t width, uint32_t height,
-        int depth) :
+        int bufferCount) :
         Camera3OutputStream(id, CAMERA3_STREAM_BIDIRECTIONAL,
                             width, height,
                             HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
-        mDepth(depth) {
+        mDepth(bufferCount) {
 
-    sp<BufferQueue> bq = new BufferQueue();
-    mProducer = new RingBufferConsumer(bq, GRALLOC_USAGE_HW_CAMERA_ZSL, depth);
-    mConsumer = new Surface(bq);
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    mProducer = new RingBufferConsumer(consumer, GRALLOC_USAGE_HW_CAMERA_ZSL, bufferCount);
+    mConsumer = new Surface(producer);
 }
 
 Camera3ZslStream::~Camera3ZslStream() {
diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.h b/services/camera/libcameraservice/device3/Camera3ZslStream.h
index c7f4490..6721832 100644
--- a/services/camera/libcameraservice/device3/Camera3ZslStream.h
+++ b/services/camera/libcameraservice/device3/Camera3ZslStream.h
@@ -37,10 +37,10 @@
         public Camera3OutputStream {
   public:
     /**
-     * Set up a ZSL stream of a given resolution. Depth is the number of buffers
+     * Set up a ZSL stream of a given resolution. bufferCount is the number of buffers
      * cached within the stream that can be retrieved for input.
      */
-    Camera3ZslStream(int id, uint32_t width, uint32_t height, int depth);
+    Camera3ZslStream(int id, uint32_t width, uint32_t height, int bufferCount);
     ~Camera3ZslStream();
 
     virtual void     dump(int fd, const Vector<String16> &args) const;
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.h b/services/camera/libcameraservice/gui/RingBufferConsumer.h
index b4ad824..a03736d 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.h
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.h
@@ -64,7 +64,7 @@
     // bufferCount parameter specifies how many buffers can be pinned for user
     // access at the same time.
     RingBufferConsumer(const sp<IGraphicBufferConsumer>& consumer, uint32_t consumerUsage,
-            int bufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS);
+            int bufferCount);
 
     virtual ~RingBufferConsumer();
 
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index 683fdf3..0c7fbbd 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -54,7 +54,7 @@
     }
 }
 
-status_t MediaLogService::dump(int fd, const Vector<String16>& args)
+status_t MediaLogService::dump(int fd, const Vector<String16>& args __unused)
 {
     // FIXME merge with similar but not identical code at services/audioflinger/ServiceUtilities.cpp
     static const String16 sDump("android.permission.DUMP");
diff --git a/tools/resampler_tools/fir.cpp b/tools/resampler_tools/fir.cpp
index cc3d509..62eddca 100644
--- a/tools/resampler_tools/fir.cpp
+++ b/tools/resampler_tools/fir.cpp
@@ -20,15 +20,25 @@
 #include <stdlib.h>
 #include <string.h>
 
-static double sinc(double x) {
+static inline double sinc(double x) {
     if (fabs(x) == 0.0f) return 1.0f;
     return sin(x) / x;
 }
 
-static double sqr(double x) {
+static inline double sqr(double x) {
     return x*x;
 }
 
+static inline int64_t toint(double x, int64_t maxval) {
+    int64_t v;
+
+    v = static_cast<int64_t>(floor(x * maxval + 0.5));
+    if (v >= maxval) {
+        return maxval - 1; // error!
+    }
+    return v;
+}
+
 static double I0(double x) {
     // from the Numerical Recipes in C p. 237
     double ax,ans,y;
@@ -54,11 +64,12 @@
     return I0(beta * sqrt(1.0 - sqr((2.0*k)/N - 1.0))) / I0(beta);
 }
 
-
 static void usage(char* name) {
     fprintf(stderr,
-            "usage: %s [-h] [-d] [-s sample_rate] [-c cut-off_frequency] [-n half_zero_crossings] [-f {float|fixed}] [-b beta] [-v dBFS] [-l lerp]\n"
-            "       %s [-h] [-d] [-s sample_rate] [-c cut-off_frequency] [-n half_zero_crossings] [-f {float|fixed}] [-b beta] [-v dBFS] -p M/N\n"
+            "usage: %s [-h] [-d] [-s sample_rate] [-c cut-off_frequency] [-n half_zero_crossings]"
+            " [-f {float|fixed|fixed16}] [-b beta] [-v dBFS] [-l lerp]\n"
+            "       %s [-h] [-d] [-s sample_rate] [-c cut-off_frequency] [-n half_zero_crossings]"
+            " [-f {float|fixed|fixed16}] [-b beta] [-v dBFS] -p M/N\n"
             "    -h    this help message\n"
             "    -d    debug, print comma-separated coefficient table\n"
             "    -p    generate poly-phase filter coefficients, with sample increment M/N\n"
@@ -66,6 +77,7 @@
             "    -c    cut-off frequency (20478)\n"
             "    -n    number of zero-crossings on one side (8)\n"
             "    -l    number of lerping bits (4)\n"
+            "    -m    number of polyphases (related to -l, default 16)\n"
             "    -f    output format, can be fixed-point or floating-point (fixed)\n"
             "    -b    kaiser window parameter beta (7.865 [-80dB])\n"
             "    -v    attenuation in dBFS (0)\n",
@@ -77,8 +89,7 @@
 int main(int argc, char** argv)
 {
     // nc is the number of bits to store the coefficients
-    const int nc = 32;
-
+    int nc = 32;
     bool polyphase = false;
     unsigned int polyM = 160;
     unsigned int polyN = 147;
@@ -88,7 +99,6 @@
     double atten = 1;
     int format = 0;
 
-
     // in order to keep the errors associated with the linear
     // interpolation of the coefficients below the quantization error
     // we must satisfy:
@@ -104,7 +114,6 @@
     // Smith, J.O. Digital Audio Resampling Home Page
     // https://ccrma.stanford.edu/~jos/resample/, 2011-03-29
     //
-    int nz = 4;
 
     //         | 0.1102*(A - 8.7)                         A > 50
     //  beta = | 0.5842*(A - 21)^0.4 + 0.07886*(A - 21)   21 <= A <= 50
@@ -123,33 +132,33 @@
     //   100 dB   10.056
     double beta = 7.865;
 
-
     // 2*nzc = (A - 8) / (2.285 * dw)
     //      with dw the transition width = 2*pi*dF/Fs
     //
     int nzc = 8;
 
-    //
-    // Example:
-    // 44.1 KHz to 48 KHz resampling
-    // 100 dB rejection above 28 KHz
-    //   (the spectrum will fold around 24 KHz and we want 100 dB rejection
-    //    at the point where the folding reaches 20 KHz)
-    //  ...___|_____
-    //        |     \|
-    //        | ____/|\____
-    //        |/alias|     \
-    //  ------/------+------\---------> KHz
-    //       20     24     28
+    /*
+     * Example:
+     * 44.1 KHz to 48 KHz resampling
+     * 100 dB rejection above 28 KHz
+     *   (the spectrum will fold around 24 KHz and we want 100 dB rejection
+     *    at the point where the folding reaches 20 KHz)
+     *  ...___|_____
+     *        |     \|
+     *        | ____/|\____
+     *        |/alias|     \
+     *  ------/------+------\---------> KHz
+     *       20     24     28
+     *
+     * Transition band 8 KHz, or dw = 1.0472
+     *
+     * beta = 10.056
+     * nzc  = 20
+     */
 
-    // Transition band 8 KHz, or dw = 1.0472
-    //
-    // beta = 10.056
-    // nzc  = 20
-    //
-
+    int M = 1 << 4; // number of phases for interpolation
     int ch;
-    while ((ch = getopt(argc, argv, ":hds:c:n:f:l:b:p:v:")) != -1) {
+    while ((ch = getopt(argc, argv, ":hds:c:n:f:l:m:b:p:v:z:")) != -1) {
         switch (ch) {
             case 'd':
                 debug = true;
@@ -169,13 +178,26 @@
             case 'n':
                 nzc = atoi(optarg);
                 break;
+            case 'm':
+                M = atoi(optarg);
+                break;
             case 'l':
-                nz = atoi(optarg);
+                M = 1 << atoi(optarg);
                 break;
             case 'f':
-                if (!strcmp(optarg,"fixed")) format = 0;
-                else if (!strcmp(optarg,"float")) format = 1;
-                else usage(argv[0]);
+                if (!strcmp(optarg, "fixed")) {
+                    format = 0;
+                }
+                else if (!strcmp(optarg, "fixed16")) {
+                    format = 0;
+                    nc = 16;
+                }
+                else if (!strcmp(optarg, "float")) {
+                    format = 1;
+                }
+                else {
+                    usage(argv[0]);
+                }
                 break;
             case 'b':
                 beta = atof(optarg);
@@ -193,11 +215,14 @@
     // cut off frequency ratio Fc/Fs
     double Fcr = Fc / Fs;
 
-
     // total number of coefficients (one side)
-    const int M = (1 << nz);
+
     const int N = M * nzc;
 
+    // lerp (which is most useful if M is a power of 2)
+
+    int nz = 0; // recalculate nz as the bits needed to represent M
+    for (int i = M-1 ; i; i>>=1, nz++);
     // generate the right half of the filter
     if (!debug) {
         printf("// cmd-line: ");
@@ -207,7 +232,7 @@
         printf("\n");
         if (!polyphase) {
             printf("const int32_t RESAMPLE_FIR_SIZE           = %d;\n", N);
-            printf("const int32_t RESAMPLE_FIR_LERP_INT_BITS  = %d;\n", nz);
+            printf("const int32_t RESAMPLE_FIR_INT_PHASES     = %d;\n", M);
             printf("const int32_t RESAMPLE_FIR_NUM_COEF       = %d;\n", nzc);
         } else {
             printf("const int32_t RESAMPLE_FIR_SIZE           = %d;\n", 2*nzc*polyN);
@@ -224,7 +249,7 @@
         for (int i=0 ; i<=M ; i++) { // an extra set of coefs for interpolation
             for (int j=0 ; j<nzc ; j++) {
                 int ix = j*M + i;
-                double x = (2.0 * M_PI * ix * Fcr) / (1 << nz);
+                double x = (2.0 * M_PI * ix * Fcr) / M;
                 double y = kaiser(ix+N, 2*N, beta) * sinc(x) * 2.0 * Fcr;
                 y *= atten;
 
@@ -232,18 +257,20 @@
                     if (j == 0)
                         printf("\n    ");
                 }
-
                 if (!format) {
-                    int64_t yi = floor(y * ((1ULL<<(nc-1))) + 0.5);
-                    if (yi >= (1LL<<(nc-1))) yi = (1LL<<(nc-1))-1;
-                    printf("0x%08x, ", int32_t(yi));
+                    int64_t yi = toint(y, 1ULL<<(nc-1));
+                    if (nc > 16) {
+                        printf("0x%08x, ", int32_t(yi));
+                    } else {
+                        printf("0x%04x, ", int32_t(yi)&0xffff);
+                    }
                 } else {
                     printf("%.9g%s ", y, debug ? "," : "f,");
                 }
             }
         }
     } else {
-        for (int j=0 ; j<polyN ; j++) {
+        for (unsigned int j=0 ; j<polyN ; j++) {
             // calculate the phase
             double p = ((polyM*j) % polyN) / double(polyN);
             if (!debug) printf("\n    ");
@@ -254,9 +281,12 @@
                 double y = kaiser(i+N, 2*N, beta) * sinc(x) * 2.0 * Fcr;;
                 y *= atten;
                 if (!format) {
-                    int64_t yi = floor(y * ((1ULL<<(nc-1))) + 0.5);
-                    if (yi >= (1LL<<(nc-1))) yi = (1LL<<(nc-1))-1;
-                    printf("0x%08x", int32_t(yi));
+                    int64_t yi = toint(y, 1ULL<<(nc-1));
+                    if (nc > 16) {
+                        printf("0x%08x, ", int32_t(yi));
+                    } else {
+                        printf("0x%04x, ", int32_t(yi)&0xffff);
+                    }
                 } else {
                     printf("%.9g%s", y, debug ? "" : "f");
                 }
@@ -277,5 +307,3 @@
 }
 
 // http://www.csee.umbc.edu/help/sound/AFsp-V2R1/html/audio/ResampAudio.html
-
-